由于在实际项目中经常用到can总线,在这里整理一下使用stm32 cubemx配置can通信的具体流程。
这里讲解一下,can2发送数据,采用can1中断接收can2发送过来的数据。
大概步骤如下:
1、使用cubemx配置can总线,自动生成关键代码。
具体的配置流程我就不具体写了,太简单了,网上有很多教程。
注意:由于这里要使用can总线的中断接收数据,要记得在cubemx中勾选上can1的中断接收功能。
2、添加can总线的过滤器代码。
void filter_to_can_1(void)
{
// add filter_0 to can_1
HAL_StatusTypeDef HAL_Status;
CAN_FilterTypeDef CAN_Filter;
CAN_Filter.FilterBank = 0;
CAN_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
CAN_Filter.FilterScale= CAN_FILTERSCALE_32BIT; // 32BIT WIDTH
CAN_Filter.FilterIdHigh = 0x0000; // 32BIT ID
CAN_Filter.FilterIdLow = 0x0000;
CAN_Filter.FilterMaskIdHigh = 0x0000; // 32BIT MASK
CAN_Filter.FilterMaskIdLow = 0x0000;
CAN_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; //filter_0 --> FIFO0
CAN_Filter.FilterActivation = ENABLE; // NOTE: deactivate it if not used!
if( HAL_OK != HAL_CAN_ConfigFilter(&hcan1, &CAN_Filter))
{
Error_Handler();
}
HAL_Status = HAL_CAN_Start(&hcan1);
if(HAL_Status!=HAL_OK){
Error_Handler();
}
// Activate CAN RX notification (HERE WE attach FIFO0 to CAN1) called "CAN0" in manual
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
// Activate CAN TX notification
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
{
Error_Handler();
}
}
void filter_to_can_2(void)
{
// add filter_0 to can_1
HAL_StatusTypeDef HAL_Status;
CAN_FilterTypeDef CAN_Filter;
CAN_Filter.FilterBank = 14; // <=27
CAN_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
CAN_Filter.FilterScale= CAN_FILTERSCALE_32BIT; // 32BIT WIDTH
CAN_Filter.FilterIdHigh = 0x0000; // 32BIT ID
CAN_Filter.FilterIdLow = 0x0000;
CAN_Filter.FilterMaskIdHigh = 0x0000; // 32BIT MASK
CAN_Filter.FilterMaskIdLow = 0x0000;
CAN_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO1; //filter_0 --> FIFO0
CAN_Filter.FilterActivation = ENABLE;
CAN_Filter.SlaveStartFilterBank = 14;
if( HAL_OK != HAL_CAN_ConfigFilter(&hcan2, &CAN_Filter))
{
Error_Handler();
}
HAL_Status = HAL_CAN_Start(&hcan2);
if(HAL_Status!=HAL_OK){
Error_Handler();
}
// Activate CAN RX notification
if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO1_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
// Activate CAN TX notification
if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
{
Error_Handler();
}
}
记得要把以上代码放在main函数里初始化一下。
3、 配置can2发送数据的代码。
extern CAN_HandleTypeDef hcan2;
CAN_TxHeaderTypeDef TxHeader; //发送句柄指针
u8 canbuf[8] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};//要发送的数据
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8)
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
u8 CAN2_Send_Msg(u8* msg,u8 len)
{
u8 i=0;
u32 TxMailbox;
u8 message[8];
TxHeader.StdId=0X12; //标准标识符
TxHeader.ExtId=0x12; //扩展标识符(29位)
TxHeader.IDE=CAN_ID_STD; //使用标准帧
TxHeader.RTR=CAN_RTR_DATA; //数据帧
TxHeader.DLC=len;
for(i=0;i<len;i++)
{
message[i]=msg[i];
}
if(HAL_CAN_AddTxMessage(&hcan2, &TxHeader, message, &TxMailbox) != HAL_OK)//发送
{
return 1;
}
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan2) != 3) {}
return 0;
}
4、配置can1中断接收代码。
extern CAN_HandleTypeDef hcan1;
CAN_RxHeaderTypeDef RxHeader; //接收句柄指针
uint8_t RXmessage[8]; //接收数据存放数组
//hal库CAN回调函数,can1口中断接收数据
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)//接受邮箱0挂起中断回调函数
{
if(hcan->Instance==CAN1)
{
HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO0,&RxHeader,RXmessage);//获取数据
}
}
5、测试can总线代码。
while(1)中添加如下代码测试:
res=CAN2_Send_Msg(canbuf,8);//发送8个字节
if(res) printf("发送失败!\r\n");//提示发送失败
printf("RX the CAN data: %02X%02X%02X%02X%02X%02X%02X%02X\r\n",RXmessage[0],RXmessage[1],RXmessage[2],RXmessage[3],RXmessage[4],RXmessage[5],RXmessage[6],RXmessage[7]);