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閃爍!