CubeMX STM32实现CAN通信——回环测试数据收发

CubeMX STM32实现CAN通信——回环测试数据收发

  • CAN通信
    • CAN协议
  • CubeMX设置
  • 代码部分
    • 过滤器初始化
    • CAN发送函数
    • CAN接收中断
  • 总结

CAN通信

在工业上,CAN通信和485通信用得比较广泛。上一篇文章中主要学习到DMX512通信,该通信协议的物理层也是485,其特别之处在于波特率为250Kbps,还有特殊的BREAK和MAB信号。今天,我继续尝试了在CubeMX上实现STM32的CAN通信。

CAN协议

CAN的全称为控制器局域网总线(Controller Area Network),这是一种稳定性极高的串行通讯协议总线,传输速率最大为1Mbps。其特点网上介绍得比较全面,这里主要说一下它的数据帧。CAN的数据帧由7个段组成:起始位、仲裁段、数据段、CRC段(错误检测)、ACK段(是否接收正常)、结束段。仲裁段中可设置ID,11位/29位均可,主要看需求,数据段可发送0-8个字节。

CubeMX设置

继续用上一篇文章的工程继续编程(有DMX512信号收发案例【请参考上一篇】),通过查看STM32F1手册可知,CAN时钟总线挂载在APB1上,这里设置的是32MHz。
由下图可以看到,CubeMX会自动计算一个位的时间,也就能计算出波特率:(32MHz/4/(1+6+3))= 800KHz,这里(1+6+3)的意思是:STM32单片机CAN通信的一个位由(1个Tq的SS段+6个Tq的PBS1段+3个Tq的PBS2段)组成。
CubeMX STM32实现CAN通信——回环测试数据收发_第1张图片
这里简单说一下基本设置
1.TTCM时间触发功能,这里无需时间触发,DISABLE;
2.ABOM自动离线管理功能,出错后可以自动尝试恢复,ENABLE;
3.AWUM自动唤醒功能,有利于节能,ENABLE;
4.NART自动重传功能,发送失败可自动重传,ENABLE;
5.RFLM锁定接收FIFO功能,看用户需要是否覆盖或者锁定,DISABLE;
6.TXFP发送报文优先级判定功能,以ID优先级发送,DISABLE。
设定完成后,打开接收中断,按需求配置优先级:
CubeMX STM32实现CAN通信——回环测试数据收发_第2张图片

代码部分

过滤器初始化

过滤器初始化参考野火教程链接: link.

#define PASS_ID ((uint32_t)0x1234)
void CAN_Filter_Init(CAN_HandleTypeDef* canHandle)
{
 CAN_FilterTypeDef sFilterConfig;
 
 sFilterConfig.FilterActivation = ENABLE;//打开过滤器
 
 sFilterConfig.FilterBank = 0;//过滤器0 这里可设0-13
 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//采用掩码模式
 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;//采用32位掩码模式
 sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0
 
 sFilterConfig.FilterIdHigh = ((PASS_ID<<3|CAN_ID_EXT|CAN_RTR_DATA)&0xffff0000)>>16; //设置过滤器ID高16位
 sFilterConfig.FilterIdLow = ((PASS_ID<<3|CAN_ID_EXT|CAN_RTR_DATA)&0xffff);//设置过滤器ID低16位
 sFilterConfig.FilterMaskIdHigh = 0xffff;//设置过滤器掩码高16位
 sFilterConfig.FilterMaskIdLow = 0x0000;//设置过滤器掩码低16位
 if(HAL_CAN_ConfigFilter(canHandle,&sFilterConfig) != HAL_OK)//初始化过滤器
 {
  Error_Handler();
 }
 if(HAL_CAN_Start(canHandle) != HAL_OK)//打开can
 {
  Error_Handler();
 }
 if(HAL_CAN_ActivateNotification(canHandle,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接收中断
 {
  Error_Handler();
 }
}

CAN发送函数

/********
can发送函数
该函数可设定输入值:长度、id、数据等
*********/
void CAN_TX_Message(void)
{
 if(can_tx_end == 0)
 {
  can_tx_end = 1;
  if(can_tx_end == 0)
  TxMessage.StdId = 0;
  TxMessage.ExtId = PASS_ID;
  TxMessage.RTR = CAN_RTR_DATA;
  TxMessage.IDE = CAN_ID_EXT;
//  TxMessage.IDE = ide == 0 ? CAN_ID_STD : CAN_ID_EXT;  // 数据长度
  TxMessage.DLC = 8;
  TxMessage.TransmitGlobalTime = DISABLE;
  if(HAL_CAN_AddTxMessage(&hcan,&TxMessage,TxData,&TxMailboxs) != HAL_OK)
  {
   Error_Handler();
  }
  while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) ==0);
 }
 if(__HAL_CAN_GET_FLAG(&hcan,CAN_FLAG_TXOK0) == 1)
 {
  can_tx_end = 0;
 }
}

CAN接收中断

void USB_LP_CAN1_RX0_IRQHandler(void)
{
  /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */
  if(HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&RxMessage,RxData) != HAL_OK)
 {
  Error_Handler();  
 }
 can_msg_info(&RxMessage,RxData);
 HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING);//重新开启接收中断
 HAL_CAN_IRQHandler(&hcan);
}

void can_msg_info(CAN_RxHeaderTypeDef* hdr, const uint8_t* data)
{
 printf("IDE     : %s\r\n",hdr->IDE == CAN_ID_STD ? "CAN_ID_STD" : "CAN_ID_EXT");
 printf("RTR     : %s\r\n",hdr->RTR == CAN_RTR_DATA ? "CAN_RTR_DATA" : "CAN_RTR_REMOTE");
 printf("DLC     : %d\r\n", hdr->DLC);
 printf("StdId   : 0x%X\r\n", hdr->StdId);
 printf("ExtId   : 0x%X\r\n", hdr->ExtId);
 printf("Data    : 0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\r\n\r\n", data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
}

接收引用了链接: link.

总结

CubeMX构建STM32工程的确方便很多,要实现CAN通信,主要做的有3件事,第一、初始化过滤器;第二、编写发送数据函数;第三、编写接收中断。这里有一点需要提及一下,用CubeMX库和官方库是有点差别的,就是判断是否发送完成这里,用TxMailbox去判断的话,官方库可以直接调用CAN_TransmitStatus(CAN1,TxMailbox)判断是否发送成功,CubeMX库我是调用HAL_CAN_GetTxMailboxesFreeLevel(&hcan)和__HAL_CAN_GET_FLAG(&hcan,CAN_FLAG_TXOK0)同时判断是否发送完成的。
最后,附上一张测试结果图,若上述有误,还请大家指出。
CubeMX STM32实现CAN通信——回环测试数据收发_第3张图片

你可能感兴趣的:(STM32,CubeMX,stm32,嵌入式,单片机,can)