在STM32F103工程上添加uCOS-II的过程

版权声明:本文为博主原创文章,欢迎转载 https://blog.csdn.net/ZLK1214/article/details/81086050

开发环境: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 <app_cfg.h>注释掉
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 <stdio.h>
#include <stm32f10x.h>
#include <ucos_ii.h>

// 必须定义两个栈变量
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();
}

猜你喜欢

转载自blog.csdn.net/ZLK1214/article/details/81086050