当前位置:   article > 正文

基于stm32单片机CAN总线通信实验示例_stm32can总线例程

stm32can总线例程

1.CAN通信介绍

 

        CAN 是控制器局域网络 (Controller Area Network) 的简称,它是由研发和生产汽车电子产品著称的德国 BOSCH 公司开发的,并最终成为国际标准(ISO11519以及ISO11898),是国际上应用最广泛的现场总线之一。CAN 总线协议已经成为汽车计算机控制系统和嵌入式工业控制局域网的标准总线,并且拥有以CAN 为底层协议专为大型货车和重工机械车辆设计的 J1939 协议。近年来,它具有的高可靠性和良好的错误检测能力受到重视,被广泛应用于汽车计算机控制系统和环境温度恶劣、电磁辐射强及振动大的工业环境。

        与 I2C、SPI 等具有时钟信号的同步通讯方式不同,CAN 通讯并不是以时钟信号来进行同步的,它是一种异步通讯,只具有 CAN_High 和 CAN_Low 两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。

 

1.2CAN总线的特点:

  • CAN波特率最高可达1Mbps
  • 具有3级发送邮箱
  • 具有3级深度的两个接收的FIFO,可变的滤波器组(最多28个)
  • CAN控制器的工作三种模式:初始化模式,正常模式,睡眠模式
  • CAN控制器的测试模式:静默模式,回环模式,环回静默模式
  • CAN提供了2.0A和2.0B两个版本,区别在于:2.0A是11位的ID,2.0B是29位的ID
  • CAN有三种工作模式:初始化模式,睡眠模式和正常模式。

在stm32L4系列开发版上原理图:

2. CAN cubeIDE配置:

2.1配置发送和接收管脚:

 2.2CAN属性配置

  • 确定 CAN传输速率 为500kbps
  • 波特率计算方法
  • CAN时钟 = CAN所在的外设时钟/Prescaler,等于分频后CAN外设得到的真正的时钟
  • 波特率 = CAN时钟/(CAN_BS1+CAN_BS2+1)* 45MHz/6= 7.5MHz;7.5MHz/(4+5+1) = 500kbits

 开启接收中断:

Ctrl+S自动生成代码 

3.配置文件:

在can.c中增加过滤器初始化代码

3.1增加发送代码,底层使用HAL_CAN_AddTxMessage函数进行CAN帧发送

 3.2增加接收中断代码,底层使用HAL_CAN_GetRxMessage函数进行数据帧的接收

  1. /* Includes ------------------------------------------------------------------*/
  2. #include "can.h"
  3. /* USER CODE BEGIN 0 */
  4. #include "gpio.h"
  5. #include "stm32l4xx_hal.h"
  6. #include "stm32l4xx_hal_conf.h"
  7. #include <stdio.h>
  8. #include "hal_oled.h"
  9. #include "ds18b20.h"
  10. /* USER CODE END 0 */
  11. CAN_HandleTypeDef hcan1;
  12. /* CAN1 init function */
  13. void MX_CAN1_Init(void)
  14. {
  15. /* USER CODE BEGIN CAN1_Init 0 */
  16. /* USER CODE END CAN1_Init 0 */
  17. /* USER CODE BEGIN CAN1_Init 1 */
  18. void getmessage();
  19. /* USER CODE END CAN1_Init 1 */
  20. hcan1.Instance = CAN1;
  21. hcan1.Init.Prescaler = 16;
  22. hcan1.Init.Mode = CAN_MODE_NORMAL;
  23. hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  24. hcan1.Init.TimeSeg1 = CAN_BS1_4TQ;
  25. hcan1.Init.TimeSeg2 = CAN_BS2_5TQ;
  26. hcan1.Init.TimeTriggeredMode = DISABLE;
  27. hcan1.Init.AutoBusOff = DISABLE;
  28. hcan1.Init.AutoWakeUp = DISABLE;
  29. hcan1.Init.AutoRetransmission = DISABLE;
  30. hcan1.Init.ReceiveFifoLocked = DISABLE;
  31. hcan1.Init.TransmitFifoPriority = DISABLE;
  32. if (HAL_CAN_Init(&hcan1) != HAL_OK)
  33. {
  34. Error_Handler();
  35. }
  36. /* USER CODE BEGIN CAN1_Init 2 */
  37. //过滤器
  38. CAN_FilterTypeDef can1FilterConfig;
  39. can1FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  40. //过滤器是接收报文,不筛选
  41. can1FilterConfig.FilterIdHigh = 0x0000;
  42. can1FilterConfig.FilterIdLow = 0x0000;
  43. can1FilterConfig.FilterMaskIdHigh = 0x0000;
  44. can1FilterConfig.FilterMaskIdLow = 0x0000;
  45. can1FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  46. can1FilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
  47. can1FilterConfig.FilterBank = 0;
  48. can1FilterConfig.SlaveStartFilterBank = 13;
  49. can1FilterConfig.FilterActivation = CAN_FILTER_ENABLE; //使能过滤器
  50. //配置和激活CAN总线的接收中断功能
  51. if(HAL_CAN_ConfigFilter(&hcan1, &can1FilterConfig) != HAL_OK)
  52. {
  53. Error_Handler();
  54. }
  55. if(HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) !=HAL_OK)
  56. {
  57. Error_Handler();
  58. }
  59. /* USER CODE END CAN1_Init 2 */
  60. }
  61. void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
  62. {
  63. GPIO_InitTypeDef GPIO_InitStruct = {0};
  64. if(canHandle->Instance==CAN1)
  65. {
  66. /* USER CODE BEGIN CAN1_MspInit 0 */
  67. /* USER CODE END CAN1_MspInit 0 */
  68. /* CAN1 clock enable */
  69. __HAL_RCC_CAN1_CLK_ENABLE();
  70. __HAL_RCC_GPIOB_CLK_ENABLE();
  71. /**CAN1 GPIO Configuration
  72. PB8 ------> CAN1_RX
  73. PB9 ------> CAN1_TX
  74. */
  75. GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
  76. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  77. GPIO_InitStruct.Pull = GPIO_NOPULL;
  78. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  79. GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
  80. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  81. /* CAN1 interrupt Init */
  82. HAL_NVIC_SetPriority(CAN1_TX_IRQn, 2, 0);
  83. HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
  84. HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 2, 0);
  85. HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
  86. /* USER CODE BEGIN CAN1_MspInit 1 */
  87. /* USER CODE END CAN1_MspInit 1 */
  88. }
  89. }
  90. void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
  91. {
  92. if(canHandle->Instance==CAN1)
  93. {
  94. /* USER CODE BEGIN CAN1_MspDeInit 0 */
  95. /* USER CODE END CAN1_MspDeInit 0 */
  96. /* Peripheral clock disable */
  97. __HAL_RCC_CAN1_CLK_DISABLE();
  98. /**CAN1 GPIO Configuration
  99. PB8 ------> CAN1_RX
  100. PB9 ------> CAN1_TX
  101. */
  102. HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9);
  103. /* CAN1 interrupt Deinit */
  104. HAL_NVIC_DisableIRQ(CAN1_TX_IRQn);
  105. HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
  106. /* USER CODE BEGIN CAN1_MspDeInit 1 */
  107. /* USER CODE END CAN1_MspDeInit 1 */
  108. }
  109. }
  110. /* USER CODE BEGIN 1 */
  111. //发送函数
  112. CAN_TxHeaderTypeDef Tx_pHeader;
  113. int CAN_TX_Message(uint8_t TxData[], uint8_t length)
  114. {
  115. uint32_t TxMailboxNumber = 0x00000000U; // 存储本次发送所使用邮箱的邮箱号
  116. Tx_pHeader.StdId = 0x122; // 以此ID发送
  117. Tx_pHeader.ExtId = 0x0000; // 扩展ID(此处无用)
  118. Tx_pHeader.IDE = CAN_ID_STD; // 标准帧
  119. Tx_pHeader.RTR = CAN_RTR_DATA; // 数据帧
  120. Tx_pHeader.DLC = length; // 发送数据的长度
  121. Tx_pHeader.TransmitGlobalTime = DISABLE;
  122. //TxData发送的数据
  123. if(HAL_CAN_AddTxMessage(&hcan1, &Tx_pHeader, TxData, &TxMailboxNumber) !=HAL_OK)
  124. {
  125. return -1;
  126. }
  127. return TxMailboxNumber;
  128. }
  129. CAN_RxHeaderTypeDef hCAN1_RxHeader; //CAN1接收消息
  130. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan1)
  131. {
  132. uint8_t aRxData[8], i;
  133. if(HAL_CAN_GetRxMessage(hcan1, CAN_RX_FIFO0, &hCAN1_RxHeader, aRxData) ==HAL_OK)
  134. {
  135. printf("\r\nGet Rx Message Success!!\r\n");
  136. printf("[ID]:0x%lX [DLC]:%ld [Data]:", hCAN1_RxHeader.StdId,hCAN1_RxHeader.DLC);
  137. for(i=0; i<hCAN1_RxHeader.DLC; i++)
  138. printf("%X ", aRxData[i]);
  139. printf("\r\n");
  140. return Tx_pHeader.DLC; //是返回发送消息的数据长度
  141. // OLED_ShowString(1, 1,"helloworld",16);
  142. // OLED_ShowChinese(1,1,1);
  143. }
  144. }
  145. #if 0
  146. uint8_t can_receive_message(uint8_t *buf)
  147. {
  148. if(HAL_CAN_GetRxFifoFillLevel(&hcan1,CAN_RX_FIFO0)==0)
  149. {
  150. return 0;
  151. }
  152. HAL_CAN_GetRxMessage(&hcan1,CAN_RX_FIFO0,&hCAN1_RxHeader,buf);
  153. return hCAN1_RxHeader.DLC;
  154. }
  155. #endif
  156. /* USER CODE END 1 */
  157. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 3.3在主函数文件main.c里面添加CAN发送函数

 

 4.实验结果:

在CAN分析仪和串口调试助手打印输出结果

CAN分析仪接收到的报文都是程序里面自己指定的报文

 


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/512795
推荐阅读
相关标签
  

闽ICP备14008679号