建立 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库 ...
随机推荐
- CD管理和检索软件比较
之前一直用EverCD+,考虑到鸡蛋不能放在一个篮子里,又找了几款功能类似的进行了比较,主要考察一下几个功能: 多个镜像:一个数据文件可以包含多个目录的镜像,便于数据管理和搜索: 目录更新:目录内容发 ...
- 快速理解VLAN与三层交换机
一.VLAN 1.1.VLAN的概述与优势 VLAN是逻辑隔离的虚拟局域网,作用是分割广播域(分为物理分割和逻辑分割) VLAN的优势:控制广播.增强网络安全性.简化网络管理 1.2.VLAN的种类 ...
- HandlerInterceptor与WebRequestInterceptor的异同
相同点 两个接口都可用于Contrller层请求拦截,接口中定义的方法作用也是一样的. //HandlerInterceptor boolean preHandle(HttpServletReques ...
- Java调用Zookeeper
watch机制 Zookeeper watch是一种监听通知机制,可以随时监听一些数据的变化,从而实现数据的及时性. Zookeeper所有的读操作getData(), getChildren()和 ...
- 一篇文章让你搞懂如何通过Nginx来解决跨域问题
Nginx跨域实现 首先大家要搞清楚什么是跨域,为什么会有跨域情况的出现.哪些情况属于跨域? 跨域:由于浏览器的同源策略,即属于不同域的页面之间不能相互访问各自的页面内容 注:同源策略,单说来就是 ...
- 为什么网络损伤仪WANsim中没有流量通过
在使用网络损伤仪 WANsim 的过程中,有时候发现网损仪中没有流量通过.有些小伙伴可能会想:自己所有配置都是正确的 ,为什么会没有流量通过呢? 有可能,是你忽略了一些东西. 下面,我总结了一些导致网 ...
- python创建一个简单的服务
python -m http.server 8000 --bind 0.0.0.0 8000为端口 0.0.0.0允许远程访问
- HTML <form> 标签的 method 属性
定义和用法 method 属性规定如何发送表单数据(表单数据发送到 action 属性所规定的页面). 表单数据可以作为 URL 变量(method="get")或者 HTTP p ...
- 一:Tomcat安装、配置和部署笔记
Tomcat安装(绿色版安装) 1.将下载的Tomcat解压到指定目录,如:D:\WorkSpaceByJava\DevtTools\Apache-Tomcat-8.0.23 2.Tomcat的目录结 ...
- 交互式查询⼯具Impala
Impala是什么: Impala是Cloudera提供的⼀款开源的针对HDFS和HBASE中的PB级别数据进⾏交互式实时查询(Impala 速度快),Impala是参照⾕歌的新三篇论⽂当中的Drem ...