uCOSii信号量

文章详细介绍了基于uCOSii操作系统的一个实践案例,涉及到信号量的创建、发送、接收和删除,以及任务的创建、优先级设置和调度。通过示例代码展示了如何使用信号量进行同步和通信,同时讨论了OS_CFG_H配置文件中参数对系统行为的影响。此外,还涵盖了中断服务子程序中信号量的使用限制以及任务管理的相关函数,如任务创建、删除和挂起。
摘要由CSDN通过智能技术生成

uCOSii信号量

主要用来测试使用uCOSii“创建信号量,发送信号量,接收信号量,删除信号量”。

学习uCOSii一定要先了解os_cfg.h文件。

信号量管理函数如下:

OSSemAccept()

无条件地等待请求一个信号量函数,中断服务子程序只能用OSSemAccept()而不能用OSSemPend(),因为中断服务子程序是不允许等待的

OSSemCreate() 建立并初始化一个信号量(计数器值)

OSSemDel() 删除一个信号量(信号指针、删除条件、错误指针)

OSSemPend() 等待一个信号量函数(信号量指针、允许等待的时钟节拍、代码错误指针)

OSSemPost() 发出一个信号量函数(信号量指针)

OSSemQuery() 查询一个信号量的当前状态(信号量指针、状态数据结构指针)

以上函数只要知道怎么调用,就可以了。

//函数功能:返回OS_ERR_NONE表示发送信号量

INT8U  OSSemPost (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u; //声明cpu_sr为unsigned int型变量

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{

        return (OS_ERR_PEVENT_NULL);

//如果pevent为空指针,则返回OS_ERR_PEVENT_NULL=4

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_SEM)

{

        return (OS_ERR_EVENT_TYPE);

//如果”pevent的事件类型”不是OS_EVENT_TYPE_SEM,则返回OS_ERR_EVENT_TYPE=1

    }

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

if (pevent->OSEventGrp != 0u)//若有任务在等待信号量

{

        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);

//告诉等待的任务进入准备准备状态,无需等待

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        OS_Sched();//切换任务,让高优先级的任务先执行

        return (OS_ERR_NONE); //返回OS_ERR_NONE=0

    }

if (pevent->OSEventCnt < 65535u) //若pevent的计数器值小于65535

{

        pevent->OSEventCnt++;//pevent的计数器值加1

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        return (OS_ERR_NONE);//返回OS_ERR_NONE=0

}

OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

return (OS_ERR_SEM_OVF);

//若pevent的计数器值等于65535,则返回OS_ERR_SEM_OVF=51

//发送信号后,对方没有接收,导致” pevent的计数器”溢出

}

//函数功能:接收信号量,返回值大于0,表示收到信号量

INT16U  OSSemAccept (OS_EVENT *pevent)

{

    INT16U     cnt;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;//声明cpu_sr为unsigned int型变量

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)//如果pevent为空指针,则返回0

{       

   return (0u);

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_SEM)

//如果”pevent的事件类型”不是OS_EVENT_TYPE_SEM,则返回0

{

        return (0u);

    }

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

    cnt = pevent->OSEventCnt;//读取pevent的计数器值

if (cnt > 0u)//若pevent的计数器值大于0

{

        pevent->OSEventCnt--;

    }

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

return (cnt);//返回信号量pevent的计数器值

}

void  OSSemPend (OS_EVENT  *pevent,

                 INT32U     timeout,

                 INT8U     *perr)

{

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u; //声明cpu_sr为unsigned int型变量

#endif

#ifdef OS_SAFETY_CRITICAL

    if (perr == (INT8U *)0) {

        OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0) //如果pevent为空指针,则返回

{

        *perr = OS_ERR_PEVENT_NULL;// *per= OS_ERR_PEVENT_NULL=4

        return;

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_SEM)

{//如果”pevent的事件类型”不是OS_EVENT_TYPE_SEM,则返回

        *perr = OS_ERR_EVENT_TYPE; // *per= OS_ERR_EVENT_TYPE =1

        return;

}

if (OSIntNesting > 0u)//中断嵌套级别大于0

{

        *perr = OS_ERR_PEND_ISR;//*per=OS_ERR_PEND_ISR=2

        return;

}

if (OSLockNesting > 0u)//多任务锁嵌套级别大于0

{

        *perr = OS_ERR_PEND_LOCKED;//*per=OS_ERR_PEND_LOCKED=13

        return;

}

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

if (pevent->OSEventCnt > 0u) //若pevent的计数器值大于0

{

        pevent->OSEventCnt--;

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        *perr = OS_ERR_NONE; //*per=OS_ERR_NONE=0

        return;

    }

///若pevent的计数器值等于0,必须等待,直到接收新的信号量///

OSTCBCur->OSTCBStat     |= OS_STAT_SEM;

    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;//资源不可用,挂起信号量

OSTCBCur->OSTCBDly       = timeout;//将timeout的值存储到TCB中

OS_EventTaskWait(pevent);//挂起任务,等待信号量到来

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

OS_Sched();//切换任务,让更高优先级的任务先执行

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

switch (OSTCBCur->OSTCBStatPend)

 {/* See if we timed-out or aborted*/

        case OS_STAT_PEND_OK:

             *perr = OS_ERR_NONE;

             break;

        case OS_STAT_PEND_ABORT:

             *perr = OS_ERR_PEND_ABORT;

/* Indicate that we aborted*/

             break;

        case OS_STAT_PEND_TO:

        default:

             OS_EventTaskRemove(OSTCBCur, pevent);

             *perr = OS_ERR_TIMEOUT;

/* Indicate that we didn't get event within TO*/

             break;

}

OSTCBCur->OSTCBStat          =  OS_STAT_RDY;

/* Set   task  status to ready*/

OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;

/* Clear pend  status*/

OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;

/* Clear event pointers*/

#if (OS_EVENT_MULTI_EN > 0u)

    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;

#endif

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

}

1、os_cfg.h文件如下:

#ifndef OS_CFG_H

#define OS_CFG_H

/*当OS_LOWEST_PRIO=63时,μC/OS-II有64个优先级,优先级的高低按编号从0(最高)到63(最低)排序;*/

/*混杂的配置MISCELLANEOUS*/

#define OS_APP_HOOKS_EN           0u

/* Application-defined hooks are called from the uC/OS-II hooks */

#define OS_ARG_CHK_EN             0u

/* Enable (1) or Disable (0) argument checking*/

#define OS_CPU_HOOKS_EN           1u

/* uC/OS-II hooks are found in the processor port files*/

#define OS_DEBUG_EN               0u

/* Enable(1) debug variables*/

#define OS_EVENT_MULTI_EN         0u

/*若置1,则使能OSEventPendMulti()函数*/

#define OS_EVENT_NAME_EN          0u

/* Enable names for Sem, Mutex, Mbox and Q*/

#define OS_LOWEST_PRIO           63u

/*设置最低优先级为63,则空闲任务优先级OS_TASK_IDLE_PRIO就等于63*/

/*OS_PRIO_SELF为255,因此OS_LOWEST_PRIO<255,最多有254个任务*/

#define OS_MAX_EVENTS            10u   /*设置"我的事件控制块总数"*/

#define OS_MAX_FLAGS              5u   /*设置"我的事件标志组总数"*/

#define OS_MAX_MEM_PART           0u   /*最大的内存块数*/

#define OS_MAX_QS                 4u   /*设置"我的消息队列总数"*/

#define OS_MAX_TASKS              5u

/*设置"我的任务总数",uCOSii至少有两个任务,分别是"空闲任务"和"统计任务";

5表示用户可以用其中的3个任务,加上"空闲任务"和"统计任务"就是5个任务

*/

#define OS_SCHED_LOCK_EN          1u

/*使能OSSchedLock()和OSSchedUnlock()*/

#define OS_TICK_STEP_EN           1u

/* Enable tick stepping feature for uC/OS-View*/

#define OS_TICKS_PER_SEC       100u

/*设置OSTimeDlyHMSM()函数中每秒的节拍数*/

/*任务堆栈大小TASK STACK SIZE*/

#define OS_TASK_TMR_STK_SIZE    128u

/*计时器任务堆栈大小,它是硬件定时器,因此没有优先级,OS_TASK_TMR_ID为65533*/

#define OS_TASK_STAT_STK_SIZE   128u

/*统计任务堆栈大小,OS_TASK_STAT_PRIO为62,是统计任务优先级,OS_TASK_IDLE_ID为65535*/

#define OS_TASK_IDLE_STK_SIZE   128u

/*空闲任务堆栈大小,OS_TASK_IDLE_PRIO为63,是空闲任务优先级,OS_TASK_STAT_ID为65534*/

/*任务管理TASK MANAGEMENT*/

#define OS_TASK_CHANGE_PRIO_EN    1u

/*使能"改变任务优先级函数"OSTaskChangePrio()*/

#define OS_TASK_CREATE_EN         1u

/*使能"创建任务函数"OSTaskCreate()*/

#define OS_TASK_CREATE_EXT_EN     1u

/*使能"创建扩展任务函数"OSTaskCreateExt()*/

#define OS_TASK_DEL_EN            1u

/*使能"删除任务函数"OSTaskDel()*/

#define OS_TASK_NAME_EN           1u

/*使能任务名Enable task names*/

#define OS_TASK_PROFILE_EN        1u

/*Include variables in OS_TCB for profiling*/

#define OS_TASK_QUERY_EN          1u

/*使能"获取任务信息函数OSTaskQuery()"*/

#define OS_TASK_REG_TBL_SIZE      1u

/*设置任务变量数组OSTCBRegTbl[]的大小,每个元素为INT32U型*/

#define OS_TASK_STAT_EN           1u

/*使能统计任务函数OSTaskStat(),统计任务每秒运行一次,计算当前系统CPU使用率,结果保存在8位变量OSCPUUsage中*/

#define OS_TASK_STAT_STK_CHK_EN   1u

/*使能检查"统计任务"任务栈的函数OS_TaskStatStkChk()*/

#define OS_TASK_SUSPEND_EN        1u

/*使能挂起任务函数OSTaskSuspend()和恢复任务OSTaskResume()*/

#define OS_TASK_SW_HOOK_EN        1u

/*使能"任务切换函数OSTaskSwHook()"*/

/*事件标志EVENT FLAGS*/

#define OS_FLAG_EN                1u

/* Enable (1) or Disable (0) code generation for EVENT FLAGS*/

#define OS_FLAG_ACCEPT_EN         1u

/*"使能检查事件标志组函数OSFlagAccept()",Include code for OSFlagAccept()*/

#define OS_FLAG_DEL_EN            1u

/*"使能删除一个事件标志组函数OSFlagDel()",Include code for OSFlagDel()*/

#define OS_FLAG_NAME_EN           1u

/*Enable names for event flag group*/

#define OS_FLAG_QUERY_EN          1u

/*"使能查询事件标志组的当前事件标志状态OSFlagQuery()",Include code for OSFlagQuery()*/

#define OS_FLAG_WAIT_CLR_EN       1u

/*Include code for Wait on Clear EVENT FLAGS*/

#define OS_FLAGS_NBITS           16u

/* Size in #bits of OS_FLAGS data type (8, 16 or 32)*/

/*消息邮箱MESSAGE MAILBOXES*/

#define OS_MBOX_EN                1u

/*使能消息邮箱,Enable (1) or Disable (0) code generation for MAILBOXES      */

#define OS_MBOX_ACCEPT_EN         1u

/*使能"无等待地从邮箱中得到一个消息函数OSMboxAccept()",Include code for OSMboxAccept()*/

#define OS_MBOX_DEL_EN            1u

/*使能"删除消息邮箱函数OSMboxDel()"Include code for OSMboxDel()*/

#define OS_MBOX_PEND_ABORT_EN     1u

/*Include code for OSMboxPendAbort()*/

#define OS_MBOX_POST_EN           1u

/*使能"发送一个消息到邮箱中函数OSMboxPost()",Include code for OSMboxPost()*/

#define OS_MBOX_POST_OPT_EN       1u

/*使能"依据条件,向邮箱发送一则消息OSMboxPostOpt()",Include code for OSMboxPostOpt()*/

#define OS_MBOX_QUERY_EN          1u

/*使能"查询一个邮箱的状态OSMboxQuery()",Include code for OSMboxQuery()                           */

/*内存管理MEMORY MANAGEMENT*/

#define OS_MEM_EN                 1u

/*使能"内存控制块",Enable (1) or Disable (0) code generation for MEMORY MANAGER */

#define OS_MEM_NAME_EN            1u

/*使能内存分区名称,Enable memory partition names*/

#define OS_MEM_QUERY_EN           1u

/*使能"查询一个内存分区的状态OSMemQuery()",Include code for OSMemQuery()*/

/*互斥型信号量MUTUAL EXCLUSION SEMAPHORES*/

#define OS_MUTEX_EN               1u

/* Enable (1) or Disable (0) code generation for MUTEX*/

#define OS_MUTEX_ACCEPT_EN        1u

/*使能"无等待地获取互斥型信号量函数OSMutexAccept()",Include code for OSMutexAccept()*/

#define OS_MUTEX_DEL_EN           1u

/*使能"删除互斥型信号量函数OSMutexDel()",Include code for OSMutexDel()*/

#define OS_MUTEX_QUERY_EN         1u

/*使能"查询一个互斥型信号量的当前状态OSMutexQuery()",Include code for OSMutexQuery()*/

/*消息队列MESSAGE QUEUES*/

#define OS_Q_EN                   1u

/*队列控制块,Enable (1) or Disable (0) code generation for QUEUES*/

#define OS_Q_ACCEPT_EN            1u

/*使能"无等待地从一个消息队列中取得消息OSQAccept()",Include code for OSQAccept()*/

#define OS_Q_DEL_EN               1u

/*删除一个消息队列OSQDel(),Include code for OSQDel()*/

#define OS_Q_FLUSH_EN             1u

/*"清空一个消息队列OSQFlush()",Include code for OSQFlush()*/

#define OS_Q_PEND_ABORT_EN        1u

/*使能函数OSQPendAbort()*/

#define OS_Q_POST_EN              1u

/*采用FIFO先入先出法方式,向消息队列发送一个消息OSQPost(),Include code for OSQPost()*/

#define OS_Q_POST_FRONT_EN        1u

/*采用LIFO后进先出法方式,向消息队列发送一个消息OSQPostFront(),Include code for OSQPostFront()*/

#define OS_Q_POST_OPT_EN          1u

/*依据条件,采用LIFO后进先出法方式,向消息队列发送一个消息OSQPostOpt(),Include code for OSQPostOpt()*/

#define OS_Q_QUERY_EN             1u

/*查询一个消息队列的状态OSQQuery(),Include code for OSQQuery()*/

/*信号量SEMAPHORES*/

#define OS_SEM_EN                 1u

/* Enable (1) or Disable (0) code generation for SEMAPHORES*/

#define OS_SEM_ACCEPT_EN          1u

/*使能"无等待地请求一个信号量OSSemAccept()",Include code for OSSemAccept()*/

#define OS_SEM_DEL_EN             1u

/*使能"删除一个信号OSSemDel()",Include code for OSSemDel()*/

#define OS_SEM_PEND_ABORT_EN      1u

/*Include code for OSSemPendAbort()*/

#define OS_SEM_QUERY_EN           1u

/*使能"查询一个信号量的当前状态OSSemQuery()",Include code for OSSemQuery()*/

#define OS_SEM_SET_EN             1u

/*将信号量计数设置为作为参数指定的值,Include code for OSSemSet()*/

/*时间管理TIME MANAGEMENT*/

#define OS_TIME_DLY_HMSM_EN       1u

/*按时分秒延时函数OSTimeDlyHMSM(),Include code for OSTimeDlyHMSM()*/

#define OS_TIME_DLY_RESUME_EN     1u

/*让处在延时期的任务结束延时OSTimeDlyResume(),Include code for OSTimeDlyResume()*/

#define OS_TIME_GET_SET_EN        1u

/*使能"系统时间函数OSTimeGet()和OSTimeSet()",Include code for OSTimeGet() and OSTimeSet()*/

#define OS_TIME_TICK_HOOK_EN      1u

/*OSTaskTimeHook()在每个时钟节拍都会被OSTaskTick()调用,Include code for OSTimeTickHook()*/

/*定时器管理TIMER MANAGEMENT*/

#define OS_TMR_EN                 0u

/* Enable (1) or Disable (0) code generation for TIMERS*/

#define OS_TMR_CFG_MAX           16u

/*Maximum number of timers*/

#define OS_TMR_CFG_NAME_EN        1u

/*Determine timer names*/

#define OS_TMR_CFG_WHEEL_SIZE     8u

/*Size of timer wheel (#Spokes)*/

#define OS_TMR_CFG_TICKS_PER_SEC 10u

/*Rate at which timer management task runs (Hz) */

#endif

2My_Task_Priority.c文件如下:

#include "My_Task_Priority.h"

__align(8) OS_STK START_TASK_STACK[START_TASK_STACK_SIZE];

//声明START_TASK任务堆栈

__align(8) OS_STK LED0_TASK_STACK[LED0_TASK_STACK_SIZE];

//声明LED0_TASK任务堆栈

__align(8) OS_STK LED1_TASK_STACK[LED1_TASK_STACK_SIZE];

//声明LED1_TASK任务堆栈

__align(8) OS_STK KEY_TASK_STACK[KEY_TASK_STACK_SIZE];

//声明KEY_TASK任务堆栈

//如果任务中使用printf来打印浮点数据的话一点要8字节对齐

OS_EVENT *Sem_Event;//定义一个事件指针,用作信号量

u8 Sem_Err;

OS_SEM_DATA Sem_Result;

3、My_Task_Priority.h文件如下:

#ifndef __MY_TASK_PRIORITY_H

#define __MY_TASK_PRIORITY_H

#include "includes.h"

/*

为了保证“启动任务”能够连续运行,必须将“启动任务”的优先级选择为最高。

否则,当“启动任务”创建一个优先级高于自己的任务时,刚刚创建的任务就

会立即进入运行状态,而与这个任务关联的其它任务可能还没有创建,它使

用的通信工具也还没有创建,系统必然出错。

*/

#define START_TASK_PRIORITY      4

//设置START_TASK任务优先级,开始任务的优先级设置为最高

#define START_TASK_STACK_SIZE   192

//设置START_TASK任务堆栈大小,为8的倍数

extern OS_STK START_TASK_STACK[START_TASK_STACK_SIZE];

//START_TASK任务堆栈

#define LED0_TASK_PRIORITY       5

//设置LED0_TASK任务优先级为5

#define LED0_TASK_STACK_SIZE     56

//设置LED0_TASK任务堆栈大小为56,为8的倍数

extern OS_STK LED0_TASK_STACK[LED0_TASK_STACK_SIZE];

//LED0_TASK任务堆栈

#define LED1_TASK_PRIORITY       6

//设置LED1_TASK任务优先级为6

#define LED1_TASK_STACK_SIZE     72

//设置LED1_TASK任务堆栈大小为72,为8的倍数

extern OS_STK LED1_TASK_STACK[LED1_TASK_STACK_SIZE];

//LED1_TASK任务堆栈

#define KEY_TASK_PRIORITY        7

//设置KEY_TASK任务优先级为7

#define KEY_TASK_STACK_SIZE      56 

//设置KEY_TASK任务堆栈大小为56,为8的倍数

extern OS_STK KEY_TASK_STACK[KEY_TASK_STACK_SIZE];

//KEY_TASK任务堆栈

extern OS_EVENT * Sem_Event;

extern u8 Sem_Err;

extern OS_SEM_DATA Sem_Result;

#endif

4Start_Task.c文件如下:

#include "Start_Task.h"

#include "stdio.h"

//使能getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "LED.h"

#include "key.h"

#include "My_Task_Priority.h"

#include "LED0_Task.h"

#include "LED1_Task.h"

#include "Key_Task.h"

void Start_Task(void *pdata);

const char Start_Task_rn_REG[]="\r\n";

const char Start_Task_Initialise_REG[]="Start_Task Initialise";

//Start_Task任务

void Start_Task(void *pdata)

{

    OS_CPU_SR cpu_sr=0;

    pdata = pdata;

    printf("%s",Start_Task_rn_REG);

    printf("%s",Start_Task_Initialise_REG);

    LED0_Init();

    LED1_Init();

    KEY_Init();

//OSTaskCreate()建立一个新任务.可以在多任务环境启动之前.或者运行任务中建立任务;

//注意:ISR中禁止建立任务,一个任务必须为无限循环结构;

    OS_ENTER_CRITICAL();

//进入临界区(无法被中断打断),需要定义cpu_sr变量 

    Sem_Event=OSSemCreate(0);

/*创建信号量Sem_Event

OSSemCreate(0)将信号量计数器的值设置为0,表示信号量1发1收;

OSSemCreate(1)将信号量计数器的值设置为1,相当于在创建信号量时,就执行OSSemPost()一次了,不建议这么创建

*/ 

    OSTaskCreate( LED0_Task,

                  (void *)0,

                   (OS_STK*)&LED0_TASK_STACK[LED0_TASK_STACK_SIZE-1],

                  LED0_TASK_PRIORITY

              );  //创建LED0_Task任务    

             

    OSTaskCreate( LED1_Task,

                  (void *)0,

                  (OS_STK*)&LED1_TASK_STACK[LED1_TASK_STACK_SIZE-1],

                            LED1_TASK_PRIORITY

              ); //创建LED1_Task任务 

    OSTaskCreate( Key_Task,

                   (void *)0,

                  (OS_STK*)&KEY_TASK_STACK[KEY_TASK_STACK_SIZE-1],

                  KEY_TASK_PRIORITY

              ); //创建Key_Task任务  

   

//OSTaskSuspend(START_TASK_PRIO);  //挂起起始任务Start_Task()

    OSTaskDel (OS_PRIO_SELF); //删除自己

    OS_EXIT_CRITICAL();      //退出临界区(可以被中断打断)

}

5Start_Task.h文件如下:

#ifndef __Start_Task_H

#define __Start_Task_H

#include "includes.h"

extern void Start_Task(void *pdata);

#endif

6main.c文件如下:

#include "stm32f10x.h"

//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,

//使能int16_t,int32_t,int64_t

#include "includes.h"

#include "delay.h"

#include "USART1.h"

#include "My_Task_Priority.h"

#include "Start_Task.h"

//创建任务,挂起任务,恢复任务,发送删除任务请求,删除任务

const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";

int main(void)

{

    SystemInit();   //系统初始化72M

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

    USART1_Serial_Interface_Enable(115200);

    printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"

    SysRstSrcRecord();//系统复位记录

   delay_init(); //延时函数初始化

    OSInit();//初始化UCOS-II函数

  OSTaskCreate(Start_Task,(void *)0,(OS_STK *)&START_TASK_STACK[START_TASK_STACK_SIZE-1],START_TASK_PRIORITY );

//创建启动任务

    OSStart();//启动操作系统,开始对任务进行调度管理

}

7LED0_Task.c文件如下:

#include "LED0_Task.h"

#include "stdio.h" 

//使能getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "LED.h"

void LED0_Task(void *pdata);

const char LED0_Task_rn_REG[]="\r\n";

const char LED0_Task_Initialise_REG[]="LED0_Task Initialise";

//LED0_Task任务

void LED0_Task(void *pdata)

{

    printf("%s",LED0_Task_rn_REG);

    printf("%s",LED0_Task_Initialise_REG);

    while(1)

    {

       OSSemPend(Sem_Event,0,&Sem_Err);

//接收信号量,等待Sem_Event信号事件到来

       LED0=!LED0;

       OSTimeDlyHMSM(0,0,0,500);//500ms闪烁一次

    }

}

8LED0_Task.h文件如下:

#ifndef __LED0_Task_H

#define __LED0_Task_H

#include "includes.h"

extern void LED0_Task(void *pdata);

#endif

9LED1_Task.c文件如下:

#include "LED1_Task.h"

#include "stdio.h" 

//使能getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "LED.h"

void LED1_Task(void *pdata);

const char LED1_Task_rn_REG[]="\r\n";

const char LED1_Task_Initialise_REG[]="LED1_Task Initialise";

//LED1_Task任务

void LED1_Task(void *pdata)

{

    printf("%s",LED1_Task_rn_REG);

    printf("%s",LED1_Task_Initialise_REG);

    while(1)

    {

       LED1=!LED1;//信号有效

       OSTimeDlyHMSM(0,0,0,500);//500毫秒闪烁1次

    }

}

10LED1_Task.h文件如下:

#ifndef __LED1_Task_H

#define __LED1_Task_H

#include "includes.h"

extern void LED1_Task(void *pdata);

#endif

11Key_Task.c文件如下:

#include "Key_Task.h"

#include "delay.h"

#include "stdio.h"

//使能getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "key.h"

#include "My_Task_Priority.h"

#include "LED1_Task.h"

const char Key_Task_rn_REG[]="\r\n";

const char Key_Task_Initialise_REG[]="Key_Task Initialise";

void Key_Task(void *pdata);

   

void Key_Task(void *pdata)

{  

    u8 key;

    printf("%s",Key_Task_rn_REG);

    printf("%s",Key_Task_Initialise_REG);

    while(1)

    {

       key=KEY_Scan(0);

       if(key==Cursor_Up)

       {

           OSSemPost(Sem_Event);//发送Sem_Event信号量事件

       }

       else if (key==Cursor_Down)

       {

       }

       else if (key==Cursor_Left)

       {

         OSSemDel(Sem_Event,OS_DEL_ALWAYS,&Sem_Err);

//删除信号量Sem_Event之后,信号量将无效,所有任务将不受此信号量限制

       }

       OSTimeDlyHMSM(0,0,0,100);//延时100ms

    }

}

12Key_Task.h文件如下:

#ifndef __Key_Task_H

#define __Key_Task_H

#include "includes.h"

extern void Key_Task(void *pdata);

#endif

13LED.c文件如下:

#include "LED.h"

void LED0_Init(void)

{

    GPIO_InitTypeDef   GPIO_InitStructure;

  //使用GPIO_InitTypeDef定义一个结构变量GPIO_InitStructure;

   

    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOE, ENABLE );

//在配置外设之前,必须先使能GPIOE的外设时钟

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;

//选择第4脚

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

//设置引脚的最高输出速率为50MHz

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

//设置引脚工作模式为推挽输出方式

    GPIO_Init( GPIOE, &GPIO_InitStructure);

//根据GPIO_InitStructure结构变量指定的参数初始化GPIOE的外设寄存器

}

void LED1_Init(void)

{

    GPIO_InitTypeDef   GPIO_InitStructure;

  //使用GPIO_InitTypeDef定义一个结构变量GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

//使能GPIOE的外设时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

//选择第5脚

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

//设置引脚工作模式为推挽输出方式

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

//设置引脚的最高输出速率为50MHz

    GPIO_Init(GPIOE, &GPIO_InitStructure);

//根据GPIO_InitStructure结构变量指定的参数初始化GPIOE的外设寄存器

}

void LED_Init(void)

{

    LED0_Init();

    LED1_Init();

}

14LED.h文件如下:

#ifndef _LED_H

#define _LED_H

#include "stm32f10x.h"

#include "sys.h"

#define LED0    PEout(4)  //PE4

#define LED1    PEout(5)  //PE5

#define LED0_OFF() GPIO_SetBits(GPIOE,GPIO_Pin_4)  //定义LED0关闭

#define LED0_ON() GPIO_ResetBits(GPIOE,GPIO_Pin_4) //定义LED0点亮

#define LED1_OFF() GPIO_SetBits(GPIOE,GPIO_Pin_5)  //定义LED1关闭

#define LED1_ON() GPIO_ResetBits(GPIOE,GPIO_Pin_5) //定义LED1点亮

extern void LED0_Init(void);

extern void LED1_Init(void);

extern void LED_Init(void); /* LED 端口初始化 */

#endif

15KEY.c文件如下:

#include "KEY.h"

#include "delay.h"

void KEY_Init(void);

u8 KEY_Scan(u8 mode);

//函数功能:将PB12,PB13,PB14,PB15,PD8初始化为输入口

void KEY_Init(void)

{

    GPIO_InitTypeDef   GPIO_InitStructure;

  //使用GPIO_InitTypeDef定义一个结构变量GPIO_InitStructure;

    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOB, ENABLE );

//在配置外设之前,必须先使能GPIOB的外设时钟

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; 

//选择第12,13,14和15脚

  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

//设置引脚的最高输出速率为50MHz

  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

//输入上拉,按钮输入低电平有效

  GPIO_Init( GPIOB, &GPIO_InitStructure);

  //根据GPIO_InitStructure结构变量指定的参数初始化GPIOB的外设寄存器

    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOD, ENABLE );

//在配置外设之前,必须先使能GPIOD的外设时钟

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;

//选择第8脚

  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

//设置引脚的最高输出速率为50MHz

  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

//输入上拉,按钮输入低电平有效

  GPIO_Init( GPIOD, &GPIO_InitStructure);

  //根据GPIO_InitStructure结构变量指定的参数初始化GPIOD的外设寄存器

}

//函数功能:按键扫描,按键检测时间为50ms

u8 KEY_Scan(u8 mode)

{

 u8 i;

 u8 ch0;

 u8 ch1;

 u8 retData;

 static u8 key_backup=1;//记录按键被释放

 if(mode == 1) key_backup=1;//记录按键被释放

 retData=0;//假定无按键按下

 ch0=0;ch1=0;

 if(key_backup==1)

 {

   if( KEY2==0) ch0=Cursor_Right; //记录按键值

   if( KEY3==0) ch0=Cursor_Up;    //记录按键值

   if( KEY1==0) ch0=Cursor_Left;  //记录按键值

   if( KEY4==0) ch0=Cursor_Down;  //记录按键值

   if( KEY5==0) ch0=OK;           //记录按键值

 }

 if(ch0) i=0;

 else i=200;

 for(;i<20;)

 {

  i++;

  ch1=0;

    delay_ms(5);

   if(KEY2==0)  ch1=Cursor_Right; //记录按键值,向右

   if(KEY3==0) ch1=Cursor_Up;   //记录按键值,向上

   if(KEY1==0) ch1=Cursor_Left; //记录按键值,向左

   if(KEY4==0) ch1=Cursor_Down; //记录按键值,向下

   if(KEY5==0) ch1=OK;          //记录按键值,确认

   if(ch1!=ch0) i=100;

 }

 if(i==20) retData=ch0;

 else retData=0;

    ch1=0;

    if(KEY1==1) ch1=1;

    if(KEY2==1) ch1=(u8)(ch1<<1);

    if(KEY3==1) ch1=(u8)(ch1<<1);

    if(KEY4==1) ch1=(u8)(ch1<<1);

    if(KEY5==1) ch1=(u8)(ch1<<1);

    if(ch1==0x20) key_backup=1;//记录按键被释放

    return retData;

}

16KEY.h文件如下:

#ifndef __KEY_H

#define __KEY_H  

#include "stm32f10x.h"

//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,

//使能int16_t,int32_t,int64_t

#include "sys.h"  //启用bool定义

#define Cursor_Left      1

#define Cursor_Right     2

#define Cursor_Up          3

#define Cursor_Down         4

#define OK               5

#define KEY3  PBin(14)          //PB14,向上

#define KEY4  PBin(13)          //PB13,向下

#define KEY1  PBin(15)          //PB15,向左

#define KEY2  PDin(8)       //PD8,向右

#define KEY5  PBin(12)          //PB12,确认

extern void KEY_Init(void);

extern u8 KEY_Scan(u8 mode);

#endif

17USART1.c文件如下:

#include "USART1.h"

#include "stdio.h"

void USART1_GPIO_Config(void);

void USART1_NVIC_Cpnfig(void);

void USART1_Mode_Cpnfig(unsigned int bound);

void USART1_SendByte(  unsigned char ch );

void USART1_SendString(  char *str);

void USART1_Serial_Interface_Enable(unsigned int bound);

//函数功能:USART1的IO口配置

void USART1_GPIO_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

//设置USART1的APB2外设时钟

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 

//使能GPIOA时钟

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9;

//选择PIN9,是USART1的TXD

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

//设置引脚为复用推挽输出  

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

//设置引脚的最高工作速率为50MHz

  GPIO_Init(GPIOA, &GPIO_InitStructure);

   

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10;

//选择PIN10,是USART1的RXD

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

//设置引脚为输入悬浮 

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

//设置引脚的最高工作速率为50MHz

  GPIO_Init(GPIOA, &GPIO_InitStructure);

}

//函数功能:USART1 NVIC 配置

void USART1_NVIC_Cpnfig(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

//NVIC_PriorityGroup_4设置NVIC中断分组4:表示抢占优先级为4位,取值为0~15,没有响应优先级,取值为0

//NVIC_PriorityGroup_3设置NVIC中断分组3:表示抢占优先级为3位,取值为0~7,响应优先级只有1位,取值为0~1

//NVIC_PriorityGroup_2设置NVIC中断分组3:表示抢占优先级为2位,取值为0~3,响应优先级只有2位,取值为0~3

//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4

   

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

//选择中断源为USART1

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;

//抢占优先级7

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

//子优先级0 

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

//IRQ通道使能

  NVIC_Init(&NVIC_InitStructure);

}

//函数功能:USART1配置:波特率为9600,数字为8位,停止位为1位,无奇偶校验,允许发送和接收数据,允许中断,使能串口模块

void USART1_Mode_Cpnfig(unsigned int bound)

{

    USART_InitTypeDef USART_InitStructure;

   

    USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    USART_InitStructure.USART_StopBits = USART_StopBits_1;

    USART_InitStructure.USART_Parity = USART_Parity_No ;

    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART1, &USART_InitStructure);

   

//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断

//当开启串口中断,一定要写其中断服务程序,否则可能会导致FreeRTOS的任务不执行

    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//开启接收中断

//当开启串口中断,一定要写其中断服务程序,否则可能会导致uCOS的任务不执行

    USART_Cmd(USART1, ENABLE); //使能串口

}

//函数功能:串口4发送一个字节

void USART1_SendByte(  unsigned char ch )

{

  USART_SendData(USART1, ch);

  while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);

//等待发送完成标志位被置1  

}

//函数功能:串口4发送字符串

void USART1_SendString(  char *str)

{

  unsigned int k=0;

  do{

      USART1_SendByte(  *(str + k) );

      k++;

    }while(*(str + k)!='\0');

}

//函数功能:USART1配置

void USART1_Serial_Interface_Enable(unsigned int bound)

{

    USART1_GPIO_Config();

  USART1_NVIC_Cpnfig();

  USART1_Mode_Cpnfig(bound);

}

//函数功能:USART1中断服务函数

void USART1_IRQHandler(void)

{

    unsigned char temp;

    (void)temp;//不让temp产生警告

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

    {

       temp=USART_ReceiveData(USART1); //从串口读取一个字节;

    }

}

//加入以下代码,支持printf函数,而不需要选择use MicroLIB

#if USART1_VirtualSerialPort == 1

#pragma import(__use_no_semihosting)

//标准库需要的支持函数

struct __FILE

{

    int handle;

};

FILE __stdout;

//定义_sys_exit()以避免使用半主机模式

void _sys_exit(int x)

{

    x = x;

}

//重定义fputc函数

//函数功能:发送ch的值给USART1串口

int fputc(int ch, FILE *f)

{

  USART_SendData(USART1, (unsigned char) ch);

  while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);

//等待发送完成标志位被置1  

    return ch;

}

#else

#define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))

#define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))

#define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))

#define DEMCR           (*((volatile unsigned long *)(0xE000EDFC)))

#define TRCENA          0x01000000

struct __FILE

{

  int handle; /* Add whatever you need here */

};

FILE __stdout;

FILE __stdin;

int fputc(int ch, FILE *f)

{

    if (DEMCR & TRCENA)

    {

    while (ITM_Port32(0) == 0);

   ITM_Port8(0) = ch;

  }

  return(ch);

}

#endif

//函数功能:USART1中断服务函数

void UART1_IRQHandler(void)

{

    unsigned char temp;

    (void)temp;

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

    {

       temp=USART_ReceiveData(USART1); //从串口读取一个字节;

    }

}

18USART1.h文件如下:

#ifndef __USART1_H

#define    __USART1_H

#include "stm32f10x.h"

//使能uint8_t,uint16_t,uint32_t,uint64_t,

//使能int8_t,int16_t,int32_t,int64_t

#include "sys.h"  //使能bool

#define USART1_VirtualSerialPort  1

//使用USART1的printf功能

//#define USART1_VirtualSerialPort  0 //使用JLINK虚拟串口的printf功能

extern void USART1_SendByte(  unsigned char ch );

extern void USART1_SendString(  char *str);

extern void USART1_Serial_Interface_Enable(unsigned int bound);

#endif /* __USART1_H */

19delay.c文件如下:

#include "delay.h"

//如果需要使用OS,则包括下面的头文件即可.

#if SYSTEM_SUPPORT_OS

#include "includes.h"    //ucos 使用    

#endif

static u8  fac_us=0; //us延时倍乘数            

static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数

#if SYSTEM_SUPPORT_OS

//如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).

//当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持

//首先是3个宏定义:

//    delay_osrunning:用于表示OS当前是否正在运行,以决定是否可以使用相关函数

//delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始哈systick

// delay_osintnesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行

//然后是3个函数:

//  delay_osschedlock:用于锁定OS任务调度,禁止调度

//delay_osschedunlock:用于解锁OS任务调度,重新开启调度

//    delay_ostimedly:用于OS延时,可以引起任务调度.

#ifdef     OS_CRITICAL_METHOD

//OS_CRITICAL_METHOD定义了,说明要支持UCOSII           

#define delay_osrunning     OSRunning

//OS是否运行标记,0,不运行;1,在运行

#define delay_ostickspersec OS_TICKS_PER_SEC

//OS时钟节拍,即每秒调度次数

#define delay_osintnesting OSIntNesting

//中断嵌套级别,即中断嵌套次数

#endif

#ifdef     CPU_CFG_CRITICAL_METHOD                //CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII   

#define delay_osrunning     OSRunning

//OS是否运行标记,0,不运行;1,在运行

#define delay_ostickspersec OSCfg_TickRate_Hz

//OS时钟节拍,即每秒调度次数

#define delay_osintnesting OSIntNestingCtr

//中断嵌套级别,即中断嵌套次数

#endif

//us级延时时,关闭任务调度(防止打断us级延迟)

void delay_osschedlock(void)

{

#ifdef CPU_CFG_CRITICAL_METHOD  //使用UCOSIII

    OS_ERR err;

    OSSchedLock(&err);   //UCOSIII的方式,禁止调度,防止打断us延时

#else  //否则UCOSII

    OSSchedLock();//UCOSII的方式,禁止调度,防止打断us延时

#endif

}

//us级延时时,恢复任务调度

void delay_osschedunlock(void)

{  

#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII

    OS_ERR err;

    OSSchedUnlock(&err); //UCOSIII的方式,恢复调度

#else  //支持UCOSII

    OSSchedUnlock();  //UCOSII的方式,恢复调度

#endif

}

//调用OS自带的延时函数延时

//ticks:延时的节拍数

void delay_ostimedly(u32 ticks)

{

#ifdef CPU_CFG_CRITICAL_METHOD

    OS_ERR err;

    OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);

//UCOSIII延时采用周期模式

#else

    OSTimeDly(ticks);

//UCOSII延时

#endif

}

//systick中断服务函数,使用ucos时用到

void SysTick_Handler(void)

{  

    if(delay_osrunning==1)

//OS开始跑了,才执行正常的调度处理

    {

       OSIntEnter();//进入中断

       OSTimeTick();//调用ucos的时钟服务程序               

       OSIntExit();//触发任务切换软中断

    }

}

#endif

             

//初始化延迟函数

//当使用OS的时候,此函数会初始化OS的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init(void)

{

#if SYSTEM_SUPPORT_OS //如果需要支持OS.

    u32 reload;

#endif

    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

//选择外部时钟  HCLK/8

    fac_us=SystemCoreClock/8000000; //为系统时钟的1/8 

#if SYSTEM_SUPPORT_OS              //如果需要支持OS.

    reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K    

    reload*=1000000/delay_ostickspersec;

//根据delay_ostickspersec设定溢出时间

//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右 

    fac_ms=1000/delay_ostickspersec;

//代表OS可以延时的最少单位   

    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;

//开启SYSTICK中断

    SysTick->LOAD=reload;

//每1/delay_ostickspersec秒中断一次  

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;

//开启SYSTICK   

#else

    fac_ms=(u16)fac_us*1000;

//非OS下,代表每个ms需要的systick时钟数  

#endif

}                              

#if SYSTEM_SUPPORT_OS //如果需要支持OS.

//延时nus

//nus为要延时的us数.                                          

void delay_us(u32 nus)

{     

    u32 ticks;

    u32 told,tnow,tcnt=0;

    u32 reload=SysTick->LOAD; //LOAD的值          

    ticks=nus*fac_us; //需要的节拍数           

    tcnt=0;

    delay_osschedlock(); //阻止OS调度,防止打断us延时

    told=SysTick->VAL;   //刚进入时的计数器值

    while(1)

    {

       tnow=SysTick->VAL;  

       if(tnow!=told)

       {      

           if(tnow<told)tcnt+=told-tnow;

//这里注意一下SYSTICK是一个递减的计数器就可以了.

           else tcnt+=reload-tnow+told;       

           told=tnow;

           if(tcnt>=ticks)break;

//时间超过/等于要延迟的时间,则退出.

       } 

    };

    delay_osschedunlock();//恢复OS调度                                   

}

//延时nms

//nms:要延时的ms数

void delay_ms(u16 nms)

{  

    if(delay_osrunning&&delay_osintnesting==0)

//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)      

    {     

       if(nms>=fac_ms)

//延时的时间大于OS的最少时间周期

       {

           delay_ostimedly(nms/fac_ms);       //OS延时

       }

       nms%=fac_ms;

//OS已经无法提供这么小的延时了,采用普通方式延时   

    }

    delay_us((u32)(nms*1000));

//普通方式延时 

}

#else //不用OS时

//延时nus

//nus为要延时的us数.                                          

void delay_us(u32 nus)

{     

    u32 temp;          

    SysTick->LOAD=nus*fac_us;                 //时间加载         

    SysTick->VAL=0x00;                        //清空计数器

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //开始倒数  

    do

    {

       temp=SysTick->CTRL;

    }while((temp&0x01)&&!(temp&(1<<16)));     //等待时间到达  

    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;  //关闭计数器

    SysTick->VAL =0X00;                        //清空计数器

}

//延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864

void delay_ms(u16 nms)

{               

    u32 temp;       

    SysTick->LOAD=(u32)nms*fac_ms; 

//时间加载(SysTick->LOAD为24bit)

    SysTick->VAL =0x00; //清空计数器

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //开始倒数  

    do

    {

       temp=SysTick->CTRL;

    }while((temp&0x01)&&!(temp&(1<<16)));     //等待时间到达   

    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;  //关闭计数器

    SysTick->VAL =0X00;                       //清空计数器          

}

#endif

20delay.h文件如下:

#ifndef __DELAY_H

#define __DELAY_H              

#include "sys.h"

void delay_init(void);

void delay_ms(u16 nms);

void delay_us(u32 nus);

#endif

21sys.c文件如下:

#include "sys.h"

//THUMB指令不支持汇编内联

//采用如下方法实现执行汇编指令WFI 

void WFI_SET(void)

{

    __ASM volatile("wfi");       

}

//关闭所有中断

void INTX_DISABLE(void)

{       

    __ASM volatile("cpsid i");

}

//开启所有中断

void INTX_ENABLE(void)

{

    __ASM volatile("cpsie i");       

}

//设置栈顶地址

//addr:栈顶地址

void __asm  MSR_MSP(u32 addr)

{

    MSR MSP, r0          //set Main Stack value

    BX r14

}

22sys.h文件如下:

#ifndef __SYS_H

#define __SYS_H  

#include "stm32f10x.h"

//0,不支持os

//1,支持os

#define SYSTEM_SUPPORT_OS       1      //定义系统文件夹是否支持OS

#define CLI()  __set_PRIMASK(1)         //关闭总中断

#define SEI()  __set_PRIMASK(0)        //打开总中断

typedef enum

{

  FALSE = 0, TRUE  = !FALSE

}

bool;

#ifndef NULL

#define NULL ((void *)0)

#endif

     

//位带操作,实现51类似的GPIO控制功能

//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).

//IO口操作宏定义

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))

#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))

#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

//IO口地址映射

#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C

#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C

#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C

#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C

#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C

#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C   

#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C   

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808

#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08

#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008

#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408

#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808

#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08

#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08

//IO口操作,只对单一的IO口!

//确保n的值小于16!

#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //A口输出

#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出

#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出

#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出

#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出

#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出

#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出

#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

//以下为汇编函数

void WFI_SET(void);      //执行WFI指令

void INTX_DISABLE(void);//关闭所有中断

void INTX_ENABLE(void);  //开启所有中断

void MSR_MSP(u32 addr);  //设置堆栈地址

#endif

23、编译结果

 

24、uCOSii主要用户函数

/*

事件标志管理 (EVENT FLAGS MANAGEMENT)

OSFlagAccept() 检查事件标志组函数(标志组的指针、事件标志位、等待事件标志位的方式、错误码指针)

OSFlagCreate() 建立一个事件标志组(初值、错误码)

OSFlagDel() 删除一个事件标志组(指针、条件值、错误值)

OSFlagPend() 等待事件标志组的事件标志位(事件组指针、需要检查的标志位、等待事件标志位的方式、

允许等待的时钟节拍、出错代码的时钟节拍)

OSFlagPost() 置位或清0事件标志组中的标志位(指针、标志位、条件值、错误码)

OSFlagQuery() 查询事件标志组的当前事件标志状态(事件标志组的指针、错误代码的指针)

*/

/*

消息邮箱管理 (MESSAGE MAILBOX MANAGEMENT)

OSMboxAccept() 查看消息邮箱(消息邮箱指针)

OSMboxCreate() 建立并初始化一个消息邮箱(msg 参数不为空含内容)

OSMboxDel() 删除消息邮箱(消息邮箱指针、删除条件、出错代码指针)

OSMboxPend() 等待一个消息邮箱函数(消息邮箱指针、允许等待的时钟节拍、代码错误指针)

OSMboxPost() 发送消息函数(消息邮箱指针、即将实际发送给任务的消息)

OSMboxPostOpt() 向邮箱发送一则消息(邮箱指针、消息、条件)

OSMboxQuery() 查询一个邮箱的当前状态(信号量指针、状态数据结构指针)

*/

/*

内存管理项 (MEMORY MANAGEMENT)

OSMemCreate() 建立并初始化一块内存区(起始地址、需要的内存块数目、内存块大小、返回错误的指针)

OSMemGet() 从内存区分配一个内存块

OSMemPut() 释放一个内存块,内存块必须释放回原先申请的内存区

OSMemQuery() 得到内存区的信息

*/

/*

互斥型信号量项管理 (MUTUAL EXCLUSION SEMAPHORE MANAGEMENT)

OSMutexAccept() 无等待地获取互斥型信号量[任务不挂起](信号量指针、错误代码)

OSMutexCreate() 建立并初始化一个互斥型信号量(优先级继承优先级(PIP)、出错代码指针)

OSMutexDel() 删除互斥型信号量(信号指针、删除条件、错误指针)

OSMutexPend() 等待一个互斥型信号量(指针、等待超时时限、出错代码指针)

OSMutexPost() 释放一个互斥型信号量(互斥型信号量指针)

OSMutexQuery() 查询一个互斥型信号量的当前状态(互斥型信号量指针、状态数据结构指针)

*/

/*

消息队列管理(MESSAGE QUEUE MANAGEMENT)

OSQAccept() 检查消息队列中是否已经有需要的消息(消息队列的指针)

OSQCreate() 建立一个消息队列(消息内存区的基地址(指针数组)、消息内存区的大小)

OSQDel() 删除一个消息队列(消息队列指针、删除条件、错误指针)

OSQFlush() 清空消息队列(指向得到消息队列的指针)

OSQPend() 任务等待消息队列中的消息(消息队列指针、允许等待的时钟节拍、代码错误指针)

OSQPost() 向消息队列发送一则消息FIFO(消息队列指针、发送的消息)

OSQPostFront() 向消息队列发送一则消息LIFO(消息队列指针、发送的消息)

OSQPostOpt() 向消息队列发送一则消息LIFO(消息队列指针、发送的消息、发送条件)

OSQQuery() 查询一个消息队列的当前状态(信号量指针、状态数据结构指针)

*/

/*

信号量管理 (SEMAPHORE MANAGEMENT)

OSSemAccept() 无条件地等待请求一个信号量函数

OSSemCreate() 建立并初始化一个信号量(输入一个信号量值)

OSSemDel() 删除一个信号量(信号指针、删除条件、错误指针)

OSSemPend() 等待一个信号量函数(信号量指针、允许等待的时钟节拍、代码错误指针)

OSSemPost() 发出一个信号量函数(信号量指针)

OSSemQuery() 查询一个信号量的当前状态(信号量指针、状态数据结构指针)

*/

/*

任务管理(TASK MANAGEMENT)

OSTaskChangePrio(任务旧的优先级,任务新的优先级),改变一个任务的优先级

OSTaskCreate(任务代码指针,传递参数指针,分配任务堆栈栈顶指针,任务优先级),建立任务

OSTaskCreateExt() 建立扩展任务(任务代码指针/传递参数指针/分配任务堆栈栈顶指针/分配任务优先级

//(未来的)优先级标识(与优先级相同)/分配任务堆栈栈底指针/指定堆栈的容量(检验用)

//指向用户附加的数据域的指针/建立任务设定选项)

OSTaskDel(任务优先级),删除任务

OSTaskDelReq(任务优先级),发送删除任务请求,请求某个任务删除自己或者其它任务

OSTaskStkChk() 检查任务堆栈状态(任务优先级、检验堆栈数据结构)

OSTaskSuspend(任务优先级),无条件挂起一个任务()

OSTaskResume(任务优先级),唤醒一个用OSTaskSuspend()函数挂起的任务

OSTaskQuery(任务指针,保存数据结构指针),获取任务信息,获得自身或其它应用任务的信息

OSTaskStat(),统计任务每秒运行一次,计算当前系统CPU使用率,结果保存在8位变量OSCPUUsage中

OSTaskSwHook(),任务切换函数App_TaskSwHook()

*/

/*

时钟管理项(TIME MANAGEMENT)

OSTimeDly() 任务延时函数(时钟节拍数)

OSTimeDlyHMSM() 将一个任务延时若干时间(设定时、分、秒、毫秒)

OSTimeDlyResume() 唤醒一个用OSTimeDly()或OSTimeDlyHMSM()函数的任务(优先级)

OSTimeGet() 获取当前系统时钟数值

OSTimeSet() 设置当前系统时钟数值

*/

/*

混杂函数定义

OSInit() 初始化UCOS-II函数

OSIntEnter() 中断函数正在执行

OSIntExit() 中断函数已经完成(脱离中断)

OSSchedLock()给调度器上锁,函数允许应用程序锁定当前任务不被其它任务抢占,

OSSchedUnlock() 给调度器解锁

确保OSSchedLock()和OSSchedUnlock()函数成对出现;

注意:在OSSchedLock()和OSSchedUnlock()之键,不调用诸如OSFlagPend()、OSMboxPend()、OSMutexPend()、OSQPend()、OSSemPend()

之类的事件等待函数!因为调度器被上锁了,其它任务不会给当前任务发送消息。

OSStart() 启动多个任务

OSStatInit() 统计任务初始化

OSVersion() 获得版本号

*/

/*

内部函数原型 INTERNAL FUNCTION PROTOTYPES

你在应用程序中不能使用它们 (Your application MUST NOT call these functions)

OS_Dummy() 建立一个虚拟函数

OS_EventTaskRdy() 使一个任务进入就绪态(OS_EVENT *pevent, void *msg, INT8U msk)

OS_EventTaskWait() 使一个任务进入等待某事件发生状态(ECB指针)

OS_EventTO() 由于超时而将任务置为就绪态(ECB指针)

OS_EventWaitListInit()事件控制块列表初始化(事件控制块指针)

OS_FlagInit() 初始化事件标志结构

OS_FlagUnlink() 把这个OS_FLAG_NODE从事件标志组的等待任务链表中删除(OS_FLAG_NODE *pnode)

OS_MemInit() 初始化内存分区

OS_QInit() 初始化事件队列结构

OS_Sched() 任务调度函数

OS_TaskIdle() 空闲任务函数(指向一个数据结构)

OS_TaskStat() 统计任务(指向一个数据结构)

OS_TCBInit() 初始化任务控制块TCB(优先级指针、栈顶指针、栈底指针、任务标志符、堆栈容量、扩展指针、选择项)

*/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值