一、项目准备工作
1、创建一个标准库项目
这里不用很麻烦,项目能跑就行,后面要以这个项目为基础移植。
2、下载ucOSⅢ源码
ucosⅢ源码:百度网盘链接:提取码:1234(STM32-F107对应版本)
也可以去官网下载:链接,这里就不介绍官网下载的方法了,可以自行搜索。
完成下载后的文件结构是这样的:
3、创建相应的文件夹
在我们第一步建立的标准库项目中的USER文件夹下新建如下几个文件夹:
二、开始移植
1.复制文件
转移APP文件夹文件
把我们下载好的源码中对应地址下的这几个文件复制到我们准备好的APP文件夹下:
转移BSP文件夹文件
把我们下载好的源码中对应地址下的这几个文件复制到我们准备好的BSP文件夹下:
转移uc-CPU文件夹
将该项目转移至自己所创建的项目User目录下:
工程中添加文件分组
1、在keil项目中创建如下图五个文件夹以对应USER文件夹里的文件:
2、向“APP”分组添加“User/APP”文件夹下的所有文件:
添加效果如下图所示:
3、向“ BSP”分组添加“ \User\BSP”文件夹下的所有文件:
4.向“ μC/CPU”分组添加“User\uC-CPU”文件夹下的所有文件和 “ \User\uC-CPU\ARM-Cortex-M3\RealView”文件夹下的所有文件:
5.向“μC/LIB”分组添加“User\uC-LIB”文件夹下的所有文件和 “User\uC-LIB\Ports\ARM-Cortex-M3\1RealView”文件夹下的所有文件:
6.向“ μC/OS-III Source”分组添加 “ \User\uCOS-III\Source”文件夹下的所有文件:
7.向“μC/OS-III Port”分组添加 “User\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView”文件夹下的所有文件:
2、添加头文件路径到工程
源码已经添加到开发环境的组文件夹下面,编译的时候需要为这些源文件指定头文件的路径,不然编译会报错,此时我们先将头文件添加到我们的 工程中:
3、具体的工程文件修改
添加完头文件路径后,我们可以编译一下整个工程,但肯定会有错误的, μC/OS-III 的移植尚未完毕,接下来需要对工程文件进行修改。 首先修改工程的启动文件“ startup_stm32f10x_hd.s”。 其中将PendSV_Handler 和 SysTick_Handler 分别改为OS_CPU_PendSVHandler 和OS_CPU_SysTickHandler,共两处,因为μC/OS官方已经给我们处理好对应的中断函数,就无需我们自己处理与系统相关的中断了, 同时我们还需要将stm32f10x_it.c文件中的PendSV_Handler和SysTick_Handler函数注释掉(不注释也不会有问题):
4、修改源码中的bsp.c与bsp.h文件
首先要知道,BSP (Board Support Package)是板级支持包,不同型号的板子对应的bsp文件是不一样的,但是里面的具体内容我们一般不去管,只有一个 BSP_Init()的初始化函数可以在里面实现一些例如电灯或者串口发送等的程序用来测试或者函数调用。这里给出bsp.c修改后的代码
bsp.c
#define BSP_MODULE
#include <bsp.h>
CPU_INT32U BSP_CPU_ClkFreq_MHz;
#define DWT_CR *(CPU_REG32 *)0xE0001000
#define DWT_CYCCNT *(CPU_REG32 *)0xE0001004
#define DEM_CR *(CPU_REG32 *)0xE000EDFC
#define DBGMCU_CR *(CPU_REG32 *)0xE0042004
#define DBGMCU_CR_TRACE_IOEN_MASK 0x10
#define DBGMCU_CR_TRACE_MODE_ASYNC 0x00
#define DBGMCU_CR_TRACE_MODE_SYNC_01 0x40
#define DBGMCU_CR_TRACE_MODE_SYNC_02 0x80
#define DBGMCU_CR_TRACE_MODE_SYNC_04 0xC0
#define DBGMCU_CR_TRACE_MODE_MASK 0xC0
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
void BSP_Init (void)
{
}
CPU_INT32U BSP_CPU_ClkFreq (void)
{
RCC_ClocksTypeDef rcc_clocks;
RCC_GetClocksFreq(&rcc_clocks);
return ((CPU_INT32U)rcc_clocks.HCLK_Frequency);
}
#if ((APP_CFG_PROBE_OS_PLUGIN_EN == DEF_ENABLED) && \
(OS_PROBE_HOOKS_EN == 1))
void OSProbe_TmrInit (void)
{
}
#endif
#if ((APP_CFG_PROBE_OS_PLUGIN_EN == DEF_ENABLED) && \
(OS_PROBE_HOOKS_EN == 1))
CPU_INT32U OSProbe_TmrRd (void)
{
return ((CPU_INT32U)DWT_CYCCNT);
}
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void CPU_TS_TmrInit (void)
{
CPU_INT32U cpu_clk_freq_hz;
DEM_CR |= (CPU_INT32U)DEM_CR_TRCENA;
DWT_CYCCNT = (CPU_INT32U)0u;
DWT_CR |= (CPU_INT32U)DWT_CR_CYCCNTENA;
cpu_clk_freq_hz = BSP_CPU_ClkFreq();
CPU_TS_TmrFreqSet(cpu_clk_freq_hz);
}
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR CPU_TS_TmrRd (void)
{
return ((CPU_TS_TMR)DWT_CYCCNT);
}
#endif
bsp.h
#ifndef BSP_PRESENT
#define BSP_PRESENT
#ifdef BSP_MODULE
#define BSP_EXT
#else
#define BSP_EXT extern
#endif
#include <stdarg.h>
#include <stdio.h>
#include <cpu.h>
#include <cpu_core.h>
#include <lib_ascii.h>
#include <lib_def.h>
#include <lib_mem.h>
#include <lib_str.h>
#include "stm32f10x.h"
#include <app_cfg.h>
void BSP_Init (void);
CPU_INT32U BSP_CPU_ClkFreq (void);
#endif
5、修改os_cfg.h(在APP目录下)
#ifndef OS_CFG_H
#define OS_CFG_H
#define OS_CFG_APP_HOOKS_EN 1u
#define OS_CFG_ARG_CHK_EN 1u
#define OS_CFG_CALLED_FROM_ISR_CHK_EN 1u
#define OS_CFG_DBG_EN 1u
#define OS_CFG_ISR_POST_DEFERRED_EN 1u
#define OS_CFG_OBJ_TYPE_CHK_EN 1u
#define OS_CFG_TS_EN 1u
#define OS_CFG_PEND_MULTI_EN 1u
#define OS_CFG_PRIO_MAX 32u
#define OS_CFG_SCHED_LOCK_TIME_MEAS_EN 1u
#define OS_CFG_SCHED_ROUND_ROBIN_EN 1u
#define OS_CFG_STK_SIZE_MIN 64u
#define OS_CFG_FLAG_EN 1u
#define OS_CFG_FLAG_DEL_EN 1u
#define OS_CFG_FLAG_MODE_CLR_EN 1u
#define OS_CFG_FLAG_PEND_ABORT_EN 1u
#define OS_CFG_MEM_EN 1u
#define OS_CFG_MUTEX_EN 1u
#define OS_CFG_MUTEX_DEL_EN 1u
#define OS_CFG_MUTEX_PEND_ABORT_EN 1u
#define OS_CFG_Q_EN 1u
#define OS_CFG_Q_DEL_EN 1u
#define OS_CFG_Q_FLUSH_EN 1u
#define OS_CFG_Q_PEND_ABORT_EN 1u
#define OS_CFG_SEM_EN 1u
#define OS_CFG_SEM_DEL_EN 1u
#define OS_CFG_SEM_PEND_ABORT_EN 1u
#define OS_CFG_SEM_SET_EN 1u
#define OS_CFG_STAT_TASK_EN 1u
#define OS_CFG_STAT_TASK_STK_CHK_EN 1u
#define OS_CFG_TASK_CHANGE_PRIO_EN 1u
#define OS_CFG_TASK_DEL_EN 1u
#define OS_CFG_TASK_Q_EN 1u
#define OS_CFG_TASK_Q_PEND_ABORT_EN 1u
#define OS_CFG_TASK_PROFILE_EN 1u
#define OS_CFG_TASK_REG_TBL_SIZE 1u
#define OS_CFG_TASK_SEM_PEND_ABORT_EN 1u
#define OS_CFG_TASK_SUSPEND_EN 1u
#define OS_CFG_TIME_DLY_HMSM_EN 1u
#define OS_CFG_TIME_DLY_RESUME_EN 1u
#define OS_CFG_TMR_EN 1u
#define OS_CFG_TMR_DEL_EN 1u
#endif
6、修改cpu_cfg.h(在APP目录下)
#ifndef CPU_CFG_MODULE_PRESENT
#define CPU_CFG_MODULE_PRESENT
#define CPU_CFG_NAME_EN DEF_ENABLED
#define CPU_CFG_NAME_SIZE 16u
#define CPU_CFG_TS_32_EN DEF_ENABLED
#define CPU_CFG_TS_64_EN DEF_DISABLED
#define CPU_CFG_TS_TMR_SIZE CPU_WORD_SIZE_32
#if 1
#define CPU_CFG_INT_DIS_MEAS_EN
#endif
#define CPU_CFG_INT_DIS_MEAS_OVRHD_NBR 1u
#if 1
#define CPU_CFG_LEAD_ZEROS_ASM_PRESENT
#endif
#endif
7、修改os_cfg_app.h(在APP目录下)
#ifndef OS_CFG_APP_H
#define OS_CFG_APP_H
#define OS_CFG_MSG_POOL_SIZE 100u
#define OS_CFG_ISR_STK_SIZE 128u
#define OS_CFG_TASK_STK_LIMIT_PCT_EMPTY 10u
#define OS_CFG_IDLE_TASK_STK_SIZE 128u
#define OS_CFG_INT_Q_SIZE 10u
#define OS_CFG_INT_Q_TASK_STK_SIZE 128u
#define OS_CFG_STAT_TASK_PRIO 11u
#define OS_CFG_STAT_TASK_RATE_HZ 10u
#define OS_CFG_STAT_TASK_STK_SIZE 128u
#define OS_CFG_TICK_RATE_HZ 1000u
#define OS_CFG_TICK_TASK_PRIO 1u
#define OS_CFG_TICK_TASK_STK_SIZE 128u
#define OS_CFG_TICK_WHEEL_SIZE 17u
#define OS_CFG_TMR_TASK_PRIO 11u
#define OS_CFG_TMR_TASK_RATE_HZ 10u
#define OS_CFG_TMR_TASK_STK_SIZE 128u
#define OS_CFG_TMR_WHEEL_SIZE 17u
#endif
7、修改app.c(在APP目录下)
#include <includes.h>
int main(void)
{
}
三、任务实现
1、添加初始化文件
由于我们的任务是用三个任务实行不同频率的点灯和串口发送,所以我们需要添加两个文件来分别初始化LED和USART串口,最好在bsp文件目录下加,作为板载文件
LED.c
#include "stm32f10x.h"
void LED1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
}
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
void LED2_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
}
LED.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED1_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
void LED2_Turn(void);
#endif
Serial.c
#include "stm32f10x.h"
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y --)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
Serial.h
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
void Serial_SendString(char *String);
#endif
在bsp.h里把LED.h和Serial.h的头文件都加进去
#include "LED.h"
#include "Serial.h"
2、任务模块介绍
1、定义任务栈
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
var foo = 'bar';
2、定义任务控制块
定义一个栈, 目前我们使用的是静态内存,所以任务栈是一个独立的全局变量。任务的栈占用的是MCU内部的RAM,当任务越多的时候, 需要使用的栈空间就越大,即需要使用的RAM空间就越多。
static OS_TCB AppTaskStartTCB;
3、定义任务主体函数
任务实际上就是一个无限循环且不带返回值的C函数。这里,我们创建一个这样的任务作为例子, 让开发板上面的LED灯以500ms的频率闪烁,
static voidLED_Task (void* parameter)
{
while (1)
{
LED1_ON;
OSTimeDly (500,OS_OPT_TIME_DLY,&err);
LED1_OFF;
OSTimeDly (500,OS_OPT_TIME_DLY,&err);
}
}
4、创建任务
一个任务的三要素是任务主体函数,任务栈,任务控制块,那么怎么样把这三个要素联合在一起?μC/OS里面有一个叫任务创建函数OSTaskCreate(), 它就是干这个活的。它将任务主体函数,任务栈和任务控制块这三者联系在一起,让任务在创建之后可以随时被系统启动与调度。
OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
5、启动任务
OSStart(&err);
3、任务具体实现
1、 创建多任务只需要按照创建单任务的套路依葫芦画瓢即可,接下来我们创建四个任务,分别是起始任务(用来开启其他任务)、 LED1 任务、 LED2 任务和USART3任务。 任务1让一个LED灯闪烁,任务2让另外一个LED闪烁,两个LED闪烁的频率不一样,任务3让串口发送字符串。三个任务的优先级不一样。
2、主函数运行时创建起始任务, 起始任务运行时进行创建两个LED 灯的任务一个串口发送任务和删除自身,之后就运行三个任务。两个 LED 灯的任务优先级不一样, LED1任务为 LED1 每隔 1秒切换一次亮灭状态, LED2 任务为 LED2 每隔 3 秒切换一次亮灭状态, USART3 任务以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”
1、首先在“ app_cfg.h”里,增加定义三个任务的优先级和栈空间大小
2、修改app.c
#include <includes.h>
static OS_TCB AppTaskStartTCB;
static OS_TCB AppTaskLed1TCB;
static OS_TCB AppTaskLed2TCB;
static OS_TCB AppTaskUSART3TCB;
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static CPU_STK AppTaskLed1Stk [ APP_TASK_LED1_STK_SIZE ];
static CPU_STK AppTaskLed2Stk [ APP_TASK_LED2_STK_SIZE ];
static CPU_STK AppTaskUSART3Stk [ APP_TASK_USART3_STK_SIZE ];
static void AppTaskStart (void *p_arg);
static void AppTaskLed1 ( void * p_arg );
static void AppTaskLed2 ( void * p_arg );
static void AppTaskUSART3 ( void * p_arg );
int main (void)
{
OS_ERR err;
OSInit(&err);
OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err);
}
static void AppTaskStart (void *p_arg)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
OS_ERR err;
LED1_Init();
(void)p_arg;
CPU_Init();
cpu_clk_freq = BSP_CPU_ClkFreq();
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;
OS_CPU_SysTickInit(cnts);
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
OSTaskCreate((OS_TCB *)&AppTaskLed1TCB,
(CPU_CHAR *)"App Task Led1",
(OS_TASK_PTR ) AppTaskLed1,
(void *) 0,
(OS_PRIO ) APP_TASK_LED1_PRIO,
(CPU_STK *)&AppTaskLed1Stk[0],
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskCreate((OS_TCB *)&AppTaskLed2TCB,
(CPU_CHAR *)"App Task Led2",
(OS_TASK_PTR ) AppTaskLed2,
(void *) 0,
(OS_PRIO ) APP_TASK_LED2_PRIO,
(CPU_STK *)&AppTaskLed2Stk[0],
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskCreate((OS_TCB *)&AppTaskUSART3TCB,
(CPU_CHAR *)"App Task USART3",
(OS_TASK_PTR ) AppTaskUSART3,
(void *) 0,
(OS_PRIO ) APP_TASK_USART3_PRIO,
(CPU_STK *)&AppTaskUSART3Stk[0],
(CPU_STK_SIZE) APP_TASK_USART3_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_USART3_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskDel ( & AppTaskStartTCB, & err );
}
static void AppTaskLed1 ( void * p_arg )
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE) {
LED1_ON();
OSTimeDly ( 3, OS_OPT_TIME_DLY, & err );
LED1_OFF();
OSTimeDly ( 3000, OS_OPT_TIME_DLY, & err );
}
}
static void AppTaskLed2 ( void * p_arg )
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE) {
LED2_ON();
OSTimeDly ( 1, OS_OPT_TIME_DLY, & err );
LED2_OFF();
OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
}
}
static void AppTaskUSART3 ( void * p_arg )
{
OS_ERR err;
(void)p_arg;
Serial_Init();
while (DEF_TRUE) {
Serial_SendString("hello uc/OS! 欢迎来到RTOS多任务环境!\r\n");
OSTimeDly ( 2000, OS_OPT_TIME_DLY, & err );
}
}
四、实验结果
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)