




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
建立一個屬于自己的AVR的RTOS[1]建立一個屬于自己的AVR的RTOS[1]/NUMPAGES96建立一個屬于自己的AVR的RTOS[1]建立一個屬于自己的AVR的RTOS[1]建立一個屬于自己的AVR的RTOS自從03年以來,對單片機的RTOS的學習和應用的熱潮可謂一浪高過一浪.03年,在離開校園前的,非典的那幾個月,在華師的后門那里買了本邵貝貝的《UCOSII》,通讀了幾次,沒有實驗器材,也不了了之。在21IC上,大家都可以看到楊屹寫的關(guān)于UCOSII在51上的移植,于是掀起了51上的RTOS的熱潮。再后來,陳明計先生推出的smallrots,展示了一個用在51上的微內(nèi)核,足以在52上進行任務(wù)調(diào)度。前段時間,在ouravr上面開有專門關(guān)于AVR的Rtos的專欄,并且不少的兄弟把自己的作品拿出來,著實開了不少眼界。這時,我重新回顧了使用單片機的經(jīng)歷,覺得很有必要,從根本上對單片機的RTOS的知識進行整理,于是,我開始了編寫一個用在AVR單片機的RTOS。當時,我所有的知識和資源有:Proteus6.7可以用來模擬仿真avr系列的單片機mega81K的ram有8K的rom,是開發(fā)8位的RTOS的一個理想的器件,并且我對它也比較熟悉。寫UCOS的JeanJ.Labrosse在他的書上有這樣一句話,“漸漸地,我自然會想到,寫個實時內(nèi)核直有那么難嗎?不就是不斷地保存,恢復CPU的那些寄存器嘛。”好了,當這一切準備好后,我們就可以開始我們的Rtosformega8的實驗之旅了。本文列出的例子,全部完整可用。只需要一個文件就可以編譯了。我相信,只要適當可用,最簡單的就是最好的,這樣可以排除一些不必要的干擾,讓大家專注到每一個過程的學習。第一篇:函數(shù)的運行在一般的單片機系統(tǒng)中,是以前后臺的方式(大循環(huán)+中斷)來處理數(shù)據(jù)和作出反應的。例子如下:makefile的設(shè)定:運行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();}首先,提出一個問題:如果要調(diào)用一個函數(shù),真是只能以上面的方式進行嗎?相信學習過C語言的各位會回答,No!我們還有一種方式,就是“用函數(shù)指針變量調(diào)用函數(shù)”,如果大家都和我一樣,當初的教科書是譚浩強先生的《C程序設(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)();//運行指針所指向的函數(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中,運行指針所指向的函數(shù)}intmain(void){RunFun(fun1);//將函數(shù)的指針作為變量傳遞}看到上面的兩種方式,很多人可能會說,“這的確不錯”,但是這樣與我們想要的RTOS,有什么關(guān)系呢?各位請細心向下看。以下是GCC對上面的代碼的編譯的情況:對main()中的RunFun(fun1);的編譯如下ldir24,lo8(pm(fun1))ldir25,hi8(pm(fun1))rcallRunFun對voidRunFun(void(*pfun)())的編譯如下/*voidRunFun(void(*pfun)())*//*(*pfun)();*/.LM6:movwr30,r24icallret在調(diào)用voidRunFun(void(*pfun)())的時候,的確可以把fun1的地址通過r24和r25傳遞給RunFun()。但是,RTOS如何才能有效地利用函數(shù)的地址呢?第二篇:人工堆棧在單片機的指令集中,一類指令是專門與堆棧和PC指針打道的,它們是rcall相對調(diào)用子程序指令icall間接調(diào)用子程序指令ret子程序返回指令reti中斷返回指令對于ret和reti,它們都可以將堆棧棧頂?shù)膬蓚€字節(jié)被彈出來送入程序計數(shù)器PC中,一般用來從子程序或中斷中退出。其中reti還可以在退出中斷時,重開全局中斷使能。有了這個基礎(chǔ),就可以建立我們的人工堆棧了。例:#include<avr/io.h>voidfun1(void){unsignedchari=0;while(1){PORTB=i++;PORTC=0x01<<(i%8);}}unsignedcharStack[100];//建立一個100字節(jié)的人工堆棧voidRunFunInNewStack(void(*pfun)(),unsignedchar*pStack){*pStack--=(unsignedint)pfun>>8;//將函數(shù)的地址高位壓入堆棧,*pStack--=(unsignedint)pfun;//將函數(shù)的地址低位壓入堆棧,SP=pStack;//將堆棧指針指向人工堆棧的棧頂__asm____volatile__("RET\n\t");//返回并開中斷,開始運行fun1()}intmain(void){RunFunInNewStack(fun1,&Stack[99]);}RunFunInNewStack(),將指向函數(shù)的指針的值保存到一個unsignedchar的數(shù)組Stack中,作為人工堆棧。并且將棧頂?shù)臄?shù)值傳遞組堆棧指針SP,因此當用"ret"返回時,從SP中恢復到PC中的值,就變?yōu)榱酥赶騠un1()的地址,開始運行fun1().上面例子中在RunFunInNewStack()的最后一句嵌入了匯編代碼"ret",實際上是可以去除的。因為在RunFunInNewStack()返回時,編譯器已經(jīng)會加上"ret"。我特意寫出來,是為了讓大家看到用"ret"作為返回后運行fun1()的過程。第三篇:GCC中對寄存器的分配與使用在很多用于AVR的RTOS中,都會有任務(wù)調(diào)度時,插入以下的語句:入棧:__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");通常大家都會認為,在任務(wù)調(diào)度開始時,當然要將所有的通用寄存器都保存,并且還應該保存程序狀態(tài)寄存器SREG。然后再根據(jù)相反的次序,將新任務(wù)的寄存器的內(nèi)容恢復。但是,事實真的是這樣嗎?如果大家看過陳明計先生寫的smallrots51,就會發(fā)現(xiàn),它所保存的通用寄存器不過是4組通用寄存器中的1組。在WinAVR中的幫助文件avr-libcManual中的RelatedPages中的FrequentlyAskedQuestions,其實有一個問題是"WhatregistersareusedbytheCcompiler?"回答了編譯器所需要占用的寄存器。一般情況下,編譯器會先用到以下寄存器1Call-usedregisters(r18-r27,r30-r31):調(diào)用函數(shù)時作為參數(shù)傳遞,也就是用得最多的寄存器。2Call-savedregisters(r2-r17,r28-r29):調(diào)用函數(shù)時作為結(jié)果傳遞,當中的r28和r29可能會被作為指向堆棧上的變量的指針。3Fixedregisters(r0,r1):固定作用。r0用于存放臨時數(shù)據(jù),r1用于存放0。還有另一個問題是"Howtopermanentlybindavariabletoaregister?",是將變量綁定到通用寄存器的方法。而且我發(fā)現(xiàn),如果將某個寄存器定義為變量,編譯器就會不將該寄存器分配作其它用途。這對RTOS是很重要的。在"InlineAsm"中的"CNamesUsedinAssemblerCode"明確表示,如果將太多的通用寄存器定義為變量,剛在編譯的過程中,被定義的變量依然可能被編譯器占用。大家可以比較以下兩個例子,看看編譯器產(chǎn)生的代碼:(在*.lst文件中)第一個例子:沒有定義通用寄存器為變量#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第二個例子:定義通用寄存器為變量#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當然,在上面兩個例子中,有部份代碼被編譯器優(yōu)化了。通過反復測試,發(fā)現(xiàn)編譯器一般使用如下寄存器:第1類寄存器,第2類寄存器的r28,r29,第3類寄存器如在中斷函數(shù)中有調(diào)用基它函數(shù),剛會在進入中斷后,固定地將第1類寄存器和第3類寄存器入棧,在退出中斷又將它們出棧。第四篇:只有延時服務(wù)的協(xié)作式的內(nèi)核CooperativeMultitasking前后臺系統(tǒng),協(xié)作式內(nèi)核系統(tǒng),與占先式內(nèi)核系統(tǒng),有什么不同呢?記得在21IC上看過這樣的比喻,“你(小工)在用廁所,經(jīng)理在外面排第一,老板在外面排第二。如果是前后臺,不管是誰,都必須按排隊的次序使用廁所;如果是協(xié)作式,那么可以等你用完廁所,老板就要比經(jīng)理先進入;如果是占先式,只要有更高級的人在外面等,那么廁所里無論是誰,都要第一時間讓出來,讓最高級別的人先用?!?include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[200];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運行的任務(wù)#defineOS_TASKS3//設(shè)定運行任務(wù)的數(shù)量structTaskCtrBlock//任務(wù)控制塊{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時時鐘}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ù)中,開啟全局中斷for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?*Stack--=i;//描述了寄存器的作用TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//將人工堆棧的棧頂,保存到堆棧的數(shù)組中OSRdyTbl|=0x01<<TaskID;//任務(wù)就緒表已經(jīng)準備好}//開始任務(wù)調(diào)度,從最低優(yōu)先級的任務(wù)的開始voidOSStartTask(){OSTaskRunningPrio=OS_TASKS;SP=TCB[OS_TASKS].OSTaskStackTop+17;__asm____volatile__("reti""\n\t");}//進行任務(wù)調(diào)度voidOSSched(void){//根據(jù)中斷時保存寄存器的次序入棧,模擬一次中斷后,入棧的情況__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;//將正在運行的任務(wù)的堆棧底保存unsignedcharOSNextTaskID;//在現(xiàn)有堆棧上開設(shè)新的空間for(OSNextTaskID=0;//進行任務(wù)調(diào)度OSNextTaskID<OS_TASKS&&!(OSRdyTbl&(0x01<<OSNextTaskID));OSNextTaskID++);OSTaskRunningPrio=OSNextTaskID;cli();//保護堆棧轉(zhuǎn)換SP=TCB[OSTaskRunningPrio].OSTaskStackTop;sei();//根據(jù)中斷時的出棧次序__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出棧并恢復__asm____volatile__("OUT__SREG__,__tmp_reg__\n\t");//__asm____volatile__("POP__tmp_reg__\n\t");//R0出棧__asm____volatile__("POP__zero_reg__\n\t");//R1出棧//中斷時出棧完成}voidOSTimeDly(unsignedintticks){if(ticks)//當延時有效{OSRdyTbl&=~(0x01<<OSTaskRunningPrio);TCB[OSTaskRunningPrio].OSWaitTick=ticks;OSSched();//從新調(diào)度}}voidTCN0Init(void)//計時器0{TCCR0=0;TCCR0|=(1<<CS02);//256預分頻TIMSK|=(1<<TOIE0);//T0溢出中斷允許TCNT0=100;//置計數(shù)起始值}SIGNAL(SIG_OVERFLOW0){unsignedchari;for(i=0;i<OS_TASKS;i++)//任務(wù)時鐘{if(TCB[i].OSWaitTick){TCB[i].OSWaitTick--;if(TCB[i].OSWaitTick==0)//當任務(wù)時鐘到時,必須是由定時器減時的才行{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();//反復進行調(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();}在上面的例子中,一切變得很簡單,三個正在運行的主任務(wù),都通過延時服務(wù),主動放棄對CPU的控制權(quán)。在時間中斷中,對各個任務(wù)的的延時進行計時,如果某個任務(wù)的延時結(jié)束,將任務(wù)重新在就緒表中置位。最低級的系統(tǒng)任務(wù)TaskScheduler(),在三個主任務(wù)在放棄對CPU的控制權(quán)后開始不斷地進行調(diào)度。如果某個任務(wù)在就緒表中置位,通過調(diào)度,進入最高級別的任務(wù)中繼續(xù)運行。第五篇:完善的協(xié)作式的內(nèi)核現(xiàn)在為上面的協(xié)作式內(nèi)核添加一些OS中所必須的服務(wù):1掛起和重新運行任務(wù)2信號量(在必要時候,可以擴展成郵箱和信息隊列)3延時#include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[400];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運行的任務(wù)#defineOS_TASKS3//設(shè)定運行任務(wù)的數(shù)量structTaskCtrBlock{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時時鐘}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ù)中,開啟全局中斷for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?*Stack--=i;//描述了寄存器的作用TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//將人工堆棧的棧頂,保存到堆棧的數(shù)組中OSRdyTbl|=0x01<<TaskID;//任務(wù)就緒表已經(jīng)準備好}//開始任務(wù)調(diào)度,從最低優(yōu)先級的任務(wù)的開始voidOSStartTask(){OSTaskRunningPrio=OS_TASKS;SP=TCB[OS_TASKS].OSTaskStackTop+17;__asm____volatile__("reti""\n\t");}//進行任務(wù)調(diào)度voidOSSched(void){//根據(jù)中斷時保存寄存器的次序入棧,模擬一次中斷后,入棧的情況__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;//將正在運行的任務(wù)的堆棧底保存unsignedcharOSNextTaskID;//在現(xiàn)有堆棧上開設(shè)新的空間for(OSNextTaskID=0;//進行任務(wù)調(diào)度OSNextTaskID<OS_TASKS&&!(OSRdyTbl&(0x01<<OSNextTaskID));OSNextTaskID++);OSTaskRunningPrio=OSNextTaskID;cli();//保護堆棧轉(zhuǎn)換SP=TCB[OSTaskRunningPrio].OSTaskStackTop;sei();//根據(jù)中斷時的出棧次序__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出棧并恢復__asm____volatile__("OUT__SREG__,__tmp_reg__\n\t");//__asm____volatile__("POP__tmp_reg__\n\t");//R0出棧__asm____volatile__("POP__zero_reg__\n\t");//R1出棧//中斷時出棧完成}////////////////////////////////////////////任務(wù)處理//掛起任務(wù)voidOSTaskSuspend(unsignedcharprio){TCB[prio].OSWaitTick=0;OSRdyTbl&=~(0x01<<prio);//從任務(wù)就緒表上去除標志位if(OSTaskRunningPrio==prio)//當要掛起的任務(wù)為當前任務(wù)OSSched();//從新調(diào)度}//恢復任務(wù)可以讓被OSTaskSuspend或OSTimeDly暫停的任務(wù)恢復voidOSTaskResume(unsignedcharprio){OSRdyTbl|=0x01<<prio;//從任務(wù)就緒表上重置標志位TCB[prio].OSWaitTick=0;//將時間計時設(shè)為0,到時if(OSTaskRunningPrio>prio)//當要當前任務(wù)的優(yōu)先級低于重置位的任務(wù)的優(yōu)先級OSSched();//從新調(diào)度//從新調(diào)度}//任務(wù)延時voidOSTimeDly(unsignedintticks){if(ticks)//當延時有效{OSRdyTbl&=~(0x01<<OSTaskRunningPrio);TCB[OSTaskRunningPrio].OSWaitTick=ticks;OSSched();//從新調(diào)度}}//信號量structSemBlk{unsignedcharOSEventType;//型號0,信號量獨占型;1信號量共享型unsignedcharOSEventState;//狀態(tài)0,不可用;1,可用unsignedcharOSTaskPendTbl;//等待信號量的任務(wù)列表}Sem[10];//初始化信號量voidOSSemCreat(unsignedcharIndex,unsignedcharType){Sem[Index].OSEventType=Type;//型號0,信號量獨占型;1信號量共享型Sem[Index].OSTaskPendTbl=0;Sem[Index].OSEventState=0;}//任務(wù)等待信號量,掛起unsignedcharOSTaskSemPend(unsignedcharIndex,unsignedintTimeout){//unsignedchari=0;if(Sem[Index].OSEventState)//信號量有效{if(Sem[Index].OSEventType==0)//如果為獨占型Sem[Index].OSEventState=0x00;//信號量被獨占,不可用}else{//加入信號的任務(wù)等待表Sem[Index].OSTaskPendTbl|=0x01<<OSTaskRunningPrio;OSRdyTbl&=~(0x01<<OSTaskRunningPrio);//從任務(wù)就緒表中去除TCB[OSTaskRunningPrio].OSWaitTick=Timeout;//如延時為0,剛無限等待OSSched();//從新調(diào)度if(TCB[OSTaskRunningPrio].OSWaitTick==0)return0;}return1;}//發(fā)送一個信號量,可以從任務(wù)或中斷發(fā)送voidOSSemPost(unsignedcharIndex){if(Sem[Index].OSEventType)//當要求的信號量是共享型{Sem[Index].OSEventState=0x01;//使信號量有效OSRdyTbl|=Sem[Index].OSTaskPendTbl;//使在等待該信號的所有任務(wù)就緒Sem[Index].OSTaskPendTbl=0;//清空所有等待該信號的等待任務(wù)}else//當要求的信號量為獨占型{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;//使信號量有效}}}//從任務(wù)發(fā)送一個信號量,并進行調(diào)度voidOSTaskSemPost(unsignedcharIndex){OSSemPost(Index);OSSched();}//清除一個信號量,只對共享型的有用。//對于獨占型的信號量,在任務(wù)占用后,就交得不可以用了。voidOSSemClean(unsignedcharIndex){Sem[Index].OSEventState=0;//要求的信號量無效}voidTCN0Init(void)//計時器0{TCCR0=0;TCCR0|=(1<<CS02);//256預分頻TIMSK|=(1<<TOIE0);//T0溢出中斷允許TCNT0=100;//置計數(shù)起始值}SIGNAL(SIG_OVERFLOW0){unsignedchari;for(i=0;i<OS_TASKS;i++)//任務(wù)時鐘{if(TCB[i].OSWaitTick){TCB[i].OSWaitTick--;if(TCB[i].OSWaitTick==0)//當任務(wù)時鐘到時,必須是由定時器減時的才行{OSRdyTbl|=(0x01<<i);//使任務(wù)在就緒表中置位}}}TCNT0=100;}voidTask0(){unsignedintj=0;while(1){PORTB=j++;OSTaskSuspend(1);//掛起任務(wù)1OSTaskSemPost(0);OSTimeDly(50);OSTaskResume(1);//恢復任務(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();//反復進行調(diào)度}}intmain(void){TCN0Init();OSRdyTbl=0;OSSemCreat(0,1);//將信號量設(shè)為共享型OSTaskCreate(Task0,&Stack[99],0);OSTaskCreate(Task1,&Stack[199],1);OSTaskCreate(Task2,&Stack[299],2);OSTaskCreate(TaskScheduler,&Stack[399],OS_TASKS);OSStartTask();}第六篇:時間片輪番調(diào)度法的內(nèi)核Round-RobinSheduling時間片輪調(diào)法是非常有趣的。本篇中的例子,建立了3個任務(wù),任務(wù)沒有優(yōu)先級,在時間中斷的調(diào)度下,每個任務(wù)都輪流運行相同的時間。如果在內(nèi)核中沒有加入其它服務(wù),感覺上就好像是有三個大循環(huán)在同時運行。本例只是提供了一個用時間中斷進行調(diào)度的內(nèi)核,大家可以根據(jù)自己的需要,添加相應的服務(wù)。要注意到:1,由于在時間中斷內(nèi)調(diào)用了任務(wù)切換函數(shù),因為在進入中斷時,已經(jīng)將一系列的寄存器入棧。2,在中斷內(nèi)進行調(diào)度,是直接通過"RJMPInt_OSSched"進入任務(wù)切換和調(diào)度的,這是GCCAVR的一個特點,為用C編寫內(nèi)核提供了極大的方便。3,在閱讀代碼的同時,請對照閱讀編譯器產(chǎn)生的*.lst文件,會對你理解例子有很大的幫助。#include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[400];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運行的任務(wù)#defineOS_TASKS3//設(shè)定運行任務(wù)的數(shù)量structTaskCtrBlock{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時時鐘}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ù)中,開啟全局中斷for(i=0;i<14;i++)//在avr-libc中的FAQ中的WhatregistersareusedbytheCcompiler?*Stack--=i;//描述了寄存器的作用TCB[TaskID].OSTaskStackTop=(unsignedint)Stack;//將人工堆棧的棧頂,保存到堆棧的數(shù)組中OSRdyTbl|=0x01<<TaskID;//任務(wù)就緒表已經(jīng)準備好}//開始任務(wù)調(diào)度,從最低優(yōu)先級的任務(wù)的開始voidOSStartTask(){OSTaskRunningPrio=OS_TASKS;SP=TCB[OS_TASKS].OSTaskStackTop+17;__asm____volatile__("reti""\n\t");}//進行任務(wù)調(diào)度voidOSSched(void){//根據(jù)中斷時保存寄存器的次序入棧,模擬一次中斷后,入棧的情況__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");//當中斷要求調(diào)度,直接進入這里__asm____volatile__("PUSHR28\n\t");//R28與R29用于建立在堆棧上的指針__asm____volatile__("PUSHR29\n\t");//入棧完成TCB[OSTaskRunningPrio].OSTaskStackTop=SP;//將正在運行的任務(wù)的堆棧底保存if(++OSTaskRunningPrio>=OS_TASKS)//輪流運行各個任務(wù),沒有優(yōu)先級OSTaskRunningPrio=0;//cli();//保護堆棧轉(zhuǎn)換SP=TCB[OSTaskRunningPrio].OSTaskStackTop;//sei();//根據(jù)中斷時的出棧次序__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出棧并恢復__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");//返回并開中斷//中斷時出棧完成}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)//計時器0{TCCR0=0;TCCR0|=(1<<CS02);//256預分頻TIMSK|=(1<<TOIE0);//T0溢出中斷允許TCNT0=100;//置計數(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();//反復進行調(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)核(只帶延時服務(wù))PreemptiveMultitasking當大家理解時間片輪番調(diào)度法的任務(wù)調(diào)度方式后,占先式的內(nèi)核的原理,已經(jīng)伸手可及了。先想想,占先式內(nèi)核是在什么地方實現(xiàn)任務(wù)調(diào)度的呢?對了,它在可以在任務(wù)中進行調(diào)度,這個在協(xié)作式的內(nèi)核中已經(jīng)做到了;同時,它也可以在中斷結(jié)束后進行調(diào)度,這個問題,已經(jīng)在時間片輪番調(diào)度法中已經(jīng)做到了。由于中斷是可以嵌套的,只有當各層嵌套中要求調(diào)度,并且中斷嵌套返回到最初進入的中斷的那一層時,才能進行任務(wù)調(diào)度。#include<avr/io.h>#include<avr/Interrupt.h>#include<avr/signal.h>unsignedcharStack[400];registerunsignedcharOSRdyTblasm("r2");//任務(wù)運行就緒表registerunsignedcharOSTaskRunningPrioasm("r3");//正在運行的任務(wù)registerunsignedcharIntNumasm("r4");//中斷嵌套計數(shù)器//只有當中斷嵌套數(shù)為0,并且有中斷要求時,才能在退出中斷時,進行任務(wù)調(diào)度registerunsignedcharOSCoreStateasm("r16");//系統(tǒng)核心標志位,R16編譯器沒有使用//只有大于R15的寄存器才能直接賦值例LDIR16,0x01//0x01正在任務(wù)切換0x02有中斷要求切換#defineOS_TASKS3//設(shè)定運行任務(wù)的數(shù)量structTaskCtrBlock{unsignedintOSTaskStackTop;//保存任務(wù)的堆棧頂unsignedintOSWaitTick;//任務(wù)延時時鐘}TCB[OS_TASKS+1];//防止被編譯器占用//registerunsignedchartempR4asm("r4");registerunsignedchartempR5asm("r5");registerunsignedchartempR6asm("r6");registerunsignedchartempR7asm("r7");registerunsignedchartempR8asm("r8");registerunsignedchartempR9asm("r9");registerunsignedchartempR10asm("r10");registerunsignedchartempR11asm("r11");registerunsignedchartem
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 預防小孩生病
- (高清版)DB12 046.54-2011 產(chǎn)品單位產(chǎn)量綜合能耗計算方法及限額 第54部分:齒輪機床
- 2019年遼寧省錦州市中考歷史試題(解析)
- 直播策劃與運營實務(wù)(第二版) 課件 項目八任務(wù)二直播間客服工作客服配合
- 五年級數(shù)學(小數(shù)乘除法)計算題專項練習及答案匯編
- 三年級數(shù)學計算題專項練習匯編及答案
- 分析汽車轉(zhuǎn)向系統(tǒng)滯回對駕駛體驗
- 電子產(chǎn)品焊接助焊劑使用
- 有機垃圾堆肥化處理指南
- 辦公技能提升月活動計劃書
- 國家基本公共衛(wèi)生服務(wù)項目培訓課件
- 《民法》全冊精講課件
- 國際象棋入門教學課件
- 食品公司電商部門組織架構(gòu)
- 母線槽安裝檢驗批質(zhì)量驗收記錄
- 管道開挖施工方案修復
- 高速公路工程質(zhì)量管理體系及保證措施
- 菠菜色素提取和分離
- 中鐵工程項目內(nèi)部控制管理手冊(492頁)
- 氣瓶充裝安全及培訓課件PPT幻燈片
- 防雷檢測專業(yè)技術(shù)人員能力認定考試題庫完整
評論
0/150
提交評論