📄 test.c
字号:
/************************************************************************************************************************
* test.c
*
*
*
************************************************************************************************************************/
#include "RTOS.h"
/************************************************************************************************************************
函数名称: OSTaskCreate
函数原型: void OSTaskCreate(void (*Task)(void),Uint_8bit *Stack,Uint_8bit TaskID)
函数功能: 建立任务
入口参数: *Task:任务函数地址;*Stack:任务堆栈指针;TaskID:任务优先级
出口参数: 无
有关说明:
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OSTaskCreate(void (*Task)(void),Uint_8bit *Stack,Uint_8bit TaskID)
{
Uint_8bit i;
*Stack--=(Uint_16bit)Task; /*将任务的地址低位压入堆栈 */
*Stack--=(Uint_16bit)Task>>8; /*将任务的地址高位压入堆栈 */
*Stack--=0x00; /*R1 __zero_reg__ */
*Stack--=0x00; /*R0 __tmp_reg__ */
*Stack--=0x80; /*SREG 在任务中,开启全局中断 */
for(i=0;i<14;i++)
*Stack--=i;
/*
在 avr-libc 中的 FAQ中的 What registers are used by the C compiler?
描述了寄存器的作用
*/
TCB[TaskID].OSTaskStackTop = (Uint_16bit)Stack;
/*
将人工堆栈的栈顶,保存到堆栈的数组中
*/
OSRdyTbl |= 0x01<<TaskID; /*任务就绪表已经准备好 */
}
/************************************************************************************************************************
函数名称: OSStartTask
函数原型: void OSStartTask(void)
函数功能: 开始任务调度,从空闲任务开始运行
入口参数: 无
出口参数: 无
有关说明: 执行"reti"指令之后打开全局中断
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OSStartTask(void)
{
OSPrioCur = OS_TASKS;
OSPrioHighRdy = OS_TASKS;
SP=TCB[OS_TASKS].OSTaskStackTop+17;
__asm__ __volatile__( "reti" "\n\t" );
}
/************************************************************************************************************************
函数名称: OS_TASK_SW
函数原型: void OS_TASK_SW(void)
函数功能: 进行任务调度
入口参数: 无
出口参数: 无
有关说明: 中断和任务都可以调用这个任务调度函数
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OS_TASK_SW(void)
{
__asm__ __volatile__("LDI R16,0x01 \n\t");
/*
清除中断要求任务切换的标志位,设置正在任务切换标志位
*/
__asm__ __volatile__("SEI \n\t");
/*
开中断,因为如果因中断在任务调度中进行,要重新进行调度时,已经关中断
*/
/* 根据中断时保存寄存器的次序入栈,模拟一次中断后,入栈的情况*/
__asm__ __volatile__("PUSH __zero_reg__ \n\t"); /*R1 */
__asm__ __volatile__("PUSH __tmp_reg__ \n\t"); /*R0 */
__asm__ __volatile__("IN __tmp_reg__,__SREG__ \n\t"); /*保存状态寄存器SREG */
__asm__ __volatile__("PUSH __tmp_reg__ \n\t");
__asm__ __volatile__("CLR __zero_reg__ \n\t"); /*R0重新清零 */
__asm__ __volatile__("PUSH R18 \n\t");
__asm__ __volatile__("PUSH R19 \n\t");
__asm__ __volatile__("PUSH R20 \n\t");
__asm__ __volatile__("PUSH R21 \n\t");
__asm__ __volatile__("PUSH R22 \n\t");
__asm__ __volatile__("PUSH R23 \n\t");
__asm__ __volatile__("PUSH R24 \n\t");
__asm__ __volatile__("PUSH R25 \n\t");
__asm__ __volatile__("PUSH R26 \n\t");
__asm__ __volatile__("PUSH R27 \n\t");
__asm__ __volatile__("PUSH R30 \n\t");
__asm__ __volatile__("PUSH R31 \n\t");
__asm__ __volatile__("Int_OSSched: \n\t"); /*当中断要求调度,直接进入这里 */
__asm__ __volatile__("SEI \n\t");
/*
开中断,因为如果因中断在任务调度中进行,已经关中断
*/
__asm__ __volatile__("PUSH R28 \n\t"); /*R28与R29用于建立在堆栈上的指针 */
__asm__ __volatile__("PUSH R29 \n\t"); /*入栈完成 */
TCB[OSPrioCur].OSTaskStackTop=SP; /*将正在运行的任务的堆栈底保存 */
OSPrioCur = OSPrioHighRdy ; /*运行当前就绪表中的最高优先级任务 */
cli(); /*保护堆栈转换,属于临界代码,要保护 */
SP=TCB[OSPrioCur].OSTaskStackTop;
sei();
/*根据中断时的出栈次序*/
__asm__ __volatile__("POP R29 \n\t");
__asm__ __volatile__("POP R28 \n\t");
__asm__ __volatile__("POP R31 \n\t");
__asm__ __volatile__("POP R30 \n\t");
__asm__ __volatile__("POP R27 \n\t");
__asm__ __volatile__("POP R26 \n\t");
__asm__ __volatile__("POP R25 \n\t");
__asm__ __volatile__("POP R24 \n\t");
__asm__ __volatile__("POP R23 \n\t");
__asm__ __volatile__("POP R22 \n\t");
__asm__ __volatile__("POP R21 \n\t");
__asm__ __volatile__("POP R20 \n\t");
__asm__ __volatile__("POP R19 \n\t");
__asm__ __volatile__("POP R18 \n\t");
__asm__ __volatile__("POP __tmp_reg__ \n\t"); /*SERG 出栈并恢复 */
__asm__ __volatile__("OUT __SREG__,__tmp_reg__ \n\t");
__asm__ __volatile__("POP __tmp_reg__ \n\t"); /*R0 出栈 */
__asm__ __volatile__("POP __zero_reg__ \n\t"); /*R1 出栈 */
/*中断时出栈完成*/
__asm__ __volatile__("CLI \n\t"); /*关中断 */
__asm__ __volatile__("SBRC R16,1 \n\t");
/*
SBRC当寄存器位为0则跳过下一条指令
检查系统正在进行任务调度时,是否有中断发生并进行要求任务调度,
如果中断要求调度则重新进行一次任务调度。
0x02是中断要求调度的标志位
*/
__asm__ __volatile__("RJMP OSSched \n\t"); /*重新调度 */
__asm__ __volatile__("LDI R16,0x00 \n\t");
/*
清除中断要求任务切换的标志位,清除正在任务切换标志位,
表示任务切换已经完成。
*/
__asm__ __volatile__("RETI \n\t"); /*返回并开中断 */
}
/************************************************************************************************************************
函数名称: IntSwitch
函数原型: void IntSwitch(void)
函数功能: 从中断退出并进行调度
入口参数: 无
出口参数: 无
有关说明: 当无中断嵌套并且中断中要求进行任务切换时才进行任务切换。
* 因为从中断到运行下一个任务共调用了两次子函数,所以要弹出四个入栈的PC
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void IntSwitch(void)
{
if((OSCoreState == 0x02) && (OSIntNesting == 0))
{
/*
进入中断时,已经保存了SREG和R0,R1,R18~R27,R30,R31,
所以没有必要再保存一次了,直接跳转到Int_OSSched进行下一个调度
*/
__asm__ __volatile__("POP R31 \n\t"); /*去除因调用子程序而入栈的PC*/
__asm__ __volatile__("POP R31 \n\t");
__asm__ __volatile__("POP R31 \n\t");
__asm__ __volatile__("POP R31 \n\t");
__asm__ __volatile__("LDI R16,0x01 \n\t");
/*
清除中断要求任务切换的标志位,设置正在任务切换标志位
*/
__asm__ __volatile__("RJMP Int_OSSched \n\t"); /*重新调度 */
}
}
/************************************************************************************************************************
函数名称: OSSched
函数原型: void OSSched(void)
函数功能: 任务调度器,进行任务调度
入口参数: 无
出口参数: 无
有关说明: 只有有更高优先级的任务就绪时才进行一次任务切换,否则不做切换
创建时间: 2007年3月7日
修改时间:
************************************************************************************************************************/
void OSSched (void)
{
OSFindPrioHighRdy(); /*找出就绪表中优先级最高的任务*/
if(OSPrioHighRdy != OSPrioCur) /*如果不是当前运行的任务,进行任务调度*/
{
OS_TASK_SW(); /*调度任务*/
}
}
/************************************************************************************************************************
函数名称: OSTaskSuspend
函数原型: void OSTaskSuspend(Uint_8bit prio)
函数功能: 挂起任务
入口参数: prio:任务优先级
出口参数: 无
有关说明: 一个任务可以挂起本身也可以挂起其他任务
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OSTaskSuspend(Uint_8bit prio)
{
OS_ENTER_CRITICAL();
TCB[prio].OSWaitTick=0;
OSRdyTbl &= ~(0x01<<prio); /*从任务就绪表上去除标志位 */
if(OSPrioCur == prio) /*当要挂起的任务为当前任务 */
{
OS_EXIT_CRITICAL();
OSSched(); /*重新调度 */
return;
}
OS_EXIT_CRITICAL();
}
/************************************************************************************************************************
函数名称: OSTaskResume
函数原型: void OSTaskResume(Uint_8bit prio)
函数功能: 恢复任务 可以让被OSTaskSuspend或 OSTimeDly暂停的任务恢复
入口参数: prio:任务优先级
出口参数: 无
有关说明:
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OSTaskResume(Uint_8bit prio)
{
OS_ENTER_CRITICAL();
OSRdyTbl |= 0x01<<prio; /*从任务就绪表上重置标志位 */
TCB[prio].OSWaitTick=0; /*将时间计时设为0,到时 */
if(OSPrioCur > prio) /*当要当前任务的优先级低于重置位的任务的优先级 */
{
OS_EXIT_CRITICAL();
OSSched(); /*重新调度 */
return;
}
OS_EXIT_CRITICAL();
}
/************************************************************************************************************************
函数名称: OSTimeDly
函数原型: void OSTimeDly(Uint_16bit ticks)
函数功能: 任务延时
入口参数: 延时的时间,任务时钟的个数
出口参数: 无
有关说明: 如果延时65535(0xffff)则为无限延时
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OSTimeDly(Uint_16bit ticks)
{
if(ticks) /*当延时有效 */
{
OS_ENTER_CRITICAL();
OSRdyTbl &= ~(0x01<<OSPrioCur); /*把任务从就绪表中去掉*/
TCB[OSPrioCur].OSWaitTick=ticks;
OS_EXIT_CRITICAL();
OSSched(); /*重新调度 */
}
}
/************************************************************************************************************************
函数名称: OSSemCreat
函数原型: void OSSemCreat(Uint_8bit Index,Uint_8bit Type)
函数功能: 初始化信号量
入口参数: Index:信号量的序号;Type:信号量类型
出口参数: 无
有关说明: Type为 0 信号量独占型;1 信号量共享型
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
void OSSemCreat(Uint_8bit Index,Uint_8bit Type)
{
Sem[Index].OSEventType=Type;
Sem[Index].OSTaskPendTbl=0; /*初始化时任务等待列表为空*/
Sem[Index].OSEventState=0; /*信号量无效*/
}
/************************************************************************************************************************
函数名称: OSTaskSemPend
函数原型: Uint_8bit OSTaskSemPend(Uint_8bit Index,Uint_16bit Timeout)
函数功能: 任务等待信号量,挂起
入口参数: Index:信号量序号;Timeout:等待时间
出口参数: 无
有关说明: 当Timeout==0xffff时,为无限等待
创建时间: 2007年3月3日
修改时间:
************************************************************************************************************************/
Uint_8bit OSTaskSemPend(Uint_8bit Index,Uint_16bit Timeout)
{
if(Sem[Index].OSEventState) /*信号量有效 */
{
if(Sem[Index].OSEventType == 0) /*如果为独占型 */
{
Sem[Index].OSEventState = 0x00; /*信号量被独占,不可用*/
}
}
else
{ /*加入信号的任务等待表*/
OS_ENTER_CRITICAL();
Sem[Index].OSTaskPendTbl |= 0x01<<OSPrioCur;
TCB[OSPrioCur].OSWaitTick = Timeout; /*定义等待超时 */
OSRdyTbl &= ~(0x01<<OSPrioCur); /*从任务就绪表中去除 */
OS_EXIT_CRITICAL();
OSSched(); /*重新调度 */
if(TCB[OSPrioCur].OSWaitTick==0 ) /*超时,未能拿到资源 */
{
return 0;
}
}
return 1;
}
/************************************************************************************************************************
函数名称: OSSemPost
函数原型: void OSSemPost(Uint_8bit Index)
函数功能: 发送一个信号量,可以从任务或中断发送,
* 发送完了信号量之后不进行任务调度,推荐在中断中调用
入口参数: Index:信号量的序号
出口参数: 无
有关说明: 如果有任务在等待该信号量则将该任务就绪,没有任务等待则仅仅是把信号量置为有效
创建时间: 2007年3月3日
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -