一.相关库的安装
-
wiringPi
链接网址: http://wiringpi.com/
一个函数库,在编程时节省底层汇编以操作pi的功能引脚,对pi的引脚也进行了再次编号。 -
BCM2835 C Library
链接网址: http://www.airspayce.com/mikem/bcm2835/
C Library可以理解为使用C语言实现的底层驱动(GPIO、SPI和UART等)
linux操作系统将 CAN 设备作为网络设备进行管理, 而且Linux 提供了SocketCAN 接口,允许同太网的socket通信一般地进行CAN 总线通信。(参考-炒鸡感谢这位博主分享了《Linux Can编程详解》)
使用 SocketCAN 实现通信。(参考华清远见)
二.编前测试
1.cansend:发送请求的命令。
命令格式:cansend {接口} {CAN-ID}#{数据}
(在CAN-ID和数据之间插入#)
2.用candump接受来自can总线的数据
接收格式:candump {接口},{CAN-ID}:{bitmask}
CAN-ID分别对应于不同的请求和响应。
bitmask指定要分配要获得的数据。(当它变成CAN-ID或bitmask自变量指定的CAN-ID时,我们就会获得比特运算所接收到的数据。)
3.开始接上BMS设备的can口后直接用candump接收没有反应,打开另一端口对BMS设备发送任意数据后出现:
多发了几次,结果出现了另一个问题:No buffer space available -----说缓冲区内存不足
而重启就可再发送了:
4.尝试解决buffer的问题,发现只能发11条。网上有人说是tx_queue_len的的问题:
先sudo ip link set can0 down
默认值为10,直接改成100试试
可以看到,之后果然cansend个几十条都没有报错。那就回到第一个问题,查看一下错误信息:
-
“ERROR-PASSIVE”:CAN控制器的当前状态:
-
“restart-ms 0”
自动重启的延时时间。如果设为非零值, 在总线关闭的情况下,在设定的数量毫秒后CAN控制器被自动触发。这个功能默认是关闭的。 -
tq 250 prop-seg 2 phase-seg1 3 phase-seg2 2 sjw 1
CAN比特时序参数:以ns为单位显示时间份额(tq-time quanta)、传播段(prop-seg : propagation segment)、相位缓冲段1和2(phase-seg:phase buffer),以tq为单位显示同步跳转宽度(sjw:synchronisation jump width)。这些变量允许定义与硬件无关。 -
“re-started bus-errors arbit-lost error-warn error-pass bus-off”
分别是显示重启的次数、总线和仲裁丢失错误,错误主动(error-warning)、错误被动(error-passive)、和总线关闭的状态变化。接收的过载错误在 统计信息的"overrun"域下面列出。
5.TX :将套接字缓冲区的CAN帧发送到CAN控制器;RX :从CAN控制器的CAN帧读取到套接字缓冲区。
5.再次尝试和解析:
打开另一终端,发送任意数据时:出现了bus-off:
CAN网络节点的三种状态:
1)主动错误,能正常的进行总线通信,错误产生时,发送主动错误帧。
2)被动错误,能够进行总线通信,错误产生时,发送被动错误帧。
3)总线关闭,不能收发任何报文。
对于bus-off也找到了比较好的回答:(参考what is CAN bus-off state ?和博友的CAN BusOff相关知识点)
(1)CAN控制器必须保留两个计数器,称为发送和接收错误计数器。它们从0开始,根据CAN标准指定的一组规则递增(在出现错误时)和递减(每当控制器执行成功的tx/rx时)。计数器的值影响控制器的错误处理模式(error-active和error-passive),并最终(当传输错误计数器超过255的值时)过渡到busoff状态。粗略地说,当控制器处于这种状态时,它就从总线断开。强制地,它停止传送和确认帧。它是否保持接收帧取决于实现。
(2)当一个CAN节点检测到错误时,它将发送错误帧,这将干扰总线通信,最终完全禁用其他节点的有效帧。为了防止这种情况,发送太多错误帧的节点将完全进入总线断开状态,在这种状态下,它不再参与流量。通常,总线断开是指向节点本身潜在问题的错误条件(错误配置…)。所有节点是因为(由于CAN的错误机制)总线上任何节点检测到的任何错误都会立即广播给(并由)所有其他节点计算,只有少数例外。
6.确实我的BMS充电均衡应该是烧坏了,会一直报错,可能是这个持续报错影响了其他节点的数据发送和接收,暂抛弃BMS,计划用Ardiuno加MCP2515来模拟BMS设备来测试发送和接收can口的数据(参考Github,Seeed-Studio大佬的分享、还有这位网友的经验贴):
接线图如下:
代码也是参考网友czw74,分享得BUS_CAN文件里的例子“send”,按其要求改了波特率设定:
(如果你的can总线波特率是500KBPS,
CAN.begin(CAN_1000KBPS) can通讯波特率设置为1000KBPS
差了1倍,原因是mcp_can.cpp的代码是以16MHz晶振的CAN总线模块编写的,而我们使用的MCP2515 CAN总线模块的晶振是8M的。所以代码里面要把CAN.begin()设高一倍。)
然鹅树莓派的接收端还是出现以上相似的错误:
can0 20000004 [8] 00 04 00 00 00 00 00 00 ERRORFRAME controller-problem {rx-error-warning}
然后折腾了一整天无果,找到一个问题帖,下面的cluse网友默默说了一句:
MCP2515模块,右下角那两个pin,要短路。
实在没有办法的时候蛮试了一下,把Arduino端接的MCP2515_CAN模块哪J1(jumper for 120Ω Termination),两个pin角短接后,竟然成功接收数据了:
测试成功,这是是什么原理呢,找了一下原理图:
这里有J1和J2 两个端口,然后我的canH/L 的线接在J2端口,此时是没有接上120Ω的电阻,而短接J1的两端口等于是在J2两端接上了一个120Ω的电阻,而接这个电阻干嘛用?
在这里也找到一位博主的解释(can总线为什么要有两个120的终端电阻):
既抗干扰:CAN总线两端必须连接终端电阻才可以正常工作,终端电阻应该与通讯电缆的阻抗相同,典型值为120欧姆.其作用是匹配总线阻抗,提高数据通信的抗干扰性及可靠行。