目录[-]
目录:
- 触发设置
- Python连接ZCANPRO
——————————————————————————————————————————————————
一、触发设置
比如当前有2个通道,can0和can1,有一个场景,就是我想要在通道0发送一个报文0x100,当发送成功后,再发送一个报文0x101,实现步骤如下
ZCANPRO—高级设置—触发设置,添加一个规则
看响应结果,在通道0发送0x100报文后,通道1收到0x100报文;同时,在通道1发送报文0x100,通道0收到0x101
造成这样的情况很简单,看上图,目前使用的是双并联短路接法,can0和can1通道的线路接在一起,导致通道0发送,通道1接收,但由于没有连接真实设备,所以只能造成这种情况
——————————————————————————————————————————————————
二、Python连接ZCANPRO
1、在ZLG官网,下载依赖文件:
- Visual C++,windows依赖库:https://manual.zlg.cn/Public/Uploads/2020-06-05/5ed995c271414.zip
- Python 对应不同型号的CAN盒的DEMO文件(必备):https://manual.zlg.cn/server/index.php?s=/api/attachment/visitFile/sign/badd984b5700b459d1c9bfa7fe473674
- 帮助文档:https://manual.zlg.cn/web/#/174/6441
2、Demo版下载并压缩后的目录结构
- 其中 zlgcan.py 是原版的Demo,新建的一个文件 ZLG_POST.py 是自己拆功能键的文件,目录如下
3、Demo版代码提取
- 本地使用的USB-CAN || 设备,包含在USB-CAN型号集合里
from zlgcan import *
import time
# 初始化数据
def reset_can_channel(zcanlib, dev_handle):
# 停止通道
zcanlib.ResetCAN(dev_handle)
# 重新初始化
chn_init_cfg = ZCAN_CHANNEL_INIT_CONFIG()
chn_init_cfg.can_type = ZCAN_TYPE_CAN
chn_init_cfg.config.can.timing0 = 0x00 # 波特率相关参数(低位) 500Kbps 波特率
chn_init_cfg.config.can.timing1 = 0x1C # 波特率相关参数(高位)
chn_handle = zcanlib.InitCAN(dev_handle, 0, chn_init_cfg)
zcanlib.StartCAN(chn_handle)
return chn_handle
# 主程序
def main():
# 周立功官方主控制类,用于操作USBCAN硬件,ZCAN()调用周立功底层DLL(zlgcan.dll),该DLL负责与硬件通信
# 1、创建控制实例
zcanlib = ZCAN()
# 2、打开 ZCAN_USB 设备
dev_handle = zcanlib.OpenDevice(ZCAN_USBCAN2, 0, 0)
if dev_handle == INVALID_DEVICE_HANDLE:
print("打开设备失败!")
return
# 3、初始化 CAN 通道
chn_handle = reset_can_channel(zcanlib, dev_handle)
# 3.1 判断通道是否连接
if chn_handle == INVALID_CHANNEL_HANDLE:
print("初始化通道失败!")
zcanlib.CloseDevice(dev_handle)
return
# 4、启动通道
zcanlib.StartCAN(chn_handle)
print("设备已启动,等待2秒...")
time.sleep(2)
# 发送自发自收报文(单个报文)
# msgs = (ZCAN_Transmit_Data * 1)()
# msgs[0].frame.can_id = 0x100
# msgs[0].frame.can_dlc = 8
# msgs[0].frame.data = (00, 11, 22, 33, 44, 55, 66, 77)
# # 第一次:自发自收(可能被覆盖)
# msgs[0].transmit_type = 2 # 自发自收
# zcanlib.Transmit(chn_handle, msgs, 1)
# # 第二次:正常发送(刷新队列)
# msgs[0].transmit_type = 0 # 正常发送
# ret = zcanlib.Transmit(chn_handle, msgs, 1)
# 报文发送数量
# transmit_num = 10
# 5、发送报文
msgs = (ZCAN_Transmit_Data * len(frame_list))()
# print(memset(byref(msgs), 0, sizeof(msgs)))
# 5.1 普通发送,刷新队列
msgs[0].transmit_type = 0 # 正常发送
zcanlib.Transmit(chn_handle, msgs, 1)
# 5.2 主要运行报文内容
for i in range(len(frame_list)):
# print(i)
msgs[i].transmit_type = 2 # 2自发自收,0普通发送
msgs[i].frame.eff = 0 # extern frame
msgs[i].frame.rtr = 0 # remote frame
msgs[i].frame.can_id = 0x200 # 报文ID
# msgs[i].frame.data = (00, 11, 22, 33, 44, 55, 66, 77)
msgs[i].frame.can_dlc = 8 # 报文长度
msgs[i].frame.__pad = 0x80 # 队列发送,0x80单位ms,0xc0单位是100us
msgs[i].frame.__res0 = 0x64 # 帧间隔低位,定时100ms,6*16^1+4*16^0=96+4=100
msgs[i].frame.__res1 = 0xc8 # 帧间隔高位,定时200ms,12*16^1+8*16^0=192+8=200
# 报文内容
msgs[i].frame.data = frame_list[i]
# 5.3 发送报文
ret = zcanlib.Transmit(chn_handle, msgs, len(frame_list))
print(f"发送结果: {ret} (0=成功)")
# 5.4 接收数据(增加重试机制)
max_retry = 3
for _ in range(max_retry):
# 此时可以读到第一次的自发自收报文
rcv_num = zcanlib.GetReceiveNum(chn_handle, ZCAN_TYPE_CAN)
# print(rcv_num)
if rcv_num > 0:
rcv_msg, _ = zcanlib.Receive(chn_handle, rcv_num)
for i in range(rcv_num):
print(f"收到报文: ID={hex(rcv_msg[i].frame.can_id)}, Data={list(rcv_msg[i].frame.data[:rcv_msg[i].frame.can_dlc])}")
break
time.sleep(0.5) # 每次重试间隔500ms
else:
print("未收到数据")
# 6、清除库接收缓存区
zcanlib.ClearBuffer(dev_handle)
# 6.1 启动通道前复位(关键!)
zcanlib.ResetCAN(dev_handle) # 复位通道0
time.sleep(2) # 关键!等待硬件完全复位
# 6.2 关闭设备
zcanlib.CloseDevice(dev_handle)
if __name__ == "__main__":
frame_list=[(0,1,2,3,4,5,6,7),
(1,2,3,4,5,6,7,8),
(10,20,30,40,50,60,70)]
main()
波特率对照表
4、Python 与 CAN盒连接
- 在保证本地使用 ZCANPRO 可以成功连接到硬件并且可以正确发送和接收报文后,就可以尝试Python连接了,运行后,显示如下信息
5、异常情况解析:
- 设备连接失败:本地是否存在已连接CAN盒的情况,比如ZCANPRO已经连接了硬件设备,而此时还用python调用,就会提示错误,需要在软件关闭通道并停止设备
- python运行库报错,如找不到zlgcan文件等等情况,都是python相关的错误,一一排查即可解决,python需要用到至少3.6版本
- 运行时,第一次运行返回报文,但是第二次运行就不返回报文,这是由于,当transmit_type=2(自发自收)时,报文会同时写入“发送队列”和“接收队列”,如果队列满时,硬件暂停发送,但已存入接收队列的自发自收报文仍存在,所以需要再发一次“正常报文”,强制刷新队列,否则永远也不能得到响应报文
END