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

【经验分享】STM32F7xx —— CAN通信

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
一、CAN基础
差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。

CAN总线的开始和结束都有一个120Ω的终端电阻。

数据帧:标准帧11位,  扩展帧29位。

其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。

STM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。

二、几个重要的CAN函数
  1. HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化

  2. HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送

  3. HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码

三、几个重要的结构
  1. // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量
  2. typedef struct
  3. {
  4.   CAN_TypeDef                 *Instance;  /*!< Register base address          */

  5.   CAN_InitTypeDef             Init;       /*!< CAN required parameters        */

  6.   CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */

  7.   CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */

  8.   __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */

  9.   HAL_LockTypeDef             Lock;       /*!< CAN locking object             */

  10.   __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */

  11. }CAN_HandleTypeDef;
复制代码
  1. // CAN配置结构体
  2. // 前5个参数来设置 CAN_BTR —— 波特率
  3. // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位
  4. typedef struct
  5. {
  6.   uint32_t Prescaler;  /*!< Specifies the length of a time quantum.
  7.                             This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */

  8.   uint32_t Mode;       /*!< Specifies the CAN operating mode.
  9.                             This parameter can be a value of @ref CAN_operating_mode */

  10.   uint32_t SJW;        /*!< Specifies the maximum number of time quanta
  11.                             the CAN hardware is allowed to lengthen or
  12.                             shorten a bit to perform resynchronization.
  13.                             This parameter can be a value of @ref CAN_synchronisation_jump_width */

  14.   uint32_t BS1;        /*!< Specifies the number of time quanta in Bit Segment 1.
  15.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */

  16.   uint32_t BS2;        /*!< Specifies the number of time quanta in Bit Segment 2.
  17.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */

  18.   uint32_t TTCM;       /*!< Enable or disable the time triggered communication mode.
  19.                             This parameter can be set to ENABLE or DISABLE. */

  20.   uint32_t ABOM;       /*!< Enable or disable the automatic bus-off management.
  21.                             This parameter can be set to ENABLE or DISABLE */

  22.   uint32_t AWUM;       /*!< Enable or disable the automatic wake-up mode.
  23.                             This parameter can be set to ENABLE or DISABLE */

  24.   uint32_t NART;       /*!< Enable or disable the non-automatic retransmission mode.
  25.                             This parameter can be set to ENABLE or DISABLE */

  26.   uint32_t RFLM;       /*!< Enable or disable the receive FIFO Locked mode.
  27.                             This parameter can be set to ENABLE or DISABLE */

  28.   uint32_t TXFP;       /*!< Enable or disable the transmit FIFO priority.
  29.                             This parameter can be set to ENABLE or DISABLE */
  30. }CAN_InitTypeDef;
复制代码
  1. // 过滤器设置
  2. typedef struct
  3. {
  4.   uint32_t FilterIdHigh;          /*!< Specifies the filter identification number (MSBs for a 32-bit
  5.                                        configuration, first one for a 16-bit configuration).
  6.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  7.   uint32_t FilterIdLow;           /*!< Specifies the filter identification number (LSBs for a 32-bit
  8.                                        configuration, second one for a 16-bit configuration).
  9.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  10.   uint32_t FilterMaskIdHigh;      /*!< Specifies the filter mask number or identification number,
  11.                                        according to the mode (MSBs for a 32-bit configuration,
  12.                                        first one for a 16-bit configuration).
  13.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  14.   uint32_t FilterMaskIdLow;       /*!< Specifies the filter mask number or identification number,
  15.                                        according to the mode (LSBs for a 32-bit configuration,
  16.                                        second one for a 16-bit configuration).
  17.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  18.   uint32_t FilterFIFOAssignment;  /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.
  19.                                        This parameter can be a value of @ref CAN_filter_FIFO */

  20.   uint32_t FilterNumber;          /*!< Specifies the filter which will be initialized.
  21.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 27 */

  22.   uint32_t FilterMode;            /*!< Specifies the filter mode to be initialized.
  23.                                        This parameter can be a value of @ref CAN_filter_mode */

  24.   uint32_t FilterScale;           /*!< Specifies the filter scale.
  25.                                        This parameter can be a value of @ref CAN_filter_scale */

  26.   uint32_t FilterActivation;      /*!< Enable or disable the filter.
  27.                                        This parameter can be set to ENABLE or DISABLE. */

  28.   uint32_t BankNumber;            /*!< Select the start slave bank filter.
  29.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 28 */

  30. }CAN_FilterConfTypeDef;
复制代码
  1. // 模式  我们使用普通模式
  2. #define CAN_MODE_NORMAL             ((uint32_t)0x00000000U)                     /*!< Normal mode   */
  3. #define CAN_MODE_LOOPBACK           ((uint32_t)CAN_BTR_LBKM)                   /*!< Loopback mode */
  4. #define CAN_MODE_SILENT             ((uint32_t)CAN_BTR_SILM)                   /*!< Silent mode   */
  5. #define CAN_MODE_SILENT_LOOPBACK    ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM))  /*!< Loopback combined with silent mode */
复制代码
  1. // 标准帧 扩展帧
  2. #define CAN_ID_STD             ((uint32_t)0x00000000U)  /*!< Standard Id */
  3. #define CAN_ID_EXT             ((uint32_t)0x00000004U)  /*!< Extended Id */
复制代码
  1. // 数据帧 远程帧
  2. #define CAN_RTR_DATA                ((uint32_t)0x00000000U)  /*!< Data frame */
  3. #define CAN_RTR_REMOTE              ((uint32_t)0x00000002U)  /*!< Remote frame */
复制代码
  1. // CAN中断使能
  2. __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码
  1. // 接收中断
  2. #define CAN_IT_FMP0                 ((uint32_t)CAN_IER_FMPIE0)  /*!< FIFO 0 message pending interrupt */
  3. #define CAN_IT_FF0                  ((uint32_t)CAN_IER_FFIE0)   /*!< FIFO 0 full interrupt            */
  4. #define CAN_IT_FOV0                 ((uint32_t)CAN_IER_FOVIE0)  /*!< FIFO 0 overrun interrupt         */
  5. #define CAN_IT_FMP1                 ((uint32_t)CAN_IER_FMPIE1)  /*!< FIFO 1 message pending interrupt */
  6. #define CAN_IT_FF1                  ((uint32_t)CAN_IER_FFIE1)   /*!< FIFO 1 full interrupt            */
  7. #define CAN_IT_FOV1                 ((uint32_t)CAN_IER_FOVIE1)  /*!< FIFO 1 overrun interrupt         */
复制代码

四、接口设计
与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。

  1. typedef enum
  2. {
  3.   CAN_CHANNEL_NONE,
  4.   CAN_CHANNEL_1,
  5.   CAN_CHANNEL_2,
  6.   CAN_CHANNEL_NUM
  7. } can_channel_t;

  8. #define CAN1_CHANNEL              CAN1
  9. #define CAN1_PREEMPT_PRIO         CAN1_RX_PRIORITY
  10. #define CAN1_RX_IRQ               CAN1_RX0_IRQn
  11. #define CAN1_RX_IRQ_FUNC          CAN1_RX0_IRQHandler
  12. #define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE()
  13. #define CAN1_TX_PORT              GPIOA
  14. #define CAN1_TX_PIN               GPIO_PIN_12
  15. #define CAN1_TX_AF                GPIO_AF9_CAN1
  16. #define CAN1_TX_CONFIG()          GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)
  17. #define CAN1_RX_PORT              GPIOA
  18. #define CAN1_RX_PIN               GPIO_PIN_11
  19. #define CAN1_RX_AF                GPIO_AF9_CAN1
  20. #define CAN1_RX_CONFIG()          GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)

  21. #define CAN2_CHANNEL              CAN2
  22. #define CAN2_PREEMPT_PRIO         CAN2_RX_PRIORITY
  23. #define CAN2_RX_IRQ               CAN2_RX0_IRQn
  24. #define CAN2_RX_IRQ_FUNC          CAN2_RX0_IRQHandler
  25. #define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()
  26. #define CAN2_TX_PORT              GPIOB
  27. #define CAN2_TX_PIN               GPIO_PIN_6
  28. #define CAN2_TX_AF                GPIO_AF9_CAN2
  29. #define CAN2_TX_CONFIG()          GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF)
  30. #define CAN2_RX_PORT              GPIOB
  31. #define CAN2_RX_PIN               GPIO_PIN_5
  32. #define CAN2_RX_AF                GPIO_AF9_CAN2
  33. #define CAN2_RX_CONFIG()          GPIOConfigExt(CAN2_RX_PORT, CAN2_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_RX_AF)
复制代码
  1. <span style="background-color: rgb(255, 255, 255);">/</span>/ 抽象出一个CAN设备结构体
  2. typedef struct
  3. {
  4.   CAN_HandleTypeDef handle; // CAN操作句柄

  5.   CanTxMsgTypeDef tx;       // CAN发送

  6.   CanRxMsgTypeDef rx;       // CAN接收

  7.   can_queue_t recv;         // 接收队列

  8. } can_dev_t;
复制代码
  1. // 将每路CAN封装成几个小函数
  2. static can_dev_t can1_dev, can2_dev;

  3. static void can1_var_init(void)
  4. {
  5.   can1_dev.recv = can1_queue_recv;

  6.   CanQueueInit(&can1_dev.recv);
  7. }

  8. static void can1_gpio_init(void)
  9. {
  10.   CAN1_TX_CONFIG();
  11.   CAN1_RX_CONFIG();
  12. }

  13. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M
  14. static void can1_mode_init(void)
  15. {
  16.   CAN1_CLK_ENABLE();

  17.   can1_dev.handle.Instance = CAN1_CHANNEL;
  18.   can1_dev.handle.pTxMsg = &can1_dev.tx;
  19.   can1_dev.handle.pRxMsg = &can1_dev.rx;
  20.   can1_dev.handle.Init.Prescaler = 6;
  21.   can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;
  22.   can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
  23.   can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
  24.   can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
  25.   can1_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
  26.   can1_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理
  27.   can1_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
  28.   can1_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
  29.   can1_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
  30.   can1_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
  31.   HAL_CAN_Init(&can1_dev.handle);
  32. }

  33. static void can1_filter_init(void)
  34. {
  35.   CAN_FilterConfTypeDef  filter;

  36.   filter.FilterNumber     = 0; // 过滤器0
  37.   filter.FilterMode       = CAN_FILTERMODE_IDMASK;
  38.   filter.FilterScale      = CAN_FILTERSCALE_32BIT;

  39.   filter.FilterIdHigh     = 0;
  40.   filter.FilterIdLow      = 0;
  41.   filter.FilterMaskIdHigh = 0;
  42.   filter.FilterMaskIdLow  = 0;

  43.   filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0
  44.   filter.FilterActivation = ENABLE; //激活滤波器0
  45.   //filter.BankNumber=14;

  46.   HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);
  47. }

  48. static void can1_nvic_init(void)
  49. {
  50.   __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.
  51.   HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);
  52.   HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);
  53. }



  54. static void can2_var_init(void)
  55. {
  56.   can2_dev.recv = can2_queue_recv;

  57.   CanQueueInit(&can2_dev.recv);
  58. }

  59. static void can2_gpio_init(void)
  60. {
  61.   CAN2_TX_CONFIG();
  62.   CAN2_RX_CONFIG();
  63. }

  64. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M
  65. static void can2_mode_init(void)
  66. {
  67.   CAN2_CLK_ENABLE();

  68.   can2_dev.handle.Instance = CAN2_CHANNEL;
  69.   can2_dev.handle.Init.Prescaler = 6;
  70.   can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;
  71.   can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
  72.   can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
  73.   can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
  74.   can2_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
  75.   can2_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理
  76.   can2_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
  77.   can2_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
  78.   can2_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
  79.   can2_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
  80.   HAL_CAN_Init(&can2_dev.handle);
  81. }

  82. static void can2_filter_init(void)
  83. {
  84.   CAN_FilterConfTypeDef  CAN_FilterInitStructure;

  85.   CAN_FilterInitStructure.FilterNumber     = 14;
  86.   CAN_FilterInitStructure.FilterMode       = CAN_FILTERMODE_IDMASK;
  87.   CAN_FilterInitStructure.FilterScale      = CAN_FILTERSCALE_32BIT;

  88.   CAN_FilterInitStructure.FilterIdHigh     = 0;
  89.   CAN_FilterInitStructure.FilterIdLow      = 0;
  90.   CAN_FilterInitStructure.FilterMaskIdHigh = 0;
  91.   CAN_FilterInitStructure.FilterMaskIdLow  = 0;

  92.   CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0
  93.   CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0
  94.   //CAN_FilterInitStructure.BankNumber=14;

  95.   HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);
  96. }

  97. static void can2_nvic_init(void)
  98. {
  99.   __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1
  100.   HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);
  101.   HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);
  102. }
复制代码
  1. // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理
  2. typedef struct
  3. {
  4.   uint8_t channel;
  5.   can_dev_t *dev;
  6.   void (* var_init_cb)(void);
  7.   void (* gpio_init_cb)(void);
  8.   void (* mode_init_cb)(void);
  9.   void (* filter_init_cb)(void);
  10.   void (* nvic_init_cb)(void);
  11. } can_config_t;

  12. static const can_config_t can_configs[] =
  13. {
  14.   {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},
  15.   {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},
  16. };

  17. static can_dev_t *can_dev_get(uint8_t channel)
  18. {
  19.   uint8_t i;

  20.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
  21.   {
  22.     if(channel == can_configs<i>.channel)
  23.     {
  24.       return can_configs<i>.dev;
  25.     }
  26.   }

  27.   return 0;
  28. }

  29. static void can_var_init(uint8_t channel)
  30. {
  31.   uint8_t i;

  32.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
  33.   {
  34.     if(channel == can_configs<i>.channel)
  35.     {
  36.       can_configs<i>.var_init_cb();
  37.       return;
  38.     }
  39.   }
  40. }

  41. static void can_gpio_init(uint8_t channel)
  42. {
  43.   uint8_t i;

  44.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
  45.   {
  46.     if(channel == can_configs<i>.channel)
  47.     {
  48.       can_configs<i>.gpio_init_cb();
  49.       return;
  50.     }
  51.   }
  52. }

  53. static void can_mode_init(uint8_t channel)
  54. {
  55.   uint8_t i;

  56.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
  57.   {
  58.     if(channel == can_configs<i>.channel)
  59.     {
  60.       can_configs<i>.mode_init_cb();
  61.       return;
  62.     }
  63.   }
  64. }

  65. static void can_filter_init(uint8_t channel)
  66. {
  67.   uint8_t i;

  68.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
  69.   {
  70.     if(channel == can_configs<i>.channel)
  71.     {
  72.       can_configs<i>.filter_init_cb();
  73.       return;
  74.     }
  75.   }
  76. }

  77. static void can_nvic_init(uint8_t channel)
  78. {
  79.   uint8_t i;

  80.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
  81.   {
  82.     if(channel == can_configs<i>.channel)
  83.     {
  84.       can_configs<i>.nvic_init_cb();
  85.       return;
  86.     }
  87.   }
  88. }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码
  1. // 对外的接口 初始化 发送和接收
  2. void CanInit(uint8_t channel)
  3. {
  4.   can_var_init(channel);
  5.   can_gpio_init(channel);
  6.   can_mode_init(channel);
  7.   can_filter_init(channel);
  8.   can_nvic_init(channel);
  9. }

  10. void CanSend(uint8_t channel, can_frame_t *frame)
  11. {
  12.   can_dev_t *dev = can_dev_get(channel);

  13.   if(dev == 0)
  14.   {
  15.     return;
  16.   }

  17.   dev->handle.pTxMsg->StdId = frame->StdId;
  18.   dev->handle.pTxMsg->IDE   = frame->IDE;
  19.   dev->handle.pTxMsg->RTR   = frame->RTR;
  20.   dev->handle.pTxMsg->DLC   = frame->DLC;
  21.   memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);

  22.   HAL_CAN_Transmit(&dev->handle, 10);
  23. }

  24. uint8_t CanRecv(uint8_t channel, can_frame_t *frame)
  25. {
  26.   can_dev_t *dev = can_dev_get(channel);

  27.   if(dev == 0)
  28.   {
  29.     return 0;
  30.   }

  31.   return CanQueueRead(&can1_dev.recv, frame);
  32. }
复制代码
  1. // CAN中断
  2. void CAN1_RX_IRQ_FUNC(void)
  3. {
  4.   HAL_CAN_IRQHandler(&can1_dev.handle);
  5. }

  6. void CAN2_RX_IRQ_FUNC(void)
  7. {
  8.   HAL_CAN_IRQHandler(&can2_dev.handle);
  9. }

  10. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)
  11. {
  12.   if(hcan == (&can1_dev.handle))
  13.   {
  14.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开
  15.     __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
  16.     CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);
  17.   }
  18.   else if(hcan == (&can2_dev.handle))
  19.   {
  20.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开
  21.     __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
  22.     CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);
  23.   }
  24. }
复制代码

        之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。




收藏 评论0 发布时间:2021-12-11 12:00

举报

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