You are on page 1of 5

/****小小调度器开始**********************************************

/
#define MAXTASKS 2
static unsigned char timers[MAXTASKS];
unsigned char currdt;
#define _SS static unsigned char _lc; switch(_lc){default:
#define _EE ;}; _lc=0; return 255;
#define WaitX(tickets) do {_lc=__LINE__+((__LINE__%256)==0);
return tickets ;} while(0); case __LINE__+((__LINE__
%256)==0):
#define RunTask(TaskName,TaskID) do { if (timers[TaskID]==0)
timers[TaskID]=TaskName(); } while(0);

#define CallSub(SubTaskName) do { _lc=__LINE__+((__LINE__


%256)==0);
return 0; case __LINE__+((__LINE__
%256)==0): currdt=SubTaskName(); if(currdt!=255) return currdt;} while(0);
#define UpdateTimers() unsigned char i;
for(i=MAXTASKS;i>0 ;i--){if((timers[i-1]!=0)&&(timers[i-1]!=255)) timers[i-1]--;}

#define SEM unsigned int


//初始化信号量
#define InitSem(sem) sem=0;
//等待信号量
#define WaitSem(sem) do{ sem=1; WaitX(0); if (sem>0) return 1;}
while(0);
//等待信号量或定时器溢出, 定时器 tickets 最大为 0xFFFE
#define WaitSemX(sem,tickets) do { sem=tickets+1; WaitX(0);
if(sem>1){ sem--; return 1;} } while(0);
//发送信号量
#define SendSem(sem) do {sem=0;} while(0);

/*****小小调度器结束*********************************************
**********/

sbit LED1 = P2^1;


sbit LED2 = P2^2;

void InitT0()
{
TMOD = 0x21;
IE |= 0x82; // 12t
TL0=0Xff;
TH0=0XDB;//22M---b7;
TR0 = 1;
}

void INTT0(void) interrupt 1 using 1


{
UpdateTimers();

TL0=0Xff; //10ms 重装
TH0=0XDB;//b7;
}
void task1(){
_SS
while(1){
WaitX(50);
LED1=!LED1;
}
_EE
}

void task2(){
_SS
while(1){
WaitX(100);
LED2=!LED2;
}
_EE
}

void main()
{
InitT0();
while(1){
RunTask(task1,0);
RunTask(task2,1);
}
}

//---------------------------------------------------------------------------------
----

自认为有如下特点:

1) 超级可以移植性,与 CPU 无关,几乎任何支持 C 语言编程的 CPU 都可以用!(本文仅仅以 51 单片机为例而


已,但实际上可以任意移植)
2) 小之又小, 原理很简单,一看就懂。
3) 省之又省, 可以说对 RAM 和 ROM 省到极致。
4) 取 protothread 之精华,将定时器与状态机和伪线程语法融合到一个框架,任务函数可以有两种写法。
5) 基于定时器触发,调度效率高,最大化减少无效的代码运行时间。
***********************************************************/
#include <stc89c51.h>
#include <stdio.h>

/*****************小小调度器部分开始********************************************/
#define _SS static char lc=0; switch(lc){ case 0: lc=0;
#define _EE }; lc=0;
#define WaitX(a,b) settimer(&lc,__LINE__,a,b); return ; case __LINE__:
struct TASK {
char td;
void (*fp)();
};
#define MAXTASKS 5
struct TASK tasks[MAXTASKS];

//设置定时器
void settimer(char *lc,char line,char tmrid,int d){
*lc=line;
tasks[tmrid].td=d;
}
//逻辑定时器处理,在定时器中断里调用
void dectimers() {
unsigned char i;
for (i=0;i<MAXTASKS;i++){
if (tasks[i].td>0) tasks[i].td--;
}
}
//任务调度函数,在 main 里面运行
void runtasks() {
unsigned char i;
for(i=0;i<MAXTASKS;i++)
{
if (tasks[i].fp!=0){
if (tasks[i].td==0){
tasks[i].td=-1;
tasks[i].fp();
}
}
}
}
/****************小小调度器部分结束***************************************************
****/

sbit KEY = P3^2;


unsigned char code
numtab[16]={0x24,0x6F,0xE0,0x62,0x2B,0x32,0x30,0x67,0x20,0x22,0x21,0x38,0xB4,0x68,0
xB0,0xB1};

sfr IAP_CONTR = 0xC7;


sfr WDT_CONTR = 0xC1;

//清除看门狗
void clr_wdt()
{
WDT_CONTR =0x3C;
}

//初始化定时器
void InitT0()
{
TMOD = 0x21;
IE |= 0x82; // 12t
TL0=0Xff;
TH0=0Xb7;
TR0 = 1;
}
//定时器中断
void INTT0(void) interrupt 1 using 1
{
TL0=0Xff; //10ms 重装
TH0=0Xb7;
dectimers();
}

sbit LED1= P2^4;

//任务一,状态机写法
void ontimer0(){
LED1=!LED1; // LED1 引脚接在发光管负极,LED1=0 为亮,LED1=1 为灭。

//重装定时器
if (LED1) tasks[0].td=45; //450mS 灭
else tasks[0].td=5; //50ms 亮
}

//任务二,状态机写法
char keycount=0;
void task1(){
if(KEY==0) {
keycount++;
if (keycount>20) IAP_CONTR = 0x60; //持续按下键 1 秒,将重启并进入固件升级
}
else{
keycount=0;
}
//重装定时器
tasks[1].td=5;
}

//任务三,伪线程写法
void task2()
{
static char i;
_SS

while(1){

for(i=0;i<=9;i++){ //从 0--9 快速显示,间隔 200mS


WaitX(2,20); // 等待 200mS,实际是设置定时器 2 为 200mS
P1=numtab[i];
}
for(i=0;i<=9;i++){ //从 0--9 慢速显示,间隔 500mS
WaitX(2,50); // 等待 500mS,实际是设置定时器 2 为 500mS
P1=numtab[i];
}
}

_EE
}
void main()
{
unsigned char KeyNum;
P3M0 = 0x00;
P3M1 =0x00;
//WDT_CONTR= 0x00; //关闭看门狗
P1 = 0xff; //关显示

clr_wdt();

InitT0();

KEY =1; //按键 IO 口


KeyNum=0; //按下次数

//装载任务:
tasks[0].fp=ontimer0;
tasks[1].fp=task1;
tasks[2].fp=task2;

//循环调度
while(1){
runtasks();
clr_wdt();
}
}

You might also like