历史上的今天
返回首页

历史上的今天

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

正在发生

2020年02月06日 | 建立一个属于自己的AVR的RTOS(第六篇:调度法)

2020-02-06 来源:eefocus

第六篇:时间片轮番调度法的内核


时间片轮调法是非常有趣的。本篇中的例子,建立了3个任务,任务没有优先级,在时间中断的调度下,每个任务都轮流运行相同的时间。如果在内核中没有加入其它服务,感觉上就好像是有三个大循环在同时运行。


本例只是提供了一个用时间中断进行调度的内核,大家可以根据自己的需要,添加相应的服务。


要注意到:

1、由于在时间中断内调用了任务切换函数,因为在进入中断时,已经将一系列的寄存器入栈。

2、在中断内进行调度,是直接通过"RJMPInt_OSSched"进入任务切换和调度的,这是GCCAVR的一个特点,为用C编写内核提供了极大的方便。

3、在阅读代码的同时,请对照阅读编译器产生的*.lst文件,会对你理解例子有很大的帮助。


#include

#include

#include

unsignedcharStack[400];


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

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


#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__("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__("PUSHR28

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

__asm____volatile__("PUSHR29

t");//入栈完成


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


if(++OSTaskRunningPrio>=OS_TASKS)//轮流运行各个任务,没有优先级

OSTaskRunningPrio=0;


//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__("RETI

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

//中断时出栈完成

}



voidIntSwitch(void)

{

__asm____volatile__("POPR31

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

__asm____volatile__("POPR31

t");

__asm____volatile__("RJMPInt_OSSched

t");//重新调度

}





voidTCN0Init(void)//计时器0

{

TCCR0=0;

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

}



SIGNAL(SIG_OVERFLOW0)

{

TCNT0=100;

IntSwitch();//任务调度

}


voidTask0()

{

unsignedintj=0;

while(1)

{

PORTB=j++;

//OSTimeDly(50);

}

}


voidTask1()

{

unsignedintj=0;

while(1)

{

PORTC=j++;

//OSTimeDly(5);

}

}


voidTask2()

{

unsignedintj=0;

while(1)

{

PORTD=j++;

//OSTimeDly(5);

}

}




voidTaskScheduler()

{

while(1)

{

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

}

}



intmain(void)

{

TCN0Init();

OSRdyTbl=0;

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

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

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

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

OSStartTask();

}

推荐阅读

史海拾趣

Chen Yang Technologies GmbH & Co KG公司的发展小趣事

Chen Yang Technologies最初是一家专注于半导体芯片研发的小型公司。在某个关键时期,公司成功研发出了一种低功耗、高性能的芯片技术,这一技术突破立即引起了市场的广泛关注。凭借这一技术,Chen Yang Technologies迅速扩大了其产品线,并开始向全球范围内的电子设备制造商供应芯片。随着市场份额的逐步增长,公司逐渐在电子行业中建立了自己的地位。

爱浦电子(AIPULNION)公司的发展小趣事

面对日益激烈的市场竞争,爱浦电子始终坚持创新驱动的发展战略。公司不断投入研发资金,引进先进技术和设备,推动产品创新和技术升级。同时,爱浦电子还积极探索新的应用领域和市场机会,拓展产品的应用范围。这些创新举措为公司未来的发展奠定了坚实的基础,也为整个电子行业的发展注入了新的活力。

Curtis Instruments Inc公司的发展小趣事

Curtis自成立以来,始终将创新作为公司的核心驱动力。公司每年将总收入的10%以上投资于研发,运营着四个研发中心,分别位于加利福尼亚、瑞士、纽约和中国。这些研发中心聚集了高度专业化的工程师和技术人员,专注于设计和开发适用于所有类型电动汽车的先进电机速度控制器等产品。正是这种持续的技术创新,使Curtis在电子行业中保持领先地位。

Aptina (ON Semiconductor)公司的发展小趣事

Aptina Imaging公司的起源可以追溯到其前身,一家专注于图像传感器技术的初创公司。在当时,随着数码相机的普及和消费者对图像质量要求的提高,图像传感器市场迎来了巨大的发展机遇。Aptina凭借其在图像捕捉和处理技术上的独特优势,迅速在市场中崭露头角。其创新的图像传感器产品不仅提升了相机的拍摄效果,还广泛应用于手机、安防监控等多个领域。

Force Technologies Ltd公司的发展小趣事

背景:随着业务的不断增长,Force Technologies Ltd意识到单一市场已无法满足其发展需求。于是,公司制定了明确的国际化战略,旨在将产品和技术推向全球。

发展:通过在欧洲、北美和亚洲等地设立研发中心和生产基地,Force Technologies Ltd成功构建起全球化的运营网络。同时,公司还积极参与国际展览和交流活动,不断提升品牌知名度和影响力。在国际市场的推动下,公司的销售额和市场份额均实现了快速增长。

Fukushima Futaba Electric Co Ltd公司的发展小趣事

随着技术的不断成熟和产品质量的提升,Futaba Electric开始将目光投向国际市场。20世纪70年代末至80年代初,公司成功进入欧美市场,与多家国际知名企业建立了合作关系。通过参加国际展会、设立海外分支机构等方式,Futaba Electric的产品逐渐在全球范围内得到推广和应用。这一时期,公司的国际化战略取得了显著成效,为公司的长远发展奠定了更加坚实的基础。

问答坊 | AI 解惑

被动电子元件

电子 初学者的 基础 基础决定高度…

查看全部问答>

全国大学生电子设计大赛历年题目

本帖最后由 paulhyde 于 2014-9-15 09:17 编辑 全国大学生电子设计大赛历年题目 分享吧  …

查看全部问答>

串行接口10位单通道A_D转换TLC1549中文数据资

本帖最后由 paulhyde 于 2014-9-15 04:12 编辑 供大家 参考  …

查看全部问答>

mc55休眠唤醒?

休眠采用AT+CFUN=7 在这MC55休眠唤醒采用的是硬件流控,但休眠后唤醒不了,怎么回事?(在这可以给CTS一个电平来唤醒不?) 除了这种外还有什么方法唤醒模块? …

查看全部问答>

文件系统的开发

我想自己做一个FAT32文件系统用于UCOS,请问哪里有源码和相关资料可以学习一下?…

查看全部问答>

nor flash nand flash问题大家指教。

现在马上要做一个东西,就是以前的板子上是nor+nand flash的方式,现在只用nand flash做uboot、kernel 文件系统。 请问我要怎样做,才能把uboot、kernel、文件系统都烧到只有nand flash的板子上并让他运行,并没问题。 请问我要怎么入手做这 ...…

查看全部问答>

iap使用问题

使用str711的iap功能向 flash bank1 写入数据 但是每次 执行写入 或者 清除片内内容时,系统都会重启,请问为何?…

查看全部问答>

iar5.40.7连接stm32f10xx问题

                                 我这有一个stm32f10xx的开发板,但是使用IAR5.40.7的开发软件,可是编译通过了,可无论如很都写不进flash,也无法 ...…

查看全部问答>

高价求芯片、电路设计,高手QQ1342451273

高价求芯片、电路设计,高手QQ1342451273…

查看全部问答>

请教一下,在沈阳做电路板制作有市场吗?

  请教一下大家,我想在沈阳开一个制作电路板的小店,主要是针对零散小批量的客户,利用雕刻机做,不知道有没有市场,需求量怎么样?有了解的朋友能不能给点建议。先谢谢大家了!…

查看全部问答>