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的功能完整。
在CubeMX生成的CAN1初始化函数中调用自己写的CAN_Config(),完成CAN的设置并开启它。
FIFO0接收到数据的中断回调函数与CAN错误回调函数如下。
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){/* 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里增加了按键中断的回调函数。
删除了main函数里的CAN数据发送HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox);
这样,数据只在按键按下时发送,其他不变。
结果
总结
以上是生活随笔为你收集整理的STM32CubeMX与HAL库学习--简单的CAN回环测试的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: hypermesh 圆周阵列-插件
- 下一篇: 如何将PPT转换成Word文档?