300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 单片机 STM32F103C8T6 cubeMX HAL库 从环境到开发 正点原子工程移植 freeRTOS

单片机 STM32F103C8T6 cubeMX HAL库 从环境到开发 正点原子工程移植 freeRTOS

时间:2021-07-28 04:57:56

相关推荐

单片机 STM32F103C8T6 cubeMX HAL库 从环境到开发 正点原子工程移植 freeRTOS

文章目录

0 准备材料1 闪烁PC13的小灯2 正点原子工程移植 注意点以及细节3 freeRTOS3.1 LED KEY 串口1 的一个实验

0 准备材料

1、需要正点原子的HAL介绍书籍可以翻阅

/docs/boards/stm32/zdyz_stm32f103_mini.html

2、下载安装cubeMX,cubeMX是初始化代码生成器,能很快地生成硬件基础配置,基于HAL库。版本越新越好,我的是en.stm32cubemx_v6-0-0。

/zh/development-tools/stm32cubemx.html

正常安装cubeMX后点击软件的这里添加包支持,我需要开发STM32F103C8T6。

3、需要keil ARM软件,用习惯了。

1 闪烁PC13的小灯

1.1 新建工程

1.2 找到芯片,开始配置。顺便一提,这里可以看到芯片的的特性、资源图、手册,真是不要太perfect。

1.3 熟悉配置界面

RCC时钟外部输入打开,实物板子的外部时钟有8MHZ和32768HZ,外部8MHZ可以使得时钟达到最高的72MHZ,没有外部8MHZ内部时钟最高能调到64MHZ。没有外部32768HZ,内部的RTC模块工作不正常。下图是打开了的。一些情况下,设置外部时钟输入这不是必须的。

一定要做的事情,设置debug方式,我用的STLINK 2线下载,SWDIO SWCLK下载,设置为这个。

配置PC13端口为输出。左键点击引脚设置即可。

时钟配置中有芯片时钟的详细配置,非常详细。我没开外部晶振输入,用的内部的,图里有颜色的就是线路,可见RTC没打开,内部40KHZ工作不工作无所谓。点击HCLK可以自己设置一个时钟,我设置为16MHZ。

工程名字写好后,创建代码。

直接打开。

加逻辑代码:

HAL_Delay(1000);HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);

设置debug

下载后即可运行。

2 正点原子工程移植 注意点以及细节

cubeMX缺点就是没printf、没delay_us,而且实际开发需要一些传感器,自己去搞就是重复造轮子,所以需要正点原子的例子支持。

过程简单粗暴,RCC中打开2个外部时钟输入,打开SYS中debug(!!注意,如果关了调试端口后不然下次只能串口下载了,很烦人),SYS中使用sysTick,使能USART1(这样cubeMX能把h啥的HAL依赖加进来,后面就不用自己加了,比较舒服,cubeMX把这些初始化,我们一样可以在keil里把初始化删了,不影响骚操作。其他的资源同理,比如需要ADC1就cube里加了再说,后面不想要就自己keil里删除)。

得到的keil工程,直接把原子的下面6个文件复制到.\Core\Src(main.c也在这里)中。

keil中添加上c文件,会得到下面这样的结构。

在main.c中添加包含

#include "sys.h"#include "delay.h"#include "usart.h"

然后修改main(),删除UART初始化函数(声明、定义、调用都删除),删除时钟初始化函数(声明、定义、调用都删除),全部用原子的。

Stm32_Clock_Init( RCC_PLL_MUL9 ); /* 设置时钟,72M */delay_init( 72 ); /* 初始化延时函数 */uart_init( 115200 );/* 初始化串口 */

点编译会出现下面这结果,就是说重复定义了,因为开始的时候用了cubeMX生成了UART1的东西和院子的重复了。

Build target 'DDDDD'compiling main.c...linking...DDDDD\DDDDD.axf: Error: L6200E: Symbol USART1_IRQHandler multiply defined (by stm32f1xx_it.o and usart.o).DDDDD\DDDDD.axf: Error: L6200E: Symbol HAL_UART_MspInit multiply defined (by stm32f1xx_hal_msp.o and usart.o).Not enough information to list image symbols.Not enough information to list the image map.Finished: 2 information, 0 warning and 2 error messages."DDDDD\DDDDD.axf" - 2 Error(s), 0 Warning(s).Target not created.Build Time Elapsed: 00:00:01

打开.\stm32f1xx_hal_msp.c找到void HAL_UART_MspInit(UART_HandleTypeDef* huart),然后可以直接把这个函数删除掉,或者像下图这样添加__weak关键字,keil发现有2处相同定义时优先用没带__weak关键字的定义,自然就用原子的定义了。

打开…/Core/Src/stm32f1xx_it.c,同样修饰一下定义void USART1_IRQHandler(void)

打开…/Core/Src/stm32f1xx_it.h去修饰一下声明__weak void USART1_IRQHandler(void);这个操作无所谓,声明而已,可以不修饰。

__weak void USART1_IRQHandler(void);

再次编译就不会有错了。

一些细节:

细节1:原子的CORE文件和cubeMX的CMSIS效果一样的。

图1 原子的CORE文件

cubeMX的CMSIS

细节2:

stm32f1xx_it.c/stm32f1xx_it.h里面是中断服务函数的定义和声明,除了SysTick_Handler和USART1_IRQHandler,其他的基本都是单片机发生异常后进入中断就再也出不去了(死机),比如发生数值溢出,keil编译的时候是不可预知这种错误的,单片机靠这个机制让自己”死掉“。

void NMI_Handler(void);void HardFault_Handler(void);void MemManage_Handler(void);void BusFault_Handler(void);void UsageFault_Handler(void);void SVC_Handler(void);void DebugMon_Handler(void);void PendSV_Handler(void);void SysTick_Handler(void);__weak void USART1_IRQHandler(void);

细节3:

stm32f1xx_hal_msp.c 文件,这文件是ST公司推出HAL的主要目的,弱化硬件配置难度,下面一段话引用自原子书籍。

MSP,全称为 MCU support package,关于怎么理解 MSP,我们后面在讲解程序运行流程的时

候会给大家举例详细讲解,这里大家只需要知道,函数名字中带有 MspInit 的函数,它们

的作用是进行 MCU 级别硬件初始化设置,并且它们通常会被上一层的初始化函数所调用,

这样做的目的是为了把MCU相关的硬件初始化剥夺出来,方便用户代码在不同型号的MCU

上移植。stm32f1xx_hal_msp.c 文件定义了两个函数 HAL_MspInit 和 HAL_MspDeInit。这两个

函数分别被文件 stm32f1xx_hal.c 中的 HAL_Init 和 HAL_DeInit 所调用。HAL_MspInit 函数的

主要作用是进行 MCU 相关的硬件初始化操作。例如我们要初始化某些硬件,我们可以硬

件相关的初始化配置写在 HAL_MspDeinit 函数中。这样的话,在系统启动后调用了 HAL_Init

之 后 , 会 自 动 调 用 硬 件 初 始 化 函 数 。 实 际 上 , 我 们 在 工 程 模 板 中 直 接 删 掉

stm32f1xx_hal_msp.c 文件也不会对程序运行产生任何影响。对于这个文件存在的意义,我

们在后面讲解完程序运行流程之后,大家会有更加清晰的理解。

细节4:

什么是回调函数?

参看/x1131230123/article/details/106507086,回调函数就是一个通过函数指针调用的函数:编写一个函数,另一个函数可以用这个函数当参数。

原子有另外的解释:STM32 不完全手册( ( H AL 库 版) Msp 回调函数执行过程解读

在 STM32 的 HAL 驱动中HAL_PPP_MspInit()作为回调,被 HAL_PPP_Init()函数所调用。当我们需要移植程序到 STM32F1平台的时候,我们只需要修改 HAL_PPP_MspInit 函数内容而不需要修改 HAL_PPP_Init 入口参数内容。

下面这个函数或许更应该称为Callback函数。但毋庸置疑的是,HAL实现都用句柄操作,大量用__weak修饰一些回调函数,用户需要自己编写逻辑实现而不用过多在意硬件底层。

void HAL_UART_RxCpltCallback( UART_HandleTypeDef *huart ){if ( huart->Instance == USART1 ) /* 如果是串口1 */{}}

细节5:

在目录ALIENTEK MiniSTM32 V3.0开发板资料\6,软件资料\3,EMWIN学习资料\stm32cubef1\STM32Cube_FW_F1_V1.0.0中打开Release_Notes。包里面资料一应俱全,我建议我自己反复翻阅一下,能够更快熟悉HAL库。

3 freeRTOS

用cubeMX肯定图谋freeRTOS,尽情玩起来。

有下面注意点:

1 单片机是单核的,freeRTOS是为了让其CPU充分利用,任务切换。

2 任务切换依靠freeRTOS里的任务就绪状态表执行,对就绪任务进行分优先级切换。

3 freeRTOS是可抢断的。

4 临界区代码是指关闭所有中断后执行的一段代码,执行完后记得打开全局中断,不然任务无法切换。

5 任务的状态与切换。

6 任务之间的通信依靠信号量、消息队列、消息邮箱等机制。

7 内存管理的一些事情。

8 内核裁剪的一些事情。

9 cubeMX把freeRTOS的方法再次封装了,在cmsis_os.c文件中。这使得程序更简单了。

/pack/doc/CMSIS/RTOS/html/usingOS.html

/pack/doc/CMSIS/RTOS/html/functionOverview.html

3.1 LED KEY 串口1 的一个实验

用cubeMX打开RCC的2个外部时钟输入

打开PC13作为LED输出

打开PB7 PB6 PB5 PB4作为按键输入

打开SYS中的serial Wire,选择TIM1作为Timebase Source(避免和freeRTOS的心跳冲突)

打开USART1并打开中断

打开中间件FREERTOS并添加2个任务进去,LED和KEY任务。

在clock configuration中选择72MHZ时钟。

生成工程。

添加下面代码在main.c中使得串口1支持printf

#include <stdio.h>//重定义fputc函数 int fputc(int ch, FILE *f){while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (unsigned char) ch;return ch;}

编写任务函数:

/* USER CODE BEGIN Header_StartTask02 *//*** @brief Function implementing the LED thread.* @param argument: Not used* @retval None*//* USER CODE END Header_StartTask02 */void StartTask02(void const * argument){/* USER CODE BEGIN StartTask02 *//* Infinite loop */for(;;){HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);//取反osDelay(1000);//延时1秒钟}/* USER CODE END StartTask02 */}/* USER CODE BEGIN Header_StartTask03 *//*** @brief Function implementing the KEY thread.* @param argument: Not used* @retval None*//* USER CODE END Header_StartTask03 */void StartTask03(void const * argument){/* USER CODE BEGIN StartTask03 *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==0){while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==0);printf(" press key1 \r\n");}osDelay(10);}/* USER CODE END StartTask03 */}

任务StartTask02每隔1000ms取反小灯,任务StartTask03每次PB7按键按下向串口发送数据。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。