前言
博主也是刚接触CAN协议的新手,如有不对的地方欢迎交流
本文旨在使用STM32Cube MX快速上手STM32 CAN协议配置教程,目的在于 “会用” CAN总线,对CAN 协议原理并未深入讲解。
CAN协议基本特点
基本特点如下:
- 可多主控制: 当CAN总线空闲时,所有在总线上的终端都可以发送报文,根据标识符(CAN ID)决定优先级,当总线上有两个以上的终端发送消息时,对各消息CAN ID的每个位进行逐个仲裁比较。CAN ID值越低,报文优先级越高
- 速度快,距离远:CAN 协议最快可达1Mbps(距离小于40m),最远可达10KM(速率小于 5Kbps)
- CAN 帧种类:CAN 通信中包含五种帧种类,数据帧、遥控帧、错误帧、过载帧、间隔帧。其中最重要的是数据帧,用于通讯节点向外传送数据。数据帧中有数据段,用于承载数据的内容,一帧可发送0~8个字节的数据,MSB先行。
简单了解上述基本特点即可快速上手CAN总线的配置。
STM32Cube MX中的配置
CAN为了实现位同步,CAN协议把每一个数据位的时序分解成SS段,PTS段,PBS1段,PBS2段,这四段的长度加起来即为一个CAN数据位的长度。但在STM32中,将上述四个时序段整合成BS1和BS2两个时序段,对这两个时序段进行配置即可得到所需的通信波特率。
这里以F103C8T6为例,APB1时钟为36Mhz
计算波特率的方法:36M/分频系数/(BS1 + BS2 + 1)
如图设置,波特率是500Kbps,36M / 18 /(1 + 2 + 1) = 0.5M = 500K
配置选项说明:
- Prescaler:分频系数
- Time Quanta in Bit Segment 1:时间段1(BS1):定义采样点的位置。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
- Time Quanta in Bit Segment 1::时间段2(BS2):定义发送点的位置。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。
以上三个参数是决定CAN通信波特率的重要参数
Automatic Bus-Off Management:自动离线管理,节点检测到它发送错误或接收错误超过一定值时,会自动进入离线状态, 在离线状态中, CAN 不能接收或发送报文。
Automatic Retransmission:自动重发机制,当CAN总线发送失败时,会自动重发。
Operating Mode:CAN模式选择,有正常、回环、静默和静默回环四种模式可选,本篇文章只讲正常模式(双机通信)。
分享一个CAN波特率计算小工具:https://download.csdn.net/download/theLeMon/13138490
开启CAN接收中断,以便进行中断接收
配置好CubeMX后,点击GENERATE CODE 生成模板代码
CAN 收发配置
做完CAN的基本配置后,为了收发CAN数据,还需要进行CAN滤波器配置和发送消息句柄、接收消息句柄设置。
CAN滤波器配置
CAN过滤器是用于处理CAN接收过滤问题的,
/**
* @brief CAN过滤器配置
* @param[in]
* @return
*/
void CAN_Filter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
/*配置CAN过滤器*/
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
while(1){}
}
//启动CAN外围设备
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
while(1){}
}
//激活可以RX通知
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
while(1){}
}
}
CAN接收中断
/**
* @brief CAN接收回调函数
*/
// can接收buffer,这里用全局变量保存,以便其他函数处理
uint8_t can_rec_dat[8];
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_RxHeaderTypeDef can_rx_header; //接收
if(hcan->Instance == CAN1)
{
HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO0,&can_rx_header,can_rec_dat);
}
}
3、CAN 发送
/**
* @brief CAN发送一组数据
* @param[in] msg:待发送的数据(最大为8个字节)
* @param[in] len:数据帧的长度(最大为8)
* @param[in] std_id:CAN_ID
* @return 0:发送成功 1:发送失败
*/
uint8_t CAN_Send_Msg(uint8_t* msg, uint8_t len, uint8_t std_id)
{
CAN_TxHeaderTypeDef can_tx_header;
uint32_t TxMailbox;
can_tx_header.StdId = std_id;
can_tx_header.IDE = CAN_ID_STD;
can_tx_header.RTR = CAN_RTR_DATA;
can_tx_header.TransmitGlobalTime = ENABLE;
can_tx_header.DLC = len;
//MailboxesFreeLevel = HAL_CAN_GetTxMailboxesFreeLevel(&hcan);
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan)==0);
if(HAL_CAN_AddTxMessage(&hcan, &can_tx_header, msg, &TxMailbox) != HAL_OK)//发送
{
return 1;
}
return 0;
}
前言
博主也是刚接触CAN协议的新手,如有不对的地方欢迎交流
本文旨在使用STM32Cube MX快速上手STM32 CAN协议配置教程,目的在于 “会用” CAN总线,对CAN 协议原理并未深入讲解。
CAN协议基本特点
基本特点如下:
- 可多主控制: 当CAN总线空闲时,所有在总线上的终端都可以发送报文,根据标识符(CAN ID)决定优先级,当总线上有两个以上的终端发送消息时,对各消息CAN ID的每个位进行逐个仲裁比较。CAN ID值越低,报文优先级越高
- 速度快,距离远:CAN 协议最快可达1Mbps(距离小于40m),最远可达10KM(速率小于 5Kbps)
- CAN 帧种类:CAN 通信中包含五种帧种类,数据帧、遥控帧、错误帧、过载帧、间隔帧。其中最重要的是数据帧,用于通讯节点向外传送数据。数据帧中有数据段,用于承载数据的内容,一帧可发送0~8个字节的数据,MSB先行。
简单了解上述基本特点即可快速上手CAN总线的配置。
STM32Cube MX中的配置
CAN为了实现位同步,CAN协议把每一个数据位的时序分解成SS段,PTS段,PBS1段,PBS2段,这四段的长度加起来即为一个CAN数据位的长度。但在STM32中,将上述四个时序段整合成BS1和BS2两个时序段,对这两个时序段进行配置即可得到所需的通信波特率。
这里以F103C8T6为例,APB1时钟为36Mhz
计算波特率的方法:36M/分频系数/(BS1 + BS2 + 1)
如图设置,波特率是500Kbps,36M / 18 /(1 + 2 + 1) = 0.5M = 500K
配置选项说明:
- Prescaler:分频系数
- Time Quanta in Bit Segment 1:时间段1(BS1):定义采样点的位置。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
- Time Quanta in Bit Segment 1::时间段2(BS2):定义发送点的位置。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。
以上三个参数是决定CAN通信波特率的重要参数
Automatic Bus-Off Management:自动离线管理,节点检测到它发送错误或接收错误超过一定值时,会自动进入离线状态, 在离线状态中, CAN 不能接收或发送报文。
Automatic Retransmission:自动重发机制,当CAN总线发送失败时,会自动重发。
Operating Mode:CAN模式选择,有正常、回环、静默和静默回环四种模式可选,本篇文章只讲正常模式(双机通信)。
分享一个CAN波特率计算小工具:https://download.csdn.net/download/theLeMon/13138490
开启CAN接收中断,以便进行中断接收
配置好CubeMX后,点击GENERATE CODE 生成模板代码
CAN 收发配置
做完CAN的基本配置后,为了收发CAN数据,还需要进行CAN滤波器配置和发送消息句柄、接收消息句柄设置。
CAN滤波器配置
CAN过滤器是用于处理CAN接收过滤问题的,
/**
* @brief CAN过滤器配置
* @param[in]
* @return
*/
void CAN_Filter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
/*配置CAN过滤器*/
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
while(1){}
}
//启动CAN外围设备
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
while(1){}
}
//激活可以RX通知
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
while(1){}
}
}
CAN接收中断
/**
* @brief CAN接收回调函数
*/
// can接收buffer,这里用全局变量保存,以便其他函数处理
uint8_t can_rec_dat[8];
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_RxHeaderTypeDef can_rx_header; //接收
if(hcan->Instance == CAN1)
{
HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO0,&can_rx_header,can_rec_dat);
}
}
3、CAN 发送
/**
* @brief CAN发送一组数据
* @param[in] msg:待发送的数据(最大为8个字节)
* @param[in] len:数据帧的长度(最大为8)
* @param[in] std_id:CAN_ID
* @return 0:发送成功 1:发送失败
*/
uint8_t CAN_Send_Msg(uint8_t* msg, uint8_t len, uint8_t std_id)
{
CAN_TxHeaderTypeDef can_tx_header;
uint32_t TxMailbox;
can_tx_header.StdId = std_id;
can_tx_header.IDE = CAN_ID_STD;
can_tx_header.RTR = CAN_RTR_DATA;
can_tx_header.TransmitGlobalTime = ENABLE;
can_tx_header.DLC = len;
//MailboxesFreeLevel = HAL_CAN_GetTxMailboxesFreeLevel(&hcan);
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan)==0);
if(HAL_CAN_AddTxMessage(&hcan, &can_tx_header, msg, &TxMailbox) != HAL_OK)//发送
{
return 1;
}
return 0;
}
举报