简述CAN总线
最近公司开发CAN总线项目,以前也学习了,没有实际的用于项目制作,现在具体的总结一下,也是借鉴了很多大神的资料,站在巨人的肩膀之上写下来这篇文章
CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信
协议。在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种
各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求
不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、
“通过多个 LAN,进行大量数据的高速通信”的需要,1986 年德国电气商博世公司开发出面
向汽车的 CAN 通信协议。此后,CAN 通过 ISO11898 及 ISO11519 进行了标准化,现在在欧
洲已是汽车网络的标准协议。
现在,CAN 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设
备、工业设备等方面。现场总线是当今自动化领域技术发展的热点之一,被誉为自动化领域的
计算机局域网。它的出现为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有
力的技术支持。
CAN 控制器根据两根线上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,
二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。
CAN 协议具有一下特点:
1) 多主控制。在总线空闲时,所有单元都可以发送消息(多主控制),而两个以上的单元
同时开始发送消息时,根据标识符(Identifier 以下称为 ID)决定优先级。ID 并不是
表示发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时开始
发送消息时,对各消息 ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级
最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。
2) 系统的柔软性。与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单
元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。
3) 通信速度较快,通信距离远。最高 1Mbps(距离小于 40M),最远可达 10KM(速率低
于 5Kbps)。
4) 具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),
检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单
元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新
发送此消息直到成功发送为止(错误恢复功能)。
5) 故障封闭功能。CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)
还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上
发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。
6) 连接节点多。CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没
有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通
信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。
正是因为 CAN 协议的这些特点,使得 CAN 特别适合工业过程监控设备的互连,因此,越
来越受到工业界的重视,并已公认为最有前途的现场总线之一。
CAN 协议经过 ISO 标准化后有两个标准:ISO11898标准和 ISO11519-2 标准。其中 ISO11898
是针对通信速率为 125Kbps~1Mbps 的高速通信标准,而 ISO11519-2 是针对通信速率为 125Kbps
以下的低速通信标准。
本章,我们使用的是 450Kbps 的通信速率,使用的是 ISO11898 标准,该标准的物理层特
征如图 30.1.1 所示:
们所要设置的寄存器CAN1->sFilterRegister[ x ].FR1便是如上图所说的标识符屏蔽模式中的 ID,
而CAN1->sFilterRegister[ x ].FR2, 就是屏蔽寄存器; 在标识符列表模式中,两者都是ID。
我们按上面的格式去设置寄存器:
标准ID / 拓展ID + IDE + RTR + x 。
已知 IDE = 0 代表标准ID, IDE =1 代表拓展ID; RTR = 0代表数据帧,RTR = 1代表远程帧;
那么,我们给个例子:
标识符列表 ID = 0x09 拓展帧 :
CAN1->sFilterRegister[0].FR1=0x09<<3|0x04; //id=0x01,拓展帧数据
CAN1->sFilterRegister[0].FR2=0x09<<3|0x04; //标识符列表,相同
过滤寄存器如此设置就能过滤拓展帧的id为0x09的数据了
标识符屏蔽 ID = 0x11 标准帧 :
CAN1->sFilterRegister[1].FR1=0x11<<21|0x04; //标准id, 0x04为屏蔽模式,
CAN1->sFilterRegister[1].FR2=0xffc00004; //id全部屏蔽,IDE屏蔽,RTR屏蔽
过滤器如此设置就能过滤标准帧id为0x11的数据。
为了使工程更加有条理,我们把CAN控制器相关的代码独立分开存储,方便以后移植。在"串口实验"之上新建"bsp_can.c"及"bsp_can.h"文件,这些文件也可根据您的喜好命名,它们不属于STM32标准库的内容,是由我们自己根据应用需要编写的。
1. 编程要点
(1) 初始化CAN通讯使用的目标引脚及端口时钟;
(2) 使能CAN外设的时钟;
(3) 配置CAN外设的工作模式、位时序以及波特率;
(4) 配置筛选器的工作方式;
(5) 编写测试程序,收发报文并校验。
2. 代码分析
CAN硬件相关宏定义
我们把CAN硬件相关的配置都以宏的形式定义到"bsp_can.h"文件中,见代码清单 242。
代码清单 404 CAN硬件配置相关的宏(bsp_can.h文件)
1
2 /*CAN硬件相关的定义*/
3 #define CANx CAN1
4 #define CAN_CLK RCC_APB1Periph_CAN1
5 /*接收中断号*/
6 #define CAN_RX_IRQ CAN1_RX0_IRQn
7 /*接收中断服务函数*/
8 #define CAN_RX_IRQHandler CAN1_RX0_IRQHandler
9
10 /*引脚*/
11 #define CAN_RX_PIN GPIO_Pin_8
12 #define CAN_TX_PIN GPIO_Pin_9
13 #define CAN_TX_GPIO_PORT GPIOB
14 #define CAN_RX_GPIO_PORT GPIOB
15 #define CAN_TX_GPIO_CLK RCC_AHB1Periph_GPIOB
16 #define CAN_RX_GPIO_CLK RCC_AHB1Periph_GPIOB
17 #define CAN_AF_PORT GPIO_AF_CAN1
18 #define CAN_RX_SOURCE GPIO_PinSource8
19 #define CAN_TX_SOURCE GPIO_PinSource9
以上代码根据硬件连接,把与CAN通讯使用的CAN号、引脚号、引脚源以及复用功能映射都以宏封装起来,并且定义了接收中断的中断向量和中断服务函数,我们通过中断来获知接收FIFO的信息。
初始化CAN的 GPIO
利用上面的宏,编写CAN的初始化函数,见代码清单 243。
代码清单 405 CAN的GPIO初始化函数(bsp_can.c文件)
1 /*
2 * 函数名:CAN_GPIO_Config
3 * 描述:CAN的GPIO 配置
4 * 输入:无
5 * 输出 : 无
6 * 调用:内部调用
7 */
8 static void CAN_GPIO_Config(void)
9 {
10 GPIO_InitTypeDef GPIO_InitStructure;
11
12 /* 使能GPIO时钟*/
13 RCC_AHB1PeriphClockCmd(CAN_TX_GPIO_CLK|CAN_RX_GPIO_CLK, ENABLE);
14
15 /* 引脚源*/
16 GPIO_PinAFConfig(CAN_TX_GPIO_PORT, CAN_RX_SOURCE, CAN_AF_PORT);
17 GPIO_PinAFConfig(CAN_RX_GPIO_PORT, CAN_TX_SOURCE, CAN_AF_PORT);
18
19 /* 配置 CAN TX 引脚 */
20 GPIO_InitStructure.GPIO_Pin = CAN_TX_PIN;
21 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
22 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
23 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
24 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
25 GPIO_Init(CAN_TX_GPIO_PORT, &GPIO_InitStructure);
26
27 /* 配置 CAN RX 引脚 */
28 GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN ;
29 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
30 GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
31 }
与所有使用到GPIO的外设一样,都要先把使用到的GPIO引脚模式初始化,配置好复用功能。CAN的两个引脚都配置成通用推挽输出模式即可。
配置CAN的工作模式
接下来我们配置CAN的工作模式,由于我们是自己用的两个板子之间进行通讯,波特率之类的配置只要两个板子一致即可。如果您要使实验板与某个CAN总线网络的通讯的节点通讯,那么实验板的CAN配置必须要与该总线一致。我们实验中使用的配置见代码清单 244。
代码清单 406 配置CAN的工作模式(bsp_can.c文件)
1 /*
2 * 函数名:CAN_Mode_Config
3 * 描述:CAN的模式配置
4 * 输入:无
5 * 输出 : 无
6 * 调用:内部调用
7 */
8 static void CAN_Mode_Config(void)
9 {
10 CAN_InitTypeDef CAN_InitStructure;
11 /************************CAN通信参数设置************************/
12 /* Enable CAN clock */
13 RCC_APB1PeriphClockCmd(CAN_CLK, ENABLE);
14
15 /*CAN寄存器初始化*/
16 CAN_DeInit(CAN1);
17 CAN_StructInit(&CAN_InitStructure);
18
19 /*CAN单元初始化*/
20 CAN_InitStructure.CAN_TTCM=DISABLE; //MCR-TTCM 关闭时间触发通信模式使能
21 CAN_InitStructure.CAN_ABOM=ENABLE; //MCR-ABOM 使能自动离线管理
22 CAN_InitStructure.CAN_AWUM=ENABLE; //MCR-AWUM 使用自动唤醒模式
23 CAN_InitStructure.CAN_NART=DISABLE; //MCR-NART 禁止报文自动重传
24 CAN_InitStructure.CAN_RFLM=DISABLE; //MCR-RFLM 接收FIFO 不锁定
25 // 溢出时新报文会覆盖原有报文
26 CAN_InitStructure.CAN_TXFP=DISABLE; //MCR-TXFP 发送FIFO优先级取决于报文标示符
27 CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; //正常工作模式
28 CAN_InitStructure.CAN_SJW=CAN_SJW_2tq; //BTR-SJW 重新同步跳跃宽度 2个时间单元
29
30 /* ss=1 bs1=5 bs2=3 位时间宽度为(1+5+3) 波特率即为时钟周期tq*(1+3+5) */
31 CAN_InitStructure.CAN_BS1=CAN_BS1_5tq; //BTR-TS1 时间段1 占用了5个时间单元
32 CAN_InitStructure.CAN_BS2=CAN_BS2_3tq; //BTR-TS1 时间段2 占用了3个时间单元
33
34 /* CAN Baudrate = 1 MBps (1MBps已为stm32的CAN最高速率) (CAN 时钟频率为 APB 1 = 45 MHz) */
35 ////BTR-BRP 波特率分频器定义了时间单元的时间长度 45/(1+5+3)/5=1 Mbps
36 CAN_InitStructure.CAN_Prescaler =5;
37 CAN_Init(CANx, &CAN_InitStructure);
38 }
这段代码主要是把CAN的模式设置成了正常工作模式,如果您阅读的是"CAN—回环测试"的工程,这里是被配置成回环模式的,除此之外,两个工程就没有其它差别了。
代码中还把位时序中的BS1和BS2段分别设置成了5Tq和3Tq,再加上SYNC_SEG段,一个CAN数据位就是9Tq了,加上CAN外设的分频配置为5分频,CAN所使用的总线时钟fAPB1 = 45MHz,于是我们可计算出它的波特率:
1Tq = 1/(45M/5)=1/9 us
T1bit=(5+3+1) x Tq =1us
波特率=1/T1bit =1Mbps
配置筛选器
以上是配置CAN的工作模式,为了方便管理接收报文,我们还要把筛选器用起来,见代码清单 245。
代码清单 407 配置CAN的筛选器(bsp_can.c文件)
1
2 /*IDE位的标志*/
3 #define CAN_ID_STD ((uint32_t)0x00000000) /*标准ID */
4 #define CAN_ID_EXT ((uint32_t)0x00000004) /*扩展ID */
5
6 /*RTR位的标志*/
7 #define CAN_RTR_Data ((uint32_t)0x00000000) /*数据帧 */
8 #define CAN_RTR_Remote ((uint32_t)0x00000002) /*远程帧*/
9
10 /************************************************************************/
11 /*
12 * 函数名:CAN_Filter_Config
13 * 描述:CAN的筛选器配置
14 * 输入:无
15 * 输出 : 无
16 * 调用:内部调用
17 */
18 static void CAN_Filter_Config(void)
19 {
20 CAN_FilterInitTypeDef CAN_FilterInitStructure;
21
22 /*CAN筛选器初始化*/
23 CAN_FilterInitStructure.CAN_FilterNumber=0; //筛选器组0
24 //工作在掩码模式
25 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
26 //筛选器位宽为单个32位。
27 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
28
29 /* 使能筛选器,按照标志符的内容进行比对筛选,
30 扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */
31//要筛选的ID高位,第0位保留,第1位为RTR标志,第2位为IDE标志,从第3位开始是EXID
32CAN_FilterInitStructure.CAN_FilterIdHigh= ((((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
33 //要筛选的ID低位
34 CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
35 //筛选器高16位每位必须匹配
36 CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0xFFFF;
37 //筛选器低16位每位必须匹配
38 CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0xFFFF;
39 //筛选器被关联到FIFO0
40 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0 ;
41 //使能筛选器
42 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
43
44 CAN_FilterInit(&CAN_FilterInitStructure);
45 /*CAN通信中断使能*/
46 CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE);
47 }
这段代码把筛选器第0组配置成了32位的掩码模式,并且把它的输出连接到接收FIFO0,若通过了筛选器的匹配,报文会被存储到接收FIFO0。
筛选器配置的重点是配置ID和掩码,根据我们的配置,这个筛选器工作在图 4017中的模式。
图 4017 一个32位的掩码模式筛选器
在该配置中,结构体成员CAN_FilterIdHigh和CAN_FilterIdLow存储的是要筛选的ID,而CAN_FilterMaskIdHigh和CAN_FilterMaskIdLow存储的是相应的掩码。在赋值时,要注意寄存器位的映射,在32位的ID中,第0位是保留位,第1位是RTR标志,第2位是IDE标志,从第3位起才是报文的ID(扩展ID)。
因此在上述代码中我们先把扩展ID"0x1314"、IDE位标志"宏CAN_ID_EXT"以及RTR位标志"宏CAN_RTR_DATA"根据寄存器位映射组成一个32位的数据,然后再把它的高16位和低16位分别赋值给结构体成员CAN_FilterIdHigh和CAN_FilterIdLow。
而在掩码部分,为简单起见我们直接对所有位赋值为1,表示上述所有标志都完全一样的报文才能经过筛选,所以我们这个配置相当于单个ID列表的模式,只筛选了一个ID号,而不是筛选一组ID号。这里只是为了演示方便,实际使用中一般会对不要求相等的数据位赋值为0,从而过滤一组ID,如果有需要,还可以继续配置多个筛选器组,最多可以配置28个,代码中只是配置了筛选器组0。
对结构体赋值完毕后调用库函数CAN_FilterInit把个筛选器组的参数写入到寄存器中。
配置接收中断
在配置筛选器代码的最后部分我们还调用库函数CAN_ITConfig使能了CAN的中断,该函数使用的输入参数宏CAN_IT_FMP0表示当FIFO0接收到数据时会引起中断,该接收中断的优先级配置如下,见代码清单 246。
代码清单 408 配置CAN接收中断的优先级(bsp_can.c文件)
1 /*接收中断号*/
2 #define CAN_RX_IRQ CAN1_RX0_IRQn
3 /*
4 * 函数名:CAN_NVIC_Config
5 * 描述:CAN的NVIC 配置,第1优先级组,0,0优先级
6 * 输入:无
7 * 输出 : 无
8 * 调用:内部调用
9 */
10 static void CAN_NVIC_Config(void)
11 {
12 NVIC_InitTypeDef NVIC_InitStructure;
13 /* Configure one bit for preemption priority */
14 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
15 /*中断设置*/
16 NVIC_InitStructure.NVIC_IRQChannel = CAN_RX_IRQ; //CAN RX中断
17 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
上一篇:结构体变量和结构体类型的定义
下一篇:STM32低功耗停止模式 以及简述判断中断的两种方式
推荐阅读最新更新时间:2024-11-16 23:39
设计资源 培训 开发板 精华推荐
- DC919A-D,LTC2204 CMOS 输出演示板,直流输入,40Msps 16 位 ADC,DC
- 适用于串行 EEPROM 的 I2C(内部集成电路)总线控制器参考设计
- 用于基础设施的 1.2V MOSFET 功率驱动器
- DER-30 - 3.3W 非隔离反激式转换器
- TB2926HQ 45W x 4ch BTL 音频电源典型应用
- 使用 Microchip Technology 的 MIC35302 的参考设计
- [实测通过]AC6905AMP3集成应急移动电源升压
- LTC3562 配置在具有按钮控制和电源排序的四通道降压转换器中
- DINGHOME_HK32F103
- LM2904EDR2G 电压基准运算放大器的典型应用
- Allegro MicroSystems 在 2024 年德国慕尼黑电子展上推出先进的磁性和电感式位置感测解决方案
- 左手车钥匙,右手活体检测雷达,UWB上车势在必行!
- 狂飙十年,国产CIS挤上牌桌
- 神盾短刀电池+雷神EM-i超级电混,吉利新能源甩出了两张“王炸”
- 浅谈功能安全之故障(fault),错误(error),失效(failure)
- 智能汽车2.0周期,这几大核心产业链迎来重大机会!
- 美日研发新型电池,宁德时代面临挑战?中国新能源电池产业如何应对?
- Rambus推出业界首款HBM 4控制器IP:背后有哪些技术细节?
- 村田推出高精度汽车用6轴惯性传感器
- 福特获得预充电报警专利 有助于节约成本和应对紧急情况
- EEworld新春感恩回馈之ST新出道“高富帅”STM32F746G-DISCO 199元包邮
- 瑞萨电子边缘AI 技术研讨会——深圳站, 火热报名中,参会有好礼!
- 有奖直播:恩智浦基于RT06F的人脸识别技术解决方案
- ST传感器闯天下之驱动移植大赛+骨振动传感器评测,分高者胜
- 【EEWORLD第二十二届社区明星人物】畅想十二月明星人物揭晓!
- TI有奖直播|如何进行更加快速、简单且成本更低的AI 摄像头应用的开发
- 抢先体验NUCLEO家族新贵,ST STM32 NUCLEO-F091RC开发板28元包邮!
- 帮助他人,成就自己:EEWORLD月度问答榜(第5期)
- MPS有奖活动|绿色AI“芯” 动力,探索节能低碳的AI供电方案!