1. 程式人生 > >ucos ii移植到STM32 (HardFault_Handler)

ucos ii移植到STM32 (HardFault_Handler)

Ucosii的移植到STM32其實非常簡單,但有些時候就是會出現一些莫名其妙的錯誤!

        Ucosii的移植網上都說是修改os_cpu.h     os_cpu_c.c      os_cpu_a.asm三個檔案,其實這樣說是不全的!還需要修改startup_stm32f10x_hd.s啟動檔案一小部分程式碼和自己實現SysTick_Handler(void)時鐘滴答中斷函式。

        os_cpu.h os_cpu_c.c       os_cpu_a.asm這三部分很簡單,網上到處都是直接複製貼上

os_cpu.h

/************************(C) COPYLEFT 2010 Leafgrass *************************
* File Name              : os_cpu_c.c 
* Author        : Librae
* Date                   : 06/10/2010
* Description   : μCOS-II在STM32上的移植程式碼C語言部分,
*                                   包括任務堆疊初始化程式碼和鉤子函式等
******************************************************************************/
#ifndef __OS_CPU_H__
#define __OS_CPU_H__
#ifdef OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#defineOS_CPU_EXT extern
#endif
/******************************************************************************
*                   定義與編譯器無關的資料型別
******************************************************************************/
typedef unsignedchar BOOLEAN;
typedef unsignedchar INT8U;                      /* Unsigned 8 bit quantity      */
typedef signed  char INT8S;                      /*Signed   8 bit quantity      */
typedef unsignedshort INT16U;                     /*Unsigned 16 bit quantity      */
typedef signed  short INT16S;                     /* Signed  16 bit quantity      */
typedef unsignedint  INT32U;                     /* Unsigned 32 bit quantity      */
typedef signed  int  INT32S;                     /*Signed  32 bit quantity      */
typedef float         FP32;                       /*Single precision floating point*/
typedef double        FP64;                       /* Double precisionfloating point*/
//STM32是32位位寬的,這裡OS_STK和OS_CPU_SR都應該為32位資料型別
typedef unsignedint  OS_STK;                     /* Each stack entry is 32-bit wide*/
typedef unsignedint  OS_CPU_SR;          /* Define size of CPU status register*/
/* 
*******************************************************************************
*                            Cortex M3
*                    Critical SectionManagement
*******************************************************************************
*/
/*
*******************************************************************************
*                         ARM Miscellaneous
*******************************************************************************
*/
//定義棧的增長方向.
//CM3中,棧是由高地址向低地址增長的,所以OS_STK_GROWTH設定為1
#define OS_STK_GROWTH       1     /* Stack grows from HIGH to LOW memory on ARM   */
//任務切換巨集,由彙編實現.
#define OS_TASK_SW()        OSCtxSw()
/*
*******************************************************************************
*                              PROTOTYPES
*                          (see OS_CPU_A.ASM)
*******************************************************************************
*/
//OS_CRITICAL_METHOD= 1 :直接使用處理器的開關中斷指令來實現巨集
//OS_CRITICAL_METHOD= 2 :利用堆疊儲存和恢復CPU的狀態
//OS_CRITICAL_METHOD= 3 :利用編譯器擴充套件功能獲得程式狀態字,儲存在區域性變數cpu_sr
#define OS_CRITICAL_METHOD  3          //進入臨界段的方法
#ifOS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL()  {OS_CPU_SR_Restore(cpu_sr);}
#endif
void      OSCtxSw(void);
void      OSIntCtxSw(void);
void      OSStartHighRdy(void);
void      OSPendSV(void);
#ifOS_CRITICAL_METHOD == 3u                     /* See OS_CPU_A.ASM                                 */
OS_CPU_SR OS_CPU_SR_Save(void);
void      OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif
OS_CPU_EXT INT32UOSInterrputSum;
#endif
/************************(C) COPYLEFT 2010 Leafgrass ************************/

os_cpu.h

/*
*********************************************************************************************************
*                                              uC/OS-II
*                                        TheReal-Time Kernel
*
*
*                               (c) Copyright2006, Micrium, Weston, FL
*                                         AllRights Reserved
*
*                                          ARMCortex-M3 Port
*
* File     : OS_CPU_C.C
* Version  : V2.86
* By       : Jean J. Labrosse
*
* For      : ARMv7M Cortex-M3
* Mode     : Thumb2
* Toolchain :RealView Development Suite
*            RealView MicrocontrollerDevelopment Kit (MDK)
*            ARM Developer Suite (ADS)
*            Keil uVision
*********************************************************************************************************
*/
#define OS_CPU_GLOBALS
#include"includes.h"
/*
*********************************************************************************************************
*                                         LOCALVARIABLES
*********************************************************************************************************
*/
#if OS_TMR_EN >0
static INT16U OSTmrCtr;
#endif
/*
*********************************************************************************************************
*                                      OSINITIALIZATION HOOK
*                                           (BEGINNING)
*
* Description:This function is called by OSInit() at the beginning of OSInit().
*
* Arguments : none
*
* Note(s)   : 1) Interrupts should be disabled duringthis call.
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookBegin (void)
{
#if OS_TMR_EN >0
   OSTmrCtr = 0;
#endif
}
#endif
/*
*********************************************************************************************************
*                                      OSINITIALIZATION HOOK
*                                              (END)
*
* Description:This function is called by OSInit() at the end of OSInit().
*
* Arguments : none
*
* Note(s)   : 1) Interrupts should be disabled duringthis call.
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookEnd (void)
{
}
#endif
/*
*********************************************************************************************************
*                                         TASKCREATION HOOK
*
* Description:This function is called when a task is created.
*
* Arguments : ptcb  is a pointer to the task control block of the task being created.
*
* Note(s)   : 1) Interrupts are disabled during thiscall.
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0
void OSTaskCreateHook (OS_TCB *ptcb)
{
#ifOS_APP_HOOKS_EN > 0
   App_TaskCreateHook(ptcb);
#else
   (void)ptcb;                                 /* Preventcompiler warning                          */
#endif
}
#endif
/*
*********************************************************************************************************
*                                          TASKDELETION HOOK
*
* Description:This function is called when a task is deleted.
*
* Arguments : ptcb  is a pointer to the task control block of the task being deleted.
*
* Note(s)   : 1) Interrupts are disabled during thiscall.
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0
void OSTaskDelHook (OS_TCB *ptcb)
{
#ifOS_APP_HOOKS_EN > 0
   App_TaskDelHook(ptcb);
#else
   (void)ptcb;                                 /* Preventcompiler warning                          */
#endif
}
#endif
/*
*********************************************************************************************************
*                                            IDLE TASK HOOK
*
* Description:This function is called by the idle task. This hook has been added to allow you to do
*             such things as STOP the CPU toconserve power.
*
* Arguments : none
*
* Note(s)   : 1) Interrupts are enabled during thiscall.
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251
void OSTaskIdleHook (void)
{
#ifOS_APP_HOOKS_EN > 0
   App_TaskIdleHook();
#endif
}
#endif
/*
*********************************************************************************************************
*                                          STATISTIC TASK HOOK
*
* Description:This function is called every second by uC/OS-II's statistics task. This allows your
*             application to add functionalityto the statistics task.
*
* Arguments : none
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0
void OSTaskStatHook (void)
{
#ifOS_APP_HOOKS_EN > 0
   App_TaskStatHook();
#endif
}
#endif
/*
*********************************************************************************************************
*                                       INITIALIZE A TASK'S STACK
*
* Description:This function is called by either OSTaskCreate() or OSTaskCreateExt() to initializethe
*             stack frame of the task beingcreated. This function is highlyprocessor specific.
*
* Arguments : task         is a pointer to the task code
*
*             p_arg        is a pointer to a user supplied dataarea that will be passed to the task
*                           when the task firstexecutes.
*
*             ptos         is a pointer to the top ofstack. It is assumed that 'ptos' pointsto
*                           a 'free' entry on the taskstack. If OS_STK_GROWTH is set to 1 then
*                           'ptos' will containthe HIGHEST valid address of the stack. Similarly, if
*                           OS_STK_GROWTH isset to 0, the 'ptos' will contains the LOWEST valid address
*                           of the stack.
*
*             opt          specifies options that can be usedto alter the behavior of OSTaskStkInit().
*                           (see uCOS_II.H forOS_TASK_OPT_xxx).
*
* Returns   : Always returns the location of the newtop-of-stack once the processor registers have
*             been placed on the stack in theproper order.
*
* Note(s)   : 1) Interrupts are enabled when your taskstarts executing.
*             2) All tasks run in Thread mode,using process stack.
*********************************************************************************************************
*/
OS_STK*OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16Uopt)
{
   OS_STK *stk;
   (void)opt;                                  /* 'opt' isnot used, prevent warning                */
   stk      = ptos;                           /* Load stack pointer                                */
                                                /* Registers stacked as if auto-saved on exception   */
   *(stk)   = (INT32U)0x01000000L;            /* xPSR                                              */
   *(--stk) = (INT32U)task;                   /* Entry Point                                       */
   *(--stk) = (INT32U)0xFFFFFFFEL;            /* R14 (LR) (init value will cause fault if ever used)*/
   *(--stk) = (INT32U)0x12121212L;            /* R12                                               */
   *(--stk) = (INT32U)0x03030303L;            /* R3                                                */
   *(--stk) = (INT32U)0x02020202L;            /* R2                                                */
   *(--stk) = (INT32U)0x01010101L;            /* R1                                                */
   *(--stk) = (INT32U)p_arg;                  /* R0 : argument                                     */
                                                /* Remaining registers saved on process stack        */
   *(--stk) = (INT32U)0x11111111L;            /* R11                                               */
   *(--stk) = (INT32U)0x10101010L;            /* R10                                               */
   *(--stk) = (INT32U)0x09090909L;            /* R9                                                */
   *(--stk) = (INT32U)0x08080808L;            /* R8                                                */
   *(--stk) = (INT32U)0x07070707L;            /* R7                                                */
   *(--stk) = (INT32U)0x06060606L;            /* R6                                                */
   *(--stk) = (INT32U)0x05050505L;            /* R5                                                */
   *(--stk) = (INT32U)0x04040404L;            /* R4                                                */
   return (stk);
}
/*
*********************************************************************************************************
*                                          TASK SWITCHHOOK
*
* Description:This function is called when a task switch is performed. This allows you to perform other
*             operations during a contextswitch.
*
* Arguments : none
*
* Note(s)   : 1) Interrupts are disabled during thiscall.
*             2) It is assumed that the globalpointer 'OSTCBHighRdy' points to the TCB of the task that
*                will be 'switched in' (i.e.the highest priority task) and, 'OSTCBCur' points to the
*                task being switched out (i.e. thepreempted task).
*********************************************************************************************************
*/
#if(OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
void OSTaskSwHook (void)
{
#ifOS_APP_HOOKS_EN > 0
   App_TaskSwHook();
#endif
}
#endif
/*
*********************************************************************************************************
*                                          OS_TCBInit() HOOK
*
* Description:This function is called by OS_TCBInit() after setting up most of the TCB.
*
* Arguments : ptcb   is a pointer to the TCB of the task being created.
*
* Note(s)   : 1) Interrupts may or may not be ENABLEDduring this call.
*********************************************************************************************************
*/
#ifOS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSTCBInitHook (OS_TCB *ptcb)
{
#ifOS_APP_HOOKS_EN > 0
   App_TCBInitHook(ptcb);
#else
   (void)ptcb;                                 /* Prevent compilerwarning                          */
#endif
}
#endif
/*
*********************************************************************************************************
*                                              TICK HOOK
*
* Description:This function is called every tick.
*
* Arguments : none
*
* Note(s)   : 1) Interrupts may or may not be ENABLEDduring this call.
*********************************************************************************************************
*/
#if(OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)
void OSTimeTickHook (void)
{
#ifOS_APP_HOOKS_EN > 0
   App_TimeTickHook();
#endif
#if OS_TMR_EN >0
   OSTmrCtr++;
   if (OSTmrCtr >= (OS_TICKS_PER_SEC /OS_TMR_CFG_TICKS_PER_SEC)) {
       OSTmrCtr = 0;
       OSTmrSignal();
   }
#endif
}
#endif
#ifOS_CPU_HOOKS_EN > 0u && OS_VERSION > 290u
voidOSTaskReturnHook(OS_TCB *ptcb)
{ 
        (void)ptcb; 
} 
#endif
/*-----------------------(C) COPYRIGHT @ 2012 liycobl ----------------- end of file -----------------*/

os_cpu_a.asm

 
;/***********************(C) COPYRIGHT 2010 Libraworks *************************
;* File Name    : os_cpu_a.asm 
;* Author                : Librae 
;* Version               : V1.0
;* Date                  : 06/10/2010
;* Description  : μCOS-II asm port      for STM32
;*******************************************************************************/
                IMPORT OSRunning              ; External references
       IMPORT OSPrioCur
       IMPORT OSPrioHighRdy
       IMPORT OSTCBCur
       IMPORT OSTCBHighRdy
       IMPORT OSIntNesting
       IMPORT OSIntExit
       IMPORT OSTaskSwHook
          
       EXPORT OSStartHighRdy              
       EXPORT OSCtxSw
       EXPORT OSIntCtxSw
                EXPORT OS_CPU_SR_Save                                     ;Functions declared in this file
        EXPORT OS_CPU_SR_Restore      
       EXPORT PendSV_Handler
       
    
NVIC_INT_CTRL  EQU    0xE000ED04 ;中斷控制暫存器
NVIC_SYSPRI2   EQU    0xE000ED20 ;系統優先順序暫存器(2)
NVIC_PENDSV_PRIEQU    0xFFFF0000 ; PendSV中斷和系統節拍中斷
                                       ; (都為最低,0xff).
NVIC_PENDSVSET EQU    0x10000000 ;觸發軟體中斷的值.
                PRESERVE8 
                
                AREA   |.text|, CODE, READONLY
       THUMB 
   
          
;********************************************************************************************************
;                                  CRITICALSECTION METHOD 3 FUNCTIONS
;
; Description:Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
;             would store the state of theinterrupt disable flag in the local variable 'cpu_sr' and then
;             disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II'sfunctions that need to
;             disable interrupts. You would restore the interrupt disable stateby copying back 'cpu_sr'
;             into the CPU's status register.
;
; Prototypes:    OS_CPU_SR OS_CPU_SR_Save(void);
;                 void      OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s)   : 1) These functions are used in generallike this:
;
;                void Task (void *p_arg)
;                {
;                #if OS_CRITICAL_METHOD ==3         /* Allocate storage for CPUstatus register */
;                    OS_CPU_SR cpu_sr;
;                #endif
;
;                         :
;                         :
;                    OS_ENTER_CRITICAL();            /* cpu_sr = OS_CPU_SaveSR();                */
;                         :
;                         :
;                    OS_EXIT_CRITICAL();             /* OS_CPU_RestoreSR(cpu_sr);               */
;                         :
;                         :
;                }
;********************************************************************************************************
OS_CPU_SR_Save
   MRS    R0, PRIMASK ;讀取PRIMASK到R0,R0為返回值
   CPSID  I                              ;PRIMASK=1,關中斷(NMI和硬體FAULT可以響應)
   BX     LR                        ;返回
OS_CPU_SR_Restore
   MSR    PRIMASK, R0           ;讀取R0到PRIMASK中,R0為引數
   BX     LR                             ;返回
;/**************************************************************************************
;* 函式名稱: OSStartHighRdy
;*
;* 功能描述:使用排程器執行第一個任務
;* 
;* 參   數: None
;*
;* 返 回 值: None
;**************************************************************************************/ 
OSStartHighRdy
       LDR    R4, =NVIC_SYSPRI2     ; set thePendSV exception priority
       LDR    R5, =NVIC_PENDSV_PRI
       STR    R5, [R4]
       MOV    R4, #0                ; set thePSP to 0 for initial context switch call
       MSR    PSP, R4
       LDR    R4, =OSRunning        ; OSRunning= TRUE
       MOV    R5, #1
       STRB   R5, [R4]
                                      ;切換到最高優先順序的任務
       LDR    R4, =NVIC_INT_CTRL    ;rigger thePendSV exception (causes context switch)
       LDR    R5, =NVIC_PENDSVSET
       STR    R5, [R4]
       CPSIE  I                     ;enableinterrupts at processor level
OSStartHang
       B      OSStartHang           ;shouldnever get here
;/**************************************************************************************
;* 函式名稱: OSCtxSw
;*
;* 功能描述:任務級上下文切換        
;*
;* 參   數: None
;*
;* 返 回 值: None
;***************************************************************************************/
 
OSCtxSw
                PUSH   {R4, R5}
       LDR    R4, =NVIC_INT_CTRL         ;觸發PendSV異常 (causes context switch)
       LDR    R5, =NVIC_PENDSVSET
       STR    R5, [R4]
                POP    {R4, R5}
       BX     LR
;/**************************************************************************************
;* 函式名稱: OSIntCtxSw
;*
;* 功能描述:中斷級任務切換
;*
;* 參   數: None
;*
;* 返 回 值: None
;***************************************************************************************/
OSIntCtxSw
                PUSH   {R4, R5}
       LDR    R4, =NVIC_INT_CTRL     ;觸發PendSV異常(causes context switch)
       LDR    R5, =NVIC_PENDSVSET
       STR    R5, [R4]
                POP    {R4, R5}
       BX     LR
       NOP
;/**************************************************************************************
;* 函式名稱: OSPendSV
;*
;* 功能描述: OSPendSV is used to cause acontext switch.
;*
;* 參   數: None
;*
;* 返 回 值: None
;***************************************************************************************/
PendSV_Handler
   CPSID  I                                                  ; Prevent interruption during context switch
   MRS    R0, PSP                                            ; PSP is process stackpointer如果在用PSP堆疊,則可以忽略儲存暫存器,參考CM3權威中的雙堆疊-白菜注
   CBZ    R0, PendSV_Handler_Nosave                                  ; Skip register save thefirst time
   SUBS   R0, R0, #0x20                                      ; Saveremaining regs r4-11 on process stack
   STM    R0, {R4-R11}
   LDR    R1, =OSTCBCur                                      ;OSTCBCur->OSTCBStkPtr = SP;
   LDR    R1, [R1]
   STR    R0, [R1]                                           ;R0 is SP of process being switched out
                                                               ; At this point, entire context of process has been saved
PendSV_Handler_Nosave
   PUSH   {R14}                                              ; Save LR exc_return value
   LDR    R0, =OSTaskSwHook                                  ;OSTaskSwHook();
   BLX    R0
   POP    {R14}
   LDR    R0, =OSPrioCur                                     ;OSPrioCur = OSPrioHighRdy;
   LDR    R1, =OSPrioHighRdy
   LDRB   R2, [R1]
   STRB   R2, [R0]
   LDR    R0, =OSTCBCur                                      ;OSTCBCur = OSTCBHighRdy;
   LDR    R1, =OSTCBHighRdy
   LDR    R2, [R1]
   STR    R2, [R0]
   LDR    R0, [R2]                                           ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
   LDM    R0, {R4-R11}                                       ;Restore r4-11 from new process stack
   ADDS   R0, R0, #0x20
   MSR    PSP, R0                                            ;Load PSP with new process SP
   ORR    LR, LR, #0x04                                      ; Ensureexception return uses process stack
   CPSIE  I
   BX     LR                                                 ; Exception return willrestore remaining context
 end 

關鍵是:

關鍵點1

官方移植好的版本里自帶STM32啟動檔案vectors.s,當然我們一般用STM32庫自帶的startup_stm32f10x_hd.s啟動檔案。這裡就有要注意的地方。按照官方移植好的版本要求PendSV的中斷函式名字是OS_CPU_OSPendSV,而startup_stm32f10x_hd.s裡面已經定義好的名字是PendSV_Handler 

PendSV_Handler PROC
               EXPORT PendSV_Handler            [WEAK]
               B      .
               ENDP

所以我們要統一一下,我的辦法是把Ucosii中所有出現的OS_CPU_OSPendSV改成PendSV_Handler。為什麼不改startup_stm32f10x_hd.s,是因為這樣移植的相容性更好,下次一直到另一個STM32工程裡時候,直接把Ucos ii的檔案全部拷貝過去,不用修改另一個STM32工程裡的startup_stm32f10x_hd.s

關鍵點2

編寫SysTick_Handler(void)時鐘滴答中斷函式。

隨便在某一個原始檔裡實現就可以,我在stm32f10x_it.c裡實現了這個函式

/**
 * @brief This function handles SysTick Handler.
 * @param None
 * @retval None
 */
//2017-5-21歐陽海賓註釋掉。
voidSysTick_Handler(void)
{
                OSIntEnter();   //進入中斷
   OSTimeTick();      //呼叫ucos的時鐘服務程式              
   OSIntExit();       //觸發任務切換軟中斷
}

關鍵點3:編寫延時函式,正點原子或劉洋都有,直接粘貼出來就是

Pbdata.h

#ifndef _pbdata_H
#define _pbdata_H
#include"stm32f10x.h"
#include"includes.h"
#include"misc.h"
//ucosII任務堆疊設定
//設定任務優先順序
#defineSTART_TASK_PRIO 8
#defineSTART_TASK2_PRIO 9
#defineSTART_TASK3_PRIO 10
//設定任務堆疊大小
#defineSTART_STK_SIZE 64 //空間大小=64*4(位元組)
#defineSTART_STK_SIZE2 64 // 空間大小=64*4(位元組)
#defineSTART_STK_SIZE3 64 // 空間大小=64*4(位元組)
//建立任務堆疊空間
static OS_STKSTART_TASK_STK[START_STK_SIZE];
static OS_STKSTART_TASK_STK2[START_STK_SIZE2];
static OS_STKSTART_TASK_STK3[START_STK_SIZE3];
extern OS_EVENT*led1_MsgQueue;
extern void*MsgQueuetb[20];
//定義函式
void delay(uint32_t nCount);
void Delay_Init(void);
void delay_us(uint32_t nus);
void delay_ms(uint16_t nms);      
void LED_GPIO_Config(void);
/* the macrodefinition to trigger the led on or off
 * 1 - on
 - 0 - off
 */
#define ON 1
#define OFF 0
//帶參巨集,可以像行內函數一樣使用
#define LED1(a) if (a)  \
                                           GPIO_ResetBits(GPIOB,GPIO_Pin_8);\
                                           else            \
                                           GPIO_SetBits(GPIOB,GPIO_Pin_8)
                                           
#endif

Pbdata.c

#include"pbdata.h"
OS_EVENT*led1_MsgQueue;
void* MsgQueuetb[20];
static uint8_t fac_us=0;//us延時倍乘數
static uint16_tfac_ms=0;//ms延時倍乘數
//初始化延遲函式
//當使用ucos的時候,此函式會初始化ucos的時鐘節拍
//SYSTICK的時鐘固定為HCLK時鐘的1/8
//SYSCLK:系統時鐘
void Delay_Init(void)    
{
        uint32_t reload;
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);       //選擇外部時鐘 HCLK/8
        fac_us=SystemCoreClock/8000000;   //為系統時鐘的1/8 
         
        reload=SystemCoreClock/8000000;   //每秒鐘的計數次數 單位為K           
        reload*=1000000/OS_TICKS_PER_SEC;//根據OS_TICKS_PER_SEC設定溢位時間
                                                                              //reload為24位暫存器,最大值:16777216,在72M下,約合1.86s左右    
        fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延時的最少單位     
        SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;  //開啟SYSTICK中斷
        SysTick->LOAD=reload;    //每1/OS_TICKS_PER_SEC秒中斷一次 
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;    //開啟SYSTICK   
}                                                                        
//延時nus
//nus為要延時的us數.                                                                                        
void delay_us(uint32_t nus)
{               
        uint32_t ticks;
        uint32_t told,tnow,tcnt=0;
        uint32_t reload=SysTick->LOAD;    //LOAD的值                
        ticks=nus*fac_us;                          //需要的節拍數                     
        tcnt=0;
        told=SysTick->VAL;       //剛進入時的計數器值
        while(1)
        {
                tnow=SysTick->VAL;       
                if(tnow!=told)
                {           
                         if(tnow<told)tcnt+=told-tnow;//這裡注意一下SYSTICK是一個遞減的計數器就可以了.
                         elsetcnt+=reload-tnow+told;          
                         told=tnow;
                         if(tcnt>=ticks)break;//時間超過/等於要延遲的時間,則退出.
                } 
        };                                                                                
}
//延時nms
//nms:要延時的ms數
void delay_ms(uint16_tnms)
{       
        if(OSRunning==TRUE)//如果os已經在跑了         
        {                 
                if(nms>=fac_ms)//延時的時間大於ucos的最少時間週期
                {
                         OSTimeDly(nms/fac_ms);//ucos延時
                }
                nms%=fac_ms;                               //ucos已經無法提供這麼小的延時了,採用普通方式延時   
        }
        delay_us((uint32_t)(nms*1000));   //普通方式延時,此時ucos無法啟動排程.
}
void delay(uint32_t nCount)
{
        for(;nCount!=0;nCount--);
}
/*
 *函式名:LED_GPIO_Config
 *描述 :配置LED用到的I/O口
 *輸入 :無
 *輸出 :無
 */
void LED_GPIO_Config(void)
{               
        /*定義一個GPIO_InitTypeDef型別的結構體*/
        GPIO_InitTypeDef GPIO_InitStructure;
        /*開啟GPIOF的外設時鐘*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        /*選擇要控制的GPIOC引腳*/                                                                                                                          
        GPIO_InitStructure.GPIO_Pin= GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_5;      
        /*設定引腳模式為通用推輓輸出*/
        GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;  
        /*設定引腳速率為50MHz */  
        GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
        /*呼叫庫函式,初始化GPIOC*/
        GPIO_Init(GPIOB,&GPIO_InitStructure);               
        /* 關閉所有led燈*/
        GPIO_SetBits(GPIOB, GPIO_Pin_8);
//      GPIO_SetBits(GPIOB, GPIO_Pin_7);
        GPIO_ResetBits(GPIOB,GPIO_Pin_7);
        GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
}

到這裡就移植完成,但是用的時候經常會有問題!這裡就針對網上最流行的一種問題進行解決

經常會有人,執行的時候卡在空閒任務或單步除錯進入硬體錯誤的中斷函式裡或者卡在延時函式。

/**
 * @brief This function handles NMI exception.
 * @param None
 * @retval None
 */
void NMI_Handler(void)
{
}
/**
 * @brief This function handles Hard Fault exception.
 * @param None
 * @retval None
 */
void HardFault_Handler(void)
{
        if (CoreDebug->DHCSR & 1) { //check C_DEBUGEN == 1 -> DebuggerConnected 
     __breakpoint(0); // halt program execution here        
 } 
 /* Go to infinite loop when Hard Faultexception occurs */
 while (1)
 {
 }
}
其實都是一個原因,就是空閒任務不能少且不能放錯位置,初始化統計任務不能放在OSInit();和OSStart();之間,必須用在另一個任務的初始化程式碼裡來,否則會出現執行的時候卡在空閒任務或單步除錯進入硬體錯誤的中斷函式裡,我就是在這裡卡了一天才移植成功,網上百度居然沒有一種方法說明白了問題的所在和解決辦法。
下面貼出我的主函式
main.c
#include"includes.h" //裡面是ucos ii的標頭檔案
#define ON 1
#define OFF 0
#define LED2(a) if (a)  \
                                           GPIO_ResetBits(GPIOB,GPIO_Pin_8);\
                                           else            \
                                           GPIO_SetBits(GPIOB,GPIO_Pin_8)
//設定任務堆疊大小
void start_task(void *pdata);
void start_task2(void *pdata);
void start_task3(void *pdata);
OS_EVENT *sem;                                    
int main(void)
{       
RCC_ClocksTypeDefRCC_Clocks;
        sem=OSSemCreate(0);
        
        
        Delay_Init(); //初始化延時函式
        SystemInit();
        LED_GPIO_Config();
        
        RCC_GetClocksFreq(&RCC_Clocks);
        
        OSInit();//初始化UCOS作業系統
//      OSStatInit();//初始化統計任務放在此處會導致硬體錯誤,必須放在下面就Ok了 歐陽海賓2017-5-22
        OSTaskCreate(start_task,//指向任務程式碼的指標
                                  (void *)0,//任務開始執行時,傳遞給任務引數的指標
                                  (OS_STK*)&START_TASK_STK[START_STK_SIZE-1],//分配給任務堆疊的棧頂指標
                                  START_TASK_PRIO);//分配給任務的優先順序
        OSTaskCreate(start_task2,//指向任務程式碼的指標
                                  (void *)0,//任務開始執行時,傳遞給任務引數的指標
                                  (OS_STK*)&START_TASK_STK2[START_STK_SIZE2-1],//分配給任務堆疊的棧頂指標
                                  START_TASK2_PRIO);//分配給任務的優先順序
        OSTaskCreate(start_task3,//指向任務程式碼的指標
                                  (void *)0,//任務開始執行時,傳遞給任務引數的指標
                                  (OS_STK*)&START_TASK_STK3[START_STK_SIZE3-1],//分配給任務堆疊的棧頂指標
                                  START_TASK3_PRIO);//分配給任務的優先順序
        
        OSStart();//啟動ucos作業系統
}
void start_task(void *pdata)
{
        INT8U error;
        OS_CPU_SR cpu_sr=0;
        pdata=pdata;
        
//      OSStatInit();//初始化統計任務,不能放在上面!
        
        while(1)
        {
                OSSemPend(sem,0,&error);
          LED2(OFF);
                delay_ms(500);
//              OSSemPost(sem);
//              delay_ms(500);
        }
}
void start_task2(void *pdata)
{
        INT8U error;
        OS_CPU_SR cpu_sr=0;
        pdata=pdata;
//      OSStatInit();//初始化統計任務
        OSStatInit();//???????
        while(1)
        {
         LED2(ON);
                delay_ms(500);
                OSSemPost(sem);
//              delay_ms(500);
//              OSSemPend(sem,0,&error);
        }
}
void start_task3(void *pdata)
{
        
                uint16_t i=0;
                         
                pdata = pdata;
                         while(1)
                         {
                //       OS_ENTER_CRITICAL();
                                                            OSIdleCtr++;
                //       OS_EXIT_CRITICAL();
                         }
}

這個程式碼是我在硬體STM32f103上實現了的,可以實現led閃爍!