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

【经验分享】STM32 F4系列HAL库使用双CAN配置及注意事项

[复制链接]
STMCU小助手 发布时间:2022-4-11 10:16
先了解几个关键词简称:
最小时间单位(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的波特率。

35T9T~SVL76_%I_XNV$IE.png

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

TS1[3:0]时间段1

TS2[2:0]时间段2

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

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

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

4f9a0ef7766841fc8671353d8cb869fe.png

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

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

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

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

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

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

时钟配置

{B$BW2T@1}~OPZ5NDXMJ@XE.png

CAN配置
     CAN外设是挂载在APB1_PCLK1时钟上的,APB1_PCLK1是42M。CAN的最大速率是1MHZ,本实验配置为500KHZ。波特率配置计算方法:

CAN波特率 = APB1_PCLK1/分频/(tq1 + tq2 + ss),其中SS是SS段,在STM32中已经固定为1个tq

本实验波特率 = 42MHZ/4分频/(14 + 6 + 1) = 0.5MHZ = 500KHZ

FUMC{T1CY`SX4$M1A]4K.png

使能CAN接收中断

PG]X3XYH(31K7GDRVV_DOEB.png

配置CAN的IO,此步骤必须!!要不然HAL库函数MX_CAN_Init初始化会失败!!

8H%}DJ2O5VZ9YMAYI%IZ(GT.png

CAN2和CAN1是同样的配置,这里不再贴CAN2的配置图了。

STM32外设CAN过滤器说明

STM32CUBEMX生成的代码默认是没有设置ID筛选器的,所以需要手动添加过滤器代码。下面一张图,STM32的过滤器组:

N%LJ~A{T4H[`7HOVKDQOZYY.png

STM32F407ZG有28组筛选器,一组筛选器有两个32位的寄存器,筛选器组可配置为四种模式:

1个32位筛选器-标识符掩码模式,这时候筛选器组的两个32位寄存器一个用来存放ID,另一个用来存放ID的掩码
两个32位筛选器-标识符列表模式,这时候筛选器组的两个32位寄存器都用来存放ID
两个16位筛选器-标识符掩码模式,这时候筛选器组被分成了4个16位的寄存器,分别存放ID高16位+掩码高16位,ID低16位+掩码低16位
四个16位筛选-标识符列表模式,这时候筛选器组被分成了4个16位的寄存器,都存放ID的高16位和低16位

贴上我的配置代码:



  1. #define CAN1_FILTER_MODE_MASK_ENABLE 1        ///< CAN1过滤器模式选择:=1:屏蔽位模式  =0:屏蔽列表模式
  2. #define CAN2_FILTER_MODE_MASK_ENABLE 1  ///< CAN2过滤器模式选择:=1:屏蔽位模式  =0:屏蔽列表模式

  3. #define CAN1_BASE_ID  0x10F00266                ///< 主CAN过滤ID
  4. #define CAN2_BASE_ID  0x10F0F126                ///< 从CAN过滤ID

  5. #define CAN1_FILTER_BANK  0             ///< 主CAN过滤器组编号
  6. #define CAN2_FILTER_BANK  14            ///< 从CAN过滤器组编号

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

  20. // CAN_FMR寄存器位宽类型定义
  21. typedef union
  22. {
  23.         __IO uint32_t value;
  24.         struct
  25.         {
  26.                 uint8_t FINIT : 1;
  27.                 uint8_t RESERVER_0 : 7;
  28.                 uint8_t CAN2SB : 6;
  29.                 uint32_t RESERVER_1 : 18;
  30.         }Sub;
  31. }FMR_TypeDef;

  32. /// 设置CAN1的过滤器(主CAN)
  33. static void CAN1_Filter_Config(void)
  34. {
  35.         CAN_FilterTypeDef sFilterConfig;
  36.     CAN_FilterRegTypeDef IDH = {0};
  37.     CAN_FilterRegTypeDef IDL = {0};

  38.         IDH.Sub.IDE  = 0;                                                                // 标准帧
  39.         IDH.Sub.STID = 0;                                                                // 标准帧ID值
  40.     IDH.Sub.EXID = (CAN1_BASE_ID >> 16) & 0xFFFF;        // 扩展帧高16位ID值
  41.         
  42.         IDL.Sub.IDE  = 1;                                                                // 扩展帧
  43.         IDL.Sub.STID = 0;                                                                // 标准帧ID值
  44.     IDL.Sub.EXID = (CAN1_BASE_ID & 0xFFFF);                        // 扩展帧低16位ID值

  45.         sFilterConfig.FilterBank           = CAN1_FILTER_BANK;                                                                // 设置过滤器组编号
  46. #if CAN1_FILTER_MODE_MASK_ENABLE
  47.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式
  48. #else
  49.         sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
  50. #endif
  51.     sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽
  52.     sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
  53.     sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位
  54.     sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位
  55.     sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
  56.     sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO0
  57.     sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器
  58.     sFilterConfig.SlaveStartFilterBank = CAN2_FILTER_BANK;                                                                // 设置CAN2的起始过滤器组(对于单CAN的CPU或从CAN此参数无效;对于双CAN的CPU此参数为从CAN的起始过滤器组编号)
  59.     if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  60.     {
  61.         Error_Handler();
  62.     }
  63.         {
  64.                 FMR_TypeDef regval = {0};
  65.                 regval.value = hcan1.Instance->FMR;
  66.                 printf("------ CAN1:> FMR:0x%0X  CAN2SB:0x%X  \r\n", regval.value, regval.Sub.CAN2SB);
  67.         }
  68. }

  69. /// 设置CAN2的过滤器(从CAN)
  70. static void CAN2_Filter_Config(void)
  71. {
  72.         CAN_FilterTypeDef sFilterConfig;
  73.     CAN_FilterRegTypeDef IDH = {0};
  74.     CAN_FilterRegTypeDef IDL = {0};

  75.         IDH.Sub.IDE  = 0;
  76.         IDH.Sub.STID = 0;
  77.     IDH.Sub.EXID = (CAN2_BASE_ID >> 16) & 0xFFFF;
  78.         
  79.         IDL.Sub.IDE  = 1;
  80.         IDL.Sub.STID = 0;
  81.     IDL.Sub.EXID = (CAN2_BASE_ID & 0xFFFF);

  82.     sFilterConfig.FilterBank           = CAN2_FILTER_BANK;                                                                // 设置过滤器组编号
  83. #if CAN2_FILTER_MODE_MASK_ENABLE
  84.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式
  85. #else
  86.         sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
  87. #endif
  88.     sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽
  89.     sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
  90.     sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位
  91.     sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位
  92.     sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
  93.     sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO0
  94.     sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器
  95.     sFilterConfig.SlaveStartFilterBank = 28;                                                                                        // 无效
  96.     if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK)
  97.     {
  98.         Error_Handler();
  99.     }
  100.         {
  101.                 FMR_TypeDef regval = {0};
  102.                 regval.value = hcan2.Instance->FMR;
  103.                 printf("------ CAN2:> FMR:0x%0X  CAN2SB:0x%X  \r\n", regval.value, regval.Sub.CAN2SB);
  104.         }
  105. }

  106. /// CAN初始化
  107. void CAN_Init(void)
  108. {
  109.     MX_CAN1_Init();                                                                                                                                                // 初始化CNA1
  110.     CAN1_Filter_Config();                                                                                                                                // 初始化CNA1过滤器
  111.     HAL_CAN_Start(&hcan1);                                                                                                                                // 启动CAN1
  112.     HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 激活CAN1 FIFO0

  113.     MX_CAN2_Init();
  114.     CAN2_Filter_Config();
  115.     HAL_CAN_Start(&hcan2);
  116.     HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);
  117. }

  118. /**
  119. * CAN数据传输
  120. * @param  buf    待发送的数据
  121. * @param  len    数据长度
  122. * @param  number CAN编号,=0:CAN1,=1:CAN2
  123. * @return        0:成功  other:失败
  124. */
  125. uint8_t CAN_Transmit(const void* buf, uint32_t len, uint8_t number)
  126. {
  127.     uint32_t txmailbox = 0;
  128.     uint32_t offset = 0;
  129.     CAN_TxHeaderTypeDef hdr;

  130.     hdr.IDE = CAN_ID_EXT;                                                                                                        // ID类型:扩展帧
  131.     hdr.RTR = CAN_RTR_DATA;                                                                                                        // 帧类型:数据帧
  132.     hdr.StdId = 0;                                                                                                                        // 标准帧ID,最大11位,也就是0x7FF
  133.     hdr.ExtId = number == 0 ? CAN1_BASE_ID : CAN2_BASE_ID;                                        // 扩展帧ID,最大29位,也就是0x1FFFFFFF
  134.     hdr.TransmitGlobalTime = DISABLE;

  135.     while (len != 0)
  136.     {
  137.         hdr.DLC = len > 8 ? 8 : len;                        // 数据长度
  138.         if (HAL_CAN_AddTxMessage(number == 0 ? &hcan1 : &hcan2, &hdr, ((uint8_t *)buf) + offset, &txmailbox) != HAL_OK)
  139.             return 1;
  140.         offset += hdr.DLC;
  141.         len -= hdr.DLC;
  142.     }
  143.     return 0;
  144. }

  145. uint8_t CAN1_RX_STA = 0;                ///< CAN1数据接收标志:[7]:数据 [6:0]:未使用
  146. uint8_t CAN2_RX_STA = 0;                ///< CAN2数据接收标志:[7]:数据 [6:0]:未使用

  147. uint8_t CAN1_RX_BUF[8];                        ///< CAN1数据接收缓存
  148. uint8_t CAN2_RX_BUF[8];                        ///< CAN2数据接收缓存

  149. uint8_t CAN1_TX_BUF[8];                        ///< CAN1数据发送缓存
  150. uint8_t CAN2_TX_BUF[8];                        ///< CAN2数据发送缓存

  151. /**
  152. * CAN FIFO0 数据接收中断回调函数
  153. * @param hcan CAN句柄
  154. */
  155. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
  156. {
  157.     static CAN_RxHeaderTypeDef CAN_RX_HDR;

  158.     // CAN1数据接收
  159.     if (hcan->Instance == hcan1.Instance)
  160.     {
  161.         // 数据已经处理
  162.         if ((CAN1_RX_STA & 0x80) == 0)
  163.         {
  164.             // 清空缓存
  165.             memset(CAN1_RX_BUF, 0, 8);

  166.             // 接收数据
  167.             if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, CAN1_RX_BUF) == HAL_OK)                // 获得接收到的数据头和数据
  168.             {
  169.                 CAN1_RX_STA |= 0x80;                                                                                                                                // 标记接收到数据
  170.                 HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 再次使能FIFO0接收中断
  171.             }
  172.         }
  173.     }

  174.     // CAN2数据接收
  175.     else if (hcan->Instance == hcan2.Instance)
  176.     {
  177.         // 数据已经处理
  178.         if ((CAN2_RX_STA & 0x80) == 0)
  179.         {
  180.             // 清空缓存
  181.             memset(CAN2_RX_BUF, 0, 8);

  182.             // 接收数据
  183.             if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, CAN2_RX_BUF) == HAL_OK)                // 获得接收到的数据头和数据
  184.             {
  185.                 CAN2_RX_STA |= 0x80;                                                                                                                                // 标记接收到数据
  186.                 HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 再次使能FIFO0接收中断
  187.             }
  188.         }
  189.     }
  190. }

  191. ///< CAN数据处理函数
  192. inline void CAN_RecvHandler(void)
  193. {
  194.     // CAN1有数据收到
  195.     if (CAN1_RX_STA & 0x80)
  196.     {
  197.                 int i = 0;
  198.                 memcpy(CAN1_TX_BUF, CAN1_RX_BUF, sizeof(CAN1_RX_BUF));                // 拷贝出数据
  199.                 CAN1_RX_STA = 0;                                                                                        // 重置CAN1接收状态
  200.                 for(i = 0; i != 8; i++)
  201.                 {
  202.                         printf("CAN1_TX_BUF[%d]:0x%X\r\n", i, CAN1_TX_BUF<i>);
  203.                 }
  204.                 printf("\r\n\r\n");
  205.     }

  206.     // CAN2有数据收到
  207.     if (CAN2_RX_STA & 0x80)
  208.     {
  209.                 int i = 0;
  210.                 memcpy(CAN2_TX_BUF, CAN2_RX_BUF, sizeof(CAN2_RX_BUF));                // 拷贝出数据
  211.                 CAN2_RX_STA = 0;                                                                                        // 重置CAN1接收状态
  212.                 for(i = 0; i != 8; i++)
  213.                 {
  214.                         printf("CAN2_TX_BUF[%d]:0x%X\r\n", i, CAN2_TX_BUF<i>);
  215.                 }
  216.                 printf("\r\n\r\n");
  217.     }
  218. }



  219. </i></i>
复制代码


收藏 评论0 发布时间:2022-4-11 10:16

举报

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