1. 程式人生 > >在STM32F103工程上新增uCOS-II的過程

在STM32F103工程上新增uCOS-II的過程

開發環境: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();
}