完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
今天有个很大的收获,就是知道了什么是【回调函数】哈哈哈。。。
好吧言归正传,这个文章是我在调试我的ABS控制器的时候写的,本来打算写在项目笔记里,但是觉得这应该算是通用型的知识,而且我一开始是用野火的开发板调试的,所以打算把它写在STM32学习笔记下面。 其实这不应该是第二篇学习笔记,因为至少之前写过一篇SPI通讯的,虽然是和5048磁编码器一起写的,但是也是用的stm32,不过无所谓。 我之前学STM32的时候用的是标准库函数编程的方法,后来又接触到了寄存器编程(托欣师兄的福。。。),可是后来我从罗明睿那里知道了Cube+HAL库编程的方法,对我的启发蛮大的。 HAL是(hardware abstract layer)硬件抽象层的意思,对函数名和函数体进行了重新定义、重新编写,标准化更高,更加通用,方便移植。配合Cube软件可以实现STM32系列MUC的可视化配置,自动生成工程代码,不需要再自己建立工程模板,而且可以随时添加新的外设和功能,不影响用户自己编写的代码,不过缺点是比较臃肿,占用空间较大。 HAL库是ST近年大力推广的编程方式,在一些高端芯片中只有HAL库没有标准库(大概是这样的)。 好吧,再言归正传,其实如果用标准库的话,野火开发板提供了详细的教学视频和应用例程,我可以直接用,但是我还是决定试一试Cube+HAL库的方式,虽然后来我觉得好像走进了一个新坑。。。 〇 Cube软件的注意事项 首先要注意的问题是,工程目录的路径里不能有中文,如果有中文的话,他生成代码的时候会报错,但不会告诉你是因为路径名字的问题,但是当你用keil打开编译的时候就会不成功。。。。切记! Cube有个让我很不习惯的地方就是,对于单片机的引脚,特别是一些重要的功能引脚来说,如果不在Cube里进行配置,他就会把它关闭,而不是默认开启。 比较重要的就是SWD的下载端口,如果在一开始没有配置的话,当你第一次把程序烧录进去之后,下载端口就被关闭了,用正常的方法就无法再给单片机下载程序了。。。虽然可以通过拉高boot0的方法重置,但是还是要主要第一次配置的时候,记得在SYS里的debug模式里面选择Serial Wire。 另外就是外部晶振,Cube里默认是使用内部高速振荡器,如果用外部晶振,需要在RCC里面的HSE里选择Crystal/Ceramic Resonator,然后在时钟配置里选择外部晶振。 下面开始具体的学习(爬坑)过程。 〇 在Cube里面配置相关功能 因为我用的是野火的开发板,所以首先在芯片选择里面选STM32F103ZE 然后就是按照上面说的方法配置仿真器引脚和晶振引脚。 然后对时钟树进行配置。 时钟树的讲解在野火的资料和视频里讲的很详细了,第一次用图形化方式配置,还有点小激动。。。这里需要注意的是CAN总线是挂载在APB1高速总线上的,PCLK1的频率直接决定了CAN模块的参数配置。 接下来配置端口,根据野火的原理图,我们知道can的端口用的是PB8和PB9. 于是在Cube里选择相应端口。 然后在configuration里面配置相应参数。 这里需要注意的是,CAN通讯里面有波特率的概念(最大1MHz),但是并不是直接设置波特率的速率,而是分别设置预分频系数,每一段指令周期的时间,最后通过计算才得出can总线的波特率。 CAN总线的物理层和协议层在野火的资料和视频里有很详细的讲解,而且可以看一看瑞萨科技的圣经《CAN入门书》,在这里我稍微搬一搬。其实我也是昨天才弄懂了can总线的波特率。。。 ♣ CAN总线的基础知识 ○ 物理层 CAN总线的硬件结构,can总线用差分线传输数据,除了can控制器外必须配有can收发器,总线两端需要串联120欧电阻。 CAN总线用CANH与CANL两线的电压差表示0和1,差为0V表示1(隐性电平),差为2V表示0(显性电平)。 ○ 协议层 CAN信号的每一位分为如图几个部分,最小的时间单位是Tq(Time Quantum),其作用和讲解就不搬了,这几部分的时长一起决定了CAN总线的波特率。 CAN总线的报文结构,如图所以,详细的就不搬了。 ○ STM32的CAN模块介绍 STM32的CAN架构 CAN控制器的基本参数 CAN的四种工作模式 位时序和波特率 此外,STM32的CAN模块还包括发送邮箱,接收FIFO,过滤器等等,我就不搬了,可以参见野火的《零死角玩转STM32》一书或相关资料。 搬完了CAN的基础知识以及STM32的can模块相关信息,然后再来看Cube的设置界面 可以看出就是对上面提到的一些参数的配置。 这里配置成1MHz的工作模式,普通收发模式。理论上来说,一般调试设备的时候都先选成回环模式或者静默回环模式,但是因为我不会STM32的在线仿真,如果设置成回环模式的话,需要同时保证发送程序和接收程序都正确才能调试成功,不过我打算先调试发送程序,再调试接收程序,用CAN信号分析仪作为辅助工具,所以这里选择普通模式。 然后在project manager里面输入工程的名字、位置、编译器的类型及版本,然后点 没有问题的话就可以点Open Project 然后就打开了熟悉的keil(然而HAL库函数看的一脸懵逼。。。),打开工程之后记得先编译一下,一般来说会0 Errors,0 Warnings。 〇 用HAL库实现CAN总线的发送 连标准库的使用都是一知半解得我在HAL库里完全不知所措,这该如何下手? 还好我们有百度,我们有CSDN。。。 在这里首先感谢下面这篇文章的作者,用非常简洁的语句和代码实现了发送的功能,其他一些文章很多都是调用自己写的函数,而作者只简单的调用了库函数,虽然可能在功能上有不足,但贵在直观。 →→→ stm32CubeMx CAN 发送数据 按照文章的示例,我在main函数的Private Variables部分添加代码 在Initialize all configured peripherals部分添加代码 在主函数的user code 2部分添加发送邮箱信息 最后在主程序while(1)部分添加代码 有一点需要注意,使用Cube+HAL库时,用户只能在生成的代码的 /* USER CODE BEGIN */ 和 /* USER CODE END */ 之间插入代码,不然在使用Cube修改程序配置时会被覆盖掉!切记! 然后编译代码,选择仿真器,连接CAN信号分析仪,烧录程序,观察分析仪软件有没有收到数据。 OK!No problem! 下面就是解决接收的问题。 ❤ 2019.12.20 〇 HAL库实现CAN总线的接收 CAN总线的接收需要配置中断,总不能用查询的方式来接收can指令吧,(而且也没有看到有人用查询的方式来接收的例程。。。),虽然can的发送是用延迟的方式发送的,但是如果发送的数据量比较大,肯定也是需要用中断方式发送的,但是发送先不用着急,先把接收中断搞好。 can的发送很简单,就几行代码,我也是在云里雾里的情况下偶然发现别人的文章才实现的,但是我并没有找到简单朴素的讲解can接收的文章。。。很多文章可能是HAL库的版本较老,函数名都有很大的差别,还有一些给出了一大堆代码,但是讲解并不详细,对于我这样的初学者很不友好。 不过有一个还比较新的工程包,作者写的很认真,注释很详细,对于初学者理解代码有一定的帮助。在这里表示感谢~ 不过这里例程里面包含了FreeRTOS系统,显得比较复杂,而且作者对函数库有一定的改动(后面说),不能直接用于cube生成的代码,而且代码有一些作者自身的编程习惯,有时候我觉得不太规范,这时候我想到了st的官方例程。 官方例程在hal库的库文件包里 埋得还是比较深的,还好里面有个索引文件,要不还真找不到。 官方例程使用中最大的障碍就是全英语。。。。 不过呢不得不说格式很规范,很有参考(搬运)价值~ 说实话直接看官方例程的话,如果不是很熟悉stm32的can模块工作方式,不熟悉hal库的编程习惯,还是很不好理解的。我首先学习了野火的视频,对stm32的can模块在标准库下的工作流程有了个初步的了解,然后参考了刚刚提到的那个有详细中文注释的工程文件,对其配置和使用有了大概的了解,随后我把官方例程和cube生成的未配置的代码进行对比,(大家来找茬?),找到他们之间不同的地方,就是我需要在我的工程里添加的部分。不过官方例程并没有像cube生成的文件里那样标出来哪些是user code 哪些是自动生成的code,因为hal库的特性,我只能更改代码里面的user code部分,所以我得把官方例程里的那些已经被cube自动生成的部分去掉。 说实话,虽然我前两天弄明白了什么是回调函数,但是具体到回调函数的使用我还不知道。比如说can的中断服务函数cube已经生成完毕,但是在库函数了,所以正常情况下我是不可以修改的。但是我却不知道应该在哪里修改。。。我甚至不知道哪个函数是负责读取接收邮箱的。。。 根据我多年的经验,我猜这个函数是用来读取接收邮箱的数据的,但是这个函数在例程里并没有被直接调用,所以我经过检索发现了蛛丝马迹。 这个是在主函数里定义的一个回调函数,看来他就是罪魁祸首。让我来看看他是在那里调用的。 哼,果然是他!这个函数就是can的中断服务函数。 现在事实已经很清楚了,下面我按照例程的格式在我的工程里添加相应的语句。 这里有个问题,我看有的文章说必须要配置过滤器,不然接收FIFO无法接收数据,这里我来验证一下,先不配置过滤器。 首先把之前测试发送的代码删除或注释掉。 然后在Cube生成的can初始化函数里添加语句(就不另外建立新的初始化函数了) /* USER CODE BEGIN CAN_Init 2 */ //开启can模块 if (HAL_CAN_Start(&hcan) != HAL_OK) { /* Start Error */ Error_Handler(); } //开启can中断 if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { /* Notification Error */ Error_Handler(); } //配置发送邮箱初始信息 TxHeader.RTR = CAN_RTR_DATA; TxHeader.IDE = CAN_ID_STD; TxHeader.StdId = std_id; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.DLC = 8; /* USER CODE END CAN_Init 2 */ 然后新建bsp_can.c和.h文件,文件里建立HAL_CAN_RxFifo0MsgPendingCallback()的回调函数,用来接收数据,CanTestSendBack()用来将接收的数据发送出去,Error_Handler()用来处理错误。 /** ****************************************************************************** * @file bsp_can.c * @author zgc * @version V1.0 * @date 2019.12.20 * @brief Cube+HAL库下的can驱动(学习版) ****************************************************************************** * @attention * * 平台: 秉火 STM32 F103-霸道 开发板 * 编译器: keil 5.25 * ****************************************************************************** */ #include “bsp_can.h” #include “stm32f1xx_hal.h” //这个是例程里带的,can发送接收的基本变量与结构体 //CAN_HandleTypeDef CanHandle; CAN_TxHeaderTypeDef TxHeader; CAN_RxHeaderTypeDef RxHeader; uint8_t TxData[8] = {0x1,0x0,0x1,0x0,0x1,0x0,0x1,0x0}; uint8_t RxData[8] = {0}; uint32_t TxMailbox; uint32_t std_id = 0x123; //************************************************** //这个是什么变量我还没想好 uint8_t MsgAvailable = 0; //接收到数据标记位 /** * @name HAL_CAN_RxFifo0MsgPendingCallback * @brief Rx Fifo 0 message pending callback in non blocking mode,大概意思就是can接收中断函数里的一个回调函数,用来接收数据 * @param CanHandle: pointer to a CAN_HandleTypeDef structure that contains the configuration information for the specified CAN. * @retval 无 */ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) { /* Get RX message */ if (HAL_CAN_GetRxMessage(CanHandle, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) { /* Reception Error */ Error_Handler(); } MsgAvailable = 1; //接收到数据标记位置1 } /** * @name Error_Handler * @brief This function is executed in case of error occurrence.大概意思就是如果出现了错误,程序就会在这里卡住,方便调试(可是怎么调试。。。) * @param None * @retval None */ static void Error_Handler(void) { while (1) { } } /** * @name CanTestSendBack * @brief Can模块测试函数,将can总线接收到的数据再通过can发送出去 * @param 无 * @retval 无 */ void CanTestSendBack(void) { uint8_t i = 0; for(i = 0; i 《 8; i++) { TxData[i] = RxData[i]; RxData[i] = 0; } if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) != HAL_OK) { /* Transmission request Error */ Error_Handler(); } HAL_Delay(100); MsgAvailable = 0; //接收到数据标记位清0 } /**************************END OF FILE************************************/ 然后在main函数里添加 主循环里添加 最后在Cube的设置里打开can的接收中断。(其实我最开始忘记了,配置完过滤器才想起来。。。不过后来我又把过滤器的配置代码注释掉之后又来测试过) 因为我用的是FIFO0,所以打开CAN RX0的中断,generate code。 打开,编译,下载,打开can信号分析仪,能接收到初始化的那条数据,向stm32发送数据,果然没反应。。。。 现在最大的可能就是因为没有设置过滤器。 这里先搬一下关于stm32can的过滤器的信息。 ○ STM32can模块过滤器(验收筛选器) 接下来对照官方例程,配置can的过滤器。 首先在初始化函数里加入结构体的声明 然后在user code部分添加代码 //配置can过滤器 sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000; sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; sFilterConfig.FilterActivation = ENABLE; sFilterConfig.SlaveStartFilterBank = 14; if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) { /* Filter configuration Error */ Error_Handler(); } 编译,下载,测试,OK~ 至此STM32的Cube+HAL库的CAN通讯学习与测试暂告一段落,后面可能还有中断方式发送can数据等等的内容,等需要的时候我再继续写。 总的来说,STM32的can模块比F28335的人性化好多,我一直对F28335的需要给每个邮箱配置ID(虽然有32个邮箱好像挺多的),然后只能发送和接收相同ID的数据这个设定很不爽。。。简直反人类。。。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1792 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1626 浏览 1 评论
1094 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
732 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1682 浏览 2 评论
1943浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
740浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
577浏览 3评论
600浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
562浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 02:27 , Processed in 0.746655 second(s), Total 44, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号