• STM32 CAN总线通讯


     使用STM32CAN通讯,利用回环模式,按键控制发送CAN数据,中断接收CAN数据并通过串口助手打印出来。

    7.2、配置引脚信息

    由于每次新建工程都需要配置信息,比较麻烦,好在STM32CubeIDE提供了导入.ioc文件的功能,可以帮我们节省时间。

    1.从Serial的项目里导入ioc文件,并命名为CAN。

    在Connectivity里找到CAN,并打勾Activated使能CAN外设。

    image-20220326121240215

    2.根据原理图可知,CAN总线连接的引脚为PB8和PB9,而默认的CAN总线引脚为PA11和PA12,所以需要手动修改CAN总线的引脚为PB8和PB9。

    image-20220326122605409

    image-20220326122759412

    image-20220326122910978

    3.设置CAN外设的参数,这里我们设置波特率为1000kbps,模式设置为Loopback。

    image-20220326121651092

    由于这里只用来测试通讯,所以选择Loopback回环模式(数据自发自收);如果需要连接第三方CAN设备,请选择为Normal常规模式(数据收/发独立)。

    image-20220326121936036

    4.中断设置里将CAN RX0中断打开,如果不打开中断就无法接收到数据。

    image-20220326122355699

    核心代码解释

    1.在BSP中新建蜂鸣器的驱动库bsp_can.h和bsp_can.c文件。在bsp_can.h中增加以下内容:

    1. /*
    2. * bsp_can.h
    3. *
    4. * Created on: Mar 7, 2022
    5. * Author: Administrator
    6. */
    7. #ifndef BSP_CAN_H_
    8. #define BSP_CAN_H_
    9. void Can_Init(void);
    10. void Can_Test_Send(void);
    11. #endif /* BSP_CAN_H_ */

    2.在bsp_can.c中添加以下内容:

    Can_Init():初始化CAN外设相关内容,设置CAN接收过滤器,开启CAN总线通讯。

    1. #include "bsp_can.h"
    2. #include "bsp.h"
    3. // Define related variables 定义相关变量
    4. CAN_TxHeaderTypeDef TxHeader;
    5. CAN_RxHeaderTypeDef RxHeader;
    6. CAN_FilterTypeDef sFilterConfig;
    7. // Initialize the CAN 初始化CAN
    8. void Can_Init(void)
    9. {
    10. sFilterConfig.FilterBank = 0;
    11. sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    12. sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    13. sFilterConfig.FilterIdHigh = 0x0000;
    14. sFilterConfig.FilterIdLow = 0x0000;
    15. sFilterConfig.FilterMaskIdHigh = 0x0000;
    16. sFilterConfig.FilterMaskIdLow = 0x0000;
    17. sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    18. sFilterConfig.SlaveStartFilterBank = 27;
    19. sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;
    20. // Setting the CAN Filter 设置CAN过滤器
    21. if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    22. {
    23. Error_Handler();
    24. }
    25. // Start the CAN peripheral 启动CAN
    26. if (HAL_CAN_Start(&hcan) != HAL_OK)
    27. {
    28. Error_Handler();
    29. }
    30. // Activate CAN RX notification 启动CAN RX通知
    31. if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    32. {
    33. Error_Handler();
    34. }
    35. }
    36. // The test sends data through CAN 测试通过CAN发送数据
    37. void Can_Test_Send(void)
    38. {
    39. uint8_t TxData[8];
    40. uint32_t TxMailbox = 0;
    41. TxHeader.StdId = 0x000F;
    42. TxHeader.ExtId = 0x00;
    43. TxHeader.RTR = CAN_RTR_DATA;
    44. TxHeader.IDE = CAN_ID_STD;
    45. TxHeader.DLC = 8;
    46. TxHeader.TransmitGlobalTime = DISABLE;
    47. for (int i = 0; i < 8; i++)
    48. {
    49. TxData[i] = 1 << i;
    50. }
    51. printf("CAN Send:%02X %02X %02X %02X %02X %02X %02X %02X \n",
    52. TxData[0], TxData[1], TxData[2], TxData[3],
    53. TxData[4], TxData[5], TxData[6], TxData[7]);
    54. // Send Data 发送数据
    55. if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) != HAL_OK)
    56. {
    57. Error_Handler();
    58. }
    59. }
    60. // CAN receives interrupt callbacks CAN接收中断回调
    61. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
    62. {
    63. if (hcan->Instance == CAN1)
    64. {
    65. uint8_t RxData[8];
    66. if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
    67. {
    68. Error_Handler();
    69. }
    70. else
    71. {
    72. printf("CAN Receive:%02X %02X %02X %02X %02X %02X %02X %02X \n",
    73. RxData[0], RxData[1], RxData[2], RxData[3],
    74. RxData[4], RxData[5], RxData[6], RxData[7]);
    75. }
    76. }
    77. }

    3.为了测试发送数据,新建Can_Test_Send()函数把数据通过CAN发送出去,并打印到串口助手上。如果需要修改发送的数据,在发送前修改TxData数组即可。

    4.CAN接收中断回调函数,将接收到CAN数据通过串口打印出来。此函数名称不能修改,否则无法调用到此函数。

    5.在BSP初始化中,调用Can_Init()函数初始化CAN外设。

    1. //bsp.c
    2. #include "bsp.h"
    3. // LED显示当前运行状态,每10毫秒调用一次,LED灯每200毫秒闪烁一次。
    4. // The LED displays the current operating status, which is invoked every 10 milliseconds, and the LED blinks every 200 milliseconds.
    5. void Bsp_Led_Show_State_Handle(void)
    6. {
    7. static uint8_t led_count = 0;
    8. led_count++;
    9. if (led_count > 20)
    10. {
    11. led_count = 0;
    12. LED_TOGGLE();
    13. }
    14. }
    15. // The peripheral device is initialized 外设设备初始化
    16. void Bsp_Init(void)
    17. {
    18. Can_Init();
    19. USART1_Init();
    20. Beep_On_Time(50);
    21. printf("start\n");
    22. }
    23. // main.c中循环调用此函数,避免多次修改main.c文件。
    24. // This function is called in a loop in main.c to avoid multiple modifications to the main.c file
    25. void Bsp_Loop(void)
    26. {
    27. // Detect button down events 检测按键按下事件
    28. if (Key1_State(KEY_MODE_ONE_TIME))
    29. {
    30. Beep_On_Time(50);
    31. Can_Test_Send();
    32. }
    33. Bsp_Led_Show_State_Handle();
    34. // The buzzer automatically shuts down when times out 蜂鸣器超时自动关闭
    35. Beep_Timeout_Close_Handle();
    36. HAL_Delay(10);
    37. }

    6.在按键按下后,增加发送CAN数据的功能。

    实验效果

    烧录程序后,LED灯每隔200毫秒闪一次,将扩展板通过micro-USB数据线与电脑连接后并打开串口助手(具体参数如下图所示),每按一次按键,蜂鸣器都会响50毫秒,可以看到串口助手会显示CAN发送的数据以及CAN接收到的数据。

    image-20220326141649900

  • 相关阅读:
    2.jQuery对象
    【访谈】Eotalk Vol.01:Eoapi,我们希望以开源的方式构建 API 生态系统
    第八章:动态内存申请
    VRRP简介
    leetcode:561. 数组拆分(python3解法)
    head first java 读书笔记 2
    即将拉开序幕!武汉市人工智能领域技术成果征集内容、范围和相关要求
    【vue3】toRef与toRefs的使用,toRef与ref的区别
    nginx常用优化
    MySQL并行复制
  • 原文地址:https://blog.csdn.net/shaodongheng/article/details/139857898