STM32学习笔记(十) CAN通讯测试(环回模式)
1.CAN通讯的理解
想学习CAN通讯,那么要对通讯协议有一定的认知。通讯协议是指通信双方对数据传送控制的一种约定。约定中包括对数据格式,同步方式,传输速度,传送步骤,检纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。
CAN通讯全称控制器局域网通讯,是用来在局域网中高效传输,处理信息的一种通讯方式。它采用数据块编码的方式,数据块根据帧类型的不同有四种格式,可使不同的节点接收到相同的数据,然后再根据各节点内CAN配置选择处理还是丢弃该信息(这与TCP/IP协议栈的链路层的MAC地址过滤很相似,是可以互通理解的),CAN的位流是按照非归零(NRZ)码方式编码,一个完整的位电平有显性和隐性两种方式。显性和隐性是根据CAN总线上的差分电压VCAN1H-VCAN1L, 若小于阈值则为隐性位,代表逻辑1,大于阈值则为显性位,代表逻辑0,这种将单电平转换成两根差分线的方式提高了电路的可靠性,不过也决定局域网里同时只能有一路数据传输,因此CAN通讯是半双工的。
2.CAN通讯帧格式
CAN报文有四种不同的帧类型:
(1).数据帧:数据帧将数据从发送器传输到接收器。
数据帧和可以使用标准帧和扩展帧两种格式。它们用一个帧间空间与前面的帧分隔。
1).帧起始(SOF) 标志帧的开始,由一个“显性(0)”位构成。只有在总线空闲时才允许节点发送(信号),其它所有节点必须同步于首先开始发送报文的节点的帧起始前沿。
2).仲裁场 由标识符和传送帧类型(RTR)组成的仲裁场
标准帧格式:
扩展帧格式:
对于数据帧 RTR恒为0,SRR恒为1,因此可以根据仲裁场起始第12个字符数判断是标准帧还是扩展帧。
3).控制场 保留位R1,R0(恒为0),以及帧长度选择位DLC(4位)构成的。
4).数据场 由数据帧里的发送数据组成,长度由DLC控制,但小于等于8字节。
5).CRC场 由CRC序列(CRC Sequence),以及CRC界定符(CRC Delimiter)构成。CRC序列之后是CRC界定符,它包含一个单独的“隐性(1)”位。
6).应答场(ACK Field) 2位,包含应答间隙(ACK Slot)和应答界定符(ACK Delimiter),当接收器正确地接收到有效的报文,接收器就会在应答间隙(ACK Slot)中写入显性位(0),在返回给发送器,完成一次通讯(半双工).
① 应答间隙
所有接收到匹配CRC序列的节点会在应答间隙期间用“显性(0)”的位写入发送器的“隐性(1)”位来组成应答数据。
② 应答界定符
应答界定符是应答场的第二位,并且必须为“隐性(1)”的位。因此,应答间隙(ACK Slot)被两个“隐性”的位所包围,也就是CRC界定符和应答界定符。
7).帧结束 由7个隐性位构成,代表帧的结束。
(2).远程帧:总线节点发出远程帧,请求发送具有同一识别符的数据帧。
远程帧除了RTR位默认为1,没有数据场外,其它与数据帧相同,不在赘述。
(3).错误帧:报文发送过程中,检测到任一节点出错,即于下一位发送出错帧,通知发送端停止发送。
错误标志:有两种形式的错误标志:激活错误标志和认可错误标志。
1).激活错误”标志由6个连续的“显性”位组成
2).“认可错误”标志由6个连续的“隐性”的位组成,除非被其他节点的“显性”位重写。
错误界定符:错误界定符包括8个“隐性”的位。
错误标志传送了以后,每一个节点就发送一个“隐性”的位,并一直监视总线直到检测出一个“隐性”的位为止,然后就开始发送其余7个“隐性”位。
(4).过载帧:接收端用于要求发送端延缓发送下一个数据帧或者远程帧。
1).超载标志: 过载标志由6个“显性”的位组成。过载标志的所有形式和“激活错误”标志的一样
2).过载界定符包括8个“隐性”的位,具体动作与错误界定符一致
CAN通讯是数据块编码的半双工通讯方式,没有主从设备区别,因此发出报文的节点为该报文的发送器,该节点在总线空闲或丢失仲裁前恒为发送器;如果一个节点不是报文发送器,并且总线不处于空闲状态,则该节点为接收器。
3.CAN通讯的STM32实现
CAN协议是比较复杂的一种通讯协议,因此需要在学习如何使用stm32实现前了解协议本身的很多内容,下面就可以开始stm32中CAN协议环回测试,用来简单的理解CAN协议的测试。既然是要STM32实现,那么步骤的设计如下:
(1).工作原理图
了解了CAN通讯,下面进入正题,CAN通讯连接首先看原理图如下:
从上面可以看出CAN1_TX: PD1 CAN1_RX PD0
(2).CAN硬件驱动配置
CAN通讯端口配置还是比较简单的:
GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStructure.GPIO_Pin = CAN1_TX_Pin;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //将CAN1输出端PD1配置为推挽输出模式 GPIO_Init(CAN1_TX_Port,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = CAN1_RX_Pin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //将CAN1输入端PD0配置为浮空输入GPIO_Init(CAN1_RX_Port, &GPIO_InitStructure);
CAN通讯模式配置(因为是简单的测试,因此配置为环回模式,过滤器配置为屏蔽位模式)
void CAN1_MODE_Config(void) {CAN_InitTypeDef CAN_InitStructure; CAN_FilterInitTypeDef CAN_FilterInitStructure; NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);CAN_DeInit(CAN1);CAN_InitStructure.CAN_ABOM = DISABLE; //离线模式由软件实现CAN_InitStructure.CAN_AWUM = DISABLE; //软件唤醒CAN_InitStructure.CAN_TTCM = DISABLE; //禁止时间触发通信模式CAN_InitStructure.CAN_NART = ENABLE; //禁止自动重传CAN_InitStructure.CAN_TXFP = DISABLE; //优先级由报文的标识符来决定CAN_InitStructure.CAN_RFLM = DISABLE; //接受溢出时FIFO不锁定,下一个收到的报文覆盖原有报文CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack; //CAN硬件工作环回模式CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; //重新同步跳跃宽度为2个时间单位CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq; //时间段为8个时间单位CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq; //时间段为7个时间单位CAN_InitStructure.CAN_Prescaler = 5; //设定一个时间单位的长度为5,范围(1~1024)CAN_Init(CAN1, &CAN_InitStructure);CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; //设定过滤器组为屏蔽位模式CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; //过滤器位宽为32位过滤器一个CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; //设定过滤器标识符高位(32为高位段,16位为第一个)CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; //设定过滤器标识符低位(32为低位段,16位为第二个)CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0x0000; //设定过滤器标识符高位(32为高位段,16位为第一个)CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0x0000; //设定过滤器标识符低位(32为低位段,16位为第二个)CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器FIFO0指向过滤器0CAN_FilterInitStructure.CAN_FilterNumber = 1; //指定待初始化的过滤器,范围1~13CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器CAN_FilterInit(&CAN_FilterInitStructure);CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //FIF0消息挂号中断允许NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn; //CAN1_RX0中断向量表中开启NVIC_Init(&NVIC_InitStructure); }
完成了驱动方面的配置,下面要进行的就是发送CAN数据和接收CAN数据的生成和实现了:
//CAN发送帧构成 void CAN_TxMessageInit(uint32_t std_id, uint32_t ext_id, uint8_t ide, uint8_t rtr, uint8_t dlc, uint8_t *pdata) {uint8_t i;assert_param(dlc>8); CanTxMessage.StdId = std_id&0x7ff; //设定标准标识符0~0x7ff 11位CanTxMessage.ExtId = ext_id&0x3ffff; //设定额外标识符0~0x3ffff 18位CanTxMessage.IDE = ide; //输出标识符类型,STD(标准标识符)或EXT(额外标识符)CanTxMessage.RTR = rtr; //输出帧类型,DATA(数据帧)或者REMOTE(远程帧)CanTxMessage.DLC = dlc; //帧长度,0~8for(i=0; i<dlc; i++){CanTxMessage.Data[i] = *(pdata+i);} }//CAN中断接收函数 void CAN1_RX0_IRQHandler(void) {ITStatus Status;Status = CAN_GetITStatus(CAN1, CAN_IT_FMP0); //判断接受到过滤器中断信号if(Status == SET){CAN_Receive(CAN1, CAN_FIFO0, &CanRxMessage); //接收一个CAN报文memcpy(rdata, &(CanRxMessage.Data[0]), 8); //将接收到的数据转存到rdata数组中}CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0); }
因为错误帧和超载帧是有stm32自带的硬件实现的,因此由我们提供的是远程帧和数据帧,单个帧内数据0~8字节,如果要发送多个数据,需要在其上添加传输层实现,具体实现我会在以后在研究(双CAN多帧通讯实验)。
主函数的实现如下:
int main(void) { BSP_Init(); //硬件初始化CAN_TxMessageInit(0x011, 0x0000, CAN_ID_STD, CAN_RTR_DATA, sizeof(tdata), tdata); //生成CAN报文CAN_Transmit(CAN1, &CanTxMessage); //发送CAN报文GPIO_ResetBits(GPIOD, GPIO_LED_1);ARM_DELAY(1000000);GPIO_SetBits(GPIOD, GPIO_LED_1);ARM_DELAY(1000000);while(1){ if(CanRxMessage.StdId == 0x11 && CanRxMessage.DLC == sizeof(tdata)) //判断接收到的报文{ if(strncmp((char *)tdata, (char *)rdata, sizeof(rdata)) == 0){GPIO_ResetBits(GPIOD, GPIO_LED_1);printf("stdID is %x, DIC is %x, receive data is %s \r\n", CanRxMessage.StdId, CanRxMessage.DLC, rdata);}memset(&CanRxMessage, 0, sizeof(CanRxMessage)); //清除接收到的报文 CAN_Transmit(CAN1, &CanTxMessage); //发送CAN报文} ARM_DELAY(1000000);GPIO_SetBits(GPIOD, GPIO_LED_1);ARM_DELAY(1000000);} }
如此就完成了简单的CAN环回测试实验,具体实验可通过串口接收端口查看,如下:
具体代码参考:http://files.cnblogs.com/files/zc110747/8.CAN-Loopback.7z
转载于:https://www.cnblogs.com/wanghuaijun/p/6433053.html
STM32学习笔记(十) CAN通讯测试(环回模式)相关推荐
- STM32学习笔记——基于正点原子例程编码器模式小结
STM32学习笔记--基于正点原子例程编码器模式小结 最近一段时间学习了,STM32f4的编码器功能,经过自己探索和他人的热心帮助,对于编码器模式有了一定了解.STM32f4单片机提供编码器模式,以便 ...
- 《STM32学习笔记》4——核心功能电路与编程(下)
接上文,文中的图片,大多数来自视频的截图(来自洋桃电子). 欢迎大家批评指正! STM32学习笔记-专栏 文章目录 一.蜂鸣器驱动 1.蜂鸣器介绍 2.蜂鸣器电路 3.蜂鸣器程序 二. MIDI 音乐 ...
- IOS之学习笔记十五(协议和委托的使用)
1.协议和委托的使用 1).协议可以看下我的这篇博客 IOS之学习笔记十四(协议的定义和实现) https://blog.csdn.net/u011068702/article/details/809 ...
- 吴恩达《机器学习》学习笔记十二——机器学习系统
吴恩达<机器学习>学习笔记十二--机器学习系统 一.设计机器学习系统的思想 1.快速实现+绘制学习曲线--寻找重点优化的方向 2.误差分析 3.数值估计 二.偏斜类问题(类别不均衡) 三. ...
- kvm虚拟化学习笔记(十)之kvm虚拟机快照备份
KVM虚拟化学习笔记系列文章列表 ---------------------------------------- kvm虚拟化学习笔记(一)之kvm虚拟化环境安装 http://koumm.blog ...
- mysql 临时表 事务_MySQL学习笔记十:游标/动态SQL/临时表/事务
逆天十三少 发表于:2020-11-12 08:12 阅读: 90次 这篇教程主要讲解了MySQL学习笔记十:游标/动态SQL/临时表/事务,并附有相关的代码样列,我觉得非常有帮助,现在分享出来大家一 ...
- Python语言入门这一篇就够了-学习笔记(十二万字)
Python语言入门这一篇就够了-学习笔记(十二万字) 友情提示:先关注收藏,再查看,12万字保姆级 Python语言从入门到精通教程. 文章目录 Python语言入门这一篇就够了-学习笔记(十二万字 ...
- STM32学习笔记 | 引起电源和系统异常复位的原因
关注+星标公众号,不错过精彩内容 每一块处理器都有复位的功能,不同处理器复位的类型可能有差异,引起复位的原因也可能有多种. STM32的复位功能非常强大,可通过软件.硬件和一些事件触发系统复位,而且通 ...
- STM32学习笔记(15)——SPI协议
STM32学习笔记(15)--SPI协议 一.SPI协议简介 1. 物理层 2. 协议层 (1) 通讯的开始与停止 (2)时钟极性CPOL.时钟相位CPHA 二.STM32的SPI外设 1. 通讯引脚 ...
最新文章
- 【研发管理】华为十大架构与设计核心原则
- 【Gunicorn】gunicorn配置文件详解
- elasticsearch6.2.4 与logstash与kibana版本6.2.4搭建同步使用
- ThinkPHP6项目基操(7.模型)
- CSS3否定伪类选择器
- Spring @Async配置4. 基于@Async无返回值调用 使用的方式非常简单,一个标注即可解决所有的问题: 1 @Async //标注使用 2 public void asyncMe
- java day38【Servlet 、HTTP协议 、Request】
- MTK平台上电话黑名单功能总结
- Dreamweaver8 V8.0.0.2766
- 解决苹果电脑OS X 10.8.5或10.7.5 老版本系统升级问题
- 傅立叶变换、拉普拉斯变换、Z 变换的联系是什么?为什么要进行这些变换?...
- Cubieboard1 引导安装 Debian 系统
- Vue.js实现点击左右按钮图片切换
- Canvas线条花环
- linux rsync文件夹增量同步
- 电脑越用越卡想清又不敢删?搞懂这些文件夹,一键删除省出几个G
- Python接口测试实战1(下)- 接口测试工具的使用
- Python中按位取反运算操作的解法
- 双翌视觉对位软件MasterAlign放入SY_License.Dat加密锁加密文件
- 在微信小程序中使用自定义字体【font-family】、同时在canvas
热门文章
- html radio 默认图片替换_用纯CSS改变html radio/checkbox默认背景颜色样式
- html立方体旋转展开,css3技术设计立方体旋转发光效果动图
- 数据结构c语言pdf2007,数据结构(C语言)严蔚敏 吴伟明 编著 07.pdf
- 机器人赛文_动漫中机器人赛文与真正的赛文奥特曼相比,谁更厉害呢?
- 随机生成元素升序向量_使用random_shuffle()算法随机化序列元素
- 常见花材的固定的方法有哪些_什么是zeta电位?常见zeta电位分析方法有哪些?...
- c语言运行程序没有,这个程序怎么运行?为什么显示没有exe??
- 表情识别(五)--MBP+CNN
- android okhttp+解析json( okhttp 工具类)
- oracle错误 无监听程序,oracle_无监听程序_错误