你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 HAL库CAN总线收发、中断方式接收示例教程

[复制链接]
STMCU小助手 发布时间:2022-4-12 10:00
配置CAN
先了解几个关键词简称:


最小时间单位(Tq,Time Quantum)
同步段(SS,Synchronization Segment)1tq
传播时间段(PTS,Propagation Time Segment)1~8tq
相位缓冲段1(PBS1,Phase Buffer Segment1)1~8tq
相位缓冲段2(PBS2,Phase Buffer Segment2)2~8tq
再同步补偿宽度(SJW,reSynchronization Jump Width)1~4tq
波特率分频器(BRP,Baud Rate Prescaler)
STM32把传播时间段(PTS)和相位缓冲段1(PBS1)合并了,形成了时间段1(TS1)。

CAN位时序寄存器(CAN_BTR)用于设置TS1、TS2、BRP、SJW等参数,这些参数直接决定CAN的波特率。

@RPJH23%IDIX8DXXKZZF4R7.png

SJW[1:0]再同步补偿宽度

TS1[3:0]时间段1

TS2[2:0]时间段2

BRP[9:0]波特率分频器

可以看到没有同步段(SS段),这是因为STM32已经将SS段固化为1。

除去这几个参数,还需要设置分频,STM32F1系列一般是跑到72M主频,CAN是挂在36M的APB1时钟上,设置CAN的分频就是分的这个36M。

下面这张图是波特率计算公式:

4f9a0ef7766841fc8671353d8cb869fe.png

整合一下波特率计算公式就是这样的:

波特率 = APB1 / [(1 + (TS1+1) + (TS2+1)) * (BRP+1)]

在简化就是:波特率 = 时钟主频 / 分频 / (tq1 + tq2 + ss)

其中SS就是同步段,已经恒为1,所以:波特率 = 时钟主频 / 分频 / (tq1 + tq2 + 1)

下面我们开始实际设置波特率,这里要注意,CAN的波特率最大为1Mbps。

stm32f103的CAN的时钟主频是36M,分9频就是4M,设置tq1=5,tq2=2,ss恒等于1,那么:波特率 = 36MHz / 9分频 /(5 + 2 + 1) = 500KHz

另外还有一向是:再同步补偿宽度(reSynchronization Jump Width) 这个参数,其实就是一个由数个Tq组成的一个段,用来对同步误差进行补偿,可以简单理解为为了提高精准度的,例如两个CAN进行通讯时由于两个板子的晶振可能存在误差从而导致CAN的波特率没有500K那么精准,所以就需要设置一个补偿参数去修正,这个参数就需要根据你实际的板子情况去调整了。

注意:stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。

XG3}YF2)VM[)56]LWKNMZE4.png

0O(JT%S7YRV7H$)3`V~R.png

代码修改
STM32CUBEMX生成的CAN配置代码是没有过滤器设置的,需要手动添加。

  1. typedef struct
  2. {
  3.         uint32_t mailbox;
  4.         CAN_TxHeaderTypeDef hdr;
  5.         uint8_t payload[8];
  6. }CAN_TxPacketTypeDef;

  7. typedef struct
  8. {
  9.         CAN_RxHeaderTypeDef hdr;
  10.         uint8_t payload[8];
  11. }CAN_RxPacketTypeDef;
复制代码
  1. /// CAN过滤器寄存器位宽类型定义
  2. typedef union
  3. {
  4.     __IO uint32_t value;
  5.     struct
  6.     {
  7.         uint8_t REV : 1;                        ///< [0]    :未使用
  8.         uint8_t RTR : 1;                        ///< [1]    : RTR(数据帧或远程帧标志位)
  9.         uint8_t IDE : 1;                        ///< [2]    : IDE(标准帧或扩展帧标志位)
  10.         uint32_t EXID : 18;                        ///< [21:3] : 存放扩展帧ID
  11.         uint16_t STID : 11;                        ///< [31:22]: 存放标准帧ID
  12.     } Sub;
  13. } CAN_FilterRegTypeDef;


  14. #define CAN_BASE_ID 0                                                ///< CAN标准ID,最大11位,也就是0x7FF

  15. #define CAN_FILTER_MODE_MASK_ENABLE 1                ///< CAN过滤器模式选择:=0:列表模式  =1:屏蔽模式

  16. #define CAN_ID_TYPE_STD_ENABLE      1       ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID

  17. void CAN_Filter_Config(void)
  18. {
  19.     CAN_FilterTypeDef sFilterConfig;
  20.     CAN_FilterRegTypeDef IDH = {0};
  21.     CAN_FilterRegTypeDef IDL = {0};

  22. #if CAN_ID_TYPE_STD_ENABLE
  23.     IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF;                // 标准ID高16位
  24.     IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF);                                // 标准ID低16位
  25. #else
  26.     IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF;                // 扩展ID高16位
  27.     IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF);                                // 扩展ID低16位
  28.     IDL.Sub.IDE  = 1;                                                                        // 扩展帧标志位置位
  29. #endif
  30.     sFilterConfig.FilterBank           = 0;                                                                                                // 设置过滤器组编号
  31. #if CAN_FILTER_MODE_MASK_ENABLE
  32.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式
  33. #else
  34.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
  35. #endif
  36.     sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽
  37.     sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
  38.     sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位
  39.     sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位
  40.     sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
  41.     sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO0
  42.     sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器
  43.     sFilterConfig.SlaveStartFilterBank = 14;                                                                                        // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
  44.     if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  45.     {
  46.         Error_Handler();
  47.     }
  48. }

  49. uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
  50. {
  51.         if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
  52.                 return 1;
  53.         return 0;
  54. }

  55. void CAN_Init(void)
  56. {
  57.     MX_CAN_Init();
  58.     CAN_Filter_Config();
  59.     HAL_CAN_Start(&hcan);
  60.     HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 使能CAN接收中断
  61. }

  62. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
  63. {
  64.         static CAN_RxPacketTypeDef packet;
  65.         
  66.     // CAN数据接收
  67.     if (canHandle->Instance == hcan.Instance)
  68.     {
  69.         if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK)                // 获得接收到的数据头和数据
  70.         {
  71.                         printf("\r\n\r\n\r\n################### CAN RECV ###################\r\n");
  72.                         printf("STID:0x%X\r\n",packet.hdr.StdId);
  73.                         printf("EXID:0x%X\r\n",packet.hdr.ExtId);
  74.                         printf("DLC :%d\r\n", packet.hdr.DLC);
  75.                         printf("DATA:");
  76.                         for(int i = 0; i < packet.hdr.DLC; i++)
  77.                         {
  78.                                 printf("0x%02X ", packet.payload<i>);
  79.                         }
  80.            HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);                                                // 再次使能FIFO0接收中断
  81.         }
  82.     }
  83. }</i>
复制代码

  1. CAN_TxPacketTypeDef g_CanTxPacket;

  2. void CAN_SetTxPacket(void)
  3. {
  4.         g_CanTxPacket.hdr.StdId = 0x321;                        // 标准ID
  5. //        g_CanTxPacket.hdr.ExtId = 0x10F01234;                // 扩展ID
  6.         g_CanTxPacket.hdr.IDE = CAN_ID_STD;                        // 标准ID类型
  7. //        g_CanTxPacket.hdr.IDE = CAN_ID_EXT;                        // 扩展ID类型
  8.         g_CanTxPacket.hdr.DLC = 8;                                        // 数据长度
  9.         g_CanTxPacket.hdr.RTR = CAN_RTR_DATA;                // 数据帧
  10. //        g_CanTxPacket.hdr.RTR = CAN_RTR_REMOTE;                // 远程帧
  11.         g_CanTxPacket.hdr.TransmitGlobalTime = DISABLE;
  12.         
  13.         for(int i = 0; i < 8; i++)
  14.         {
  15.                 g_CanTxPacket.payload<i> = i;
  16.         }
  17. }

  18. int main()
  19. {
  20.     HAL_Init();
  21.     SystemClock_Config();
  22.     MX_GPIO_Init();
  23.     MX_USART1_UART_Init();
  24.     CAN_Init();
  25.         printf("----------------------------------------\r\n");

  26.         CAN_SetTxPacket();
  27.         
  28.     while(1)
  29.     {
  30.                 if(CAN_Transmit(&g_CanTxPacket) != 0)
  31.                         printf("failed\r\n");
  32.                 HAL_Delay(1000);
  33.     }
  34. }

复制代码


收藏 评论0 发布时间:2022-4-12 10:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版