版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
建立一個(gè)屬于自己的AVR的RTOS[1]建立一個(gè)屬于自己的AVR的RTOS[1]/NUMPAGES96建立一個(gè)屬于自己的AVR的RTOS[1]建立一個(gè)屬于自己的AVR的RTOS[1]建立一個(gè)屬于自己的AVR的RTOS自從03年以來(lái),對(duì)單片機(jī)的RTOS的學(xué)習(xí)和應(yīng)用的熱潮可謂一浪高過(guò)一浪.03年,在離開(kāi)校園前的,非典的那幾個(gè)月,在華師的后門(mén)那里買(mǎi)了本邵貝貝的《UCOSII》,通讀了幾次,沒(méi)有實(shí)驗(yàn)器材,也不了了之。在21IC上,大家都可以看到楊屹寫(xiě)的關(guān)于UCOSII在51上的移植,于是掀起了51上的RTOS的熱潮。再后來(lái),陳明計(jì)先生推出的smallrots,展示了一個(gè)用在51上的微內(nèi)核,足以在52上進(jìn)行任務(wù)調(diào)度。前段時(shí)間,在ouravr上面開(kāi)有專門(mén)關(guān)于AVR的Rtos的專欄,并且不少的兄弟把自己的作品拿出來(lái),著實(shí)開(kāi)了不少眼界。這時(shí),我重新回顧了使用單片機(jī)的經(jīng)歷,覺(jué)得很有必要,從根本上對(duì)單片機(jī)的RTOS的知識(shí)進(jìn)行整理,于是,我開(kāi)始了編寫(xiě)一個(gè)用在AVR單片機(jī)的RTOS。當(dāng)時(shí),我所有的知識(shí)和資源有:Proteus6.7可以用來(lái)模擬仿真avr系列的單片機(jī)mega81K的ram有8K的rom,是開(kāi)發(fā)8位的RTOS的一個(gè)理想的器件,并且我對(duì)它也比較熟悉。寫(xiě)UCOS的JeanJ.Labrosse在他的書(shū)上有這樣一句話,“漸漸地,我自然會(huì)想到,寫(xiě)個(gè)實(shí)時(shí)內(nèi)核直有那么難嗎?不就是不斷地保存,恢復(fù)CPU的那些寄存器嘛?!焙昧?,當(dāng)這一切準(zhǔn)備好后,我們就可以開(kāi)始我們的Rtosformega8的實(shí)驗(yàn)之旅了。本文列出的例子,全部完整可用。只需要一個(gè)文件就可以編譯了。我相信,只要適當(dāng)可用,最簡(jiǎn)單的就是最好的,這樣可以排除一些不必要的干擾,讓大家專注到每一個(gè)過(guò)程的學(xué)習(xí)。第一篇:函數(shù)的運(yùn)行在一般的單片機(jī)系統(tǒng)中,是以前后臺(tái)的方式(大循環(huán)+中斷)來(lái)處理數(shù)據(jù)和作出反應(yīng)的。例子如下:makefile的設(shè)定:運(yùn)行WinAvr中的Mfile,設(shè)定如下MCUType:mega8Optimizationlevel:sDebugformat:AVR-COFFC/C++sourcefile:選譯要編譯的C文件#include<avr/io.h>voidfun1(void){unsignedchari=0;while(1){PORTB=i++;PORTC=0x01<<(i%8);}}intmain(void){fun1();}首先,提出一個(gè)問(wèn)題:如果要調(diào)用一個(gè)函數(shù),真是只能以上面的方式進(jìn)行嗎?相信學(xué)習(xí)過(guò)C語(yǔ)言的各位會(huì)回答,No!我們還有一種方式,就是“用函數(shù)指針變量調(diào)用函數(shù)”,如果大家都和我一樣,當(dāng)初的教科書(shū)是譚浩強(qiáng)先生的《C程序設(shè)計(jì)》的話,請(qǐng)找回書(shū)的第9.5節(jié)。例子:用函數(shù)指針變量調(diào)用函數(shù)#include<avr/io.h>voidfun1(void){unsignedchari=0;while(1){PORTB=i++;PORTC=0x01<<(i%8);}}void(*pfun)();//指向函數(shù)的指針intmain(void){pfun=fun1;//(*pfun)();//運(yùn)行指針?biāo)赶虻暮瘮?shù)}第二種,是“把指向函數(shù)的指針變量作函數(shù)參數(shù)”#include<avr/io.h>voidfun1(void){unsignedchari=0;while(1){PORTB=i++;PORTC=0x01<<(i%8);}}voidRunFun(void(*pfun)())//獲得了要傳遞的函數(shù)的地址{(*pfun)();//在RunFun中,運(yùn)行指針?biāo)赶虻暮瘮?shù)}intmain(void){RunFun(fun1);//將函數(shù)的指針作為變量傳遞}看到上面的兩種方式,很多人可能會(huì)說(shuō),“這的確不錯(cuò)”,但是這樣與我們想要的RTOS,有什么關(guān)系呢?各位請(qǐng)細(xì)心向下看。以下是GCC對(duì)上面的代碼的編譯的情況:對(duì)main()中的RunFun(fun1);的編譯如下ldir24,lo8(pm(fun1))ldir25,hi8(pm(fun1))rcallRunFun對(duì)voidRunFun(void(*pfun)())的編譯如下/*voidRunFun(void(*pfun)())*//*(*pfun)();*/.LM6:movwr30,r24icallret在調(diào)用voidRunFun(void(*pfun)())的時(shí)候,的確可以把fun1的地址通過(guò)r24和r25傳遞給RunFun()。但是,RTOS如何才能有效地利用函數(shù)的地址呢?第二篇:人工堆棧在單片機(jī)的指令集中,一類(lèi)指令是專門(mén)與堆棧和PC指針打道的,它們是rcall相對(duì)調(diào)用子程序指令icall間接調(diào)用子程序指令ret子程序返回指令reti中斷返回指令對(duì)于ret和reti,它們都可以將堆棧棧頂?shù)膬蓚€(gè)字節(jié)被彈出來(lái)送入程序計(jì)數(shù)器PC中,一般用來(lái)從子程序或中斷中退出。其中reti還可以在退出中斷時(shí),重開(kāi)全局中斷使能。有了這個(gè)基礎(chǔ),就可以建立我們的人工堆棧了。例:#include<avr/io.h>voidfun1(void){unsignedchari=0;while(1){PORTB=i++;PORTC=0x01<<(i%8);}}unsignedcharStack[100];//建立一個(gè)100字節(jié)的人工堆棧voidRunFunInNewStack(void(*pfun)(),unsignedchar*pStack){*pStack--=(unsignedint)pfun>>8;//將函數(shù)的地址高位壓入堆棧,*pStack--=(unsignedint)pfun;//將函數(shù)的地址低位壓入堆棧,SP=pStack;//將堆棧指針指向人工堆棧的棧頂__asm____volatile__("RET\n\t");//返回并開(kāi)中斷,開(kāi)始運(yùn)行fun1()}intmain(void){RunFunInNewStack(fun1,&Stack[99]);}RunFunInNewStack(),將指向函數(shù)的指針的值保存到一個(gè)unsignedchar的數(shù)組Stack中,作為人工堆棧。并且將棧頂?shù)臄?shù)值傳遞組堆棧指針SP,因此當(dāng)用"ret"返回時(shí),從SP中恢復(fù)到PC中的值,就變?yōu)榱酥赶騠un1()的地址,開(kāi)始運(yùn)行fun1().上面例子中在RunFunInNewStack()的最后一句嵌入了匯編代碼"ret",實(shí)際上是可以去除的。因?yàn)樵赗unFunInNewStack()返回時(shí),編譯器已經(jīng)會(huì)加上"ret"。我特意寫(xiě)出來(lái),是為了讓大家看到用"ret"作為返回后運(yùn)行fun1()的過(guò)程。第三篇:GCC中對(duì)寄存器的分配與使用在很多用于AVR的RTOS中,都會(huì)有任務(wù)調(diào)度時(shí),插入以下的語(yǔ)句:入棧:__asm____volatile__("PUSHR0\n\t");__asm____volatile__("PUSHR1\n\t");__asm____volatile__("PUSHR31\n\t");出棧__asm____volatile__("POPR31\n\t");__asm____volatile__("POPR1\n\t");__asm____volatile__("POPR0\n\t");通常大家都會(huì)認(rèn)為,在任務(wù)調(diào)度開(kāi)始時(shí),當(dāng)然要將所有的通用寄存器都保存,并且還應(yīng)該保存程序狀態(tài)寄存器SREG。然后再根據(jù)相反的次序,將新任務(wù)的寄存器的內(nèi)容恢復(fù)。但是,事實(shí)真的是這樣嗎?如果大家看過(guò)陳明計(jì)先生寫(xiě)的smallrots51,就會(huì)發(fā)現(xiàn),它所保存的通用寄存器不過(guò)是4組通用寄存器中的1組。在WinAVR中的幫助文件avr-libcManual中的RelatedPages中的FrequentlyAskedQuestions,其實(shí)有一個(gè)問(wèn)題是"WhatregistersareusedbytheCcompiler?"回答了編譯器所需要占用的寄存器。一般情況下,編譯器會(huì)先用到以下寄存器1Call-usedregisters(r18-r27,r30-r31):調(diào)用函數(shù)時(shí)作為參數(shù)傳遞,也就是用得最多的寄存器。2Call-savedregisters(r2-r17,r28-r29):調(diào)用函數(shù)時(shí)作為結(jié)果傳遞,當(dāng)中的r28和r29可能會(huì)被作為指向堆棧上的變量的指針。3Fixedregisters(r0,r1):固定作用。r0用于存放臨時(shí)數(shù)據(jù),r1用于存放0。還有另一個(gè)問(wèn)題是"Howtopermanentlybindavariabletoaregister?",是將變量綁定到通用寄存器的方法。而且我發(fā)現(xiàn),如果將某個(gè)寄存器定義為變量,編譯器就會(huì)不將該寄存器分配作其它用途。這對(duì)RTOS是很重要的。在"InlineAsm"中的"CNamesUsedinAssemblerCode"明確表示,如果將太多的通用寄存器定義為變量,剛在編譯的過(guò)程中,被定義的變量依然可能被編譯器占用。大家可以比較以下兩個(gè)例子,看看編譯器產(chǎn)生的代碼:(在*.lst文件中)第一個(gè)例子:沒(méi)有定義通用寄存器為變量#include<avr/io.h>unsignedcharadd(unsignedcharb,unsignedcharc,unsignedchard){returnb+c*d;}intmain(void){unsignedchara=0;while(1){a++;PORTB=add(a,a,a);}}在本例中,"add(a,a,a);"被編譯如下:movr20,r28movr22,r28movr24,r28rcalladd第二個(gè)例子:定義通用寄存器為變量#include<avr/io.h>unsignedcharadd(unsignedcharb,unsignedcharc,unsignedchard){returnb+c*d;}registerunsignedcharaasm("r20");//將r20定義為變量aintmain(void){while(1){a++;PORTB=add(a,a,a);}}在本例中,"add(a,a,a);"被編譯如下:movr22,r20movr24,r20rcalladd當(dāng)然,在上面兩個(gè)例子中,有部份代碼被編譯器優(yōu)化了。通過(guò)反復(fù)測(cè)試,發(fā)現(xiàn)編譯器一般使用如下寄存器:第1類(lèi)寄存器,第2類(lèi)寄存器的r28,r29,第3類(lèi)寄存器如在中斷函數(shù)中有調(diào)用基它函數(shù),剛會(huì)在進(jìn)入中斷后,固定地將第1類(lèi)寄存器和第3類(lèi)寄存器入棧,在退出中斷又將它們出棧。第四篇:只有延時(shí)服務(wù)的協(xié)作式的內(nèi)核CooperativeMultitasking前后臺(tái)系統(tǒng),協(xié)作式內(nèi)核系統(tǒng),與占先式內(nèi)核系統(tǒng),有什么不同呢?記得在21IC上看過(guò)這樣的比喻,“你(小工)在用廁所,經(jīng)理在外面排第一,老板在外面排第二。如果是前后臺(tái),不管是誰(shuí),都必須按排隊(duì)的次序使用廁所;如果是協(xié)作式,那么可以等你用完廁所,老板就要比經(jīng)理先進(jìn)入;如果是占先式,只要有更高級(jí)的人在外面等,那么廁所里無(wú)論是誰(shuí),都要第一時(shí)間讓出來(lái),讓最高級(jí)別的人先用?!?include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[200];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運(yùn)行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運(yùn)行的任務(wù)#defineOS_TASKS3//設(shè)定運(yùn)行任務(wù)的數(shù)量structTaskCtrBlock//任務(wù)控制塊{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時(shí)時(shí)鐘}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");//建立任務(wù)voidOSTaskCreate(void(*Task)(void),unsignedchar*Stack,unsignedcharTaskID){unsignedchari;*Stack--=(unsignedint)Task>>8;//將任務(wù)的地址高位壓入堆棧,*Stack--=(unsignedint)Task;//將任務(wù)的地址低位壓入堆棧,*Stack--=0x00;//R1__zero_reg__*Stack--=0x00;//R0__tmp_reg__*Stack--=0x80;//SREG在任務(wù)中,開(kāi)啟全局中斷for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?*Stack--=i;//描述了寄存器的作用TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//將人工堆棧的棧頂,保存到堆棧的數(shù)組中OSRdyTbl|=0x01<<TaskID;//任務(wù)就緒表已經(jīng)準(zhǔn)備好}//開(kāi)始任務(wù)調(diào)度,從最低優(yōu)先級(jí)的任務(wù)的開(kāi)始voidOSStartTask(){OSTaskRunningPrio=OS_TASKS;SP=TCB[OS_TASKS].OSTaskStackTop+17;__asm____volatile__("reti""\n\t");}//進(jìn)行任務(wù)調(diào)度voidOSSched(void){//根據(jù)中斷時(shí)保存寄存器的次序入棧,模擬一次中斷后,入棧的情況__asm____volatile__("PUSH__zero_reg__\n\t");//R1__asm____volatile__("PUSH__tmp_reg__\n\t");//R0__asm____volatile__("IN__tmp_reg__,__SREG__\n\t");//保存狀態(tài)寄存器SREG__asm____volatile__("PUSH__tmp_reg__\n\t");__asm____volatile__("CLR__zero_reg__\n\t");//R0重新清零__asm____volatile__("PUSHR18\n\t");__asm____volatile__("PUSHR19\n\t");__asm____volatile__("PUSHR20\n\t");__asm____volatile__("PUSHR21\n\t");__asm____volatile__("PUSHR22\n\t");__asm____volatile__("PUSHR23\n\t");__asm____volatile__("PUSHR24\n\t");__asm____volatile__("PUSHR25\n\t");__asm____volatile__("PUSHR26\n\t");__asm____volatile__("PUSHR27\n\t");__asm____volatile__("PUSHR30\n\t");__asm____volatile__("PUSHR31\n\t");__asm____volatile__("PUSHR28\n\t");//R28與R29用于建立在堆棧上的指針__asm____volatile__("PUSHR29\n\t");//入棧完成TCB[OSTaskRunningPrio].OSTaskStackTop=SP;//將正在運(yùn)行的任務(wù)的堆棧底保存unsignedcharOSNextTaskID;//在現(xiàn)有堆棧上開(kāi)設(shè)新的空間for(OSNextTaskID=0;//進(jìn)行任務(wù)調(diào)度OSNextTaskID<OS_TASKS&&!(OSRdyTbl&(0x01<<OSNextTaskID));OSNextTaskID++);OSTaskRunningPrio=OSNextTaskID;cli();//保護(hù)堆棧轉(zhuǎn)換SP=TCB[OSTaskRunningPrio].OSTaskStackTop;sei();//根據(jù)中斷時(shí)的出棧次序__asm____volatile__("POPR29\n\t");__asm____volatile__("POPR28\n\t");__asm____volatile__("POPR31\n\t");__asm____volatile__("POPR30\n\t");__asm____volatile__("POPR27\n\t");__asm____volatile__("POPR26\n\t");__asm____volatile__("POPR25\n\t");__asm____volatile__("POPR24\n\t");__asm____volatile__("POPR23\n\t");__asm____volatile__("POPR22\n\t");__asm____volatile__("POPR21\n\t");__asm____volatile__("POPR20\n\t");__asm____volatile__("POPR19\n\t");__asm____volatile__("POPR18\n\t");__asm____volatile__("POP__tmp_reg__\n\t");//SERG出棧并恢復(fù)__asm____volatile__("OUT__SREG__,__tmp_reg__\n\t");//__asm____volatile__("POP__tmp_reg__\n\t");//R0出棧__asm____volatile__("POP__zero_reg__\n\t");//R1出棧//中斷時(shí)出棧完成}voidOSTimeDly(unsignedintticks){if(ticks)//當(dāng)延時(shí)有效{OSRdyTbl&=~(0x01<<OSTaskRunningPrio);TCB[OSTaskRunningPrio].OSWaitTick=ticks;OSSched();//從新調(diào)度}}voidTCN0Init(void)//計(jì)時(shí)器0{TCCR0=0;TCCR0|=(1<<CS02);//256預(yù)分頻TIMSK|=(1<<TOIE0);//T0溢出中斷允許TCNT0=100;//置計(jì)數(shù)起始值}SIGNAL(SIG_OVERFLOW0){unsignedchari;for(i=0;i<OS_TASKS;i++)//任務(wù)時(shí)鐘{if(TCB[i].OSWaitTick){TCB[i].OSWaitTick--;if(TCB[i].OSWaitTick==0)//當(dāng)任務(wù)時(shí)鐘到時(shí),必須是由定時(shí)器減時(shí)的才行{OSRdyTbl|=(0x01<<i);//使任務(wù)在就緒表中置位}}}TCNT0=100;}voidTask0(){unsignedintj=0;while(1){PORTB=j++;OSTimeDly(2);}}voidTask1(){unsignedintj=0;while(1){PORTC=j++;OSTimeDly(4);}}voidTask2(){unsignedintj=0;while(1){PORTD=j++;OSTimeDly(8);}}voidTaskScheduler(){while(1){OSSched();//反復(fù)進(jìn)行調(diào)度}}intmain(void){TCN0Init();OSRdyTbl=0;OSTaskRunningPrio=0;OSTaskCreate(Task0,&Stack[49],0);OSTaskCreate(Task1,&Stack[99],1);OSTaskCreate(Task2,&Stack[149],2);OSTaskCreate(TaskScheduler,&Stack[199],OS_TASKS);OSStartTask();}在上面的例子中,一切變得很簡(jiǎn)單,三個(gè)正在運(yùn)行的主任務(wù),都通過(guò)延時(shí)服務(wù),主動(dòng)放棄對(duì)CPU的控制權(quán)。在時(shí)間中斷中,對(duì)各個(gè)任務(wù)的的延時(shí)進(jìn)行計(jì)時(shí),如果某個(gè)任務(wù)的延時(shí)結(jié)束,將任務(wù)重新在就緒表中置位。最低級(jí)的系統(tǒng)任務(wù)TaskScheduler(),在三個(gè)主任務(wù)在放棄對(duì)CPU的控制權(quán)后開(kāi)始不斷地進(jìn)行調(diào)度。如果某個(gè)任務(wù)在就緒表中置位,通過(guò)調(diào)度,進(jìn)入最高級(jí)別的任務(wù)中繼續(xù)運(yùn)行。第五篇:完善的協(xié)作式的內(nèi)核現(xiàn)在為上面的協(xié)作式內(nèi)核添加一些OS中所必須的服務(wù):1掛起和重新運(yùn)行任務(wù)2信號(hào)量(在必要時(shí)候,可以擴(kuò)展成郵箱和信息隊(duì)列)3延時(shí)#include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[400];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運(yùn)行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運(yùn)行的任務(wù)#defineOS_TASKS3//設(shè)定運(yùn)行任務(wù)的數(shù)量structTaskCtrBlock{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時(shí)時(shí)鐘}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");//建立任務(wù)voidOSTaskCreate(void(*Task)(void),unsignedchar*Stack,unsignedcharTaskID){unsignedchari;*Stack--=(unsignedint)Task>>8;//將任務(wù)的地址高位壓入堆棧,*Stack--=(unsignedint)Task;//將任務(wù)的地址低位壓入堆棧,*Stack--=0x00;//R1__zero_reg__*Stack--=0x00;//R0__tmp_reg__*Stack--=0x80;//SREG在任務(wù)中,開(kāi)啟全局中斷for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?*Stack--=i;//描述了寄存器的作用TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//將人工堆棧的棧頂,保存到堆棧的數(shù)組中OSRdyTbl|=0x01<<TaskID;//任務(wù)就緒表已經(jīng)準(zhǔn)備好}//開(kāi)始任務(wù)調(diào)度,從最低優(yōu)先級(jí)的任務(wù)的開(kāi)始voidOSStartTask(){OSTaskRunningPrio=OS_TASKS;SP=TCB[OS_TASKS].OSTaskStackTop+17;__asm____volatile__("reti""\n\t");}//進(jìn)行任務(wù)調(diào)度voidOSSched(void){//根據(jù)中斷時(shí)保存寄存器的次序入棧,模擬一次中斷后,入棧的情況__asm____volatile__("PUSH__zero_reg__\n\t");//R1__asm____volatile__("PUSH__tmp_reg__\n\t");//R0__asm____volatile__("IN__tmp_reg__,__SREG__\n\t");//保存狀態(tài)寄存器SREG__asm____volatile__("PUSH__tmp_reg__\n\t");__asm____volatile__("CLR__zero_reg__\n\t");//R0重新清零__asm____volatile__("PUSHR18\n\t");__asm____volatile__("PUSHR19\n\t");__asm____volatile__("PUSHR20\n\t");__asm____volatile__("PUSHR21\n\t");__asm____volatile__("PUSHR22\n\t");__asm____volatile__("PUSHR23\n\t");__asm____volatile__("PUSHR24\n\t");__asm____volatile__("PUSHR25\n\t");__asm____volatile__("PUSHR26\n\t");__asm____volatile__("PUSHR27\n\t");__asm____volatile__("PUSHR30\n\t");__asm____volatile__("PUSHR31\n\t");__asm____volatile__("PUSHR28\n\t");//R28與R29用于建立在堆棧上的指針__asm____volatile__("PUSHR29\n\t");//入棧完成TCB[OSTaskRunningPrio].OSTaskStackTop=SP;//將正在運(yùn)行的任務(wù)的堆棧底保存unsignedcharOSNextTaskID;//在現(xiàn)有堆棧上開(kāi)設(shè)新的空間for(OSNextTaskID=0;//進(jìn)行任務(wù)調(diào)度OSNextTaskID<OS_TASKS&&!(OSRdyTbl&(0x01<<OSNextTaskID));OSNextTaskID++);OSTaskRunningPrio=OSNextTaskID;cli();//保護(hù)堆棧轉(zhuǎn)換SP=TCB[OSTaskRunningPrio].OSTaskStackTop;sei();//根據(jù)中斷時(shí)的出棧次序__asm____volatile__("POPR29\n\t");__asm____volatile__("POPR28\n\t");__asm____volatile__("POPR31\n\t");__asm____volatile__("POPR30\n\t");__asm____volatile__("POPR27\n\t");__asm____volatile__("POPR26\n\t");__asm____volatile__("POPR25\n\t");__asm____volatile__("POPR24\n\t");__asm____volatile__("POPR23\n\t");__asm____volatile__("POPR22\n\t");__asm____volatile__("POPR21\n\t");__asm____volatile__("POPR20\n\t");__asm____volatile__("POPR19\n\t");__asm____volatile__("POPR18\n\t");__asm____volatile__("POP__tmp_reg__\n\t");//SERG出棧并恢復(fù)__asm____volatile__("OUT__SREG__,__tmp_reg__\n\t");//__asm____volatile__("POP__tmp_reg__\n\t");//R0出棧__asm____volatile__("POP__zero_reg__\n\t");//R1出棧//中斷時(shí)出棧完成}////////////////////////////////////////////任務(wù)處理//掛起任務(wù)voidOSTaskSuspend(unsignedcharprio){TCB[prio].OSWaitTick=0;OSRdyTbl&=~(0x01<<prio);//從任務(wù)就緒表上去除標(biāo)志位if(OSTaskRunningPrio==prio)//當(dāng)要掛起的任務(wù)為當(dāng)前任務(wù)OSSched();//從新調(diào)度}//恢復(fù)任務(wù)可以讓被OSTaskSuspend或OSTimeDly暫停的任務(wù)恢復(fù)voidOSTaskResume(unsignedcharprio){OSRdyTbl|=0x01<<prio;//從任務(wù)就緒表上重置標(biāo)志位TCB[prio].OSWaitTick=0;//將時(shí)間計(jì)時(shí)設(shè)為0,到時(shí)if(OSTaskRunningPrio>prio)//當(dāng)要當(dāng)前任務(wù)的優(yōu)先級(jí)低于重置位的任務(wù)的優(yōu)先級(jí)OSSched();//從新調(diào)度//從新調(diào)度}//任務(wù)延時(shí)voidOSTimeDly(unsignedintticks){if(ticks)//當(dāng)延時(shí)有效{OSRdyTbl&=~(0x01<<OSTaskRunningPrio);TCB[OSTaskRunningPrio].OSWaitTick=ticks;OSSched();//從新調(diào)度}}//信號(hào)量structSemBlk{unsignedcharOSEventType;//型號(hào)0,信號(hào)量獨(dú)占型;1信號(hào)量共享型unsignedcharOSEventState;//狀態(tài)0,不可用;1,可用unsignedcharOSTaskPendTbl;//等待信號(hào)量的任務(wù)列表}Sem[10];//初始化信號(hào)量voidOSSemCreat(unsignedcharIndex,unsignedcharType){Sem[Index].OSEventType=Type;//型號(hào)0,信號(hào)量獨(dú)占型;1信號(hào)量共享型Sem[Index].OSTaskPendTbl=0;Sem[Index].OSEventState=0;}//任務(wù)等待信號(hào)量,掛起unsignedcharOSTaskSemPend(unsignedcharIndex,unsignedintTimeout){//unsignedchari=0;if(Sem[Index].OSEventState)//信號(hào)量有效{if(Sem[Index].OSEventType==0)//如果為獨(dú)占型Sem[Index].OSEventState=0x00;//信號(hào)量被獨(dú)占,不可用}else{//加入信號(hào)的任務(wù)等待表Sem[Index].OSTaskPendTbl|=0x01<<OSTaskRunningPrio;OSRdyTbl&=~(0x01<<OSTaskRunningPrio);//從任務(wù)就緒表中去除TCB[OSTaskRunningPrio].OSWaitTick=Timeout;//如延時(shí)為0,剛無(wú)限等待OSSched();//從新調(diào)度if(TCB[OSTaskRunningPrio].OSWaitTick==0)return0;}return1;}//發(fā)送一個(gè)信號(hào)量,可以從任務(wù)或中斷發(fā)送voidOSSemPost(unsignedcharIndex){if(Sem[Index].OSEventType)//當(dāng)要求的信號(hào)量是共享型{Sem[Index].OSEventState=0x01;//使信號(hào)量有效OSRdyTbl|=Sem[Index].OSTaskPendTbl;//使在等待該信號(hào)的所有任務(wù)就緒Sem[Index].OSTaskPendTbl=0;//清空所有等待該信號(hào)的等待任務(wù)}else//當(dāng)要求的信號(hào)量為獨(dú)占型{unsignedchari;for(i=0;i<OS_TASKS&&!(Sem[Index].OSTaskPendTbl&(0x01<<i));i++);if(i<OS_TASKS)//如果有任務(wù)需要{Sem[Index].OSTaskPendTbl&=~(0x01<<i);//從等待表中去除OSRdyTbl|=0x01<<i;//任務(wù)就緒}else{Sem[Index].OSEventState=1;//使信號(hào)量有效}}}//從任務(wù)發(fā)送一個(gè)信號(hào)量,并進(jìn)行調(diào)度voidOSTaskSemPost(unsignedcharIndex){OSSemPost(Index);OSSched();}//清除一個(gè)信號(hào)量,只對(duì)共享型的有用。//對(duì)于獨(dú)占型的信號(hào)量,在任務(wù)占用后,就交得不可以用了。voidOSSemClean(unsignedcharIndex){Sem[Index].OSEventState=0;//要求的信號(hào)量無(wú)效}voidTCN0Init(void)//計(jì)時(shí)器0{TCCR0=0;TCCR0|=(1<<CS02);//256預(yù)分頻TIMSK|=(1<<TOIE0);//T0溢出中斷允許TCNT0=100;//置計(jì)數(shù)起始值}SIGNAL(SIG_OVERFLOW0){unsignedchari;for(i=0;i<OS_TASKS;i++)//任務(wù)時(shí)鐘{if(TCB[i].OSWaitTick){TCB[i].OSWaitTick--;if(TCB[i].OSWaitTick==0)//當(dāng)任務(wù)時(shí)鐘到時(shí),必須是由定時(shí)器減時(shí)的才行{OSRdyTbl|=(0x01<<i);//使任務(wù)在就緒表中置位}}}TCNT0=100;}voidTask0(){unsignedintj=0;while(1){PORTB=j++;OSTaskSuspend(1);//掛起任務(wù)1OSTaskSemPost(0);OSTimeDly(50);OSTaskResume(1);//恢復(fù)任務(wù)1OSSemClean(0);OSTimeDly(50);}}voidTask1(){unsignedintj=0;while(1){PORTC=j++;OSTimeDly(5);}}voidTask2(){unsignedintj=0;while(1){OSTaskSemPend(0,10);PORTD=j++;OSTimeDly(5);}}voidTaskScheduler(){while(1){OSSched();//反復(fù)進(jìn)行調(diào)度}}intmain(void){TCN0Init();OSRdyTbl=0;OSSemCreat(0,1);//將信號(hào)量設(shè)為共享型OSTaskCreate(Task0,&Stack[99],0);OSTaskCreate(Task1,&Stack[199],1);OSTaskCreate(Task2,&Stack[299],2);OSTaskCreate(TaskScheduler,&Stack[399],OS_TASKS);OSStartTask();}第六篇:時(shí)間片輪番調(diào)度法的內(nèi)核Round-RobinSheduling時(shí)間片輪調(diào)法是非常有趣的。本篇中的例子,建立了3個(gè)任務(wù),任務(wù)沒(méi)有優(yōu)先級(jí),在時(shí)間中斷的調(diào)度下,每個(gè)任務(wù)都輪流運(yùn)行相同的時(shí)間。如果在內(nèi)核中沒(méi)有加入其它服務(wù),感覺(jué)上就好像是有三個(gè)大循環(huán)在同時(shí)運(yùn)行。本例只是提供了一個(gè)用時(shí)間中斷進(jìn)行調(diào)度的內(nèi)核,大家可以根據(jù)自己的需要,添加相應(yīng)的服務(wù)。要注意到:1,由于在時(shí)間中斷內(nèi)調(diào)用了任務(wù)切換函數(shù),因?yàn)樵谶M(jìn)入中斷時(shí),已經(jīng)將一系列的寄存器入棧。2,在中斷內(nèi)進(jìn)行調(diào)度,是直接通過(guò)"RJMPInt_OSSched"進(jìn)入任務(wù)切換和調(diào)度的,這是GCCAVR的一個(gè)特點(diǎn),為用C編寫(xiě)內(nèi)核提供了極大的方便。3,在閱讀代碼的同時(shí),請(qǐng)對(duì)照閱讀編譯器產(chǎn)生的*.lst文件,會(huì)對(duì)你理解例子有很大的幫助。#include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[400];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運(yùn)行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運(yùn)行的任務(wù)#defineOS_TASKS3//設(shè)定運(yùn)行任務(wù)的數(shù)量structTaskCtrBlock{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時(shí)時(shí)鐘}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");//建立任務(wù)voidOSTaskCreate(void(*Task)(void),unsignedchar*Stack,unsignedcharTaskID){unsignedchari;*Stack--=(unsignedint)Task>>8;//將任務(wù)的地址高位壓入堆棧,*Stack--=(unsignedint)Task;//將任務(wù)的地址低位壓入堆棧,*Stack--=0x00;//R1__zero_reg__*Stack--=0x00;//R0__tmp_reg__*Stack--=0x80;//SREG在任務(wù)中,開(kāi)啟全局中斷for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?*Stack--=i;//描述了寄存器的作用TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//將人工堆棧的棧頂,保存到堆棧的數(shù)組中OSRdyTbl|=0x01<<TaskID;//任務(wù)就緒表已經(jīng)準(zhǔn)備好}//開(kāi)始任務(wù)調(diào)度,從最低優(yōu)先級(jí)的任務(wù)的開(kāi)始voidOSStartTask(){OSTaskRunningPrio=OS_TASKS;SP=TCB[OS_TASKS].OSTaskStackTop+17;__asm____volatile__("reti""\n\t");}//進(jìn)行任務(wù)調(diào)度voidOSSched(void){//根據(jù)中斷時(shí)保存寄存器的次序入棧,模擬一次中斷后,入棧的情況__asm____volatile__("PUSH__zero_reg__\n\t");//R1__asm____volatile__("PUSH__tmp_reg__\n\t");//R0__asm____volatile__("IN__tmp_reg__,__SREG__\n\t");//保存狀態(tài)寄存器SREG__asm____volatile__("PUSH__tmp_reg__\n\t");__asm____volatile__("CLR__zero_reg__\n\t");//R0重新清零__asm____volatile__("PUSHR18\n\t");__asm____volatile__("PUSHR19\n\t");__asm____volatile__("PUSHR20\n\t");__asm____volatile__("PUSHR21\n\t");__asm____volatile__("PUSHR22\n\t");__asm____volatile__("PUSHR23\n\t");__asm____volatile__("PUSHR24\n\t");__asm____volatile__("PUSHR25\n\t");__asm____volatile__("PUSHR26\n\t");__asm____volatile__("PUSHR27\n\t");__asm____volatile__("PUSHR30\n\t");__asm____volatile__("PUSHR31\n\t");__asm____volatile__("Int_OSSched:\n\t");//當(dāng)中斷要求調(diào)度,直接進(jìn)入這里__asm____volatile__("PUSHR28\n\t");//R28與R29用于建立在堆棧上的指針__asm____volatile__("PUSHR29\n\t");//入棧完成TCB[OSTaskRunningPrio].OSTaskStackTop=SP;//將正在運(yùn)行的任務(wù)的堆棧底保存if(++OSTaskRunningPrio>=OS_TASKS)//輪流運(yùn)行各個(gè)任務(wù),沒(méi)有優(yōu)先級(jí)OSTaskRunningPrio=0;//cli();//保護(hù)堆棧轉(zhuǎn)換SP=TCB[OSTaskRunningPrio].OSTaskStackTop;//sei();//根據(jù)中斷時(shí)的出棧次序__asm____volatile__("POPR29\n\t");__asm____volatile__("POPR28\n\t");__asm____volatile__("POPR31\n\t");__asm____volatile__("POPR30\n\t");__asm____volatile__("POPR27\n\t");__asm____volatile__("POPR26\n\t");__asm____volatile__("POPR25\n\t");__asm____volatile__("POPR24\n\t");__asm____volatile__("POPR23\n\t");__asm____volatile__("POPR22\n\t");__asm____volatile__("POPR21\n\t");__asm____volatile__("POPR20\n\t");__asm____volatile__("POPR19\n\t");__asm____volatile__("POPR18\n\t");__asm____volatile__("POP__tmp_reg__\n\t");//SERG出棧并恢復(fù)__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__("RETI\n\t");//返回并開(kāi)中斷//中斷時(shí)出棧完成}voidIntSwitch(void){__asm____volatile__("POPR31\n\t");//去除因調(diào)用子程序而入棧的PC__asm____volatile__("POPR31\n\t");__asm____volatile__("RJMPInt_OSSched\n\t");//重新調(diào)度}voidTCN0Init(void)//計(jì)時(shí)器0{TCCR0=0;TCCR0|=(1<<CS02);//256預(yù)分頻TIMSK|=(1<<TOIE0);//T0溢出中斷允許TCNT0=100;//置計(jì)數(shù)起始值}SIGNAL(SIG_OVERFLOW0){TCNT0=100;IntSwitch();//任務(wù)調(diào)度}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();//反復(fù)進(jìn)行調(diào)度}}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();}第七篇:占先式內(nèi)核(只帶延時(shí)服務(wù))PreemptiveMultitasking當(dāng)大家理解時(shí)間片輪番調(diào)度法的任務(wù)調(diào)度方式后,占先式的內(nèi)核的原理,已經(jīng)伸手可及了。先想想,占先式內(nèi)核是在什么地方實(shí)現(xiàn)任務(wù)調(diào)度的呢?對(duì)了,它在可以在任務(wù)中進(jìn)行調(diào)度,這個(gè)在協(xié)作式的內(nèi)核中已經(jīng)做到了;同時(shí),它也可以在中斷結(jié)束后進(jìn)行調(diào)度,這個(gè)問(wèn)題,已經(jīng)在時(shí)間片輪番調(diào)度法中已經(jīng)做到了。由于中斷是可以嵌套的,只有當(dāng)各層嵌套中要求調(diào)度,并且中斷嵌套返回到最初進(jìn)入的中斷的那一層時(shí),才能進(jìn)行任務(wù)調(diào)度。#include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[400];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運(yùn)行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運(yùn)行的任務(wù)registerunsignedcharIntNumasm("r4");//中斷嵌套計(jì)數(shù)器//只有當(dāng)中斷嵌套數(shù)為0,并且有中斷要求時(shí),才能在退出中斷時(shí),進(jìn)行任務(wù)調(diào)度registerunsignedcharOSCoreStateasm("r16");//系統(tǒng)核心標(biāo)志位,R16編譯器沒(méi)有使用//只有大于R15的寄存器才能直接賦值例LDIR16,0x01//0x01正在任務(wù)切換0x02有中斷要求切換#defineOS_TASKS3//設(shè)定運(yùn)行任務(wù)的數(shù)量structTaskCtrBlock{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時(shí)時(shí)鐘}TCB[OS_TASKS+1];//防止被編譯器占用//registerunsignedchartempR4asm("r4");registerunsignedchartempR5asm("r5");registerunsignedchartempR6asm("r6");registerunsignedchartempR7asm("r7");registerunsignedchartempR8asm("r8");registerunsignedchartempR9asm("r9");registerunsignedchartempR10asm("r10");registerunsignedchartempR11asm("r11");registerunsignedchartem
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 行業(yè)趨勢(shì)研究與應(yīng)對(duì)措施計(jì)劃
- 2024微信小程序技術(shù)支持與維護(hù)服務(wù)合同3篇
- 2024年綠色建筑綠化景觀維護(hù)驗(yàn)收合同3篇
- 2024年度學(xué)生交通安全責(zé)任承諾協(xié)議6篇
- 零售店鋪設(shè)計(jì)師的產(chǎn)品展示與空間布局
- 體育行業(yè)人才選拔實(shí)踐探討
- 教育行業(yè)課程設(shè)計(jì)培訓(xùn)總結(jié)
- 心血管科護(hù)士工作總結(jié)
- 紡織行業(yè)銷(xiāo)售工作總結(jié)
- 法律知識(shí)學(xué)習(xí)總結(jié)
- 缺血性腸病完整版本課件
- 汽車(chē)起重機(jī)基本結(jié)構(gòu)、工作原理課件
- ××領(lǐng)導(dǎo)班子及成員分析研判報(bào)告(模板)
- 08S305-小型潛水泵選用及安裝圖集
- 視頻監(jiān)控室值班記錄表
- 四川2020版清單定額
- 教材編寫(xiě)工作總結(jié)
- 企業(yè)員工上下班交通安全培訓(xùn)(簡(jiǎn)詳共2份)
- 城市高密度建成區(qū)合流制溢流污染系統(tǒng)研究-黃孝河機(jī)場(chǎng)河水環(huán)境綜合治理項(xiàng)目實(shí)踐
- word 公章 模板
- T∕ZSQX 008-2020 建設(shè)工程全過(guò)程質(zhì)量行為導(dǎo)則
評(píng)論
0/150
提交評(píng)論