目录
1、首先打开STM32CubeMx,选择New Project,选择芯片型号
2、其次,选择RCC时钟配置
3、第三,选择对应的debug接口
4、配置主频时钟
5、不生成PendSV_IRQn代码
6、配置LED灯的IO用于测试
7、配置代码生成选项,点击生成
8、先修改keil设置,验证HAL_Delay
8.1 使用微库,不使用浮点单元(target选项)
8.2 选择编译输出文件的目录,并去掉索引编译
8.3 选择最低代码优化等级
8.4 选择烧录工具
9、注释掉Error_Handler中的初始代码
10、在main函数while(1)中添加测试代码
11、移植ucOSII代码
11.1 拷贝ucOSII源码
11.2 添加到工程中,并添加头文件路径包含
11.3 移植和运行
12、结束
本篇文章记录和讲述一下,如何创建一个新的keil工程,并将ucOSII移植进去。
我的板子MCU是STM32F429ZGT6,有3个LED灯,支持USB/BT通讯。
1、首先打开STM32CubeMx,选择New Project,选择芯片型号
2、其次,选择RCC时钟配置
根据自己的MCU外围电路选择时钟,如下图,一般都是直接勾选这两个选项。
3、第三,选择对应的debug接口
4、配置主频时钟
比如F4芯片,如果有类似USB/SDIO等需要单独提供时钟,而不是来自APB1、APB2上的,建议先使能接口,再选择时钟。
比如我这里,先勾选上 1、USB接口和 2、USB虚拟串口设备(从机),时钟配置选项那里就会提示警告。
然后再去配置时钟。
5、不生成PendSV_IRQn代码
把下图中的勾选取消掉。
否则移植ucOSII代码时,会提示重复定义。因为在ucOSII的汇编代码中,已经定义了其处理函数。
6、配置LED灯的IO用于测试
如下图,点击IO选择output功能,然后在GPIO设置中定义一个标签名。
7、配置代码生成选项,点击生成
注意点1:路径中不要有中文名,否则最后生成会提示失败;其次最好是自己创建工程目录,不要用Cubemx去新建文件夹。
注意点2:尽量勾选“Copy Only the libraryies into the project files”,否则Drivers目录下会有一大堆冗余文件,用git存储时就比较浪费空间了。
8、先修改keil设置,验证HAL_Delay
8.1 使用微库,不使用浮点单元(target选项)
8.2 选择编译输出文件的目录,并去掉索引编译
HAL库代码虽然简单易用,但是代码量剧增,编译起来速度会相当慢。
8.3 选择最低代码优化等级
8.4 选择烧录工具
如下,以Jlink为例,先选择Jlink,再选择SWD port,
右侧如果出现ID code表示识别成功。
最后记得,在Download选项中勾选reset,否则你烧录程序之后,需要手动进行硬件复位。
9、注释掉Error_Handler中的初始代码
如下,将这段代码注释掉,可以自行添加代码打印或其它操作代码。
Error_Handler函数,是用在HAL库的初始化失败时调用,但是有些初始化失败是没有影响的,不能直接死掉。
10、在main函数while(1)中添加测试代码
测试LED灯闪烁及HAL库延时函数。
编译,然后烧录,可以看到板子开始循环闪烁。
11、移植ucOSII代码
11.1 拷贝ucOSII源码
STM32F4平台的源码,是非常少的。
不像F7、H7系列,还有BSP、CPU等多个文件夹。
具体结构如下图。
源码文件:
Core目录下文件:
Port目录下文件:
11.2 添加到工程中,并添加头文件路径包含
1)添加内核文件
不需要的模块可以不添加,比如事件标志组和内存管理的文件,我就没添加,但前提是ucOSII的配置文件没有使能这两个模块。
2)添加cpu.c和cpu.asm文件
3)包含路径
至此,先编译一下,没有警告和错误,证明移植成功了。
11.3 移植和运行
对于,ucOSii再做两个加工。
一是SysTickHandler,二是OSStart。顾名思义,分别是systick中断调用服务和系统启动函数。
1)SysTickHandler和OSStart
void OS_CPU_SysTickHandler (void)
{OSIntEnter(); /* Tell uC/OS-II that we are starting an ISR */OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
}
#define START_UP_TASK_PRIO 8#define START_UP_TASK_SIZE 512OS_STK START_UP_TASK[START_UP_TASK_SIZE];__weak void StartUpTask(void *pdata) { pdata = pdata; OSStatInit(); for(;;) { OSTimeDly(1); } }void OS_CPU_Start(void)
{OSInit();OSTaskCreate(StartUpTask,(void *)0,(OS_STK *)&START_UP_TASK[START_UP_TASK_SIZE-1],START_UP_TASK_PRIO);OSStart();
}
2)头文件封装
实现 includes.h 文件,并在main.h文件中进行调用。
这样在涉及底层HAL库驱动和RTOS的API时,只需要调用这一个文件。
/*
************************************************************************************************
文 件: INCLUDES.C ucos主要的包含文件
************************************************************************************************
*/#ifndef __INCLUDES_H__
#define __INCLUDES_H__#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <stdint.h>#include "ucos_ii.h"
#include "os_cpu.h"
#include "os_cfg.h"#endif
其中,系统启动函数,内部定义了1个弱函数,内部循环delay。
我们可以在外部直接定义这个任务函数。
参考流程如下:
1. main文件包含includes.h 文件
#include "includes.h"
2. SysTick_Handler中调用OS_CPU_SysTickHandler
void SysTick_Handler(void)
{/* USER CODE BEGIN SysTick_IRQn 0 */OS_CPU_SysTickHandler();/* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 *//* USER CODE END SysTick_IRQn 1 */
}
3. main函数中调用OS_CPU_Start
/* Initialize all configured peripherals */MX_GPIO_Init();MX_USB_DEVICE_Init();/* USER CODE BEGIN 2 */OS_CPU_Start();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_GPIO_TogglePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin);HAL_Delay(200);}/* USER CODE END 3 */
4. 定义起始任务
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */void StartUpTask(void *pdata)
{pdata = pdata;OSStatInit();for(;;){HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin);OSTimeDly(200);}
}/* USER CODE END 0 */
5. 烧录执行,观察结果
可以看到,黄灯不亮了,蓝灯开始闪烁。
说明,main函数中启动OS之后,在启动代码之后的代码便不再执行,
只会执行任务或中断中的代码。