网上上对CAN总线的介绍很多,对于CAN总线的介绍就到这了。接下来是对硬件的搭建。前文说过了硬件使用的是树莓派与MCP2515模块。
MCP2515模块
MCP2515是一个CAN总线控制器,其实上面还集成了一个CAN收发器。但是由于MCP2515占主要功能(将SPI总线扩展称CAN总线),因此我们就暂且叫它MCP2515模块吧。
![](https://i-blog.csdnimg.cn/blog_migrate/e7d5f64b32f84432d4c707341a845bae.png)
树莓派
树莓派是一个基于Linux系统的卡片型电脑,相对于单片机来说,它的性能是非常强大的。树莓派上有40个引脚可以用来扩展一些外部设备。树莓派上没有自带CAN总线的,但是可以通过SPI接口,通过MCP2515模块扩展出一个CAN总线处理。因此需要将是,树莓派的SPI总线与模块的SPI总线相连。网上也有很多配置树莓派的CAN通讯文章。参考文章:微雪电子
功能引脚 | 树莓派(BCM) | 描述 |
3.3V | 3.3V | 3.3V电源正 |
GND | GND | 电源地 |
SCK | SCK | SPI时钟 |
MOSI | MOSI | SPI数据输入 |
MISO | MISO | SPI数据输出 |
CS | CS | 片选信号 |
INT | 25 | 中断接口 |
配置开发环境
在连接好硬件线之后之后,通过以下可以查看内核是否正确加载好模块。
dmesg | grep -i '\(can\|spi\)'
接下来就是配置开发环境了。首先是安装Python-CAN模块。这个模块非常有用。通过官方文档我们可以看到,它支持非常多种的CAN设备。例如: SocketCAN,Kvaser’s CANLIB,CAN over Serial,CAN over Serial / SLCAN,IXXAT Virtual CAN Interface,PCAN Basic API,USB2CAN Interface,NI-CAN,isCAN,NEOVI Interface,Vector,Virtual,CANalyst-II,SYSTEC interface。市场上大部分的CAN设备都能使用。我们这次使用的是SocketCAN,Linux 提供了SocketCAN 接口,使得 CAN 总线通信近似于和以太网的通信,应用程序开发接口 更加通用, 也更加灵活。
本次开发主要使用的是基于Python的UDS。为什么要选择Python语言呢?首先就是C语言需要根据平台的不同需要编译,而不同平台对CAN接口的定义都是不一样的。调用方式都可能有很大的不同。而Python就不一样了。使用Python-CAN模块能跨平台开发,这样我们在window上写好的代码,只需要复制就能移植到Linux平台。如果只想快速开发,学习通信协议,并不想纠结与C语言代码的调试,那么Python是最好的选择了。
在安装好udsoncan之后,我们就官方例程进行中文注释一下吧。
import SomeLib.SomeCar.SomeModel as MyCar #导入一个汽车模型配置
import udsoncan #导入uds库
from udsoncan.connections import IsoTPSocketConnection #从uds库中导入连接方式
from udsoncan.client import Client #从uds库中导入客户端
from udsoncan.exceptions import * #从uds库中导入出错方式
from udsoncan.services import * #从uds库中导入服务列表
udsoncan.setup_logging() #开始记录数据
conn = IsoTPSocketConnection('can0', rxid=0x123, txid=0x456) #设置连接端口为can0,接受数帧id,发送帧id
with Client(conn, request_timeout=2, config=MyCar.config) as client:#初始化客户端,注意要加载配置文件
try:
client.change_session(DiagnosticSessionControl.Session.extendedDiagnosticSession) # 将控制器改为扩展会话
client.unlock_security_access(MyCar.debug_level) # Fictive security level. Integer coming from fictive lib, let's say its value is 5 安全验证
client.write_data_by_identifier(udsoncan.DataIdentifier.VIN, 'ABC123456789') #修改汽车的VIN号 # Standard ID for VIN is 0xF190. Codec is set in the client configuration
print('Vehicle Identification Number successfully changed.')
client.ecu_reset(ECUReset.ResetType.hardReset) # 重启ECU
except NegativeResponseException as e:
print('Server refused our request for service %s with code "%s" (0x%02x)' % (e.response.service.get_name(), e.response.code_name, e.response.code))
except InvalidResponseException, UnexpectedResponseException as e:
print('Server sent an invalid payload : %s' % e.response.original_payload)