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
2、My_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
4、Start_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(); //退出临界区(可以被中断打断)
}
5、Start_Task.h文件如下:
#ifndef __Start_Task_H
#define __Start_Task_H
#include "includes.h"
extern void Start_Task(void *pdata);
#endif
6、main.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();//启动操作系统,开始对任务进行调度管理
}
7、LED0_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闪烁一次
}
}
8、LED0_Task.h文件如下:
#ifndef __LED0_Task_H
#define __LED0_Task_H
#include "includes.h"
extern void LED0_Task(void *pdata);
#endif
9、LED1_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次
}
}
10、LED1_Task.h文件如下:
#ifndef __LED1_Task_H
#define __LED1_Task_H
#include "includes.h"
extern void LED1_Task(void *pdata);
#endif
11、Key_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
}
}
12、Key_Task.h文件如下:
#ifndef __Key_Task_H
#define __Key_Task_H
#include "includes.h"
extern void Key_Task(void *pdata);
#endif
13、LED.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();
}
14、LED.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
15、KEY.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;
}
16、KEY.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
17、USART1.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); //从串口读取一个字节;
}
}
18、USART1.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 */
19、delay.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
//这里注意一下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
20、delay.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
21、sys.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
}
22、sys.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控制功能
//具体实现思想,参考<
//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(优先级指针、栈顶指针、栈底指针、任务标志符、堆栈容量、扩展指针、选择项)
*/