STM32(HAL)——CAN通信
8. CAN
8.1 基本概念
全称Controller Area Network,是一种半双工,异步通讯。没有主从的说法,每个设备都可以发送和接收。
8.1.1 物理层
两条信号线,CAN_High和CAN_Low两条差分信号线,以差分形式通讯
两种网络形式:
闭环:允许总线最长40m,最高速1Mbps
规定总线两端各有一个120Ω电阻。
CAN控制器是各个连接到总线上的设备的控制器,一般需要配备一个CAN收发器(比如咱们战队码盘上的CAN收发器用的是TJA1050),用于将CAN控制器的二进制码流转换为CAN总线的差分电平,在两条有差分电压的总线电缆上传输数据
开环:最大传输距离1Km,最高速125Kbps
规定每根线串联一个2.2kΩ的电阻
CAN协议差分信号
显性电平对应“0”,隐性电平对应“1”。隐性电平(1)两条线电压都是2.5V,即压差为0;显性电平(0)CAN_High和CAN_Low分别为3.5V和1.5V,压差为2V。
总线上,只要有一个节点输出显性,则总线上为显性电平;只有所有节点都是隐性电平,总线才为隐性电平
由于CAN是半双工的,收发分开进行,且是总线通讯,所以一个时刻只能有一个节点发送,其他节点在此时只能接收
8.1.2 协议层
位时序
意义:为了实现正确的总线电平采样,确保通讯正常。最小单位是Tq(Time Quantum),一个完整位由8~25个Tq组成
组成:SS段、PTS 段、PBS1段、PBS2段
段名 | 意义 | 作用 |
---|---|---|
SS(1Tq) | 同步段 | 使总线各节点同步 |
PTS(1~8Tq) | 传播时间段 | 补偿物理延时,是传播时间、收发器延时之和的两倍 |
PBS1(1~8Tq) | 相位缓冲段1 | 补偿变压阶段误差 |
PBS2(2~8Tq) | 相位缓冲段2 | 补偿边沿阶段误差 |
SJW(1~4Tq) | 再同步补偿宽度 | 补偿时钟频率偏差、传输延迟等 |
例如
通讯波特率的计算:CAN使用的时钟线是APB1 peripheral clocks(假设是APC),即一般是SYSCLK的四分频。而CAN通讯还要对此进行预分频(假设是Prescaler),则一个Tq为 Prescaler / APC(单位s)。而一个数据位占(SS+PTS+PBS1+PBS2+SJW)个Tq。则一秒可以传输的位数就是
例如:在时钟树查得APB1 peripheral clocks是45MHz,预分频为5,则一个Tq为 ,上图中有19个Tq,则此时波特率为
报文
帧类型:
类型 | 用途 |
---|---|
数据帧 | 发送单元向接收单元信息内容 |
遥控帧 | 接收单元发送单元请求数据 |
错误帧 | 通知其他单元检测到错误 |
过载帧 | 通知还没有准备好接收 |
间隔帧 | 将数据帧或遥控帧前面的帧隔开 |
数据帧结构:
以一个显性位(0)开始,以一个7个连续隐形位(1)结束。中间依次是仲裁段、控制段、数据段、CRC段、ACK段,一共7段
帧起始(SOF):一个显性电平。用于通知各个节点将有数据传输
仲裁段:用于表示优先级。标准格式和扩展格式得区别就是在这里,标准格式ID为11位,扩展格式为11+18=29位。RTR(远程传输请求位),用显隐性电平区别数据帧和遥控帧。
IDR(标识符扩展位),显性是标准形式,隐性是扩展形式。
SSR,即标准格式的RTR,是隐性位。
ID决定数据帧的优先级,当两个节点同时竞争总线,则先出现隐性电平的节点失去占有权,进入接收状态
控制段:r1和r0是保留位,默认显性。DLC,数据数组长度,0~8
数据段:08个字节(064位)
CRC段:共16位。15位的CRC校验码,1位的界定符,隐性
ACK段:共2位。一位是ACK槽位,发送端发送隐性,接收端发送显性表示应答;一位是与帧结束的界定符
帧结束(ROF):7个隐形位
8.1.3 过滤器
目的:过滤掉不感兴趣的消息,即与本节点无关的消息
两种模式:列表模式和掩码模式
过滤器个数:使用一个CAN时可选013号过滤器;使用两个CAN是,可选用037号过滤器
模式
列表模式:将关注的报文ID做成一张表,当收到的报文ID符合时则接收,否则不接收
优点,精确,能完全过滤掉不需要的报文
缺点,列表数量有限,当感兴趣的消息数量过多时则无法全部包含
掩码模式通过与操作,将部分ID符合的报文接收
优点,感兴趣的范围可以更大
缺点,并不一定能完全过滤掉不关注的报文,精确程度取决于屏蔽码
位宽
过滤器有32位和16位两种可选。其中16位只能过滤标准帧,不能过滤扩展帧。
8.2 STM32的CAN
STM32有两组CAN控制器,CAN1是主设备,负责管理bxCAN(基本扩展CAN,就是CAN)和512字节的SRAM。CAN2是从控制器,不能直接访问SRAM。使用CAN2必须使能CAN1外设时钟
STM32中,当CAN接收过滤器使用32位时,掩码和验证码分别拆分成两个寄存器,每个16位,分别代表高16位和低16位
8.3 CubeMX配置步骤
-
左侧目录>Connectivity>点CAN1/CAN2~> Mode勾选Master Mode / Slave Mode
-
配置参数,含义如下:
参数 意思 Prescaler 预分频,即位时序提到的APB1 peripheral clocks继续分一次频 Time Quantum 最小时间单位Tq,自动计算出来的,不需要填写 Time Quanta in Bit Segment 1 PBS1段长度 Time Quanta in Bit Segment 2 PBS2段长度 ReSynchronization Jump Width 重同步跳跃宽度,即位时序提到的SJW Time Triggered Communication Mode 是否使能时间触发 Automatic Bus-Off Management 是否使能自动离线管理 Automatic Wake-Up Mode 是否使能自动唤醒 Qutomatic Retransmission 是否使能自动重传 Receive Fifo Locked Mode 是否使能锁定FIFO Transmit Fifo Priority 配置报文优先级的判断方法 Oprating Mode 操作模式 这些参数也可以在can.c中自行修改
-
中断(NVIC)设置,根据需要设置,一般勾上CAN1 RX0 Interrupt
8.4 编程
HAL库关于CAN的所有函数定义和结构体分别在 Drivers/STM32F4xx_HAL_Driver 文件夹下 stm32f4xx_HAL_Driver.c 和 stm32f4xx_HAL_Driver.h 中
下面列举一些基本的和常用的
8.4.1 CAN基本结构体
发送报文定义结构体(CAN_TxHeaderTypeDef)
typedef struct
{
uint32_t StdId; /*!标准ID。参数值只能是 0 到 0x7FF(二进制的11位1) */
uint32_t ExtId; /*!扩展ID。参数值只能是 0 到 0x1FFFFFFF(二进制的29位1)*/
uint32_t IDE; /*!IDE。HAL库编程时,标准帧填写CAN_ID_STD,扩展帧填写CAN_ID_EXT */
uint32_t RTR; /*!RTR。HAL库编程时,数据帧填写CAN_RTR_DATA,遥控帧填写CAN_RTR_REMOTE */
uint32_t DLC; /*!DLC。数据长度,参数值只能是 0 到 8 */
FunctionalState TransmitGlobalTime; /*!< Specifies whether the timestamp counter value captured on start
of frame transmission, is sent in DATA6 and DATA7 replacing pData[6] and pData[7].
@note: Time Triggered Communication Mode must be enabled.
@note: DLC must be programmed as 8 bytes, in order these 2 bytes are sent.
This parameter can be set to ENABLE or DISABLE. */
} CAN_TxHeaderTypeDef;
接收报文定义结构体(CAN_RxHeaderTypeDef)
typedef struct
{
uint32_t StdId;
uint32_t ExtId;
uint32_t IDE;
uint32_t RTR;
uint32_t DLC;
uint32_t Timestamp; /*!< Specifies the timestamp counter value captured on start of frame reception.
@note: Time Triggered Communication Mode must be enabled.
This parameter must be a number between Min_Data = 0 and Max_Data = 0xFFFF. */
uint32_t FilterMatchIndex; /*!< Specifies the index of matching acceptance filter element.
This parameter must be a number between Min_Data = 0 and Max_Data = 0xFF. */
} CAN_RxHeaderTypeDef;
接收过滤器类型定义结构体(CAN_FilterTypeDef)
typedef struct
{
uint32_t FilterIdHigh; /*!过滤器验证码ID高16位,只能填0到0xFFFF 中间的数值 */
uint32_t FilterIdLow; /*!过滤器ID低16位,只能填0到0xFFFF 中间的数值*/
uint32_t FilterMaskIdHigh; /*!过滤器掩码ID高16位,只能填0到0xFFFF中间的数值 */
uint32_t FilterMaskIdLow; /*!过滤器掩码ID低16位,只能填0到0xFFFF中间的数值 */
uint32_t FilterFIF(x)Assignment; /*!将通过的报文放入哪个FIFOx中,填写FIFO(x) */
uint32_t FilterBank; /*!使用过滤器编号。使用一个CAN,则可选 0~13;使用两个CAN可选 0~27 */
uint32_t FilterMode; /*!过滤器模式选择。掩码模式填写 CAN_FILTERMODE_IDMASK,列表模
式填写 CAN_FILTERMODE_IDLIST */
uint32_t FilterScale; /*!过滤器位宽,32位是CAN_FILTERSCALE_32BIT,
16位是CAN_FILTERSCALE_16BIT */
uint32_t FilterActivation; /*!是否使能过滤器,DISABLE 或 ENABLE */
uint32_t SlaveStartFilterBank; /*!< Select the start filter bank for the slave CAN instance.
For single CAN instances, this parameter is meaningless.
For dual CAN instances, all filter banks with lower index are assigned to master
CAN instance, whereas all filter banks with greater index are assigned to slave
CAN instance.
This parameter must be a number between Min_Data = 0 and Max_Data = 27. */
} CAN_FilterTypeDef;
注意:FilterIdHigh、FilterIdLow、FilterMaskIdLow、FilterMaskIdLow这四个成员不是它的名字那么简单,
他们的功能取决于使用的过滤器模式。若为列表模式,则不管是FilterId还是FilterMaskId都表示的是列
表成员。
上述四个成员都是16位的,一定注意下面说的移位操作
在32位过滤器中,一组High和Low检验同一个CAN ID;16位过滤器,则可分别独立检验一个ID
过滤器寄存器如下:(使用HAL库可以不必深挖具体的寄存器,只需注意Mapping每一位的内容)
32位列表模式
16位列表模式
32位掩码模式
16位掩码模式
标准帧用16位过滤器表示:FilterIdHigh、FilterIdLow、FilterMaskIdLow、FilterMaskIdLow各可以表示一个列表成员。由于标准帧的ID是11位的,所以需要将其ID左移5位
标准帧用32位过滤器表示:FilterIdHigh、FilterIdLow共同表示一个ID,FilterMaskIdLow、FilterMaskIdLow共同表示一个ID。由于标准帧ID是11位的,故表示时其ID需左移5位存入High,且LOW = 0 | CAN_ID_STD (意思是将IDE位置为0)
扩展帧用32位过滤器表示:扩展帧的ID是29位的,所以将扩展帧ID先左移3位与32位按高位对齐,再右移16位并取低16位,存入High;将扩展帧ID左移3位与32位对齐,再取低16位存入Low。具体操作如下
CAN_FilterTypeDef sFilterConfig //定义过滤器设置结构体变量
uint32_t StdId =0x321; //一个标准CAN ID
uint32_t ExtId =0x1800f001; //一个扩展CAN ID
sFilterConfig.FilterIdHigh = StdId<<5; //标准ID放入FilterIdHigh
sFilterConfig.FilterIdLow = 0|CAN_ID_STD; //标准ID,故设置IDE位为0
sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff; //扩展帧ID高16位放入 FilterMaskIdHigh
sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT; //扩展帧ID高16位放入 FilterMaskIdLow,并设置 IDE位为1
关于验证码和掩码:假设有一个关注列表,里面全是感兴趣的报文。验证码可以是关注列表中任意一个成员的ID(经上述处理),而掩码是所有感兴趣的成员的同或的结果
综上,两种位宽,两种模式,共四种过滤模式,特点总结如下:
模式 | 特点 |
---|---|
16位列表 | 可包含四个列表成员 |
32位列表 | 可包含两个列表成员 |
16位掩码 | 可检验两对验证码和掩码 |
32位掩码 | 可检验一对验证码和掩码 |
8.4.2 CAN 基本函数
控制函数如下表
函数 | 功能 |
---|---|
HAL_CAN_Start | 开启CAN通讯 |
HAL_CAN_Stop | 关闭CAN通讯 |
HAL_CAN_RequestSleep | 尝试进入休眠模式 |
HAL_CAN_WakeUp | 从休眠模式中唤醒 |
HAL_CAN_IsSleepActive | 检查是否成功进入休眠模式 |
HAL_CAN_AddTxMessage | 向 Tx 邮箱中增加一个消息,并且**对应的传输请求 |
HAL_CAN_AbortTxRequest | 请求中断传输 |
HAL_CAN_GetTxMailboxesFreeLevel | Return Tx mailboxes free level |
HAL_CAN_IsTxMessagePending | 检查是否有传输请求在指定的 Tx 邮箱上等待 |
HAL_CAN_GetRxMessage | 从Rx FIFO 收取一个 CAN 帧 |
HAL_CAN_GetRxFifoFillLevel | Return Rx FIFO fill level |
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan)**
功能:开启CAN,一般一开始就要打开
参数:CAN句柄指针,&hcan1 或 &hcan2
返回值:返回值:HAL状态
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig)
功能:配置CAN过滤器
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,CAN配置结构体的指针
返回值:返回值:HAL状态
HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan, uint32_t ActiveITs)
功能:使能中断
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,使能哪个中断,在stm32f4xx_HAL_Driver.h中,搜索Receive Interrupts可以查到各宏定义
返回值:返回值:HAL状态
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)(根据使用0可能替换成1)
功能:接收回调函数,CAN回调后进行的操作。一般在此接收数据
参数:第一个,CAN句柄指针
返回值:void
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox)**
功能:增加一个消息到第一个空闲的 Tx 邮箱,并且**对应的传输请求
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,发送报文定义结构体的指针
第三个,数据帧数组的内容,长度不能超过定义的长度
第四个,Tx邮箱,可填 (uint32_t*)CAN_TX_MAILBOX0 ,CAN_TX_MAILBOX1 , CAN_TX_MAILBOX3
返回值:HAL状态
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
功能:从Rx FIFO收取一个 CAN 帧
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,Rx FIFO,可填 CAN_RX_FIFO0, CAN_RX_FIFO1
第三个,接收报文定义结构体的指针
第四个,接受数据数组
返回值:HAL状态
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig)
功能:设置接收过滤器
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,过滤器类型定义结构体指针
返回值:HAL状态
8.4.3 CAN编程步骤示例
-
定义接收过滤器类型定义结构体(CAN_FilterTypeDef)变量
-
配置CAN接收过滤器HAL_CAN_ConfigFilter
-
开启CAN,HAL_CAN_Start
-
发送,HAL_CAN_AddTxMessage
-
接收,需要先开启中断HAL_CAN_ActivateNotification,第二个参数设置为CAN_IT_RX_FIFO0_MSG_PENDING
接收中断回调函数HAL_CAN_RxFifo0MsgPendingCallback,里面定义接收报文定义结构体(CAN_RxHeaderTypeDef)结构体变量。用接收函数HAL_CAN_GetRxMessage接收
下一篇: MySQL数据库安全设置与注意事项小结