当前位置: 首页 > news >正文

细说STM32F407单片机轮询方式CAN通信

目录

一、项目介绍

二、项目配置

1、时钟、DEBUG、USART6、NVIC、GPIO、CodeGenerator

2、CAN1

(1)Bit Timings Parameters组,位时序参数

(2)Basic Parameters组,基本参数

(3)Advanced Parameters组,高级参数

三、软件设计

1、KEYLED

2、can.h

3、can.c

4、main.c 

四、下载与调试 


        本文旨在以案例说明STM32F407单片机轮询方式CAN通信的方法。本文仍然使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0。需要参考本文作者的其他文章:

        参考文章1:细说STM32F407单片机轮询方式读写SPI FLASH W25Q16BV_stm32f407 spiflash驱动程序-CSDN博客  https://wenchm.blog.csdn.net/article/details/144587209

        参考文章2:细说STM32F407单片机CAN基础知识及其HAL驱动程序-CSDN博客  https://wenchm.blog.csdn.net/article/details/144769950

一、项目介绍

        本文实例的动作说明:使用开发板上的按键S2、S3,按下S2后,发送一个数据帧,按下S3后,发送一个遥控帧。开发板上的LED1、LED2,依次响应按键的动作。按下S6后,开发板复位。

[S2]KeyUp  = Send a Data Frame.   LED1 ON
[S3]KeyDown= Send a Remote Frame. LED2 ON

        示例还有以下功能:

  • 使用CAN测试模式中的回环模式,进行自发自收的测试。
  • 设置筛选器组,只接收消息ID为奇数的消息。
  • 使用轮询方式接收数据。

        开发板上CAN收发器型号是VD230。相关跳线的操作在这里省略10000字。有关CAN的原理图如下:

二、项目配置

1、时钟、DEBUG、USART6、NVIC、GPIO、CodeGenerator

        与参考文章1相同或近似。其中的时钟在本例中,HCLK=100MHz,PCLK1=25MHz,PCLK2=50MHz。

2、CAN1

CAN1的参数设置分为3个部分:

(1)Bit Timings Parameters组,位时序参数

        位时序和波特率的原理详见参考文章2,这里设置的参数如下:

  • Prescaler,预分频系数,这里设置为5,可设置范围是1~1024。CAN1的时钟频率f_{CAN}由PCLK1经过分频后得到,本例中PCLK1=25MHz,经过5分频后,f_{CAN}=5MHz。
  • Time Quantum,时间片。在设置预分频系数后,时间片会被自动计算:tq=1/(5×1000000)=200ns。
  • Time Quantam in Bit Segment 1,位段1的时间片个数为m,范围为1~16,本例设置为4。
  • Time Quantam in Bit Segment 2,位段2的时间片个数为n,范围为1~8,本例设置为3。
  • ReSynchronization Jump Width(SJW),再同步跳转宽度,设置范围为1~4,本例设置为1。CAN通信的波特率由同步段、BS1、BS2的时间片个数决定,波特率计算公式如下:Baudrate=1/(1+m+n)=1s/(8×200ns)=625kbit/s。

        注意,STM32F407的CAN控制器在闭环CAN网络中波特率范围是125kbit/s~1Mbit/s,如果计算的实际波特率不在这个范围内,则需要调整分频系数或各位段的时间片个数。 

(2)Basic Parameters组,基本参数

        基本参数与CAN主控制寄存器CAN_MCR中的一些位对应,对CAN模块的一些特性进行设置。

  • Time Triggered Communication Mode(TTCM位),时间触发通信模式。设置为Disable表示禁止时间触发通信模式,若启用TTCM,则在发送或接收消息时,会加上一个内部计数器的计数值。
  • Automatic Bus-Off Management(ABOM位),自动的总线关闭管理。设置为Disable表示不使用自动的总线关闭。
  • Automatic Wake-Up Mode(AWUM位),自动唤醒模式。这个参数用于控制CAN模块在睡眠模式下接收消息时的行为,如果设置为Enable,则表示只要接收消息,就通过硬件自动退出睡眠模式。
  • Automatic Retransmission(NART位),自动重发。若设置为Enable,CAN模块将自动重发消息,直到发送成功为止。若设置为Disable,则无论发送结果如何,消息只发送一次。这个设定值实际是对NART位值取反,因为NART表示禁止自动重发。
  • Receive Fifo Locked Mode(RFLM位),接收FIFO锁定模式。若设置为Disable,表示FIFO上溢不锁定,下一条新消息覆盖前一条消息。若设置为Enable,则表示上溢后锁定,丢弃下一条新消息。
  • Transmit Fifo Priority(TXFP位),发送FIFO优先级。若设置为Disable,表示消息优先级由标识符决定;若设置为Enable,表示优先级由请求顺序决定。

(3)Advanced Parameters组,高级参数

  • Operating Mode,用于设置CAN模块的工作模式,有4种工作模式可选,即正常(Normal)、静默(Silent)、回环(Loopback)、回环静默(Loopback combined with Silent)。其中,后3种是CAN模块的测试模式。本例设置为Loopback,使用其自发自收功能进行CAN收发功能的测试。

        本例使用轮询方式测试CAN模块的数据发送和接收功能,所以不开启CAN1的任何中断。

三、软件设计

1、KEYLED

        本例的项目中要使用KEYLED,其中的keyled.c和keyled.h的使用方法与参考文章1相同。

2、can.h

/* USER CODE BEGIN Prototypes */
HAL_StatusTypeDef CAN_SetFilters();
void CAN_TestPoll(uint8_t msgID,uint8_t frameType);
/* USER CODE END Prototypes */

3、can.c

/* USER CODE BEGIN 0 */
#include <stdio.h>
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
//设置筛选器,要在完成CAN初始化之后调用此函数
HAL_StatusTypeDef CAN_SetFilters()
{CAN_FilterTypeDef canFilter;//筛选器结构体变量// Configure the CAN FiltercanFilter.FilterBank = 0;	//筛选器组编号canFilter.FilterMode = CAN_FILTERMODE_IDMASK;	//ID掩码模式canFilter.FilterScale = CAN_FILTERSCALE_32BIT;	//32位长度//设置1:接收所有帧
//	canFilter.FilterIdHigh = 0x0000;		//CAN_FxR1 的高16位
//	canFilter.FilterIdLow = 0x0000;			//CAN_FxR1 的低16位
//	canFilter.FilterMaskIdHigh = 0x0000;	//CAN_FxR2 的高16位,所有位任意
//	canFilter.FilterMaskIdLow = 0x0000;		//CAN_FxR2 的低16位,所有位任意//设置2:只接收stdID为奇数的帧canFilter.FilterIdHigh = 0x0020;		//CAN_FxR1 的高16位canFilter.FilterIdLow = 0x0000;			//CAN_FxR1 的低16位canFilter.FilterMaskIdHigh = 0x0020;	//CAN_FxR2 的高16位canFilter.FilterMaskIdLow = 0x0000;		//CAN_FxR2 的低16位canFilter.FilterFIFOAssignment = CAN_RX_FIFO0;		//应用于FIFO0canFilter.FilterActivation = ENABLE;	//使用筛选器canFilter.SlaveStartFilterBank = 14;	//从CAN控制器筛选器起始的BankHAL_StatusTypeDef result=HAL_CAN_ConfigFilter(&hcan1,&canFilter);return result;
}void CAN_TestPoll(uint8_t msgID, uint8_t frameType)
{
//1. 要发送的数据uint8_t TxData[8];	//发送数据缓存区,最多8字节TxData[0]=msgID;TxData[1]=msgID+11;CAN_TxHeaderTypeDef TxHeader;	//发送消息的结构体变量TxHeader.StdId = msgID;			//stdIDTxHeader.RTR = frameType;		//数据帧或遥控帧,CAN_RTR_DATA或CAN_RTR_REMOTETxHeader.IDE = CAN_ID_STD;		//标准格式TxHeader.DLC = 2;   			//数据字节数TxHeader.TransmitGlobalTime = DISABLE;//禁用时间戳while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) < 1) {} //等待有可用的发送邮箱uint32_t TxMailbox;				//临时变量,用于返回使用的邮箱编号/* 将消息发送到邮箱 */if(HAL_CAN_AddTxMessage(&hcan1,&TxHeader,TxData,&TxMailbox) != HAL_OK){printf("Transmit error.\r\n");return;}printf("Send MsgID= %X\r\n",msgID);//2. 轮询方式接收消息/* 等待邮箱发送完毕,也就是等待空闲邮箱个数恢复为3 */while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) != 3) {}CAN_RxHeaderTypeDef RxHeader;	//接收消息的结构体变量uint8_t             RxData[8]; 	//接收数据缓存区HAL_Delay(1);if(HAL_CAN_GetRxFifoFillLevel(&hcan1,CAN_RX_FIFO0) != 1){printf("Message is not received.\r\n");return;}printf("Message is received.\r\n");if(HAL_CAN_GetRxMessage(&hcan1,CAN_RX_FIFO0,&RxHeader,RxData) == HAL_OK){printf("StdID= %lX\r\n",RxHeader.StdId);printf("RTR(0=Data,2=Remote)= %lX\r\n",RxHeader.RTR);printf("IDE(0=Std,4=Ext)= %lX\r\n",RxHeader.IDE);printf("DLC(Data length)= %lX\r\n",RxHeader.DLC);//数据帧,显示数据内容,遥控帧没有数据if (TxHeader.RTR == CAN_RTR_DATA){printf("Data[0]= %X\r\n",RxData[0]);printf("Data[1]= %X\r\n",RxData[1]);}}
}
/* USER CODE END 1 */

        在文件can.h中有两个自定义函数,其中函数CAN_SetFilters()用于筛选器设置。

4、main.c 

/* USER CODE BEGIN Includes */
#include "keyled.h"
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */printf("Demo18_1_CAN:CAN Polling.\r\n");printf("Test mode:Loopback.\r\n");if (CAN_SetFilters() == HAL_OK)   //设置筛选器printf("ID Filter: Only Odd IDs.\r\n");if (HAL_CAN_Start(&hcan1) == HAL_OK)  //启动CAN1模块printf("CAN is started.\r\n");printf("[S2]KeyUp  = Send a Data Frame.\r\n");printf("[S3]KeyDown= Send a Remote Frame.\r\n");// MCU output low level LED light is onLED1_OFF();LED2_OFF();/* USER CODE END 2 */
 /* USER CODE BEGIN WHILE */uint8_t msgID=1;while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */KEYS curKey=ScanPressedKey(KEY_WAIT_ALWAYS);if (curKey==KEY_UP){CAN_TestPoll(msgID++,CAN_RTR_DATA);	  //发送数据帧LED1_ON();LED2_OFF();}else if (curKey==KEY_DOWN){CAN_TestPoll(msgID++,CAN_RTR_REMOTE); //发送遥控帧LED1_OFF();LED2_ON();}printf("** Reselect menu or reset **\r\n");HAL_Delay(500);}/* USER CODE END 3 */

        在进入while循环之前,显示了菜单提示信息。

        在while()循环中,检测按键输入,当KeyUp键按下时,调用函数CAN_TestPoll()测试发送数据帧,当KeyDown键按下时,调用函数CAN_TestPoll()测试发送遥控帧。函数CAN_TestPoll()是在文件can.c中实现的自定义函数。 函数CAN_TestPoll()用于测试CAN1模块在轮询方式下的数据发送和接收。

/* USER CODE BEGIN 4 *///串口打印
int __io_putchar(int ch)
{HAL_UART_Transmit(&huart6,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END 4 */

四、下载与调试 

        下载后,自动显示:

        按下S2键,可以按下多次: 

        按下S3键,可以按下多次: 


http://www.mrgr.cn/news/82256.html

相关文章:

  • NDA:Non-Disclosure Agreement
  • 二、CSS基础
  • 如何二次封装组件(vue3版本)
  • 上升沿下降沿递增
  • MySQL - 函数
  • React native 原生环境搭建(最新版本RN环境搭建,不是expo)
  • 矩阵运算提速——玩转opencv::Mat
  • 解析 SQL 中的 NULL 与比较操作:NULL 值与任何值的比较会返回 UNKNOWN
  • 期末速成C++【知识点汇总完】
  • Flutter:打包apk,详细图文介绍(一)
  • 【系统分析师】- 案例 -数据库特训
  • Redis(一)基本特点和常用全局命令
  • 免费开源跨平台SSH工具 WindTerm:媲美 xshell 的最佳平替(含详细使用教程)
  • Wend看源码-Java-Collections 工具集学习
  • blender中合并的模型,在threejs中显示多个mesh;blender多材质烘培成一个材质
  • 数据挖掘——决策树分类
  • ChatBI来啦!NBAI 正式上线 NL2SQL 功能
  • Linux postgresql-15部署文档
  • Flink operator实现自动扩缩容
  • AWVS安装使用教程
  • SpringCloud源码-openFeign
  • 关于无线AP信道调整的优化(锐捷)
  • Linux的源码在Windows下解压时提示文件名字相同(重名)的原因及解决办法
  • Promise实现原理解析,及实现方法。
  • rouyi(前后端分离版本)配置
  • msposd 开源代码之树莓派3B+ Bookworm部署