第2章 开发环境搭建:Keil/IAR环境配置,STM32CubeMX生成基础工程,RTOS内核移植步骤详解
好,咱们直接进入正题。做嵌入式开发,环境搭不好,后面全是坑。我见过太多新手卡在编译报错上,一查发现是工具链没配对。这一章,我带你一步步把Keil和IAR的环境搞定,再用STM32CubeMX生成一个干净的基础工程,最后把RTOS内核移植进去。
2.1 Keil MDK环境配置
Keil MDK,说白了就是ARM开发的老牌工具。我个人习惯用MDK 5.38版本,太新的版本反而容易有兼容性问题。
2.1.1 安装与激活
- 去ARM官网下载MDK-ARM安装包,注意选对版本
- 安装路径不要有中文,不要有空格。我见过有人装在“程序文件”目录下,结果编译报错找半天
- 激活时用管理员权限运行,否则注册信息写不进去
2.1.2 工程配置要点
新建工程时,选芯片型号要精确到具体后缀。比如STM32F407VGT6和STM32F407ZGT6,Flash大小不一样,选错了后面调试会出问题。
嗯,这里有个小技巧:在Target标签页里,把ARM Compiler选成V6版本。V5虽然稳定,但V6编译出来的代码更小,跑起来更快。我在做扫地机导航算法时,用V6编译后RAM占用少了12%。
2.2 IAR Embedded Workbench配置
IAR的优化能力比Keil强,但界面没那么友好。我个人建议:如果你做量产项目,用IAR;如果只是学习,Keil就够了。
2.2.1 安装注意事项
- IAR的License管理比较严格,建议用浮动License
- 安装路径同样不要有中文
- 装完后检查一下C-SPY调试器的驱动,有时候需要手动更新
2.3 STM32CubeMX生成基础工程
STM32CubeMX是个好东西,能省掉你80%的初始化代码。但记住,它生成的只是骨架,血肉还得你自己填。
2.3.1 配置步骤
- 打开CubeMX,选择芯片型号。我建议直接搜“STM32F407VG”
- 配置时钟树:外部晶振8MHz,主频168MHz。别问我为什么是168MHz,这是F4系列的经典频率
- 配置GPIO:至少留一个串口(USART1)和一个LED灯(PA5)
- 配置NVIC:把PendSV和SysTick的中断优先级设好
2.3.2 生成代码
点击GENERATE CODE,等几秒钟。你会得到一个包含HAL库、启动文件、main.c的工程。这时候别急着写代码,先编译一次,确保0错误0警告。
// 这是CubeMX生成的main.c骨架
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 你的代码从这里开始
while (1)
{
}
}
2.4 RTOS内核移植步骤详解
移植RTOS,说白了就是把内核的调度器、任务管理、内存管理这些模块,跟你的硬件平台对接起来。我用FreeRTOS举例,因为它是开源的,资料也多。
2.4.1 移植前的准备
- 下载FreeRTOS源码,我推荐V10.4.6版本,稳定且文档齐全
- 找到portable文件夹,里面有针对不同编译器的移植文件
- 确认你的芯片是Cortex-M4,带FPU
2.4.2 核心文件复制
你需要把以下文件复制到工程目录:
| 文件 | 来源路径 | 说明 |
|---|---|---|
| list.c, queue.c, tasks.c | FreeRTOS/Source/ | 内核核心代码 |
| port.c, portmacro.h | FreeRTOS/Source/portable/RVDS/ARM_CM4F/ | 移植层,注意选带F的(支持FPU) |
| heap_4.c | FreeRTOS/Source/portable/MemMang/ | 内存管理,heap_4支持碎片合并 |
| FreeRTOSConfig.h | Demo/CORTEX_M4F_STM32F407ZG-SK/ | 配置文件,需要自己修改 |
2.4.3 修改FreeRTOSConfig.h
这个配置文件决定了RTOS的行为。我一般这样改:
#define configUSE_PREEMPTION 1 // 抢占式调度
#define configCPU_CLOCK_HZ ((unsigned long)168000000) // 168MHz
#define configTICK_RATE_HZ ((TickType_t)1000) // 1ms一个tick
#define configMAX_PRIORITIES 5 // 优先级数量,够用就行
#define configMINIMAL_STACK_SIZE ((unsigned short)128) // 最小栈大小
#define configTOTAL_HEAP_SIZE ((size_t)20 * 1024) // 20KB堆空间
为什么tick设1000Hz?因为扫地机的运动控制需要1ms的精度。如果你做的是温湿度采集,100Hz就够了。
2.4.4 中断处理适配
RTOS接管了SysTick和PendSV中断。你需要确保:
- SysTick_Handler()里调用xPortSysTickHandler()
- PendSV_Handler()里调用xPortPendSVHandler()
- SVC_Handler()里调用vPortSVCHandler()
嗯,这里要注意:如果你用了HAL库的HAL_Delay(),它依赖SysTick。但RTOS也用了SysTick。解决办法是:把HAL_Delay()改成基于RTOS的vTaskDelay()。我在第一个扫地机项目里就踩过这个坑,两个延时函数混用,结果任务调度全乱。
2.4.5 验证移植是否成功
写一个简单的测试任务:
void vTaskLED(void *pvParameters)
{
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
vTaskDelay(pdMS_TO_TICKS(500)); // 500ms翻转一次
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
xTaskCreate(vTaskLED, "LED", 128, NULL, 1, NULL);
vTaskStartScheduler(); // 启动调度器
while(1); // 正常情况下不会跑到这里
}
下载到板子上,如果LED以1Hz的频率闪烁,恭喜你,移植成功了。
2.5 本章小结
环境搭建这一步,说白了就是磨刀。刀磨好了,砍柴才快。Keil和IAR各有优劣,我建议你两个都装,但主力用一个。CubeMX生成的工程是很好的起点,别嫌弃它代码啰嗦。RTOS移植看着步骤多,其实核心就三件事:复制文件、改配置、调中断。
下一章,我们会创建第一个任务——扫地机的电机控制任务。到时候你就知道,今天搭的环境有多重要了。