建立 F103C8T6 HAL库 Makefile FreeRTOS 工程
F103C8T6 HAL库 Makefile FreeRTOS 工程模板
环境
该工程的开发平台为 ARM-GCC 工具链和 Make
> arm-none-eabi-gcc -v
gcc version 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599] (GNU Tools for Arm Embedded Processors 9-2019-q4-major)
> make -v
GNU Make 3.81
下载调试工具为 OpenOCD + CMSIS-DAP
Open On-Chip Debugger 0.10.0 (2020-01-14) [https://github.com/sysprogs/openocd]
固件信息
- 官方 HAL 库版本:
STM32Cube_FW_F1_V1.8.0
- FreeRTOS API :
CMSIS v2
- FreeRTOS version :
10.0.1
- CMSIS-RTOS version :
2.00
- 官方 HAL 库版本:
适配芯片为
STM32F103C8
开发环境为
Windows10_64bit
+VSCode
资源
BSP_LED -> PB12:板载LED, 指示灯用
USART1:串口,主要调试工具
- TxD -> PA9
- RxD -> PA10
TIM4:HAL 库时基源
SysTick:FreeRTOS 时基源
现象
单片机上电后先通过串口发送一堆测试数据。
BSP_LED 闪烁。
串口每隔一段时间向上位机发送一段测试信息。
- 现象 2 和 3 “同时”进行、互不影响。
目录结构
├─.vscode/ // vscode 配置文件
├─build/ // 编译生成的中间文件
├─DOC/ // 说明文档
├─Drivers/ // ST HAL 库的库文件
├─Inc/ // 用户层的 .h 文件
├─Middlewares/ // 中间件,里面主要包含的是 FreeRTOS 的源码
├─Peripheral/ // 外设。用户层,usart 初始化的 c 和 h 我就写在了这里边
├─Src/ // 用户层的 .c 文件
├─Makefile // 最最重要的 Markfile 文件,工程编译全靠它
├─startup_stm32f103xb.s // 单片机的启动文件,程序其实是从这里开始运行的
├─STM32F103C8Tx_FLASH.ld // 单片机的内存管理相关文件
└─STM32F103xx.svd // 单片机的 svd 文件,大概相当于寄存器的目录吧,调试时使用
工程中的其他注意事项
中断优先级分为4,16级抢占优先级(0~15,越低越优先)无响应优先级。
(HAL_Init() --> HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);)
GCC 中 printf() 底层的实现方式与 Keil 中的不一样,移植工程时须留意。
在 Src 目录下有一个 stm32f1xx_hal_timebase_tim.c 文件,让 TIM 取代 SysTick 就是在这里实现的。(FreeRTOS 的任务调度仍是使用的 SysTick)
因为用到了 TIM4 做 HAL 库时基源 ,所以在 main.c 文件中使用了 HAL_TIM_PeriodElapsedCallback() 函数,以后再使用定时器中断时注意这里 !!!
过程
以完美的 VSCode + GCC工具链 + OpenOCD 的 HAL 库工程为基础再做一个 FreeRTOS 的模板就很简单了。
stm32CubeMX . 用它新建一个工程,配置好 RCC, SYS 和 GPIO , 需要注意的时由于 OS 需要使用 SysTick , 因此将 HAL 库的 时基源调为 TIM1 时基源调为 TIM4 , 因为 TIM1 是高级定时器,高级定时器不多,省着点用。而 TIM4 是 F103C8 的最后一个定时器,后来我又看了几款芯片,发先惯例是每款芯片的最后一个定时器都是那些定时器里最不高级的,因此就用这个吧,免得以后用到什么高级功能麻烦。
在 Middleware 中启用 FreeRTOS (CMSIS_V2) 然后进行一些简单的配置(其实也没什么可配置的)。因为以后我们要自己创建任务所以可以先在这里把总任务堆栈调大一点,其他的配置跟原子推荐的都差不多,用不着动。
可以发现当我们启用 OS 后系统中断发生了一些变化,大概像下图那样。因为 OS 的任务调度跟中断关联很大,所以图上那些灰色不给改的中断配置千万要留意,在 CubeMX 中不能改,在代码中也千万别去改。
配置一下工程的输出参数,然后生成工程吧。
生成工程后先删掉一些不需要的东西,否则工程文件夹太大了。一般来说删掉 \Drivers\CMSIS 目录下除 Device 和 Include 之外的所有文件就可以了。
将前面制作的 HAL 库工程里的 .vscode 文件夹和 STM32F103xx.svd 文件复制到新工程里。最好测试一下串口,所以把 Peripheral 文件夹和 config.h, syscalls.c 也复制过来,然后去 Makefile 和 stm32f1xx_hal_conf.h 中做相应的修改。如果 vscode 报错就看看 makefile 引用了什么新的头文件,然后包含进 c_cpp_properties.json .
现在编译一次应该能通过的,然后再看着改改试试能不能正常用就行了,应该没什么大问题。
补充
关于新建任务。新建任务其实并不复杂,甚至比原子的方式还要简单。仿照默认任务的创建代定义一个新任务的结构体,然后声明一下任务函数,在 main() 中创建一下任务,最后在找个空白的地方写下这个任务函数的一些实现就 OK 了。
注意!接下来要说的事非常重要!!
在任务函数中无法打印浮点数
这个问题的确出现了而且很令人抓狂,我在第二个任务中放了一个
printf("%f\r\n",3.14)
但是程序一旦运行到这里就会死机,陷入到HardFault_Handler()
中。使用操作系统时遇到莫名其妙的问题最先想到的可能就是堆栈溢出,但是直到我把运行 printf() 函数的任务堆栈调大到 10kB 后仍没解决问题时我就觉得没那么简单。从网上了找到了修复使用 newlib 库时遇到这个问题的方案,但是我应该没有使用这个东西。查了一晚上的资料(真的是一晚上,我六点才睡觉)也没什么有效的解决方案,但是我隐约明白了这个东西应该跟内存分配有关系。今天下午又修了修也实在是没什么效果,但是果然正当我打算放弃的时候转机就出现了——还记得当初重定向 printf() 函数时用到了一个文件叫 syscalls.c (这个在上文也有提到),重定向 printf() 其实只要用到里面的 _write() 函数就行了,但是我当时的打算是其他函数现在虽然不知道有什么用但难保以后用不着,所以并没有删掉里面的其他函数。今天下午在我放弃之前的最后一刻我突然想到了我的代码中最不可靠的因素——就是那个 syscalls.c 文件,整个工程的核心代码是 STM32CubeMX 根据我的配置自动生成的应该没什么问题,我手动在 main.c 里边写了些东西但那都是我能解释的应该也没什么问题,所以这样说来工程中最可能出问题的就是那个我擅自从 STM32 的 HAL 库例程中复制过来的 syscalls.c 文件了!
果然当我注释掉 syscalls.c 除与 _write() 函数相关的其余所有代码后问题就解决了。事实上后来查明主要原因是因为 syscalls.c 中的 _sbrk() 函数,但是当我查明后还是果断地把除 _write() 之外的所有函数都注释掉了,永绝后患。
这件事告诉我们对于未知的事物一定要时刻保持最大限度的怀疑。你以为 ST 官方的 HAL 库的例程中的文件都是好的、不会坑你?不存在的。
另注:printf() 这种函数还是很耗费内存的,在任务中运行时虽然不用给任务堆栈分配 10kB 那么夸张,但最低给分配 512*4B 还是有必要的。
附录
CubeMX 中关于 FreeRTOS 配置的中文翻译
建立 F103C8T6 HAL库 Makefile FreeRTOS 工程的更多相关文章
- STM32,下载HAL库写的代码后J-Link识别不到芯片,必须要按住复位才能下载?
问题描述:最近在学STM32的HAL库,据说可以统一STM32江湖,前途无量.最近一段时间参照STM32CubeMX和原子的资料自己学着建了两个HAL库的工程模板,F4的还好说,F1的出现了一个玄学问 ...
- 新建基于STM32F103ZET6的工程-HAL库版本
1.STM32F103ZET6简介 STM32F103ZET6的FLASH容量为512K,64K的SRAM.按照STM32芯片的容量产品划分,STM32F103ZET6属于大容量的芯片. 2.下载HA ...
- 【GMT43智能液晶模块】基于HAL库的SDRAM和LCD驱动例程(MDK工程&CubeMX工程)
说明: 1.该工程基于HAL库实现动态存储器SDRAM驱动以及液晶控制器LCD驱动. 2.工程通过STM32CubeMX(Version 4.22.0)配置生成,可直接打开进行配置. 3.KEIL M ...
- STM32F072从零配置工程-基于HAL库的串口UART中断配置
先上一个采用串口直接传输的Demo: 此处的思路是完全采用HAL库来实现的,核心是运用HAL_UART_Transmit_IT和HAL_UART_Receive_IT两个函数来实现的,可以作为一个De ...
- STM32 HAL库利用DMA实现串口不定长度接收方法
参考:https://blog.csdn.net/u014470361/article/details/79206352 我这里使用的芯片是 F1 系列的,主要是利用 DMA 数据传输方式实现的,在配 ...
- 【STM32H7教程】第32章 STM32H7的TIM定时器基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第32章 STM32H7的TIM定时器基础知识和H ...
- 【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第29章 STM32H7的USART串口基础知识和 ...
- 如何使用keil5将stm32的hal库编译成lib文件——F1版本
hal库中keil5中编译的速度是比较慢的,相同情况下,每次都要编译的时候,比标准库是要慢很多的,因此就hal库编译成lib文件是一种加快编译速度的方法,当然也有其自身的缺点.一.步骤1.使用cube ...
- 【STM32H7教程】第59章 STM32H7的DAC基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第59章 STM32H7的DAC基础知识和HAL库 ...
随机推荐
- gRPC学习之四:实战四类服务方法
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- JavaScript学习06(操作BOM和表单)
操作BOM window 所有浏览器都支持 window 对象.它代表浏览器的窗口. 所有全局 JavaScript 对象,函数和变量自动成为 window 对象的成员. 全局变量是 window 对 ...
- spring-data-jdbc的基础使用(一)
前言 很多人知道Mybatis,知道Jpa,但是对spring-data-jdbc可能了解的少之又少.注意我们这里说的是data-jdbc,而不是普通的jdbc.它拥有了类似jpa的一些特性,比如能够 ...
- QZEZTEST2021.7.27分析
T1 qzez 错误检测 题意 思路 代码 T2 qzez 比赛 题意 题面 有\(AB\)两队,每队\(n\)人,两队间进行\(n\)场比赛,每个人都要参赛,对手随机且概率均等.每人都有一个实力值, ...
- 常见web中间件漏洞(四)Tomcat漏洞
这部分好久没写了,继续更新web中间件漏洞思路整理(不复现) ,争取...整理完 前几篇指路链接: nginx: https://www.cnblogs.com/lcxblogs/p/13596239 ...
- CentOS7 安装Oracle12c数据库
在centos7上安装oracle是一个比较麻烦的事,在安装前需要做一些服务器的准备工作 我是在虚拟机里测试的所以需要下载centos7的镜像,可以去官网然后找到中国的镜像站用迅雷插件下载速度比较快这 ...
- Nodejs koa2读取服务器图片返回给前端直接展示
参考:https://blog.csdn.net/lihefei_coder/article/details/105435358 const fs = require('fs'); const pat ...
- C++11 shared_ptr智能指针(超级详细)
在实际的 C++ 开发中,我们经常会遇到诸如程序运行中突然崩溃.程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的.比如: 有些内存资源已经被释放,但指向它的指针并没 ...
- Qt生成和调用动态库dll,和静态库.a(windows和linux通用)
系统1:ThinkPad T570.Windows10.QT5.12.2(Qt Creater 4.8.2)一.动态库.dll的创建和调用1.在qtcreater中按如下步骤创建动态库,动态库名为my ...
- C#多线程---委托实现异步
一.概述 通过调用ThreadPool的QueueUserWorkItem方法来来启动工作者线程非常方便,但委托WaitCallback指向的是带有一个参数的无返回值的方法. 如果我们实际操作中需要有 ...