早就想寫寫這個(gè)了,正好趕上有點(diǎn)時(shí)間,寫了一下基于51單片機(jī)的時(shí)間片輪轉(zhuǎn)調(diào)度系統(tǒng),簡(jiǎn)單的rtos,呵呵。直接上代碼。文章來源:http://www.zghlxwxcb.cn/news/detail-784015.html
//基于51單片機(jī)時(shí)間片輪轉(zhuǎn)的簡(jiǎn)單rtos。
#include"reg52.h"
sbit led1 = P2^7;
sbit led2 = P2^0;
sbit key = P1^0;
#define MAX_TASKS 3 //定義任務(wù)個(gè)數(shù).必須和實(shí)際任務(wù)數(shù)一至
#define PUSH_TIMES 3 //時(shí)間中斷中push使用的次數(shù)用debug看進(jìn)入時(shí)間中斷時(shí)的次數(shù)。
#define MAX_TASK_DEP (PUSH_TIMES+4) //任務(wù)槽深度;
//經(jīng)過實(shí)驗(yàn),看debug的push次數(shù),加上4就行了。//沒有考慮中斷嵌套。有嵌套的再大。
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP]; //任務(wù)堆棧.
unsigned char current_id; //當(dāng)前活動(dòng)任務(wù)號(hào)
unsigned char task_sp[MAX_TASKS]; //堆棧指針組,每個(gè)任務(wù)一個(gè)字節(jié),任務(wù)調(diào)度前指向入棧的pc高字節(jié)。
unsigned int cicle1,cicle2;
void Timer0_Init(void) //10毫秒@11.0592MHz
{
AUXR &= 0x7F; //定時(shí)器時(shí)鐘12T模式
TMOD &= 0xF0; //設(shè)置定時(shí)器模式
TL0 = 0x00; //設(shè)置定時(shí)初始值
TH0 = 0xDC; //設(shè)置定時(shí)初始值
TF0 = 0; //清除TF0標(biāo)志
ET0 = 1; //使能定時(shí)器0中斷
EA=1; //開總中斷
}
//任務(wù)裝入函數(shù),將任務(wù)的首地址(參數(shù)1)裝入(參數(shù)2)指定的任務(wù)槽中.
void task_load(unsigned int func, unsigned char taskid)
{
task_stack[taskid][0] = (unsigned int)func & 0xff; //把任務(wù)地址的低八位裝入任務(wù)槽0號(hào)地址。
task_stack[taskid][1] = (unsigned int)func >> 8; //把任務(wù)地址的高八位裝入任務(wù)槽1號(hào)地址
task_sp[taskid] = (unsigned char)&task_stack[taskid][0]; //把堆棧的首地址送給sp數(shù)組。
task_sp[taskid]++;//先把保存的數(shù)組sp值加1,使它指向堆棧入棧pc的高位
//這里模擬了入棧過程,先把任務(wù)地址放在任務(wù)槽的最低位置,下次切換的時(shí)候就直接來這里找。
if(taskid!=0) //如果不是0號(hào)任務(wù);
{
task_sp[taskid]+= PUSH_TIMES; //給push和pop語句留下空間,用debuge看匯編進(jìn)入中斷后的push
//次數(shù),在文件首部改數(shù)字值;
}
}
void os_start() //啟動(dòng)程序
{
current_id = 0; //把0號(hào)sp當(dāng)作當(dāng)前的首個(gè)sp
SP = task_sp[0];
}
void task1() //任務(wù)1,循環(huán)夠5萬次燈閃動(dòng)一次
{
while(1)
{
cicle1++;
if (cicle1>50000)
{
cicle1=0;
led1=!led1;
}
}
}
void task2() //任務(wù)2,循環(huán)夠5萬次燈閃動(dòng)一次
{
while(1)
{
cicle2++;
if (cicle2>30000)
{
cicle2=0;
led2=!led2;
}
}
}
void task3()
{
while(1)
{
if(key==0)
cicle2=10000;
// cicle1=10000;
}
}
void Timer0_Isr(void) interrupt 1 //時(shí)間中斷。調(diào)度任務(wù)。
{
EA=0; //進(jìn)入核心臨界區(qū)關(guān)中斷
task_sp[current_id] = SP; //將進(jìn)入時(shí)鐘中斷時(shí)的sp存入任務(wù)槽。
if(++current_id == MAX_TASKS) //當(dāng)前任務(wù)指向下一個(gè)任務(wù)號(hào)。如果任務(wù)號(hào)超過任務(wù)總數(shù)
current_id=0; //指向任務(wù)0;
SP = task_sp[current_id]; //把新任務(wù)的pc地址給sp,這樣在時(shí)間中斷出函數(shù)的時(shí)候系統(tǒng)自動(dòng)把sp指向的值作為pc高8位;并出棧。
EA=1; //開中斷。
}
void main()
{
//這里裝載了三個(gè)個(gè)任務(wù),因此在文件首部定義MAX_TASKS時(shí)也必須定義為3
task_load(task1, 0);//將task1函數(shù)裝入0號(hào)槽,任務(wù)可以裝入任意槽。
task_load(task2, 1);//將task2函數(shù)裝入1號(hào)槽
task_load(task3, 2);//將task3函數(shù)裝入2號(hào)槽
Timer0_Init(); //定時(shí)器0初始化
key=1; //口線置位。
TR0 = 1; //開始計(jì)時(shí)
os_start(); //必須從任務(wù)在0號(hào)槽的任務(wù)開始;
}
雖然簡(jiǎn)單,也可以繼續(xù)學(xué)習(xí)了。文章來源地址http://www.zghlxwxcb.cn/news/detail-784015.html
到了這里,關(guān)于51單片機(jī)基于時(shí)間片輪轉(zhuǎn)的簡(jiǎn)單rtos的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!