在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 建立一個(gè)屬于自己的AVR的RTOS

            建立一個(gè)屬于自己的AVR的RTOS

            作者: 時(shí)間:2011-04-29 來(lái)源:網(wǎng)絡(luò) 收藏

            自從03年以來(lái),對(duì)單片機(jī)的的學(xué)習(xí)和應(yīng)用的熱潮可謂一浪高過(guò)一浪.03年,在離開校園前的,非典的那幾個(gè)月,在華師的后門那里買了本邵貝貝的《UCOSII》,通讀了幾次,沒(méi)有實(shí)驗(yàn)器材,也不了了之。

            在21IC上,大家都可以看到楊屹寫的關(guān)于UCOSII在51上的移植,于是掀起了51上的的熱潮。

            再后來(lái),陳明計(jì)先生推出的smallrots,展示了用在51上的微內(nèi)核,足以在52上進(jìn)行任務(wù)調(diào)度。

            前段時(shí)間,在ouravr上面開有專門關(guān)于的Rtos的專欄,并且不少的兄弟把的作品拿出來(lái),著實(shí)開了不少眼界。這時(shí),我重新回顧了使用單片機(jī)的經(jīng)歷,覺(jué)得很有必要,從根本上對(duì)單片機(jī)的的知識(shí)進(jìn)行整理,于是,我開始了編寫用在單片機(jī)的RTOS。

            當(dāng)時(shí),我所有的知識(shí)和資源有:

            Proteus6.7可以用來(lái)模擬仿真avr系列的單片機(jī)
            Winv2.0.5.48基于GCCAVR的編譯環(huán)境,好處在于可以在C語(yǔ)言中插入asm的語(yǔ)句
            mega81K的ram有8K的rom,是開發(fā)8位的RTOS的理想的器件,并且我對(duì)它也比較熟悉。

            寫UCOS的JeanJ.Labrosse在他的書上有這樣一句話,“漸漸地,我自然會(huì)想到,寫個(gè)實(shí)時(shí)內(nèi)核直有那么難嗎?不就是不斷地保存,恢復(fù)CPU的那些寄存器嘛。”

            好了,當(dāng)這一切準(zhǔn)備好后,我們就可以開始我們的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:mega8
            Optimizationlevel:s
            Debugformat:AVR-COFF
            C/C++sourcefile:選譯要編譯的C文件

            #includeavr/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)初的教科書是譚浩強(qiáng)先生的《C程序設(shè)計(jì)》的話,請(qǐng)找回書的第9.5節(jié)。

            例子:用函數(shù)指針變量調(diào)用函數(shù)


            #includeavr/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ù)”

            #includeavr/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,r24
            icall
            ret

            在調(diào)用voidRunFun(void(*pfun)())的時(shí)候,的確可以把fun1的地址通過(guò)r24和r25傳遞給RunFun()。但是,RTOS如何才能有效地利用函數(shù)的地址呢?

            本文引用地址:http://www.biyoush.com/article/172857.htm

            第二篇:人工堆棧

            在單片機(jī)的指令集中,一類指令是專門與堆棧和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í),重開全局中斷使能。
            有了這個(gè)基礎(chǔ),就可以我們的人工堆棧了。
            例:
            #includeavr/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__(RETnt);//返回并開中斷,開始運(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()的地址,開始運(yùn)行fun1().

            上面例子中在RunFunInNewStack()的最后一句嵌入了匯編代碼ret,實(shí)際上是可以去除的。因?yàn)樵赗unFunInNewStack()返回時(shí),編譯器已經(jīng)會(huì)加上ret。我特意寫出來(lái),是為了讓大家看到用ret作為返回后運(yùn)行fun1()的過(guò)程。

            第三篇:GCC中對(duì)寄存器的分配與使用

            在很多用于AVR的RTOS中,都會(huì)有任務(wù)調(diào)度時(shí),插入以下的語(yǔ)句:

            入棧:
            __asm____volatile__(PUSHR0nt);
            __asm____volatile__(PUSHR1nt);
            ......
            __asm____volatile__(PUSHR31nt);

            出棧
            __asm____volatile__(POPR31nt);
            ......
            __asm____volatile__(POPR1nt);
            __asm____volatile__(POPR0nt);

            通常大家都會(huì)認(rèn)為,在任務(wù)調(diào)度開始時(shí),當(dāng)然要將所有的通用寄存器都保存,并且還應(yīng)該保存程序狀態(tài)寄存器SREG。然后再根據(jù)相反的次序,將新任務(wù)的寄存器的內(nèi)容恢復(fù)。

            但是,事實(shí)真的是這樣嗎?如果大家看過(guò)陳明計(jì)先生寫的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)有定義通用寄存器為變量

            #includeavr/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,r28
            movr22,r28
            movr24,r28
            rcalladd

            第二個(gè)例子:定義通用寄存器為變量

            #includeavr/io.h>

            unsignedcharadd(unsignedcharb,unsignedcharc,unsignedchard)
            {
            returnb+c*d;
            }


            registerunsignedcharaasm(r20);//將r20定義為變量a

            intmain(void)
            {

            while(1)
            {
            a++;
            PORTB=add(a,a,a);
            }
            }

            在本例中,add(a,a,a);被編譯如下:
            movr22,r20
            movr24,r20
            rcalladd

            當(dāng)然,在上面兩個(gè)例子中,有部份代碼被編譯器優(yōu)化了。

            通過(guò)反復(fù)測(cè)試,發(fā)現(xiàn)編譯器一般使用如下寄存器:
            第1類寄存器,第2類寄存器的r28,r29,第3類寄存器

            如在中斷函數(shù)中有調(diào)用基它函數(shù),剛會(huì)在進(jìn)入中斷后,固定地將第1類寄存器和第3類寄存器入棧,在退出中斷又將它們出棧。

            第四篇:只有延時(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í)別的人先用。”


            #includeavr/io.h>
            #includeavr/Interrupt.h>
            #includeavr/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ù)的堆棧頂


            上一頁(yè) 1 2 3 4 5 6 下一頁(yè)

            關(guān)鍵詞: AVR RTOS 自己 屬于 一個(gè) 建立

            評(píng)論


            相關(guān)推薦

            技術(shù)專區(qū)

            關(guān)閉