日期 | 作者 | 版本 | 说明 |
---|---|---|---|
2023.02.03 | Mr.Zheng | V1.1 | CAN通讯个人笔记,初版 |
目录
声明
最近刚刚做完一个较复杂项目,为强化巩固,准备写几篇笔记方便后续回溯,本篇重点是个人对CAN通讯的理解与实现,第一部分为CAN的模型架构,CAN的功能实现是第二部分,需要一定的编程基础,希望能够给初学者带来启发。
一、CAN的模型架构
1.CAN总线的通讯模型
CAN协议有不同的国际标准,设计之初需要确认标准,这里用ISO11898CAN 高速通信标准,它的通信速度为 5kbps至1Mbps。下述为此标准下的CAN总线通信模型
第一层:物理层:规定信号传输媒介、电平、硬件收发等
第二层:数据层:物理层接收有用数据进行报错、响应、通知等职能
第三层:网络层:数据传输地址管理
第四层:传输层:数据传输缓冲、排序与错误回溯
第五层:会话层:通讯环中的收发响应、数据收发
第六层:表示层:传输数据的格式转换
第七层:应用层:协议应用,功能表达,需求实现
2.CAN总线的通讯帧结构
以项目用到的某某协议进行CAN的扩展帧结构说明,提前声明,不同公司的CAN协议可能会有不同,这里用一种举例,后续应用换汤不换药基本用法完全一致
起始帧:1 bit 硬件自动生成
仲裁帧:29 bit 就是常说的CAN的ID!仲裁帧扩展ID结构看下一个表
控制帧:6 bit 这里是控制帧存放位置
数据帧:0-64 bit 这就是协议中数据具体传输位置了,收发协议确定后在这传
校验帧:15+1 bit 硬件自动生成
确认帧:2 bit 硬件自动生成
结束帧:7 bit 硬件自动生成
这里选用的扩展帧的方式通讯,仲裁帧的29个bit将会如下图拆分成五项段码
ID28-ID24 源ID:代表载体终端,比如说这个是电池程序就是电池协议ID
ID23-ID19 目标ID:代表联系终端,比如说电池想给bms发数据就填bmsID
ID18-ID16 控制命令:读/写/应答/错误应答/长起始/长传输/长结束/状态码
ID15-ID8 索引:字典型命令集,靠索引与子索引来定向调动命令集中的数据
ID7-ID0 子索引:同上,可以看成目录集的一级标题和二级标题关系
二、CAN协议通讯实现
这里开始附代码并讲解如何实现,不同的协议有差别但是思路完全一致,比如说我想写一个功能:控制器调用电池的当前实时数据,那么你首先就要去根据你的协议设定的各种功能或者数据的存放集合(后面我叫他字典集),写个对应ID的结构体以便于后面使用。
1.数据结构体
根据协议字典集合将你需要用到的数据先打包成结构体,里面根据需求存放一些数据,这也将会是你后面CAN数据传输的必经中转站,我这里直接敲个小demo:
typedef union
{
struct
{
uint8_t S0 : 8; //数据这里可以拆的更细
uint8_t S1 : 8; //占一位
uint16_t S2 : 16; //占两位
uint8_t S4 : 8;
} Sig;