发布这个小小调度器主要起个抛砖引玉的作用。
自认为有如下特点:
1) 超级可以移植性,与CPU无关,几乎任何支持C语言编程的CPU都可以用!
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,0xB0,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();
}
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
牛!
Wait配合伪线程这个结构LZ怎么想出来的……
能不能再加入事件等待呢?这样就更完美了,因为线程block有时候是等待时间,有时候是等待事件
另外感觉可以在任务中加入this指针全局变量,切换任务的时候顺便切换this,this指向的结构体可以包含任务号的信息,这样wait函数中不用指定任务号了。
还有,以前我用STM8状态机的时候,主循环喜欢加上WFI,类似这样的结构:
- #define WFI _asm("wfi")
- main(void) {
- init();
- while(1) {
- switch(state) {
- case STATE_INIT:
- case STATE_A:
- case STATE_B:
- } /* end switch */
- WFI;
- } /* end while */
- }
复制代码新版本已无需指定定时器的。
- /**********************************************************/
- #include "STC89C51.h"
- /****小小调度器开始**********************************************/
- #define MAXTASKS 3
- unsigned char currid;
- unsigned char timers[MAXTASKS];
- #define _SS static unsigned char lc=0; switch(lc){ case 0:
- #define _EE ;}; lc=0;
- #define WaitX(b) {lc=__LINE__; timers[currid]=b;} return ; case __LINE__:
- #define RunTask(a,b) {currid=b; if (timers[b]==0){timers[b]=255; a();}}
- #define CallSub(x) WaitX(0); x(); if (timers[currid]!=255) return;
- /*****小小调度器结束*******************************************************/
- 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
- {
- unsigned char i;
- TL0=0Xff; //10ms 重装
- TH0=0XDB;//b7;
- for (i=0;i<MAXTASKS;i++){
- if ((timers[i]!=0)&&(timers[i]!=255)) {
- timers[i]--;
- }
- }
- }
- void task1(){
- _SS
- while(1){
- WaitX(100);
- LED1=!LED1;
- }
- _EE
- }
- void task2(){
- _SS
- while(1){
- WaitX(100);
- LED2=!LED2;
- }
- _EE
- }
- void main()
- {
- InitT0();
- while(1){
- RunTask(task1,1);
- RunTask(task2,2);
- }
- }
复制代码settimer(&lc,__LINE__,500);return;case __LINE__:
void settimer(char *lc,char line,unsigned char d)
{
*lc=line;
timers[currid]=d;
}
这段代码没看懂,请楼主讲解下,那个_LINE_宏有什么用,为什么要加入这个,如何能去掉
一周热门 更多>