ucos ii移植到STM32 (HardFault_Handler)

 转载请注明原文地址:http://blog.csdn.net/oyhb_1992/article/details/72654582

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=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闪烁!




你可能感兴趣的:(ucos,ii,stm32)