历史上的今天
返回首页

历史上的今天

今天是:2025年02月06日(星期四)

正在发生

2020年02月06日 | 建立一个属于自己的AVR的RTOS(第七篇:占先式内核)

2020-02-06 来源:eefocus

第七篇:占先式内核(只带延时服务)


当大家理解时间片轮番调度法的任务调度方式后,占先式的内核的原理,已经伸手可及了。

先想想,占先式内核是在什么地方实现任务调度的呢?对了,它在可以在任务中进行调度,这个在协作式的内核中已经做到了;同时,它也可以在中断结束后进行调度,这个问题,已经在时间片轮番调度法中已经做到了。


由于中断是可以嵌套的,只有当各层嵌套中要求调度,并且中断嵌套返回到最初进入的中断的那一层时,才能进行任务调度。


#include

#include

#include

unsignedcharStack[400];


registerunsignedcharOSRdyTblasm("r2");//任务运行就绪表

registerunsignedcharOSTaskRunningPrioasm("r3");//正在运行的任务

registerunsignedcharIntNumasm("r4");//中断嵌套计数器

//只有当中断嵌套数为0,并且有中断要求时,才能在退出中断时,进行任务调度

registerunsignedcharOSCoreStateasm("r16");//系统核心标志位,R16编译器没有使用

//只有大于R15的寄存器才能直接赋值例LDIR16,0x01

//0x01正在任务切换0x02有中断要求切换


#defineOS_TASKS3//设定运行任务的数量

structTaskCtrBlock

{

unsignedintOSTaskStackTop;//保存任务的堆栈顶

unsignedintOSWaitTick;//任务延时时钟

}TCB[OS_TASKS+1];


//防止被编译器占用

//registerunsignedchartempR4asm("r4");

registerunsignedchartempR5asm("r5");

registerunsignedchartempR6asm("r6");

registerunsignedchartempR7asm("r7");

registerunsignedchartempR8asm("r8");

registerunsignedchartempR9asm("r9");

registerunsignedchartempR10asm("r10");

registerunsignedchartempR11asm("r11");

registerunsignedchartempR12asm("r12");

registerunsignedchartempR13asm("r13");

registerunsignedchartempR14asm("r14");

registerunsignedchartempR15asm("r15");

//registerunsignedchartempR16asm("r16");

registerunsignedchartempR16asm("r17");



//建立任务

voidOSTaskCreate(void(*Task)(void),unsignedchar*Stack,unsignedcharTaskID)

{

unsignedchari;

*Stack--=(unsignedint)Task>>8;//将任务的地址高位压入堆栈,

*Stack--=(unsignedint)Task;//将任务的地址低位压入堆栈,


*Stack--=0x00;//R1__zero_reg__

*Stack--=0x00;//R0__tmp_reg__

*Stack--=0x80;


//SREG在任务中,开启全局中断

for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?

*Stack--=i;//描述了寄存器的作用

TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//将人工堆栈的栈顶,保存到堆栈的数组中

OSRdyTbl|=0x01<}


//开始任务调度,从最低优先级的任务的开始

voidOSStartTask()

{

OSTaskRunningPrio=OS_TASKS;

SP=TCB[OS_TASKS].OSTaskStackTop+17;

__asm____volatile__("reti""

t");

}


//进行任务调度

voidOSSched(void)

{


__asm____volatile__("LDIR16,0x01

t");

//清除中断要求任务切换的标志位,设置正在任务切换标志位

__asm____volatile__("SEI

t");

//开中断,因为如果因中断在任务调度中进行,要重新进行调度时,已经关中断

//根据中断时保存寄存器的次序入栈,模拟一次中断后,入栈的情况

__asm____volatile__("PUSH__zero_reg__

t");//R1

__asm____volatile__("PUSH__tmp_reg__

t");//R0

__asm____volatile__("IN__tmp_reg__,__SREG__

t");//保存状态寄存器SREG

__asm____volatile__("PUSH__tmp_reg__

t");

__asm____volatile__("CLR__zero_reg__

t");//R0重新清零

__asm____volatile__("PUSHR18

t");

__asm____volatile__("PUSHR19

t");

__asm____volatile__("PUSHR20

t");

__asm____volatile__("PUSHR21

t");

__asm____volatile__("PUSHR22

t");

__asm____volatile__("PUSHR23

t");

__asm____volatile__("PUSHR24

t");

__asm____volatile__("PUSHR25

t");

__asm____volatile__("PUSHR26

t");

__asm____volatile__("PUSHR27

t");

__asm____volatile__("PUSHR30

t");

__asm____volatile__("PUSHR31

t");


__asm____volatile__("Int_OSSched:

t");//当中断要求调度,直接进入这里

__asm____volatile__("SEI

t");

//开中断,因为如果因中断在任务调度中进行,已经关中断

__asm____volatile__("PUSHR28

t");//R28与R29用于建立在堆栈上的指针

__asm____volatile__("PUSHR29

t");//入栈完成


TCB[OSTaskRunningPrio].OSTaskStackTop=SP;//将正在运行的任务的堆栈底保存


unsignedcharOSNextTaskPrio;//在现有堆栈上开设新的空间

for(OSNextTaskPrio=0;//进行任务调度

OSNextTaskPrioOSNextTaskPrio++);

OSTaskRunningPrio=OSNextTaskPrio;


cli();//保护堆栈转换

SP=TCB[OSTaskRunningPrio].OSTaskStackTop;

sei();


//根据中断时的出栈次序

__asm____volatile__("POPR29

t");

__asm____volatile__("POPR28

t");

__asm____volatile__("POPR31

t");

__asm____volatile__("POPR30

t");

__asm____volatile__("POPR27

t");

__asm____volatile__("POPR26

t");

__asm____volatile__("POPR25

t");

__asm____volatile__("POPR24

t");

__asm____volatile__("POPR23

t");

__asm____volatile__("POPR22

t");

__asm____volatile__("POPR21

t");

__asm____volatile__("POPR20

t");

__asm____volatile__("POPR19

t");

__asm____volatile__("POPR18

t");

__asm____volatile__("POP__tmp_reg__

t");//SERG出栈并恢复

__asm____volatile__("OUT__SREG__,__tmp_reg__

t");//

__asm____volatile__("POP__tmp_reg__

t");//R0出栈

__asm____volatile__("POP__zero_reg__

t");//R1出栈

//中断时出栈完成

__asm____volatile__("CLI

t");//关中断

__asm____volatile__("SBRCR16,1

t");//SBRC当寄存器位为0刚跳过下一条指令

//检查是在调度时,是否有中断要求任务调度0x02是中断要求调度的标志位

__asm____volatile__("RJMPOSSched

t");//重新调度

__asm____volatile__("LDIR16,0x00

t");

//清除中断要求任务切换的标志位,清除正在任务切换标志位

__asm____volatile__("RETI

t");//返回并开中断

}



//从中断退出并进行调度

voidIntSwitch(void)

{

//当中断无嵌套,并且没有在切换任务的过程中,直接进行任务切换

if(OSCoreState==0x02&&IntNum==0)

{

//进入中断时,已经保存了SREG和R0,R1,R18~R27,R30,R31

__asm____volatile__("POPR31

t");//去除因调用子程序而入栈的PC

__asm____volatile__("POPR31

t");

__asm____volatile__("LDIR16,0x01

t");

//清除中断要求任务切换的标志位,设置正在任务切换标志位

__asm____volatile__("RJMPInt_OSSched

t");//重新调度

}

}


//任务延时

voidOSTimeDly(unsignedintticks)

{

if(ticks)//当延时有效

{

OSRdyTbl&=~(0x01<TCB[OSTaskRunningPrio].OSWaitTick=ticks;

OSSched();//从新调度

}

}




voidTCN0Init(void)//计时器0

{

TCCR0=0;

TCCR0|=(1<TIMSK|=(1<TCNT0=100;//置计数起始值


}


SIGNAL(SIG_OVERFLOW0)

{

IntNum++;//中断嵌套+1

sei();//在中断中,重开中断


unsignedchari,j=0;

for(i=0;i{

if(TCB[i].OSWaitTick)

{

TCB[i].OSWaitTick--;

if(TCB[i].OSWaitTick==0)//当任务时钟到时,必须是由定时器减时的才行

{

OSRdyTbl|=(0x01<OSCoreState|=0x02;//要求任务切换的标志位

}

}

}

TCNT0=100;

cli();

IntNum--;//中断嵌套-1

IntSwitch();//进行任务调度

}


voidTask0()

{

unsignedintj=0;

while(1)

{

PORTB=j++;

OSTimeDly(50);

}

}


voidTask1()

{

unsignedintj=0;

while(1)

{

PORTC=j++;

OSTimeDly(20);

}

}


voidTask2()

{

unsignedintj=0;

while(1)

{

PORTD=j++;

OSTimeDly(5);

}

}




voidTaskScheduler()

{

OSSched();

while(1)

{

//OSSched();//反复进行调度

}

}



intmain(void)

{

TCN0Init();

OSRdyTbl=0;

IntNum=0;

OSTaskCreate(Task0,&Stack[99],0);

OSTaskCreate(Task1,&Stack[199],1);

OSTaskCreate(Task2,&Stack[299],2);

OSTaskCreate(TaskScheduler,&Stack[399],OS_TASKS);

OSStartTask();

}

推荐阅读

史海拾趣

ACL staticide公司的发展小趣事

ACL Staticide是一家专业生产静电控制产品的公司,以下是该公司发展的五个相关故事:

  1. 公司成立和起步阶段: ACL Staticide成立于1971年,总部位于美国伊利诺伊州,是一家专注于静电控制产品的制造商。公司最初致力于研发和生产静电消除剂、清洁剂和防静电地板涂层等产品,用于解决静电问题带来的种种困扰,如静电放电、静电积聚等。

  2. 技术创新和产品拓展: 随着市场对静电控制需求的增长,ACL Staticide不断进行技术创新,并拓展了产品线。公司推出了一系列静电控制产品,包括静电消除器、清洁剂、防静电地板涂层、静电测试仪器等,以满足各种不同行业的需求。

  3. 市场拓展和国际合作: ACL Staticide积极开拓国内外市场,与全球各地的客户建立了合作关系。公司的产品被广泛应用于电子制造、半导体、医疗、航空航天、汽车等领域,赢得了客户的信赖。同时,ACL Staticide与国际知名企业合作,共同推动静电控制技术的发展。

  4. 持续投入研发和质量控制: ACL Staticide不断加大研发投入,致力于产品质量和技术创新。公司设立了专门的研发团队和实验室,不断改进现有产品,并开发新的静电控制解决方案,以满足客户不断变化的需求。

  5. 未来发展展望: ACL Staticide将继续致力于静电控制产品的研发和应用,不断推出更先进、更可靠的产品和解决方案,以满足客户在各个领域的需求。公司将加强国际市场拓展,提升自身在全球市场的竞争力,为行业的发展做出更大的贡献。

Apex [Apex Microtechnology]公司的发展小趣事

Apex Microtechnology一直致力于开发在性能、质量和可靠性方面引领行业的产品。通过不断创新和研发,公司成功推出了多款具有竞争力的功率模拟产品,为全球客户提供高效的解决方案。同时,Apex Microtechnology也积极拓展全球市场,与众多知名企业建立了合作关系,进一步提升了其在电子行业的影响力。

Apacer公司的发展小趣事

1997年,Apacer宇瞻科技在台湾创立,初期专注于DRAM模组的专业供货。公司凭借对半导体垂直整合的完整内存模组技术能力和专业营销业务,迅速在全球市场上打响了Apacer的自有品牌。1999年,宇瞻科技更是跃升为全球第四大内存模组厂商,奠定了其在行业内的领先地位。

意普(ESPE)公司的发展小趣事

随着工业自动化和智能化的不断发展,意普(ESPE)公司开始将光电保护技术与智能制造相结合,推出了多款智能光电保护产品。这些产品具有更高的检测精度和更快的反应速度,能够更好地保护操作人员的安全。同时,公司还积极参与工业互联网和物联网的建设,推动光电保护技术的智能化发展。

Hendon Semiconductors公司的发展小趣事

随着电子产品的不断小型化和集成化,表面贴装技术(SMT)成为了电子制造行业的重要趋势。Hendon Semiconductors紧跟这一趋势,不断提升其表面贴装和精密制造能力。公司引进了先进的生产设备和测试仪器,确保产品的质量和可靠性。同时,Hendon Semiconductors还加强了对生产过程的监控和管理,通过严格的质量控制体系确保每一片电路板都符合客户的要求。

Fabrimex AG公司的发展小趣事

1995年,Fabrimex GmbH成立,作为电子组装和电源生产的生产公司。这一举措标志着公司进一步向国际化发展迈进。通过设立生产公司,Fabrimex AG能够更好地控制产品质量和生产成本,提高市场竞争力。同时,公司还加强了在全球范围内的销售活动,进一步扩大了市场份额。

问答坊 | AI 解惑

塑封料发展状况及其工艺选择

[ip]塑封料发展状况及其工艺选择 上海常祥实业有限公司   刘志:13611616628 引言 塑封料,又称环氧塑封料(EMC,Epoxy Molding Compound)以其高可靠性、低成本、生产工艺简单、适合大规模生产等特点,占据了整个微电子封装材料97%以上的市场。 ...…

查看全部问答>

模拟电子电路的解读

通常我们头脑发热,在网上找到一个电路图准备"发烧"一下的时候,通常要将这个电路图读懂。 那么什么是"读"电路图呢?所谓的读图,就是对电路进行分析。通过读图,能够对以后的制作,特别 是生产的过程,能够少走很少的弯路是很正常的。 在 ...…

查看全部问答>

protel99se 的 插件

上传一个protel99se 的 插件,用这个插件放大缩小电路图就不麻烦了。…

查看全部问答>

想学嵌入式系统,自己做点小项目

我在学校读的是应付用电子,会画点PCB,懂得电子基础,学过一点C,一点单片机,一点汇编,一点VB,都是学了一点,谈不上熟,出来工作有五年了,基本上没怎么接触这一块,现在想学嵌入式系统,自己搞点项目,对于我这种情况还能学不,各位大哥出个注意!…

查看全部问答>

智能手机的操作系统,哪个比较人性化?

最好把塞班 WM linux 黑莓OS...乱七八糟的挨个试用一遍,哈哈 你们觉得呢?…

查看全部问答>

一种简易高精度频率信号发生器的设计与实现

一种简易高精度频率信号发生器的设计与实现…

查看全部问答>

WinCE6.0修改.cpl文件属性

包括去掉文件保护,只读,隐藏等。(用代码的哦)…

查看全部问答>

EDB的一些API没有定义的问题

平台:自己定制的wince5.0平台,非mobile 问题:CeCreateDatabaseWithProps和CeCreateSession函数未定义;本机上没有wincebase_edb.h和coredll.dll; coredll.lib和winbase.h中没有这些函数的定义。    是我定制的平台有问题,还是winc ...…

查看全部问答>

哥今天估计被忽悠了

     本来,哥明天要去某家公司实习。      然后,直到昨天我才收到那家公司给我的地址和乘车路线。中午吃完饭我就照着路线找过去,想自个看看。本来我还想就是想看看哪家公司在那座写字楼就好了。 &nbs ...…

查看全部问答>

IAR5.XX关于实时查看变量变化的功能

在STVD(调试STM8)里watch变量有"ON THE FLY"可以实时查看变量的变化。 在IAR5.XX调试STM32F103XXX不知道有没有这样的功能??? 或者类似的功能也行啊??? 请IAR EARM 高手指点!!!…

查看全部问答>