学习CANopen | 您所在的位置:网站首页 › ode怎么读 › 学习CANopen |
文章目录
前言一 工作原理二 使用范围三 例子1. COB-ID分析2. 报文内容分析 --- 读操作命令提示符索引和子索引报文中的数据值
3. 报文内容分析 --- 写操作命令提示符索引和子索引报文中的数据值
3. Segment传输读的发起读的数据传输写的发起和数据传输
4. Block传输5. Abort
四 总结
前言
SDO是Service Data Object的缩写,中文叫服务数据对象,关键是这个服务二字,指的是读写服务,Client可以通过SDO读写Server里的对象字典(Object Dictionary,简称OD) OD存在于Server中,用户在和Server通信之前,也会有一份相同的OD表,不然没法继续操作。如果用户想读写OD里的值,那么就可以使用SDO。 PS:要记住:用户是Client,CANOpen设备是Server;如果2个CANOpen设备间互相通信,那么发起通信的那个就是Client,这里统一使用Client指代 一 工作原理SDO的收发有点像TCP,读写请求发送出去后必须要有一个来自Server的应答,如下图 Client一般都会设置个SDO超时时间,如果在规定时间内没有收到应答,Client这边就会报错。 PS:CANOpen文档里读叫upload,写叫download,感觉是从Server角度来看的 二 使用范围只有当Server处于Pre-Operational和Operational状态下,Client才可以使用SDO去和Server通信,如下图, 关于状态切换,请查看讲NMT的那篇文章。 三 例子下面讲例子,实战可以让理解更加深入,首先使用pythonCANOpen来创建2个文件:server.py和client.py,如下, ''' server.py ''' import signal import canopen import time running = True def sigint_handler(signum, frame): global running print('') running = False exit(0) # 处理按键发送的信号,优雅的关闭程序 signal.signal(signal.SIGINT, sigint_handler) signal.signal(signal.SIGHUP, sigint_handler) signal.signal(signal.SIGTERM, sigint_handler) # 创建一个网络用来表示CAN总线 network = canopen.Network() # 连接到CAN总线 network.connect(bustype='socketcan', channel='vcan0') # 创建slave节点,其id是6,对象字典为CANopenSocket.eds node = network.create_node(6, 'CANopenSocket.eds') # node向CAN总线上发送启动消息 node.nmt.send_command(0) # node进入PRE-OPERATIONAL状态 node.nmt.state = 'PRE-OPERATIONAL' # node发送心跳报文,每隔1s发送一次 node.nmt.start_heartbeat(1000) # 1000ms # 循环, 持续睡眠 while running: time.sleep(0.6)client.py如下, ''' client.py ''' import time import canopen # 创建一个网络用来表示CAN总线 network = canopen.Network() # 添加slave节点,其id是6,对象字典为CANopenSocket.eds node = canopen.RemoteNode(6, 'CANopenSocket.eds') network.add_node(node) # 连接到CAN总线 network.connect(bustype='socketcan', channel='vcan0') # 读取Index为0x2341,Subindex是2的OD项 data = node.sdo[0x2341][2].raw print('0x2341_02: 0x{:X}'.format(data)) time.sleep(2) # 修改Index为0x2341,Subindex是2的OD项 node.sdo[0x2341][2].raw = 0x123 time.sleep(2) # 再读一次验证一下 data = node.sdo[0x2341][2].raw print('0x2341_02: 0x{:X}'.format(data))PS:eds文件来自这个 然后创建vcan0, $ sudo modprobe vcan $ sudo ip link add dev vcan0 type vcan $ sudo ip link set up vcan0创建好之后开一个终端,然后使用candump进行观察, candump vcan0最后是运行,先运行server.py, python3 server.py接着运行client.py, python3 client.pyclient运行结束后,观察得到的CAN报文如下,有三组,注意数字都是16进制, 先看606和586,这2个是SDO报文的COB-ID, 对于发送的SDO报文来说,其COB-ID是0x600+设备id,例子中Server的id是6,所以是0x606,由Client发出,表示发给id是6的设备对于返回的应答报文来说,其COB-ID是0x580+设备id,例子中Server的id是6,所以是0x586,由Server发出,表示该报文是由id为6的设备返回的PS:0x600号0x580是专属于SDO的,且是固定的 2. 报文内容分析 — 读操作报文内容的基本结构如下,发送和接收的报文结构一样, 例子中第一个SDO报文是读取字典项0x2341_02,读操作对应的CS字节如下,注意这是一个字节, Server返回报文的CS值则需要考虑被读字典项的数据类型,n, e, s的含义如下, 例子中返回的CS是0x4B,转为二进制后得出:n值为10b,十进制数字为2,e=1b,s=1b,根据上述含义可以得出: 字节8-n到字节7,即字节6-7不包含数据,那么有效数据在字节4-5,总共2个字节e为1b表示这是expedited传输,意思是数据可以一次传输完成,可以想象只要数据字节数不大于4,那么都可以一次传输完成s为1b,但是在expedited传输里s是没有意义的,只有在e=0时s才有意义然后打开eds文件,找到0x2341_02对应的描述,如下, 字节1的值为0x41,字节2的值是0x23,从右往左读就是0x2341,即字典项的索引 字节3的值是0x02,也就是字典项的子索引 发送报文和返回报文在字节1~3写入的都是相同的索引和子索引 报文中的数据值发送报文的最后四个字节都是0,因为是读,这4个字节都是无意义的,虽然无意义,但是还是要传输,所以就写0 返回报文里字节5的值为0x7F,字节4的值为0xFF,合起来就是0x7FFF,与EDS文件里看到的这个字典项对应的默认值相同 3. 报文内容分析 — 写操作写操作的内容结构和读一样, 写操作的CS值如下, 返回报文的CS值则是固定的0x60,表示写入OK 索引和子索引与读操作相同,就是把0x2341_02写入到字节1~3里 报文中的数据值由于是写,所以在发送报文的字节4~5里填入期望的目标值,这里是0x123,字节4是0x23,字节5是0x01,字节6和7则为0 在返回报文里字节4~7都是无意义的,虽然无意义,但是还是要传输,所以都写0 3. Segment传输前面的读写操作都是expedited传输,即一个来回就能传输完成,要求数据长度 |
CopyRight 2018-2019 实验室设备网 版权所有 |