欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

STM32CubeMX与HAL库学习--简单的CAN回环测试

发布时间:2024/1/1 67 豆豆
生活随笔 收集整理的这篇文章主要介绍了 STM32CubeMX与HAL库学习--简单的CAN回环测试 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

STM32CubeMX与HAL库学习--简单的CAN回环测试

  • 前言
  • STM32CubeMX生成初始化代码
  • 在MDK-ARM里编辑代码
  • 其他
  • 后续

前言

本人小白,最近看了CAN协议与STM32的bxCAN外设的一些资料,简单地做个CAN回环测试练习一下。这只是一个初学者的简单练习记录,学习的话还是要看对应的教程啦。

使用到的工具及版本:
STM32CubeMX版本:6.3.0
HAL库:STM32CubeF4 Firmware Package V1.26.1
MDK-ARM:V5.32.0.0
开发板:野火的霸天虎开发板V2(主控芯片是STM32F407ZGT6)

大概的框图如下:

STM32CubeMX生成初始化代码

时钟、串口配置之类的略过。
关于CAN配置:

在NVIC那里打开CAN1 RX0中断允许,并设定一下优先级。

在MDK-ARM里编辑代码

CAN的设置尚未完成,CubeMX那里只是设置了模式,打开can.c,接下来设置筛选器。我配置的是列表模式,筛选了拓展ID 0x2233和标准ID 0。

/** 函数名:CAN_Filter_Config* 描述 :CAN的过滤器 配置* 输入 :无* 输出 : 无* 调用 :内部调用*/ static void CAN_Filter_Config(void) {CAN_FilterTypeDef CAN_FilterTypeDef;/*CAN筛选器初始化*/CAN_FilterTypeDef.FilterBank=0; //筛选器组0CAN_FilterTypeDef.FilterMode=CAN_FILTERMODE_IDLIST; //工作在列表模式CAN_FilterTypeDef.FilterScale=CAN_FILTERSCALE_32BIT; //筛选器位宽为单个32位。/* 使能筛选器,按照标志的内容进行比对筛选,扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */CAN_FilterTypeDef.FilterIdHigh= ((((uint32_t)0x2233<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16; //要筛选的ID高位 CAN_FilterTypeDef.FilterIdLow= (((uint32_t)0x2233<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要筛选的ID低位 CAN_FilterTypeDef.FilterMaskIdHigh= 0; //第二个ID的高位CAN_FilterTypeDef.FilterMaskIdLow= 0; //第二个ID的低位CAN_FilterTypeDef.FilterFIFOAssignment=CAN_FILTER_FIFO0 ; //筛选器被关联到FIFO0CAN_FilterTypeDef.FilterActivation=ENABLE; //使能筛选器HAL_CAN_ConfigFilter(&hcan1,&CAN_FilterTypeDef); }

发送或者接收数据都有对应的结构体对帧的ID、帧类别、数据长度等进行了描述(CAN_RxHeaderTypeDef、CAN_TxHeaderTypeDef),发送时需要根据数据特性配置发送结构体,接收则是把接收数据的特性存储到指定的接收结构体。
消息发送函数

获取接收消息函数

因为只是简单的测试,我就在初始化阶段把他们设置好。
用一个CAN_Config把CAN的功能完整。

__IO uint32_t CAN_RxFlag = 0; //用于标志是否接收到数据,在中断函数中赋值CAN_TxHeaderTypeDef TxMes; //发送结构体 CAN_RxHeaderTypeDef RxMes; //接收结构体uint8_t CAN_TxDate[9]="CAN LOOP"; //发送缓冲区 uint8_t CAN_RxDate[9]; //接收缓冲区uint32_t TxMailbox; //用于指示CAN消息发送函数HAL_CAN_AddTxMessage使用了哪个邮箱来发送数据/*** @brief 初始化 Rx Message数据结构体* @param RxMessage: 指向要初始化的数据结构体* @retval None*/ void CAN_RxMesInit(CAN_RxHeaderTypeDef* RxMessage) {/*把接收结构体清零*/(*RxMessage).StdId = 0x00;(*RxMessage).ExtId = 0x00;(*RxMessage).IDE = CAN_ID_STD;(*RxMessage).DLC = 0;(*RxMessage).RTR = 0;(*RxMessage).FilterMatchIndex = 0;(*RxMessage).Timestamp = 0; }/** 函数名:CAN_TxMsgInit* @brief 初始化TxMessage数据结构体* @param TxMessage: 指向要初始化的数据结构体* @retval None*/ void CAN_TxMsgInit(CAN_TxHeaderTypeDef* TxMessage) { (*TxMessage).StdId=0x00; (*TxMessage).ExtId=0x2233; //使用的扩展ID(*TxMessage).IDE=CAN_ID_EXT; //扩展模式(*TxMessage).RTR=CAN_RTR_DATA; //发送的是数据(*TxMessage).DLC=8; //数据长度为8字节 }/** 函数名:CAN_Config* 描述 :完整配置CAN的功能* 输入 :无* 输出 : 无* 调用 :MX的CAN初始化调用*/ void CAN_Config(void) {CAN_Filter_Config();CAN_TxMsgInit(&TxMes); CAN_RxMesInit(&RxMes);HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING); //使能FIFO0接收到数据中断HAL_CAN_Start(&hcan1); //开启CAN1 }

在CubeMX生成的CAN1初始化函数中调用自己写的CAN_Config(),完成CAN的设置并开启它。

FIFO0接收到数据的中断回调函数与CAN错误回调函数如下。

/*** @brief CAN接收完成中断(非阻塞) * @param hcan: CAN句柄指针* @retval 无*/ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan) {/* 比较ID是否为0x2233 */HAL_CAN_GetRxMessage(&hcan1,CAN_RX_FIFO0,&RxMes,CAN_RxDate);if((RxMes.ExtId==0x2233) && (RxMes.IDE==CAN_ID_EXT) && (RxMes.DLC==8) ){CAN_RxFlag = 1; //接收成功 }else{CAN_RxFlag = 0; //接收失败} } /*** @brief CAN错误回调函数* @param hcan: CAN句柄指针* @retval 无*/ void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {printf("\r\nCAN出错\r\n"); }

main函数。

/* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ extern __IO uint32_t CAN_RxFlag; //用于标志是否接收到数据,在中断函数中赋值extern uint8_t CAN_TxDate[9]; //发送缓冲区 extern uint8_t CAN_RxDate[9]; //接收缓冲区extern CAN_TxHeaderTypeDef TxMes; //发送结构体 extern CAN_RxHeaderTypeDef RxMes; //接收结构体 extern uint32_t TxMailbox; //用于指示CAN消息发送函数HAL_CAN_AddTxMessage使用了哪个邮箱来发送数据 /* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/ int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_CAN1_Init();/* Initialize interrupts */MX_NVIC_Init();/* USER CODE BEGIN 2 */printf("CAN LOOP TEST\r\n");HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox); //发送数据/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */if(CAN_RxFlag){CAN_RxFlag = 0;printf("Transmit message:%s\r\n",CAN_TxDate);printf("Receive message:%s\r\n",CAN_RxDate);}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */ }

效果

其他

最初,我把发送数组和接收数组的长度设为8

uint8_t CAN_TxDate[8]="CAN LOOP"; //发送缓冲区 uint8_t CAN_RxDate[8]; //接收缓冲区

结果是这样:

不出意外的话这两个数组在内存中是这样的(注:其实可以在map文件里查看具体地址):

如果只是用来存储CAN数据这倒是没什么问题,但是用printf把它们作为字符数组输出的话就可能会像图中一样越界了。
所以我把这两个数组长度定义为9,0~7字节是数据,第8字节一直是0(编译器给它初始化为0),这样就可以防止printf输出越界。

后续

接下来,在原来的基础上增加一个按键,把按键按下次数转换为字符串存储到CAN_TxDate数组,并在按键按下的中断里通过CAN发送,其他基本与上文无异,我的实现步骤如下:
首先打开原来的CubeMX工程文件,找到按键的引脚,把它配置为外部中断

使能中断

然后就可以生成代码了,别忘了勾选保留用户代码

写在用户区域的代码会得以保留,写的时候注意一下位置,我前面while循环里的代码写错位置了,重新生成文件时就被删了。
正确的位置

/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(CAN_RxFlag){CAN_RxFlag = 0;printf("Transmit message:%s\r\n",CAN_TxDate);printf("Receive message:%s\r\n",CAN_RxDate);}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

错误的位置

/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */if(CAN_RxFlag){CAN_RxFlag = 0;printf("Transmit message:%s\r\n",CAN_TxDate);printf("Receive message:%s\r\n",CAN_RxDate);}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */

其实看注释名字就知道了。
在main.c里增加了按键中断的回调函数。

//按键中断 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {static uint16_t KeyTime = 0;if(GPIO_Pin == KEY1_Pin){KeyTime++;sprintf((char*)CAN_TxDate,"%d",KeyTime);HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox); //发送数据} }

删除了main函数里的CAN数据发送HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox);
这样,数据只在按键按下时发送,其他不变。
结果

总结

以上是生活随笔为你收集整理的STM32CubeMX与HAL库学习--简单的CAN回环测试的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。