• STM32F103 CAN通讯实操


    目的:学习使用STM32CubeIDE进行CAN通讯编程学习;

    准备条件:STM32F103ZET6开发板,PA11 PA12用于CAN + TJA1040,USB-CAN适配器1个;

    操作流程:

    第一步:使用cubeIDE自动生成代码;

    第二步: 编辑代码,loopback条件下工作,中断接收CAN消息;

    第三步:连接USB-CAN适配器,进行通讯测试。

    详细操作步骤如下:

    Step1:cubeIDE 生成project;File\New\STM32 Project;

    Step2: Part Number中输入 STM32F103ZE, 选择LQFP144 package;

    Step3:配置晶振和调试方法(PinOUT&Configuration)

    Step4:配置时钟Clock Configration,确认APB1 peripheral clocks(MHz) = 16

    bxCAN 对应的时钟为:APB1外设时钟; 见《STM32F10xx中文参考手册》“2.3 存储器映像” page28/547;

    Step5: 配置bxCAN的波特率为100K

    Step6:配置bxCAN的接收中断

    Step7:配置读取中断的优先级别为15; USB low priority or CAN RX0 interrupts, preemption Priority =15;

    Step8:生成代码后,在main.c中添加bxCAN初始化代码:

    1. static void MX_CAN_Init(void)
    2. {
    3.   /* USER CODE BEGIN CAN_Init 0 */
    4.   /* USER CODE END CAN_Init 0 */
    5.   /* USER CODE BEGIN CAN_Init 1 */
    6.   /* USER CODE END CAN_Init 1 */
    7.   hcan.Instance = CAN1;
    8.   hcan.Init.Prescaler = 16;
    9.   hcan.Init.Mode = CAN_MODE_NORMAL;
    10.   hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
    11.   hcan.Init.TimeSeg1 = CAN_BS1_6TQ;
    12.   hcan.Init.TimeSeg2 = CAN_BS2_3TQ;
    13.   hcan.Init.TimeTriggeredMode = DISABLE;
    14.   hcan.Init.AutoBusOff = DISABLE;
    15.   hcan.Init.AutoWakeUp = DISABLE;
    16.   hcan.Init.AutoRetransmission = DISABLE;
    17.   hcan.Init.ReceiveFifoLocked = DISABLE;
    18.   hcan.Init.TransmitFifoPriority = DISABLE;
    19.   if (HAL_CAN_Init(&hcan) != HAL_OK)
    20.   {
    21.     Error_Handler();
    22.   }
    23.   /* USER CODE BEGIN CAN_Init 2 */
    24.    CAN_FilterTypeDef _CAN_FilterTypeDef;
    25. _CAN_FilterTypeDef.FilterBank = 0; // filter 0
    26. _CAN_FilterTypeDef.FilterMode = CAN_FILTERMODE_IDMASK; // mask mode
    27. _CAN_FilterTypeDef.FilterScale = CAN_FILTERSCALE_32BIT;
    28. _CAN_FilterTypeDef.FilterIdHigh = 0;
    29. _CAN_FilterTypeDef.FilterIdLow = 0;
    30. _CAN_FilterTypeDef.FilterMaskIdHigh = 0;
    31. _CAN_FilterTypeDef.FilterMaskIdLow = 0; // set mask 0 to receive all   can id
    32. _CAN_FilterTypeDef.FilterFIFOAssignment = CAN_RX_FIFO0; // assign to fifo0
    33. _CAN_FilterTypeDef.FilterActivation = CAN_FILTER_ENABLE;// enable can filter
    34. _CAN_FilterTypeDef.SlaveStartFilterBank = 27;
    35. if(HAL_CAN_ConfigFilter(&hcan,&_CAN_FilterTypeDef) != HAL_OK)
    36. Error_Handler();
    37. if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    38. Error_Handler();
    39. if(HAL_CAN_Start(&hcan) != HAL_OK)
    40. Error_Handler();
    41.   /* USER CODE END CAN_Init 2 */
    42. }

    Step9:生成代码后,在main.c中添加bxCAN读、写、中断接收代码:

    1. /* USER CODE BEGIN 0 */
    2. #define Tx_Error 3
    3. #define Rx_Error 2
    4. #define Rx_OK 0
    5. CAN_TxHeaderTypeDef Tx_pHeader;
    6. /*
    7. * @brief: CAN Send Message.
    8. * @param: "TxData[]" stored the message of ready to send, which length must between 0 and 8.
    9. * @param: "length" stored the number of the data (one data is 8 bit) of ready to send.
    10. * @retval: Tx_Error: send error; other: the mailbox which has been used, this parameter can be a CAN_TX_MAILBOX0,
    11. * CAN_TX_MAILBOX1,
    12. * CAN_TX_MAILBOX2.
    13. */
    14. uint32_t CAN_TX_Message(uint8_t TxData[], uint8_t length)
    15. {
    16. uint32_t TxMailboxNumber = 0x00000000U; // 存储本次发所使用邮箱的邮箱号
    17. Tx_pHeader.StdId = 0x030; // 以此ID发
    18. Tx_pHeader.ExtId = 0x0000; // 扩展ID(此处无用)
    19. Tx_pHeader.IDE = CAN_ID_STD; // 标准
    20. Tx_pHeader.RTR = CAN_RTR_DATA; // 数据
    21. Tx_pHeader.DLC = length; // 发数据的长度
    22. Tx_pHeader.TransmitGlobalTime = DISABLE;
    23. if(HAL_CAN_AddTxMessage(&hcan, &Tx_pHeader, TxData, &TxMailboxNumber) != HAL_OK)
    24. {
    25. return Tx_Error;
    26. }
    27. return TxMailboxNumber;
    28. }
    29. CAN_RxHeaderTypeDef Rx_pHeader;
    30. /*
    31. * @brief: CAN Receive Message.
    32. * @param: "RxData[]" will store the message which has been received, which length must between 0 and 8.
    33. * @retval: receive status.
    34. */
    35. uint32_t CAN_RX_Message(uint8_t RxData[])
    36. {
    37. uint8_t aData[8]; // 缓存接收到的信息
    38. Rx_pHeader.StdId = 0x000; // 接收ID(此处无用,can接收有的ID号)
    39. Rx_pHeader.ExtId = 0x0000;
    40. Rx_pHeader.IDE = CAN_ID_STD; // 接收标准
    41. Rx_pHeader.DLC = 8; // 接收8bit数据
    42. Rx_pHeader.RTR = CAN_RTR_DATA; // 接收数据
    43. Rx_pHeader.FilterMatchIndex = 0; // 使用0号过滤器
    44. Rx_pHeader.Timestamp = 0;
    45. if(HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &Rx_pHeader, aData) != HAL_OK)
    46. {
    47. return Rx_Error;
    48. }
    49. else
    50. {
    51. // 取出接收到的信息
    52. for(uint8_t i = 0; i
    53. {
    54. RxData[i] = aData[i];
    55. }
    56. return Rx_OK;
    57. }
    58. }
    59. uint8_t RxData[8] = {0}; // 缓存接收到的信息
    60. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
    61. {
    62. // 判断是哪路的CAN发生了中
    63. if(hcan->Instance == CAN1)
    64. {
    65. if(CAN_RX_Message(RxData) != Rx_OK)
    66. {
    67. // 接收信息失败
    68. printf("MCU Received CAN Data ERROR!!!");
    69. printf("\n\r");
    70. printf("\n\r");
    71. }
    72. else
    73. {
    74. // 接受信息成功,处理数
    75. printf("MCU Received CAN Data: ");
    76. for(uint8_t i = 0; i<8; i++)
    77. {
    78. printf("%d ", RxData[i]);
    79. }
    80. printf("\n\r");
    81. printf("\n\r");
    82. }
    83. }
    84. }
    85. uint8_t TxData[8] = {0}; // 缓存待发送的信息
    86. uint8_t length = 0x00; // 待发送信息的长度
    87. /* USER CODE END 0 */

    Step10:生成代码后,在main.c中添加main函数中添加主代码:

    1. int main(void)
    2. {
    3. /* USER CODE BEGIN 1 */
    4. /* USER CODE END 1 */
    5. /* MCU Configuration--------------------------------------------------------*/
    6. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    7. HAL_Init();
    8. /* USER CODE BEGIN Init */
    9. /* USER CODE END Init */
    10. /* Configure the system clock */
    11. SystemClock_Config();
    12. /* USER CODE BEGIN SysInit */
    13. /* USER CODE END SysInit */
    14. /* Initialize all configured peripherals */
    15. MX_GPIO_Init();
    16. MX_CAN_Init();
    17. /* USER CODE BEGIN 2 */
    18. TxData[7] = 0x1a; // 给定待发送的信息
    19. TxData[6] = 0x1b;
    20. TxData[5] = 0x1c;
    21. TxData[4] = 0x1d;
    22. TxData[3] = 0x1e;
    23. TxData[2] = 0x1f;
    24. TxData[1] = 0x10;
    25. TxData[0] = 0x11;
    26. length = 0x08; // 更新待发送信息的数据长度
    27. /* USER CODE END 2 */
    28. /* Infinite loop */
    29. /* USER CODE BEGIN WHILE */
    30. while (1)
    31. {
    32. /* USER CODE END WHILE */
    33. /* USER CODE BEGIN 3 */
    34. if (CAN_TX_Message(TxData, length) == Tx_Error) // 轮询方式发CAN信息
    35. {
    36. Error_Handler();
    37. }
    38. HAL_Delay(500); // 延时0.5
    39. }
    40. /* USER CODE END 3 */
    41. }

    结果:调试成功后,可以在usb can收到消息

    使用注意事项:

    stm32的bxCAN配置和使用流程在cubeide软件中如下:

    Step1: ioc文件里图形化使能can并配置工作时钟、波特率、工作模式、中断优先级;

    Step2:自动生成代码后,在can.c文件里添加滤波器的配置并使能FIFO中断;

    Step3:在MX_CAN_Init初始化完毕后启动can,才能发送信息;

    Step4:在main.c文件下的main()外用户自定义中断回调函数。

    常见错误点总结:

    1. 没有启动can,can是无法发送信息、接收不到信息的。对应库函数HAL_CAN_Start。
    2. 没有使能FIFO中断,can是不会中断的。
    3. 回调函数的函数名使用错误(因为有多个用途不同的函数名),can中断后不调用该函数。对应函数名:HAL_CAN_RxFifo0MsgPendingCallback;
    4. CAN调试的时候,可以先使用loopback模式,进行发送接收测试,没问题后,再设置为normal模块,连接USB-CAN适配器,进行实际测试;
    5. 波特率设置中的 Time Quanta Bit Segmenet1 和Time Quanta Bit Segmenet 2,尽量大于2,否则会影响发送和接收的稳定性。
    6. 希望自己能记住,同时看到的人也有帮助。
    7. 本文的源代码下载链接:https://download.csdn.net/download/qq_23313467/86730136

  • 相关阅读:
    海外多家权威媒体热议波场TRON:为互联网去中心化奠定基础
    【.net core】yisha框架 SQL SERVER数据库 反向递归查询部门(子查父)
    鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    使用小程序制作一个飞机大战小游戏
    【LeetCode热题100】--34.在排序数组中查找元素的第一个和最后一个位置
    PostCSS概述
    Elastic Search 7.x 学习笔记
    多层感知机学习XOR实例
    认识前端包常用包管理工具(npm、cnpm、pnpm、nvm、yarn)
    【代码随想录】二刷-链表
  • 原文地址:https://blog.csdn.net/qq_23313467/article/details/127131440