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

STM32的CAN环回测试

[复制链接]
攻城狮Melo 发布时间:2023-6-28 14:42
CAN基础知识介绍文中介绍了CAN协议的基础知识,以及STM32F4芯片的CAN控制器相关知识,下面将通过实例,利用STM32CubeMX图形化配置工具,来实现CAN通讯的环回测试

1. STM32CubeMX配置


⏩ CAN是挂载在APB1总线上,设置PCLK1时钟频率到最大45MHz

微信图片_20230628143758.png


⏩ 激活CAN1,配置位时序参数,其他基本参数以及工作模式(此处设置为Loopback环回模式)


微信图片_20230628143755.png

CAN波特率的计算公式:只需要知道BS1和BS2的设置,以及APB1的时钟频率,就可以方便的计算出波特率。比如设置TS1=8、TS2=6和BRP=6,在APB1频率为45Mhz的条件下,即可得到CAN通信的波特率=45000/6/(8+6+1)=500Kbps

微信图片_20230628143751.png


⏩ 激活USART1作为调试串口,配置相关LED对应的GPIO引脚作为指示灯


2. MDK-ARM编程

2.1 几个重要的结构体


⏩ 主控寄存器 CAN_MCR:负责管理 CAN 的工作模式
  1. typedef struct
  2. {
  3.   uint32_t Prescaler;       /* 配置 CAN 外设的时钟分频,可设置为 1-1024*/
  4.   uint32_t Mode;            /* 配置 CAN 的工作模式,回环或正常模式 */
  5.   uint32_t SyncJumpWidth;   /* 配置 SJW 极限值 */
  6.   uint32_t TimeSeg1;        /* 配置 BS1 段长度 */
  7.   uint32_t TimeSeg2;        /* 配置 BS2 段长度 */
  8.   FunctionalState TimeTriggeredMode;    /* 是否使能 TTCM 时间触发功能 */
  9.   FunctionalState AutoBusOff;           /* 是否使能 ABOM 自动离线管理功能 */
  10.   FunctionalState AutoWakeUp;           /* 是否使能 AWUM 自动唤醒功能 */
  11.   FunctionalState AutoRetransmission;   /* 是否使能 NART 自动重传功能 */
  12.   FunctionalState ReceiveFifoLocked;    /* 是否使能 RFLM 锁定 FIFO 功能 */
  13.   FunctionalState TransmitFifoPriority; /* 配置 TXFP 报文优先级的判定方法 */
  14. } CAN_InitTypeDef;
复制代码

⏩ 发送及接收头结构体:主要用于构造发送报文,以及接收报文。收发发文时,需要自定义头结构体变量


  1. typedef struct
  2. {
  3.   uint32_t StdId;       /* 存储报文的标准标识符 11 位,0-0x7FF. */
  4.   uint32_t ExtId;       /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */
  5.   uint32_t IDE;        /* 存储 IDE 扩展标志 */
  6.   uint32_t RTR;        /* 存储 RTR 远程帧标志 */
  7.   uint32_t DLC;        /* 存储报文数据段的长度,0-8 */
  8.   FunctionalState TransmitGlobalTime;
  9. } CAN_TxHeaderTypeDef;

  10. typedef struct
  11. {
  12.   uint32_t StdId;      /* 存储报文的标准标识符 11 位,0-0x7FF. */
  13.   uint32_t ExtId;      /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */
  14.   uint32_t IDE;        /* 存储 IDE 扩展标志 */
  15.   uint32_t RTR;        /* 存储 RTR 远程帧标志 */
  16.   uint32_t DLC;        /* 存储报文数据段的长度,0-8 */
  17.   uint32_t Timestamp;
  18.   uint32_t FilterMatchIndex;
  19. } CAN_RxHeaderTypeDef;
复制代码


⏩ 过滤器结构体:STM32CubeMX不会初始化过滤器的相关内容,需要自己添加


  1. typedef struct
  2. {
  3.   uint32_t FilterIdHigh;         /*CAN_FxR1 寄存器的高 16 位 */
  4.   uint32_t FilterIdLow;          /*CAN_FxR1 寄存器的低 16 位 */
  5.   uint32_t FilterMaskIdHigh;     /*CAN_FxR2 寄存器的高 16 位 */
  6.   uint32_t FilterMaskIdLow;      /*CAN_FxR2 寄存器的低 16 位 */
  7.   uint32_t FilterFIFOAssignment; /* 设置经过筛选后数据存储到哪个接收 FIFO */
  8.   uint32_t FilterBank;           /* 筛选器编号,范围0-27,CAN1是0-13,CAN2是14-27 */
  9.   uint32_t FilterMode;           /* 筛选器模式 */
  10.   uint32_t FilterScale;          /* 设置筛选器的尺度 */
  11.   uint32_t FilterActivation;     /* 是否使能本筛选器 */
  12.   uint32_t SlaveStartFilterBank; /* CAN2起始过滤器组 */
  13. } CAN_FilterTypeDef;
复制代码


2.2 程序编写


⏩ 生成工程后,打开can.c文件,可见STM32CubeMX已经对位时序参数、其他基本参数以及工作模式进行了初始化。但是并没有初始化过滤器的相关内容,因此需要我们自己添加,并在CAN初始化时调用


  1. //下面的设置只使能了FIFO0,并不过滤任何消息
  2. void CAN_Filter_Config(){
  3.   CAN_FilterTypeDef sFilterConfig;

  4.   sFilterConfig.FilterBank = 0;      //筛选器编号, CAN1是0-13, CAN2是14-27
  5.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //采用掩码模式
  6.   sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置筛选器的尺度, 采用32位
  7.   sFilterConfig.FilterIdHigh = 0X0000;    //过滤器ID高16位,即CAN_FxR1寄存器的高16位
  8.   sFilterConfig.FilterIdLow = 0X0000;     //过滤器ID低16位,即CAN_FxR1寄存器的低16位
  9.   sFilterConfig.FilterMaskIdHigh = 0X0000;   //过滤器掩码高16位,即CAN_FxR2寄存器的高16位
  10.   sFilterConfig.FilterMaskIdLow = 0X0000;    //过滤器掩码低16位,即CAN_FxR2寄存器的低16位
  11.   sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //设置经过筛选后数据存储到哪个接收FIFO
  12.   sFilterConfig.FilterActivation = ENABLE;   //是否使能本筛选器
  13.   sFilterConfig.SlaveStartFilterBank = 14;   //指定为CAN1分配多少个滤波器组

  14.   if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  15.   {
  16.     Error_Handler();
  17.   }
  18. }
复制代码

⏩ 编写发送和接收数据函数:此处将格式固定为标准数据帧,ID为12


  1. uint8_t CAN1_Send_Msg(uint8_t *msg, uint8_t len){
  2.   uint16_t i = 0;
  3.   uint32_t txMailBox;
  4.   uint8_t send_buf[8];

  5.   txHeader.StdId = 12;
  6.   txHeader.ExtId = 12;
  7.   txHeader.IDE = CAN_ID_STD;
  8.   txHeader.RTR = CAN_RTR_DATA;
  9.   txHeader.DLC = len;

  10.   for(i = 0; i < len; i++)
  11.     send_buf[i] = msg[i];

  12.   if(HAL_CAN_AddTxMessage(&hcan1, &txHeader, send_buf, &txMailBox) != HAL_OK)
  13.     return 1;
  14.   return 0;
  15. }

  16. uint8_t CAN1_Recv_Msg(uint8_t *buf){
  17.   uint16_t i = 0;
  18.   HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);

  19.   if(rxHeader.IDE == CAN_ID_STD)
  20.     printf("StdId ID: %d\r\n", rxHeader.StdId);
  21.   else
  22.     printf("ExtId ID: %d\r\n", rxHeader.ExtId);

  23.   printf("CAN IDE: %d\r\n", rxHeader.IDE);
  24.   printf("CAN RTR: %d\r\n", rxHeader.RTR);
  25.   printf("CAN DLC: %d\r\n", rxHeader.DLC);
  26.   printf("Recv Data: ");

  27.   for(i = 0; i < rxHeader.DLC; i++)
  28.     printf("%c",buf[i]);

  29.   printf("\n");
  30.   return rxHeader.DLC;
  31. }
复制代码

⏩ 默认Cubemx生成的代码并没有can start,没有调用HAL_CAN_Start(&hcan1) 来使能CAN,因此需要在CAN初始化代码中添加


  1. void MX_CAN1_Init(void){
  2.   ......
  3.   /* USER CODE BEGIN CAN1_Init 2 */
  4.   CAN_Filter_Config();
  5.   HAL_CAN_Start(&hcan1);
  6.   /* USER CODE END CAN1_Init 2 */
  7. }
复制代码

⏩ 主函数main.c中,代码如下


  1. int main(void){
  2.   HAL_Init();
  3.   SystemClock_Config();
  4.   MX_GPIO_Init();
  5.   MX_CAN1_Init();
  6.   MX_USART1_UART_Init();
  7.   /* USER CODE BEGIN 2 */
  8.   uint8_t ret,i;
  9.   printf("CAN Testing....!\r\n");
  10.   uint8_t txdata[8] = {76, 79, 79, 80, 66, 65, 67, 75};
  11.   uint8_t rxdata[8];
  12.    /* USER CODE END 2 */
  13.    /* Infinite loop */
  14.    /* USER CODE BEGIN WHILE */
  15.   while (1)
  16.   {
  17.     HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);
  18.     HAL_Delay(1000);
  19.     printf("Start Send data...\r\n");
  20.   
  21.     ret = CAN1_Send_Msg(txdata, 8);
  22.     if(ret == 0)
  23.       printf("CAN Send success!\r\n");
  24.     else
  25.       printf("CAN Send failed!\r\n");
  26.   
  27.     CAN1_Recv_Msg(rxdata);
  28.     printf("+++++++++++++++++++++++++++++++\r\n");
  29.     /* USER CODE END WHILE */
  30.     /* USER CODE BEGIN 3 */
  31.   }
  32.   /* USER CODE END 3 */
  33. }
复制代码

3. 下载测试


编译无误后下载到开发板,可以看到系统运行时D1指示灯不断闪烁,串口不断的打印CAN环回测试的数据


微信图片_20230628143747.png


转载自: 嵌入式攻城狮
如有侵权请联系删除




收藏 评论0 发布时间:2023-6-28 14:42

举报

0个回答

所属标签

相似分享

官网相关资源

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