uCOSii信号量

news2024/11/18 3:22:11

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(优先级指针、栈顶指针、栈底指针、任务标志符、堆栈容量、扩展指针、选择项)

*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker介绍、常用命令、项目部署

什么是Docker 简单说&#xff1a;Docker就是一个虚拟机&#xff0c;专业说&#xff1a;它是一个开源的容器平台。它和我们常用的VMware有很多相似的地方。 名词解释 镜像/images 由本体打包出来的文件。并不是文件本身&#xff0c;但是具有该文件的功能。举个不太贴切的例子&…

离线安装python、pip和python的第三方库

1.安装python3 1.1下载python3 安装python3的网址为点击这里 选择想要下载的对应版本进行下载&#xff0c;这里使用的是63位的Windows系统&#xff0c;因此下载的选的是&#xff1a; 下载后如图&#xff1a; python-3.7.9-amd64.exe是python3的安装程序 1.2安装python3 1…

5月第3周榜单丨飞瓜数据B站UP主排行榜单(哔哩哔哩)发布!

飞瓜轻数发布2023年5月15日-5月21日飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的B…

BLE协议栈结构

// 开坑BLE协议栈 0 镇楼图 接下来会自下往上粗略分析各个层级&#xff0c;后续会有对各层的细致解读 1 CONTROLLER 1.1 PHY BLE使用ISM频段&#xff08;频率范围是2.400-2.4835 GHz&#xff09;。将整个频带分为40份&#xff0c;每份的带宽为2MHz&#xff0c;称作RF Chann…

CASAIM与北京体育大学达成合作,高精度三维扫描技术助力体育运动装备仿真分析

近期&#xff0c;CASAIM与北京体育大学开展合作交流&#xff0c;基于高精度三维扫描技术助力体育运动装备仿真分析&#xff0c;为体育运动装备可靠性研究提供准确的数据参考。 北京体育大学是全国重点院校、国家“211工程”重点建设大学、国家首批“双一流”建设高校&#xff0…

基于springboot+vue社区团购系统(分前后台springboot+mybatis+mysql+maven+vue+html)

基于springbootvue社区团购系统 一、项目简介二、技术实现三、开发运行环境四、系统功能五、页面展示六、数据库七、项目结构八、部分代码展示九、源码地址 一、项目简介 本项目是一套基于springboot社区团购系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项…

【正点原子STM32连载】 第十六章 外部中断实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十六…

【Sentinel】流控、熔断、热点基本介绍和使用

目录 环境介绍Sentinel的使用可以分为两个部分Sentinel管理控制台客户端接入控制台配置启动参数流控规则名词解释 熔断策略公共字段说明慢调用比例字段说明 异常比例字段说明异常数字段说明 热点规则 环境介绍 开发依赖版本Spring Boot3.0.6Spring Cloud2022.0.2Spring Cloud …

一文搞清RabbitMQ的部署运维及使用

1.通过docker-compose安装RabbitMQ 1.0 初始化yum和Docker yum update yum install epel-release -y yum clean all yum list yum install docker-io -y1.1 dockerfile FROM rabbitmq:management MAINTAINER LCJ # 添加插件到指定目录 可按照此方式自行扩展其他插件 # ADD .…

shopee虾皮跨境电商网站商品数据支持网站后缀(.com.my;.vn;.ph)

作为一名技术爱好者&#xff0c;我们总会遇到各种各样的技术问题&#xff0c;需要寻找合适的技术解决方案。而在互联网时代&#xff0c;我们可以快速通过搜索引擎获取丰富的技术资源和解决方案。然而&#xff0c;在不同的技术分享中&#xff0c;我们常常会遇到质量参差不齐的文…

【新星计划·2023】单臂路由的原理讲解

单臂路由是指在路由器的一个接口上通过配置子接口的方式&#xff0c;实现原来互相隔离的VLAN之间可以互相通信。 一、单臂路由概述 网络中通过VLAN技术来实现隔离广播、方便管理及提高安全性等功能&#xff0c;一旦划分VLAN后&#xff0c;同—VLAN之间可以相互通信&#xff0…

【统计模型】瑞典生育率现状与影响因素分析

目录 瑞典生育率现状与影响因素分析 一、研究目的 二、数据来源和相关说明 三、描述性分析 3.1 样本描述 3.2 数据可视化 四、数学建模 4.1 模型建立 4.2 模型结果 &#xff08;1&#xff09;全模型A &#xff08;2&#xff09;全模型B &#xff08;3&#xff09;全…

传奇手游三职业1.80合击服务端三端互通版搭建教程

传奇手游三职业1.80合击服务端三端互通版搭建教程 大家好&#xff0c;我是驰网艾西。随着时代的发展&#xff0c;以前我们热爱的传奇游戏也越来越没有时间玩了&#xff0c;到了一定的年纪大家都有自己的事业以及生活压力。以前我们总是玩PC端所谓的端游&#xff0c;现在大家都…

highcharts矢量图放在图表的最上方

将矢量图对应的y轴的top和height都设置为0 即可 下面红色标注全是y轴的设置 以上这中图怎么实现 其中top是指图表中每个模块的位置&#xff0c;offset表示偏移的位置&#xff0c;height表示每个模块占据整个图标的高度的百分比&#xff0c;opposite表示该y轴是否在右侧&#xf…

麒麟系统安装HDP【已解决】

麒麟系统安装HDP 麒麟系统安装HDP1、软件版本介绍2、文件替换3 报错解决3.1 解决KeyError: HDP-3.1&#xff08;所有机器&#xff09;3.2 安装smartsense-hst&#xff08;所有机器&#xff09;3.3 解决Non-ASCII character \xe5 in file&#xff08;所有机器&#xff09;3.4 解…

如何解决端口号被占用的方法

在学习JavaWeb的过程中&#xff0c;在运行代码的时候经常会提示端口号被占用的情况&#xff1b;出现这情况的主要原因就是没有正常关闭tomcat。 那么遇到这种情况应该怎么解决呢&#xff1f; 首先第一种方式就是把电脑关机重启&#xff0c;这种方法可谓是百试百灵&#xff1b;另…

分类逻辑回归实例一

一、实例背景 假设根据【推荐分值】来对推荐者类型进行分类&#xff1a;高推荐、中推荐、低推荐 二、任务目标 训练出一个模型&#xff0c;来实现根据【推荐分值】&#xff0c;来预测【推荐类型】的分类 三、机器学习实现 1. 核心步骤 实现全流程&#xff1a; 1. 1 建立…

Niagara—— Events and Event Handlers

目录 一&#xff0c;Events 二&#xff0c;Event Handlers 多数情况下&#xff0c;系统中的发射器需相互交互&#xff0c;才能创建所需效果&#xff1b;意味着&#xff0c;一发射器生成数据&#xff0c;另一发射器监听该数据&#xff0c;以执行相应行为&#xff1b;在Niagar…

Linux-初学者系列_docker

目录 Linux-初学者系列_docker一、概念二、安装docker&#xff08;可忽略 跳到第三步&#xff09;三、获取镜像1、下载nginx镜像2、查看本地镜像3、将镜像运行成一个容器01-查看运行的容器02-通过ip端口号访问03-删除端口04-指定镜像名字 4、dockerfile构建镜像5、dockersave构…

HLS入门实践

HLS入门实践 文章目录 HLS入门实践1.HLS基本知识简述1.1 HLS简介1.2 HLS相关知识概念 2. HLS技术认识2.1 与VHDL/Verilog关系2.2 关键技术问题2.3 存在的技术局限性 3. HLS 完成 led 灯闪烁3.1. 新建一个 HLS 工程3.2 添加源文件3.2.1 led.h3.2.2 led.cpp3.2.3 添加 C 仿真文件…