第十四篇,STM32的CAN总线通信
1.CAN总线的概念
CAN指的是控制器局域网网络(Controller Area Network),由德国博世汽车电子厂商开发出来。
CAN使用差分信号,具有较强的抗干扰能力和传输稳定性
CAN属于多主通信,网络中所有的节点都可以作为主设备进行通信
CAN的网络扩展极其方便,CAN网络中扩展了新的通信单元,网络中旧的单元和硬件无需任何改变。
CAN具有较强的纠错能力,可以发现传输中出现的错误,并对错误节点进行隔离;所有的单元都可以检测错误;检测出错误的单元会立即同时通知其他所有单元;正在发送消息的单元一旦检测出错误,会强制结束当前的发送。被强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止。
2.CAN的差分信号
模分信号使用电平的绝对值来表示逻辑的差别;
差分信号使用两个电平的差值来表示逻辑值。CAN传输使用两根数据线 ------------- CANH和CANL
CAN总线高速ISO11898标准:
如果CANH(3.5V)和CANL(1.5V)的电压差 = 2V,此时表示逻辑0,叫做显性电平 ;
如果CANH(2.5V)和CANL(2.5V)的电压差 = 0V,此时表示逻辑1,叫做隐性电平
//如果多个节点同时控制总线电平,由总线仲裁最终显示的是显性电平(0)
3.CAN通信协议
CAN使用5种通信帧,下面以数据帧为例来介绍帧结构
数据帧的分析:
数据帧分为标准数据帧和扩展数据帧l两种格式。
D --- 表示显性电平
R --- 表示隐性电平
数据帧由7部分组成:
数据帧七个部分的实现
标准格式中标识符(ID)有11bit,从ID28到ID18被依次发送,禁止高7位都为隐性(禁止设定:ID = 1111 111X XXX);
扩展格式的ID有29bit,基本ID从ID28到ID18,扩展ID由ID17到ID0表示,禁止高7位都为隐性(禁止设定:ID = 1111 111X XXX)。
RTR位用于标识是否是远程帧(0:数据帧;1:遥控帧);
IDE位用于标识符选择位(0:使用标准标识符;1:使用扩展标识符);
SRR位代替遥控帧请求位,为隐性位,代替了标准帧中的RTR位。
(1)帧起始
显示1位显性电平
(2)仲裁段
用来实现帧的优先级和帧的过滤
1.标准帧
标准数据帧的仲裁段由11位ID和1位RTR位组成,RTR用来区分数据帧(显性电平)和遥控帧
2.扩展帧
扩展数据帧由 29位ID,1位RTR,1位SRR和1位IDE组成;
RTR用来区分数据帧(显性电平)和遥控帧
SRR用来代替标准帧中的RTR位,由于SRR是隐性电平,相同ID的标准帧优先级高于扩展帧
IDE用来区分标准帧(显性电平)和扩展帧,显性电平表示标准帧,隐性电平表示扩展帧
报文的优先级由总线通过ID仲裁来判断,当总线上同时出现显性电平和隐形电平时,最终显示为显性电平;当多个节点同时竞争总线占有权时,谁先出现隐形电平,将失去总线占有权,转为接收状态
(3)控制段
表数据帧里数据段的字节数,r0,r1为保留位,默认是显性电平 ;
4位DLC表示数据段的长度(0~8)
(4)数据段
用户需要发送的数据内容,可一次性发送0–8个字节的数据(每个数据占用一个字节)
长度0~8字节,高位先出
(5)CRC段
CRC错误校验,由15位CRC校验码和1位CRC界定符组成, 校验出了错误信息,可利用错误帧请求重发,重发次数可设定;用于检查帧传输错误(检查范围:起始端,仲裁段,控制段,数据段)。
(6)ACK段
由1位ACK槽和1位ACK界定符组成,发送方的ACK槽是隐性电平 ,接收方确认收到正确的数据后以显性电平应答
(7)帧结束
7位隐形电平,由7个隐形位(逻辑1)组成,因此ID仲裁断禁止出现1111111****形式的格式
4.CAN的位时序
CAN传输1位由4段组成:同步段,传播段,相位缓冲段1,相位缓冲段2;
1位结束后会使用再同步补偿宽度(SJW)进行再补偿。这样设计的原因是让发送方和接收方的时序保持一致(消除误差)
(1)同步段(SS)
同步段用于实现实训的调整,完成显性/隐形电平的转换,也就是准备该位要发送的电平
(2)传播时间段(PTS)
用于吸收网络上的物理延迟,物理延迟包括发送的延迟,接收的延迟和信号传播的延迟
(3)相位缓冲段(PBS)
对于电平转换未被包含的部分进行补偿,同时和SJW一起补偿各单位的时钟误差,电平的读取在该段完成。
(4)再同步补偿宽度(SJW)
补偿前面同步的误差
接收方的采样一定在PBS1和PBS2之间,由于SS和PTS误差的变动,PBS的补偿也会随着误差的变化而变化,实现传输1位时间的固定,SJW对PBS的补偿进行二次补偿。
1位时间 = 8 ~ 25Tq, SS = 1Tq ,PTS = 1 ~ 8Tq ,PBS = 2 ~ 8Tq ,SKW = 1 ~ 4Tq
5.stm32f407的CAN控制器
stm32芯片带有bxCAN控制器,支持CAN协议的2.0A和2.0B,最快速度1Mbps,能够自动发送CAN报文,支持标准和扩展数据帧,控制器带有三个发送邮箱存储发送的报文,还有两个FIFO,支持ID过滤,可配置自动重发等功能。
(1)工作模式
初始化模式:初始化CAN控制器
正常模式:正常收发数据
睡眠模式:低功耗
(2)测试模式
静默模式:停止对外发送报文
环回模式:报文不发往总线,直接发给自己
环回和静默组合模式
测试模式
(3)传输速率
波特率 = 42MHz/分频系数/(tbs1+tbs2+sjw)
(4)接收中断
FMPx表示收到了报文
6.原理图
查看原理图可知
CAN总结的接口最终连接到了CPU的PD0和PD1,具有CAN的复用功能。
7.CAN总线通信的库函数实现
添加CAN通信的库函数源码
(1)开启时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
(2)将GPIO配置为CAN复用功能
GPIO_Init(...); GPIO_PinAFConfig(...);
(3)初始化CAN
uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct);
参数:
CANx - 哪个CAN
CAN_InitStruct - CAN初始化结构 typedef struct
{ uint16_t CAN_Prescaler; /*!< 预分频系数 1 to 1024. */ uint8_t CAN_Mode; /*!< 工作模式 @ref CAN_operating_mode */ uint8_t CAN_SJW; /*!< 再同步补偿宽度极限值 @ref CAN_synchronisation_jump_width */ uint8_t CAN_BS1; /*!< 相位缓冲段1长度 @ref CAN_time_quantum_in_bit_segment_1 */ uint8_t CAN_BS2; /*!< 相位缓冲段2长度 @ref CAN_time_quantum_in_bit_segment_2 */ FunctionalState CAN_TTCM; /*!< 时间触发使能 ENABLE or DISABLE. */ FunctionalState CAN_ABOM; /*!< 自动离线使能 ENABLE or DISABLE. */ FunctionalState CAN_AWUM; /*!< 自动唤醒使能 ENABLE or DISABLE. */ FunctionalState CAN_NART; /*!< 自动重发使能 ENABLE or DISABLE. */ FunctionalState CAN_RFLM; /*!< 接收FIFO锁定使能 ENABLE or DISABLE. */ FunctionalState CAN_TXFP; /*!< 发送FIFO优先级使能 ENABLE or DISABLE. */ } CAN_InitTypeDef;
(4)初始化过滤器
void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct);
//参数就是过滤器初始化结构typedef struct
{ uint16_t CAN_FilterIdHigh; /*!< 过滤器ID寄存器高16位 0x0000 and 0xFFFF */ uint16_t CAN_FilterIdLow; /*!< 过滤器ID寄存器低16位 0x0000 and 0xFFFF */ uint16_t CAN_FilterMaskIdHigh; /*!< 过滤器ID掩码寄存器高16位 0x0000 and 0xFFFF */ uint16_t CAN_FilterMaskIdLow; /*!< 过滤器ID掩码寄存器低16位 0x0000 and 0xFFFF */ uint16_t CAN_FilterFIFOAssignment; /*!< 接收FIFO的选择 @ref CAN_filter_FIFO */ uint8_t CAN_FilterNumber; /*!< 过滤器编号 0 to 13. */ uint8_t CAN_FilterMode; /*!< 过滤模式 @ref CAN_filter_mode */ uint8_t CAN_FilterScale; /*!< 过滤器长度 @ref CAN_filter_scale */ FunctionalState CAN_FilterActivation; /*!< 使能/禁止 ENABLE or DISABLE. */ } CAN_FilterInitTypeDef;
(5)配置发送/接收的结构体
//发送数据结构体typedef struct{ uint32_t StdId; /*!< 标准帧ID 0 to 0x7FF. */ uint32_t ExtId; /*!< 扩展帧ID 0 to 0x1FFFFFFF. */ uint8_t IDE; /*!< IDE标志 标准帧/扩展帧 @ref CAN_identifier_type */ uint8_t RTR; /*!< RTR标志 数据帧/遥控帧 @ref CAN_remote_transmission_request */ uint8_t DLC; /*!< 数据段长度 0 to 8 */ uint8_t Data[8]; /*!< 发送的数据 0 to 0xFF. */
} CanTxMsg;//接收数据结构体typedef struct
{ uint32_t StdId; /*!< 标准帧ID 0 to 0x7FF. */ uint32_t ExtId; /*!< 扩展帧ID 0 to 0x1FFFFFFF. */ uint8_t IDE; /*!< IDE标志 标准帧/扩展帧 @ref CAN_identifier_type */ uint8_t RTR; /*!< RTR标志 数据帧/遥控帧 @ref CAN_remote_transmission_request */ uint8_t DLC; /*!< 数据段长度 0 to 8 */ uint8_t Data[8]; /*!< 接收的数据 0 to 0xFF. */ uint8_t FMI; /*!< 过滤器放入的内容 0 to 0xFF */
} CanRxMsg;
(6)初始化CAN的接收中断
NVIC_Init(...); CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
(7)发送和接收数据
接收: void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage);
发送:
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage); uint8_t CAN_TransmitStatus(CAN_TypeDef* CANx, uint8_t TransmitMailbox);
8.上位机的使用
打开软件
(1)串口设置
打开后会读到当前模块的配置
(2)将CAN模块设置为环回模式,波特率500Kbps
(4)测试模块的发送和接收
9.连接模块和开发板
下一步需要编写程序实现CAN总线的通信 ,如果没有can模块进行测试,可以在初始化can 的时候把模式设置为环回模式,把数据发送给自己进行数据收发的测试。
#include <stm32f4xx.h>
#include <can.h>
#include <stdio.h>void can1_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;CAN_InitTypeDef CAN_InitStruct;CAN_FilterInitTypeDef CAN_FilterInitStruct;NVIC_InitTypeDef NVIC_InitStruct;//1.开启GPIOD和CAN1时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);//2.初始化GPIO为CAN功能GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//高速GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;GPIO_Init(GPIOD,&GPIO_InitStruct);GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_CAN1);GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_CAN1);//3.初始化CAN 42M / 4 /(1+12+8) = 500KbpsCAN_InitStruct.CAN_Prescaler = 4;//4分频CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;//SJW宽度CAN_InitStruct.CAN_BS1 = CAN_BS1_12tq;//PBS1宽度CAN_InitStruct.CAN_BS2 = CAN_BS2_8tq;//PBS2宽度CAN_InitStruct.CAN_Mode = CAN_Mode_LoopBack;//CAN_Mode_Normal;//正常模式CAN_InitStruct.CAN_ABOM = DISABLE;//自动离线CAN_InitStruct.CAN_AWUM = DISABLE;//自动唤醒CAN_InitStruct.CAN_NART = DISABLE;//自动重发CAN_InitStruct.CAN_RFLM = DISABLE;//锁定接收CAN_InitStruct.CAN_TTCM = DISABLE;//时间触发CAN_InitStruct.CAN_TXFP = DISABLE;//发送报文优先级CAN_Init(CAN1,&CAN_InitStruct);//4.初始化过滤器CAN_FilterInitStruct.CAN_FilterActivation = ENABLE;//使能过滤器CAN_FilterInitStruct.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;//安装过滤器到FIFO0CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdMask;//过滤器模式 --- 掩码CAN_FilterInitStruct.CAN_FilterNumber = 0;//过滤器0CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_16bit;//过滤器长度CAN_FilterInitStruct.CAN_FilterIdHigh = 0x0000;CAN_FilterInitStruct.CAN_FilterIdLow = 0x0000;CAN_FilterInitStruct.CAN_FilterMaskIdHigh = 0x0000;CAN_FilterInitStruct.CAN_FilterMaskIdLow = 0x0000;CAN_FilterInit(&CAN_FilterInitStruct);//5.初始化CAN接收中断NVIC_InitStruct.NVIC_IRQChannel = CAN1_RX0_IRQn;//CAN1 FIFO0接收中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x2;//抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;//响应优先级NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能NVIC_Init(&NVIC_InitStruct);CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}CanTxMsg CAN1_TX_MSG;
CanRxMsg CAN1_RX_MSG;//can1发送函数 0 - 成功 非0 - 失败
u8 can1_send_message(u8 *data,u8 len,u32 message_id)
{u8 i,mailbox;u32 cnt = 0;if(len>8)return 1;//根据id选择标准帧/扩展帧if(message_id>0x7ff){//扩展帧CAN1_TX_MSG.IDE = CAN_Id_Extended;}else{CAN1_TX_MSG.IDE = CAN_Id_Standard;}CAN1_TX_MSG.RTR = CAN_RTR_Data;//数据帧CAN1_TX_MSG.DLC = len;//数据长度CAN1_TX_MSG.ExtId = message_id;//扩展帧IDCAN1_TX_MSG.StdId = message_id;//标准帧ID//发送的数据for(i=0;i<len;i++){CAN1_TX_MSG.Data[i] = data[i];}//发送数据等待发送成功mailbox = CAN_Transmit(CAN1,&CAN1_TX_MSG);do{cnt++;}while(CAN_TransmitStatus(CAN1,mailbox)!=CAN_TxStatus_Ok&&cnt<1000);if(cnt<1000)return 0;elsereturn 1;
}//CAN FIFO1中断处理函数
void CAN1_RX0_IRQHandler(void)
{if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)==SET){//收到数据CAN_Receive(CAN1,CAN_FIFO0,&CAN1_RX_MSG);/*//原路发回if(CAN1_RX_MSG.IDE==CAN_Id_Standard){//标准帧can1_send_message(CAN1_RX_MSG.Data,CAN1_RX_MSG.DLC,CAN1_RX_MSG.StdId);}else if(CAN1_RX_MSG.IDE==CAN_Id_Extended){can1_send_message(CAN1_RX_MSG.Data,CAN1_RX_MSG.DLC,CAN1_RX_MSG.ExtId);}*/printf("%s\r\n",CAN1_RX_MSG.Data);//清除标志CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);}
}
第十四篇,STM32的CAN总线通信相关推荐
- Python之路【第十四篇】:AngularJS --暂无内容-待更新
Python之路[第十四篇]:AngularJS --暂无内容-待更新 转载于:https://www.cnblogs.com/weiman3389/p/6224181.html
- CCIE-LAB-第十四篇-PIM Sparst+IGMP
CCIE-LAB-第十四篇-PIM Sparst+IGMP 实际中,思科只会给你5个小时去做下面的全部配置 这个是CCIE-LAB的拓扑图 问题 翻译 FABD2正准备在其网络中启用PIM稀疏模式的中 ...
- CCNP-第十四篇-BGP综合实验
CCNP-第十四篇-BGP综合实验 大家好呀,学了那么长时间的BGP,又是一个巨大分水岭,那怎么能没综合实验呢? 答案以及个人录制视屏(数字那个视频因为录制软件的问题看不到命令行可以直接看后面的,不喜 ...
- CCNA-第十四篇-NAT-下+链路聚合(LACP)+DHCP
CCNA-第十四篇-NAT-下 这一篇是是针对一下华为设备的nat,然后讲讲链路聚合 下一篇来一个DHCP+一点点的SDN的介绍 **然后讲完SDN就基本上CCNA结束了哦** 华为的链路聚合叫Eth ...
- python原创第十四篇~判断,循环实战训练+答案
2017-12-07 09:23:55 December Thursday the 49 week, the 341 day #原创第十四篇~判断,循环实战训练 题目:一个整数,它加上100后是一个完 ...
- python学习[第十四篇] 文件的输入与输出
python学习[第十四篇] 文件的输入与输出 标准文件类型 一般来说只要程序一执行,就会访问3个文件: 标准输入(键盘) stdin 标准输出(显示器缓冲区) stdout 默认输出到屏幕 标准错误 ...
- JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快!
JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快! 一.ReentrantReadWriteLock(读写锁) 1.读写锁存在 ...
- 第七十四篇:机器学习优化方法及超参数设置综述
第七十四篇:机器学习优化方法及超参数设置综述 置顶 2019-08-25 23:03:44 廖佳才 阅读数 207更多 分类专栏: 深度学习 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-S ...
- MySQL数据库,从入门到精通:第十四篇——MySQL视图详解
MySQL数据库,从入门到精通:第十四篇--MySQL视图详解 第 14 篇_视图 1. 常见的数据库对象 2. 视图概述 2. 1 为什么使用视图? 2. 2 视图的理解 3. 创建视图 3. 1 ...
- 基于STM32的CAN总线通信学习笔记
转自:https://blog.csdn.net/ludaoyi88/article/details/53350077 基于STM32的CAN总线通信学习笔记 本文主要简单介绍CAN总线的相关概念,以 ...
最新文章
- 如何1秒内向Sql Server插入几万条数据
- Microsoft.VsHub.Server.HttpHost
- AngularJS+RequireJS集成环境
- vsftp配置文件详解
- 2020 年的算法,降温之后会更好
- Floyd算法的动态规划本质
- linux操作系统基本配置
- [转帖]每天看一遍,释怀所有难过
- 到底什么是 ROI Pooling Layer ???
- pycharm修改选中字体颜色
- ConcurrentHashMap(JDK1.8)的源码解析
- 计算机组成原理 论文总结,计算机组成原理论文
- 得力人脸识别考勤机密码设置_得力人脸识别考勤机使用与上传数据方法哪位清楚?...
- 批处理常用DOS命令简述
- 您可能不了解JS:JavaScript圣经的见解
- 程序员必备神器(FastStoneCapture)
- kali之永恒之蓝使用流程(操作全套步骤)
- 【微信小程序】横向/纵向布局(98/100)
- 猫和老鼠服务器未响应是怎么回事,猫和老鼠手游怎么玩不了?游戏设置及异常解决方法[多图]...
- Java 实现OCR 识别图像文字(手写中文)----tess4j
热门文章
- 干货|2021年以后人工智能的几点思考?
- 计算机网络实验:CISCO IOS 路由器基本配置
- 鸿蒙思维闪卡训练,提高孩子智力,父母不妨使用思维导图来提升孩子记忆力和创造力...
- 国科大首期“一生一芯”计划初见成效——本科生带着自己设计的处理器芯片毕业
- win10启动虚拟机蓝屏的一种解决方法
- 【洛谷八连测R2】fateice-or
- WAVE SUMMIT+峰会,飞桨八大亮点发布,全面助力产业智能化
- Linux手机DIY.夏新E600和飞利浦968的重大突破
- debian怎么安装oracle数据库,Debian上安装Oracle客户端
- Python戏说NBA:谁是季后赛最强得分手