开发环境:Keil uVision5
去官网下载:Micrium_STM32xxx_uCOS-II.exe
1.创建uCOS-II文件夹
2.将以下文件复制到uCOS-II文件夹(不创建子文件夹)
Micrium\Software\uCOS-II\Source\* (1个h文件,10个c文件)
Micrium\Software\uCOS-II\Ports\ARM-Cortex-M3\Generic\RealView\* (1个h文件,2个c文件,1个asm文件)
Micrium\Software\EvalBoards\ST\STM3210B-EVAL\RVMDK\OS-Probe\os_cfg.h
(共计3个头文件,12个c文件和1个asm文件)
3.在Keil工程中新建分组uCOS-II,将12个c文件和1个asm文件添加到该分组中
4.打开os_cfg.h,将OS_APP_HOOKS_EN的值改为0
5.打开ucos_ii.h文件,将#include
6.打开STM32单片机的启动文件(如RTE\Device\STM32F103ZE\startup_stm32f10x_hd.s),将PendSV_Handler替换为OS_CPU_PendSVHandler,再将SysTick_Handler替换为OS_CPU_SysTickHandler(各三处)
7.把uCOS-II文件夹添加到项目属性的C/C++选项卡下的Include Paths文本框内,并在Target选项卡中勾选上Use MicroLIB(供printf使用)
8.编写main.c
#include
#include
#include
// 必须定义两个栈变量
static OS_STK main_stack[128];
static OS_STK my_stack[64];
// 信号量
static OS_EVENT *my_sem;
/* 供printf使用 */
int fputc(int ch, FILE *fp)
{
if (fp == stdout)
{
if (ch == '\n')
{
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, '\r');
}
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
}
return ch;
}
/* 这个函数供操作系统使用, 必须定义 */
INT32U OS_CPU_SysTickClkFreq(void)
{
return SystemCoreClock;
}
/* 示例任务: 按下PA0按键后输出一段文字 */
void test(void *arg)
{
uint16_t value = 0;
while (1)
{
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == SET)
{
OSTimeDlyHMSM(0, 0, 0, 15);
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == SET)
{
printf("[%d] STM32F103ZE\n", value);
value++;
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == SET)
OSTimeDlyHMSM(0, 0, 0, 15);
}
}
OSTimeDlyHMSM(0, 0, 0, 30);
}
}
/* 主任务 */
void main_task(void *arg)
{
uint8_t bit, err;
GPIO_InitTypeDef gpio;
NVIC_InitTypeDef nvic;
TIM_TimeBaseInitTypeDef tim;
USART_InitTypeDef usart;
OS_CPU_SysTickInit(); // 必须调用这个函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_USART1, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
gpio.GPIO_Mode = GPIO_Mode_IPD;
gpio.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &gpio);
// 可以创建新任务
OSTaskCreate(test, NULL, &my_stack[63], 1);
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
gpio.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_9;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
USART_StructInit(&usart);
usart.USART_BaudRate = 115200;
USART_Init(USART1, &usart);
USART_Cmd(USART1, ENABLE);
printf("Started!\n");
TIM_TimeBaseStructInit(&tim);
tim.TIM_Period = 9999;
tim.TIM_Prescaler = 7199;
TIM_TimeBaseInit(TIM1, &tim);
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM1, ENABLE);
my_sem = OSSemCreate(0);
nvic.NVIC_IRQChannel = TIM1_UP_IRQn;
nvic.NVIC_IRQChannelCmd = ENABLE;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&nvic);
while (1)
{
bit = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4);
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)!bit);
GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)bit);
OSSemPend(my_sem, 0, &err); // 等待信号量
}
}
int main(void)
{
OSInit();
OSTaskCreate(main_task, NULL, &main_stack[127], 0);
OSStart();
}
/* 中断处理函数的写法 */
void TIM1_UP_IRQHandler(void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL();
OSIntNesting++;
OS_EXIT_CRITICAL();
/** 中断处理开始 **/
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
OSSemPost(my_sem); // 唤醒主任务
/** 中断处理结束 **/
OSIntExit();
}