中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 建立一個AVR單片機(jī)RTOS(8)—占先式內(nèi)核(完善的服務(wù))

        建立一個AVR單片機(jī)RTOS(8)—占先式內(nèi)核(完善的服務(wù))

        作者: 時間:2016-12-03 來源:網(wǎng)絡(luò) 收藏
        第八篇:占先式內(nèi)核(完善的服務(wù))

        如果將前面所提到的占先式內(nèi)核和協(xié)作式內(nèi)核組合在一起,很容易就可以得到一個功能較為完善的占先式內(nèi)核,它的功能有:

        本文引用地址:http://www.antipu.com.cn/article/201612/325279.htm

        1,掛起和恢復(fù)任務(wù)

        2,任務(wù)延時

        3,信號量(包括共享型和獨(dú)占型)

        另外,在本例中,在各個任務(wù)中加入了從串口發(fā)送任務(wù)狀態(tài)的功能。

        #include <avr/io.h>

        #include

        #include

        unsigned char Stack[400];

        register unsigned char OSRdyTbl asm("r2"); //任務(wù)運(yùn)行就緒表

        register unsigned char OSTaskRunningPrio asm("r3"); //正在運(yùn)行的任務(wù)

        register unsigned char IntNum asm("r4"); //中斷嵌套計數(shù)器

        //只有當(dāng)中斷嵌套數(shù)為0,并且有中斷要求時,才能在退出中斷時,進(jìn)行任務(wù)調(diào)度

        register unsigned char OSCoreState asm("r16"); //系統(tǒng)核心標(biāo)志位,R16編譯器沒有使用

        //只有大于R15的寄存器才能直接賦值例LDI R16,0x01

        //0x01正在任務(wù)切換0x02有中斷要求切換

        #define OS_TASKS 3 //設(shè)定運(yùn)行任務(wù)的數(shù)量

        struct TaskCtrBlock

        {

        unsigned int OSTaskStackTop; //保存任務(wù)的堆棧頂

        unsigned int OSWaitTick; //任務(wù)延時時鐘

        } TCB[OS_TASKS+1];

        //防止被編譯器占用

        //register unsigned char tempR4 asm("r4");

        register unsigned char tempR5 asm("r5");

        register unsigned char tempR6 asm("r6");

        register unsigned char tempR7 asm("r7");

        register unsigned char tempR8 asm("r8");

        register unsigned char tempR9 asm("r9");

        register unsigned char tempR10 asm("r10");

        register unsigned char tempR11 asm("r11");

        register unsigned char tempR12 asm("r12");

        register unsigned char tempR13 asm("r13");

        register unsigned char tempR14 asm("r14");

        register unsigned char tempR15 asm("r15");

        //register unsigned char tempR16 asm("r16");

        register unsigned char tempR16 asm("r17");

        //建立任務(wù)

        void OSTaskCreate(void (*Task)(void),unsigned char *Stack,unsigned char TaskID)

        {

        unsigned char i;

        *Stack--=(unsigned int)Task>>8; //將任務(wù)的地址高位壓入堆棧,

        *Stack--=(unsigned int)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中的What registers are used by the C compiler?

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

        TCB[TaskID].OSTaskStackTop=(unsigned int)Stack; //將人工堆棧的棧頂,保存到堆棧的數(shù)組中

        OSRdyTbl|=0x01<

        }

        //開始任務(wù)調(diào)度,從最低優(yōu)先級的任務(wù)的開始

        void OSStartTask()

        {

        OSTaskRunningPrio=OS_TASKS;

        SP=TCB[OS_TASKS].OSTaskStackTop+17;

        __asm__ __volatile__( "reti" "nt" );

        }

        //進(jìn)行任務(wù)調(diào)度

        void OSSched(void)

        {

        __asm__ __volatile__("LDI R16,0x01 nt");

        //清除中斷要求任務(wù)切換的標(biāo)志位,設(shè)置正在任務(wù)切換標(biāo)志位

        __asm__ __volatile__("SEI nt");

        //開中斷,因?yàn)槿绻蛑袛嘣谌蝿?wù)調(diào)度中進(jìn)行,要重新進(jìn)行調(diào)度時,已經(jīng)關(guān)中斷

        //根據(jù)中斷時保存寄存器的次序入棧,模擬一次中斷后,入棧的情況

        __asm__ __volatile__("PUSH __zero_reg__ nt"); //R1

        __asm__ __volatile__("PUSH __tmp_reg__ nt"); //R0

        __asm__ __volatile__("IN __tmp_reg__,__SREG__ nt"); //保存狀態(tài)寄存器SREG

        __asm__ __volatile__("PUSH __tmp_reg__ nt");

        __asm__ __volatile__("CLR __zero_reg__ nt"); //R0重新清零

        __asm__ __volatile__("PUSH R18 nt");

        __asm__ __volatile__("PUSH R19 nt");

        __asm__ __volatile__("PUSH R20 nt");

        __asm__ __volatile__("PUSH R21 nt");

        __asm__ __volatile__("PUSH R22 nt");

        __asm__ __volatile__("PUSH R23 nt");

        __asm__ __volatile__("PUSH R24 nt");

        __asm__ __volatile__("PUSH R25 nt");

        __asm__ __volatile__("PUSH R26 nt");

        __asm__ __volatile__("PUSH R27 nt");

        __asm__ __volatile__("PUSH R30 nt");

        __asm__ __volatile__("PUSH R31 nt");

        __asm__ __volatile__("Int_OSSched: nt"); //當(dāng)中斷要求調(diào)度,直接進(jìn)入這里

        __asm__ __volatile__("SEI nt");

        //開中斷,因?yàn)槿绻蛑袛嘣谌蝿?wù)調(diào)度中進(jìn)行,已經(jīng)關(guān)中斷

        __asm__ __volatile__("PUSH R28 nt"); //R28與R29用于建立在堆棧上的指針

        __asm__ __volatile__("PUSH R29 nt"); //入棧完成

        TCB[OSTaskRunningPrio].OSTaskStackTop=SP; //將正在運(yùn)行的任務(wù)的堆棧底保存

        unsigned char OSNextTaskPrio; //在現(xiàn)有堆棧上開設(shè)新的空間

        for (OSNextTaskPrio = 0; //進(jìn)行任務(wù)調(diào)度

        OSNextTaskPrio < OS_TASKS && !(OSRdyTbl & (0x01<

        OSNextTaskPrio++);

        OSTaskRunningPrio = OSNextTaskPrio ;

        cli(); //保護(hù)堆棧轉(zhuǎn)換

        SP=TCB[OSTaskRunningPrio].OSTaskStackTop;

        sei();

        //根據(jù)中斷時的出棧次序

        __asm__ __volatile__("POP R29 nt");

        __asm__ __volatile__("POP R28 nt");

        __asm__ __volatile__("POP R31 nt");

        __asm__ __volatile__("POP R30 nt");

        __asm__ __volatile__("POP R27 nt");

        __asm__ __volatile__("POP R26 nt");

        __asm__ __volatile__("POP R25 nt");

        __asm__ __volatile__("POP R24 nt");

        __asm__ __volatile__("POP R23 nt");

        __asm__ __volatile__("POP R22 nt");

        __asm__ __volatile__("POP R21 nt");

        __asm__ __volatile__("POP R20 nt");

        __asm__ __volatile__("POP R19 nt");

        __asm__ __volatile__("POP R18 nt");

        __asm__ __volatile__("POP __tmp_reg__ nt"); //SERG出棧并恢復(fù)

        __asm__ __volatile__("OUT __SREG__,__tmp_reg__ nt"); //

        __asm__ __volatile__("POP __tmp_reg__ nt"); //R0出棧

        __asm__ __volatile__("POP __zero_reg__ nt"); //R1出棧

        //中斷時出棧完成

        __asm__ __volatile__("CLI nt"); //關(guān)中斷

        __asm__ __volatile__("SBRC R16,1 nt"); //SBRC當(dāng)寄存器位為0剛跳過下一條指令

        //檢查是在調(diào)度時,是否有中斷要求任務(wù)調(diào)度0x02是中斷要求調(diào)度的標(biāo)志位

        __asm__ __volatile__("RJMP OSSched nt"); //重新調(diào)度

        __asm__ __volatile__("LDI R16,0x00 nt");

        //清除中斷要求任務(wù)切換的標(biāo)志位,清除正在任務(wù)切換標(biāo)志位

        __asm__ __volatile__("RETI nt"); //返回并開中斷

        }

        //從中斷退出并進(jìn)行調(diào)度

        void IntSwitch(void)

        {

        //當(dāng)中斷無嵌套,并且沒有在切換任務(wù)的過程中,直接進(jìn)行任務(wù)切換

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

        {

        //進(jìn)入中斷時,已經(jīng)保存了SREG和R0,R1,R18~R27,R30,R31

        __asm__ __volatile__("POP R31 nt"); //去除因調(diào)用子程序而入棧的PC

        __asm__ __volatile__("POP R31 nt");

        __asm__ __volatile__("LDI R16,0x01 nt");

        //清除中斷要求任務(wù)切換的標(biāo)志位,設(shè)置正在任務(wù)切換標(biāo)志位

        __asm__ __volatile__("RJMP Int_OSSched nt"); //重新調(diào)度

        }

        }

        ////////////////////////////////////////////任務(wù)處理

        //掛起任務(wù)

        void OSTaskSuspend(unsigned char prio)

        {

        TCB[prio].OSWaitTick=0;

        OSRdyTbl &= ~(0x01<

        if(OSTaskRunningPrio==prio) //當(dāng)要掛起的任務(wù)為當(dāng)前任務(wù)

        OSSched(); //從新調(diào)度

        }

        //恢復(fù)任務(wù)可以讓被OSTaskSuspend或OSTimeDly暫停的任務(wù)恢復(fù)

        void OSTaskResume(unsigned char prio)

        {

        OSRdyTbl |= 0x01<

        TCB[prio].OSWaitTick=0; //將時間計時設(shè)為0,到時

        if(OSTaskRunningPrio>prio) //當(dāng)要當(dāng)前任務(wù)的優(yōu)先級低于重置位的任務(wù)的優(yōu)先級

        OSSched(); //從新調(diào)度//從新調(diào)度

        }

        //任務(wù)延時

        void OSTimeDly(unsigned int ticks)

        {

        if(ticks) //當(dāng)延時有效

        {

        OSRdyTbl &= ~(0x01<

        TCB[OSTaskRunningPrio].OSWaitTick=ticks;

        OSSched(); //從新調(diào)度

        }

        }

        //信號量

        struct SemBlk

        {

        unsigned char OSEventType; //型號0,信號量獨(dú)占型;1信號量共享型

        unsigned char OSEventState; //狀態(tài)0,不可用;1,可用

        unsigned char OSTaskPendTbl; //等待信號量的任務(wù)列表

        } Sem[10];

        //初始化信號量

        void OSSemCreat(unsigned char Index,unsigned char Type)

        {

        Sem[Index].OSEventType=Type; //型號0,信號量獨(dú)占型;1信號量共享型

        Sem[Index].OSTaskPendTbl=0;

        Sem[Index].OSEventState=0;

        }

        //任務(wù)等待信號量,掛起

        //當(dāng)Timeout==0xffff時,為無限延時

        unsigned char OSTaskSemPend(unsigned char Index,unsigned int Timeout)

        {

        //unsigned char i=0;

        if(Sem[Index].OSEventState) //信號量有效

        {

        if(Sem[Index].OSEventType==0) //如果為獨(dú)占型

        Sem[Index].OSEventState = 0x00; //信號量被獨(dú)占,不可用

        }

        else

        { //加入信號的任務(wù)等待表

        Sem[Index].OSTaskPendTbl |= 0x01<

        TCB[OSTaskRunningPrio].OSWaitTick=Timeout; //如延時為0,剛無限等待

        OSRdyTbl &= ~(0x01<

        OSSched(); //從新調(diào)度

        if(TCB[OSTaskRunningPrio].OSWaitTick==0 ) //超時,未能拿到資源

        return 0;

        }

        return 1;

        }

        //發(fā)送一個信號量,可以從任務(wù)或中斷發(fā)送

        void OSSemPost(unsigned char Index)

        {

        if(Sem[Index].OSEventType) //當(dāng)要求的信號量是共享型

        {

        Sem[Index].OSEventState=0x01; //使信號量有效

        OSRdyTbl |=Sem [Index].OSTaskPendTbl; //使在等待該信號的所有任務(wù)就緒Sem[Index].OSTaskPendTbl=0; //清空所有等待該信號的等待任務(wù)

        }

        else //當(dāng)要求的信號量為獨(dú)占型

        {

        unsigned char i;

        for (i = 0; i < OS_TASKS && !(Sem[Index].OSTaskPendTbl & (0x01<

        if(i < OS_TASKS) //如果有任務(wù)需要

        {

        Sem[Index].OSTaskPendTbl &= ~(0x01<

        OSRdyTbl |= 0x01<

        }

        else

        {

        Sem[Index].OSEventState =1; //使信號量有效

        }

        }

        }

        //從任務(wù)發(fā)送一個信號量,并進(jìn)行調(diào)度

        void OSTaskSemPost(unsigned char Index)

        {

        OSSemPost(Index);

        OSSched();

        }

        //清除一個信號量,只對共享型的有用。

        //對于獨(dú)占型的信號量,在任務(wù)占用后,就交得不可以用了。

        void OSSemClean(unsigned char Index)

        {

        Sem[Index].OSEventState =0; //要求的信號量無效

        }

        void TCN0Init(void) //計時器0

        {

        TCCR0 = 0;

        TCCR0 |= (1<

        TIMSK |= (1<

        TCNT0 = 100; //置計數(shù)起始值

        }

        SIGNAL(SIG_OVERFLOW0)

        {

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

        sei(); //在中斷中,重開中斷

        unsigned char i;

        for(i=0;i

        {

        if(TCB[i].OSWaitTick && TCB[i].OSWaitTick!=0xffff)

        {

        TCB[i].OSWaitTick--;

        if(TCB[i].OSWaitTick==0) //當(dāng)任務(wù)時鐘到時,必須是由定時器減時的才行

        {

        OSRdyTbl |= (0x01<

        OSCoreState|=0x02; //要求任務(wù)切換的標(biāo)志位

        }

        }

        }

        TCNT0=100;

        cli();

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

        IntSwitch(); //進(jìn)行任務(wù)調(diào)度

        }

        unsigned char __attribute__ ((progmem)) proStrA[]="Task ";

        unsigned char strA[20];

        SIGNAL(SIG_UART_RECV) //串口接收中斷

        {

        strA[0]=UDR;

        }

        /////////////////////////////////////串口發(fā)送

        unsigned char *pstr_UART_Send;

        unsigned int nUART_Sending=0;

        void UART_Send(unsigned char *Res,unsigned int Len) //發(fā)送字符串?dāng)?shù)組

        {

        if(Len>0)

        {

        pstr_UART_Send=Res; //發(fā)送字串的指針

        nUART_Sending=Len; //發(fā)送字串的長度

        UCSRB=0xB8; //發(fā)送中斷使能

        }

        }

        //SIGNAL在中斷期間,其它中斷禁止

        SIGNAL(SIG_UART_DATA) //串口發(fā)送數(shù)據(jù)中斷

        {

        IntNum++; //中斷嵌套+1,不充許中斷

        if(nUART_Sending) //如果未發(fā)完

        {

        UDR=*pstr_UART_Send; //發(fā)送字節(jié)

        pstr_UART_Send++; //發(fā)送字串的指針加1

        nUART_Sending--; //等待發(fā)送的字串?dāng)?shù)減1

        }

        if(nUART_Sending==0) //當(dāng)已經(jīng)發(fā)送完

        {

        OSSemPost(0);

        OSCoreState|=0x02; //要求任務(wù)切換的標(biāo)志位

        UCSRB=0x98;

        }

        cli(); //關(guān)發(fā)送中斷

        IntNum--;

        IntSwitch(); //進(jìn)行任務(wù)調(diào)度

        }

        void UARTInit() //初始化串口

        {

        #define fosc 8000000 //晶振8 MHZ UBRRL=(fosc/16/(baud+1))%256;

        #define baud 9600 //波特率

        OSCCAL=0x97; //串口波特率校正值,從編程器中讀出

        //UCSRB=(1<

        UCSRB=0x98;

        //UCSRB=0x08;

        UBRRL=(fosc/16/(baud+1))%256;

        UBRRH=(fosc/16/(baud+1))/256;

        UCSRC=(1<

        UCSRB=0xB8;

        UDR=0;

        }

        //打印unsigned int到字符串中00000

        void strPUT_uInt(unsigned char *Des,unsigned int i)

        {

        unsigned char j;

        Des=Des+4;

        for(j=0;j<5;j++)

        {

        *Des=i%10+’0’;

        i=i/10;

        Des--;

        }

        }

        void strPUT_Star(unsigned char *Des,unsigned char i)

        {

        unsigned char j;

        for(j=0;j

        {

        *Des++=’*’;

        }

        *Des++=13;

        }

        unsigned int strPUT_TaskState(unsigned char *Des,unsigned char TaskID,unsigned char Num)

        {

        //unsigned int i=0;

        *(Des+4)=’0’+TaskID;

        strPUT_uInt(Des+6,Num);

        strPUT_Star(Des+12,TaskID);

        return 12+TaskID+1;

        }

        void Task0()

        {

        unsigned int j=0;

        while(1)

        {

        PORTB=j++;

        if(OSTaskSemPend(0,0xffff))

        {

        unsigned int m;

        m=strPUT_TaskState(strA,OSTaskRunningPrio,j);

        UART_Send(strA,m);

        }

        OSTimeDly(200);

        }

        }

        void Task1()

        {

        unsigned int j=0;

        while(1)

        {

        PORTC=j++;

        if(OSTaskSemPend(0,0xffff))

        {

        unsigned int m;

        m=strPUT_TaskState(strA,OSTaskRunningPrio,j);

        UART_Send(strA,m);

        }

        OSTimeDly(100);

        }

        }

        void Task2()

        {

        unsigned int j=0;

        while(1)

        {

        if(OSTaskSemPend(0,0xffff))

        {

        unsigned int m;

        m=strPUT_TaskState(strA,OSTaskRunningPrio,j);

        UART_Send(strA,m);

        }

        PORTD=j++;

        OSTimeDly(50);

        }

        }

        void TaskScheduler()

        {

        OSSched();

        while(1)

        {}

        }

        int main(void)

        {

        strlcpy_P(strA,proStrA,20);

        UARTInit();

        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();

        }



        評論


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

        關(guān)閉