smset
发表于 2012-11-28 15:43:46
本帖最后由 smset 于 2012-11-28 15:48 编辑
说明:以上是新版的程序,调度器只有十行左右代码,想看明白的,把宏替换了,然后多看几遍就明白了。
不想看得太明白的,跟着例程用也行。
这个调度器已经是可以正常使用了。 前提条件: 1) cpu支持c语言编译器2)cpu支持产生定时器中断 ( 好像还没用过不支持这两个条件的单片机哈 )
前面有个帖子说需要有一个监测机制,监测那些占用时间过多的任务,这个我已经实现了一个方案----(在大脑里)。下个版本将一起公布。
我希望大家先测试和应用下这个调度器,调度器再好,没有投入实际应用,也等于零。
所以我希望在各种cpu下做些实验,能反馈一些信息才好。 毕竟这个调度器的一个特点是与单片机无关,所以也需要多种cpu例程供大家一起参考。
希望大家多多发扬莫大提倡的开源精神,发布一些应用例子,不要藏着自己独享。独乐乐,不如众乐乐。
如果能avr或者lgt下,能有些测试用例,大家一起探讨就更好,以此表示对莫大的敬意,和对lgt的支持。
我希望下个版本能够以多种cpu例程的方式来发布。希望得到大家的帮助。
liumaojun_cn
发表于 2012-11-28 15:49:36
支持。{:smile:}{:smile:}{:smile:}{:smile:}
kentzhtao_top
发表于 2012-11-28 17:01:13
改成这样不就是按照顺序执行三个“任务函数”吗?每次执行完一个函数后才能执行下一个,感觉和在main()里面直接写封装好的函数没太大区别吧?而且还有个问题就是你给的两个程序中P1 = numtab;好像永远都不会被执行吧?因为每次调用Delay(x)后,函数直接return(宏里面已经定义)了。我一直很纳闷,不知楼主是何用意啊?
smset
发表于 2012-11-28 17:06:57
本帖最后由 smset 于 2012-11-28 17:12 编辑
kentzhtao_top 发表于 2012-11-28 17:01 static/image/common/back.gif
改成这样不就是按照顺序执行三个“任务函数”吗?每次执行完一个函数后才能执行下一个,感觉和在main()里 ...
正是因为要给其他任务机会,所以才return啊。
{:smile:}你先找个板子实际跑跑看,能否按设想的运行,先不急下结论嘛,呵呵。
kentzhtao_top
发表于 2012-11-28 17:17:12
你一执行return;这个task2函数就退出了,然后就执行后面的程序,轮询一圈之后又回到task2来,结果还是一样return退出task2, return后面的P1永远都不执行,循环往复。。。没完没了。。。不知道我说的对不,而且我用keil 仿真的结果也是这样
formatme
发表于 2012-11-28 17:21:45
编译出现这个errorMAIN.C(120): error C213: left side of asn-op not an lvalue
grash
发表于 2012-11-28 17:24:59
有深度,仔细研究下
Jason022
发表于 2012-11-28 17:30:17
楼主,如果要把18b20的驱动加进去该怎么操作?
my_avr
发表于 2012-11-28 17:50:19
#define RunTask(a,b) currid=b; if (timers==0){timers=-1; a();} //运行顶层任务
这里是否笔误?timers本来定义是一个数组
smset
发表于 2012-11-28 18:28:35
my_avr 发表于 2012-11-28 17:50
#define RunTask(a,b) currid=b; if (timers==0){timers=-1; a();} //运行顶层任务
这里是否笔误?timers ...
应该是timers
smset
发表于 2012-11-28 18:33:02
我知道原因了,论坛自动吃掉数组下标了,晕。
Talsinpo
发表于 2012-11-28 19:17:59
kentzhtao_top 发表于 2012-11-28 17:17 static/image/common/back.gif
你一执行return;这个task2函数就退出了,然后就执行后面的程序,轮询一圈之后又回到task2来,结果还是一样 ...
是的啊,同问,还有个问题:
voidtask2(){ static char i; static char lc=0; switch(lc) { case 0: lc=0; while(1) { for(i=0; i<=9; i++) //从0--9快速显示,间隔200mS { settimer(&lc,__LINE__,2,20); return ; case __LINE__: P1=numtab[i]; } for(i=0; i<=9; i++) //从0--9慢速显示,间隔500mS { settimer(&lc,__LINE__,2,50); return ; case __LINE__: P1=numtab[i]; } } }; lc=0;}
while中的CASE是怎么回事
smset
发表于 2012-11-28 22:55:23
重发一次:
#include <STC89C51.h>
/**************小小调度器开始 *********************************/
#define MAXTASKS 3 //顶层任务数量,可按需增加,最大为255个。
unsigned chartimers;
char currid; //当前运行的任务号
#define _SS static char lc=0; switch(lc){ case 0: //跳转开始
#define _EE }; lc=0;//跳转结束
#define DelayX(b)settimer(&lc,__LINE__,b); return ; case __LINE__: //任务内延时等待“函数”
#define RunTask(a,b) currid=b; if (timers==0){timers=-1; a();} //运行顶层任务
#define CallSub(x)DelayX(0);x(); if (timers!=-1) return; //调用子任务
void settimer(char *lc,charline,unsigned char d){//设置定时器
*lc=line;timers=d;
}
/****************小小调度器结束*** (我很短,但用起来很爽)******************************/
sbit KEY = P3^2;
unsigned char code numtab={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;
}
//初始化定时器,产生10ms中断
void InitT0()
{
TMOD = 0x21;
IE |= 0x82;// 12t
TL0=0Xff;
TH0=0Xb7;
TR0 = 1;
}
//定时器中断处理函数
void INTT0(void) interrupt 1 using 1
{
unsigned char i;
TL0=0Xff; //10ms 重装
TH0=0Xb7;
//逻辑定时器处理
for (i=0;i<MAXTASKS;i++){
if (timers>0) {
timers--;
}
}
}
sbit LED1= P2^4;
//任务一,状态机写法
void ontimer0(){
LED1=!LED1; // LED1引脚接在发光管负极,LED1=0 为亮,LED1=1为灭
if (LED1) timers=45; //450mS 灭
else timers=5; //50ms亮
}
//任务二,状态机写法
char keycount=0;
void task1(){
if(KEY==0) {
keycount++;
if (keycount>20) IAP_CONTR = 0x60;
}
else{
keycount=0;
}
timers=5; //重装定时器
}
//这是一个子任务函数
voidsubtask()
{
static char i;
_SS
for(i=0;i<=5;i++){
DelayX(20);
P1=numtab;
}
_EE
}
//任务三,“线程”写法,复杂任务请用这种方式来写,比传统状态机写法更简单,更自然,而且更省ROM!
voidtask2()
{
static char i; //变量请申明为静态的。
_SS
while(1){
for(i=0;i<=9;i++){ //先从0--9快速显示,间隔200mS
DelayX(20);
P1=numtab;
}
for(i=0;i<=9;i++){//然后从0--9慢速显示,间隔500mS
DelayX(50);
P1=numtab;
CallSub(subtask); //顶层任务的任何地方都可以调用子任务
}
//CallSub(subtask); //顶层任务的任何地方都可以调用子任务
}
_EE
}
void main()
{
P3M0 = 0x00;
P3M1 =0x00;
P1 = 0xff; //关LED数码管显示
InitT0(); //初始化定时器,以便产生10ms中断
KEY =1; //按键IO口
while(1){
clr_wdt(); //清除看门狗
//这里,只需运行顶层任务即可
RunTask(ontimer0,0); //ontimer0任务放在第0个任务槽
RunTask(task1,1); //task1任务放在第1个任务槽
RunTask(task2,2); //task2任务放在第2个任务槽
//...还可以增加更多任务
}
}
zenghl
发表于 2012-11-28 23:08:32
以下编译出错:
void INTT0(void) interrupt 1 using 1
{
unsigned char i;
TL0=0Xff; //10ms 重装
TH0=0Xb7;
//逻辑定时器处理
for (i=0;i<MAXTASKS;i++)
{
if (timers>0)
{
timers--;
}
}
}
zenghl
发表于 2012-11-28 23:10:36
timers是一个数组,可以直接操作吗?
是否要改为:
if(timers>0)
{
timers--;
}
261854681
发表于 2012-11-28 23:21:14
记号 记号
zhonggp
发表于 2012-11-28 23:28:32
Talsinpo 发表于 2012-11-28 19:17 static/image/common/back.gif
是的啊,同问,还有个问题:
voidtask2(){ static char i; static char lc=0; switch(lc ...
编译后运行就知道了,switch case 语句怎么用就知道了/
xizi
发表于 2012-11-28 23:31:45
请楼主发个文件包上来,比复制粘贴更完整。
zhuisuoji
发表于 2012-11-28 23:41:20
很是精彩,我也来顶一个,可惜错过了顶100楼{:victory:}
zhonggp
发表于 2012-11-28 23:46:04
加载应用函数修改为函数方式:
LoadTaskFun(void *Fun,U8 funId);
删除通过
DelTaskFun(U8 funId);
做动态加载程序.这样加功能就不动原来的东西了.
shotstar
发表于 2012-11-29 08:39:40
再加入 PT的信号量
leicai05
发表于 2012-11-29 09:17:38
看看,是否神奇
grash
发表于 2012-11-29 09:20:25
如果用到串口通讯呢,如何处理
kentzhtao_top
发表于 2012-11-29 09:48:25
Talsinpo 发表于 2012-11-28 19:17 static/image/common/back.gif
是的啊,同问,还有个问题:
voidtask2(){ static char i; static char lc=0; switch(lc ...
对于数码管这类需要动态扫描,延时时间较长的操作,这个任务调度器好像有点不能胜任呢! while里面的case语句估计楼主是想用来记录每次执行到此处退出时记录本次的行号和显示部分信息用的,目前没有用到好像也用不上吧,task2这个函数似乎没用处啊,很好奇。。。个人愚见,请手下留情{:lol:}
smset
发表于 2012-11-29 09:56:14
本帖最后由 smset 于 2012-11-29 09:57 编辑
数码管不论是动态还是静态扫描,都支持。 这是一个时间多任务调度器。
我把文件作为附件传上来,以此文件为准吧,应该不会有问题。
kentzhtao_top
发表于 2012-11-29 10:05:41
grash 发表于 2012-11-29 09:20 static/image/common/back.gif
如果用到串口通讯呢,如何处理
接收和发送都是用中断资源,任务里面只是简单的处理接收和要发送的数据,同时控制发送开启功能,效率会很高,基本上不会对其他任务造成影响。
思路 :
voidUartInter(void)interrupt 5/* 串口中断服务函数不记得51的串口是不是5了 */
{
if(接收到一个字节数据)
{
将数据存放到定义好的缓冲区里
清除接收标志位
}
else//发送数据中断启动了 一般启动发送中断后 只要发送缓冲器SBUF 为空就会产生中断申请
{
SBUF = 发送的数据;
if(i == 发送的个数)
{
i = 0;
关闭发送中断功能;//在任务里开启发送功能
}
}
}//完成
voidtask3(void)
{
处理接收到的数据 或 把需要发送的数据写入自己定义的缓冲区 并且 确定个数 i = ?;
需要发送数据则开启发送中断
}//完成
formatme
发表于 2012-11-29 10:08:37
将楼主的改了一点,用仿真,
formatme
发表于 2012-11-29 10:14:17
上传一个图片
kentzhtao_top
发表于 2012-11-29 10:14:44
smset 发表于 2012-11-29 09:56 static/image/common/back.gif
数码管不论是动态还是静态扫描,都支持。 这是一个时间多任务调度器。
我把文件作为附件传上来,以此文件为 ...
程序还是一样的呀,楼主并没有改啊,也没有解释啊 很明显return;之后就退出了整个函数这个是肯定的吧,task2永远都只执行里面的那个while(1)里的第一个for()语句,并且也只执行了i = 0;和Delay(20);return;这几条固定语句,后面的都不会执行了,不知道我想的对不对! 希望楼主能解释下,我不是来找麻烦的而是来学习的,相信有交流能学到的东西更多。。。
grash
发表于 2012-11-29 10:17:05
kentzhtao_top 发表于 2012-11-29 10:05 static/image/common/back.gif
接收和发送都是用中断资源,任务里面只是简单的处理接收和要发送的数据,同时控制发送开启功能,效率会很 ...
谢谢解答
smset
发表于 2012-11-29 11:10:08
kentzhtao_top 发表于 2012-11-29 10:14 static/image/common/back.gif
程序还是一样的呀,楼主并没有改啊,也没有解释啊 很明显return;之后就退出了整个函数这个是肯定的吧,t ...
那是因为你还没有跟踪过它应该有的延时之后。
maxims
发表于 2012-11-29 11:11:16
zhonggp 发表于 2012-11-28 23:46 static/image/common/back.gif
加载应用函数修改为函数方式:
LoadTaskFun(void *Fun,U8 funId);
删除通过
对这个说法有兴趣,能详细举个栗子么?
比方用AVr Atmega8芯片,做串口收PC,LCd1602显示,转发PC
smset
发表于 2012-11-29 11:15:29
maxims 发表于 2012-11-29 11:11 static/image/common/back.gif
对这个说法有兴趣,能详细举个栗子么?
比方用AVr Atmega8芯片,做串口收PC,LCd1602显示,转发PC ...
最早的版本就是有函数指针的,但是这样RAM占用会增加
在下个版本里,支持预装任务,我会加上任务的动态启停机制,顶级任务之间可以相互控制,控制启动暂停,停止。
kentzhtao_top
发表于 2012-11-29 11:33:06
smset 发表于 2012-11-29 11:10 static/image/common/back.gif
那是因为你还没有跟踪过它应该有的延时之后。
keil软件联合protues仿真,全速运行显示P1口数据是变化的,但是在keil 里P1处设置中断竟然不允许,但是数码管是一直在变化的(有点快和乱但是数据是0--F的字符),我很凌乱啊,不能理解,看来我的C语言功底是在是太差劲啦,要去补补宏这一章啦{:dizzy:}
formatme
发表于 2012-11-29 12:10:58
这个仿真可以看到task2里的三种运行状态
omlarn
发表于 2012-11-29 12:18:11
好贴!顶起!
miscell
发表于 2012-11-29 12:21:31
在PIC中编译通不过。
wtliu
发表于 2012-11-29 13:06:58
说实在的,没怎么看懂。是不是有人试过了?
eduhf_123
发表于 2012-11-29 13:16:17
本帖最后由 eduhf_123 于 2012-11-29 13:17 编辑
看见这么多人讨论的这么热烈,却搞不定代码格式的问题,忍不住想说一句:当你需要发代码时,请使用如下的形式:
要插入的代码片断
[/ code] //实际使用时去掉方括号里的那个空格
eduhf_123
发表于 2012-11-29 13:20:11
示例:#include <stdio.h>
int main(void)
{
printf("Hello World!");
return 0;
}
holts2
发表于 2012-11-29 13:22:15
试插一下,真的好用哈
#include <STC89C51.h>
/**************小小调度器开始啦 *********************************/
#define MAXTASKS 3 //顶层任务数量,可按需增加,最大为255个。
chartimers;
char currid; //当前运行的任务号
#define _SS static char lc=0; switch(lc){ case 0: //跳转开始
#define _EE }; lc=0;//跳转结束
#define DelayX(b)settimer(&lc,__LINE__,b); return ; case __LINE__: //任务内延时等待“函数”
#define RunTask(a,b) currid=b; if (timers==0){timers=-1; a();} //运行顶层任务
#define CallSub(x)DelayX(0);x(); if (timers!=-1) return; //调用子任务
void settimer(char *lc,charline,char d){//设置定时器
*lc=line;timers=d;
}
/****************小小调度器结束啦*********************************/
sbit KEY = P3^2;
unsigned char code numtab={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;
}
//初始化定时器,产生10ms中断
void InitT0()
{
TMOD = 0x21;
IE |= 0x82;// 12t
TL0=0Xff;
TH0=0Xb7;
TR0 = 1;
}
//定时器中断处理函数
void INTT0(void) interrupt 1 using 1
{
unsigned char i;
TL0=0Xff; //10ms 重装
TH0=0Xb7;
//逻辑定时器处理
for (i=0;i<MAXTASKS;i++){
if (timers>0) {
timers--;
}
}
}
sbit LED1= P2^4;
//任务一,状态机写法
void ontimer0(){
LED1=!LED1; // LED1引脚接在发光管负极,LED1=0 为亮,LED1=1为灭
if (LED1) timers=45; //450mS 灭
else timers=5; //50ms亮
}
//任务二,状态机写法
char keycount=0;
void task1(){
if(KEY==0) {
keycount++;
if (keycount>20) IAP_CONTR = 0x60;
}
else{
keycount=0;
}
timers=5; //重装定时器
}
//这是一个子任务函数
voidsubtask()
{
static char i;
_SS
for(i=0;i<=5;i++){
DelayX(20);
P1=numtab;
}
_EE
}
//任务三,“线程”写法,复杂任务请用这种方式来写,比传统状态机写法更简单,更自然,而且更省ROM!
voidtask2()
{
static char i; //变量请申明为静态的。
_SS
while(1){
for(i=0;i<=9;i++){ //先从0--9快速显示,间隔200mS
DelayX(20);
P1=numtab;
}
for(i=0;i<=9;i++){//然后从0--9慢速显示,间隔500mS
DelayX(50);
P1=numtab;
CallSub(subtask); //顶层任务的任何地方都可以调用子任务
}
//CallSub(subtask); //顶层任务的任何地方都可以调用子任务
}
_EE
}
void main()
{
P3M0 = 0x00;
P3M1 =0x00;
P1 = 0xff; //关LED数码管显示
InitT0(); //初始化定时器,以便产生10ms中断
KEY =1; //按键IO口
while(1){
clr_wdt(); //清除看门狗
//这里,只需运行顶层任务即可
RunTask(ontimer0,0); //ontimer0任务放在第0个任务槽
RunTask(task1,1); //task1任务放在第1个任务槽
RunTask(task2,2); //task2任务放在第2个任务槽
//...还可以增加更多任务
}
}
formatme
发表于 2012-11-29 14:25:25
#include "stdafx.h"
static char i;
void subtask()
{
// static char i;
static char lc=0;
//lc=79;
switch(lc)
{
case 0: //跳转开始
for(i=0;i<=5;i++)
{
//DelayX(20);
lc=79;
printf("i=%d\r\n",i);
return ;
case 79:
printf("79\r\n");
}
}; lc=0;//跳转结束
// return i;
}
int main(int argc, char* argv[])
{
char ii=0;
char b=0;
while(b<5)
{
b++;
printf("ii=%d\r\n",i);
subtask();
}
printf("Hello World!\n");
return 0;
}[/ code]
formatme
发表于 2012-11-29 14:28:37
ii=0
i=0 //第一次return
ii=0
79
i=1 //第2次return
ii=1
79
i=2 //第3次return
ii=2
79
i=3 //第4次return
ii=3
79
i=4 //第5次return
Hello World!
Press any key to continue
formatme
发表于 2012-11-29 14:32:08
第一次return后先进 case 79,再for,再return.上面是在c++调试后的结果
kentzhtao_top
发表于 2012-11-29 15:18:54
Talsinpo 发表于 2012-11-28 19:17 static/image/common/back.gif
是的啊,同问,还有个问题:
voidtask2(){ static char i; static char lc=0; switch(lc ...
知道怎么回事了case 语句用法还可以这样 晕啊
voidtask2()
{
static char i;
static char lc=0;
switch(lc)
{
case 0: lc=0;
while(1)
{
for(i=0;i<=9;i++)
{ //从0--9快速显示,间隔200mS
WaitX(2,20);//等待200mS,每次执行到这里后就会因为执行return语句而退出task2函数,
// 但是当下次来到switch(lc)时,由于lc = __LINE__;即函数直接跳到case __LINE__ :
// 语句开始执行P1=numtab语句 直到遇到第一个for()语句的结束符“}”而重新开始第一个for()语句
//settimer(&lc,__LINE__,2,20);return ;case __LINE__ ://当lc==__LINE__时,执行此语句
P1=numtab;
}
for(i=0;i<=9;i++)
{ //从0--9慢速显示,间隔500mS
WaitX(2,50);//等待500mS每次执行到这里后就会因为执行return语句而退出task2函数,
// 但是当下次来到switch(lc)时,由于lc = __LINE__;即函数直接跳到case __LINE__ :
// 语句开始执行P1=numtab语句 直到遇到第二个for()语句的结束符“}”而重新开始第2个for()语句
//settimer(&lc,__LINE__,2,50);return ;case __LINE__://当lc==__LINE__时,执行此语句
P1=numtab;
}
}
}; lc=0;
}
Talsinpo
发表于 2012-11-29 18:18:54
kentzhtao_top 发表于 2012-11-29 15:18 static/image/common/back.gif
知道怎么回事了case 语句用法还可以这样 晕啊
voidtask2()
return不是推出task2任务哦,而是return所在最里面的那个循环,即例子中的for循环吧!!!!
Talsinpo
发表于 2012-11-29 18:26:09
楼主啊,您的小调度器,关键点是switch语句和__line__的特殊用法,请问楼主是在什么地方获取的这个知识?还有其他的一些好玩的特殊的吗?如果有相关的书籍麻烦介绍一下!
shotstar
发表于 2012-11-30 08:43:23
应该 是来源于 Protothread
kentzhtao_top
发表于 2012-11-30 14:26:19
Talsinpo 发表于 2012-11-29 18:18 static/image/common/back.gif
return不是推出task2任务哦,而是return所在最里面的那个循环,即例子中的for循环吧!!!! ...
return 是直接退出函数 这个函数就是task2啦,然后定时时间到了,在顶层任务查询到task.timer = 0;重新进入task2函数 根据switch(lc)选择分支(直接跳到case __LINE__ : 开始执行P1= ???;然后遇到“}”后进入for(。。。) 此时 i= 1,然后又记录行号 return啦) 此时lc = 上次退出时那行的行号__LINE__
顺便说下P1的赋值慢了一个延时(一次for(...))因为第一次执行Delay(2,20)后 P1没有被执行,下次才开始执行。。。
eddia2012
发表于 2012-12-3 22:31:12
#include <STC89C51.h>
/**************小小调度器开始 *********************************/
#define MAXTASKS 3 //顶层任务数量,可按需增加,最大为255个。
unsigned chartimers;
char currid; //当前运行的任务号
#define _SS static char lc=0; switch(lc){ case 0: //跳转开始
#define _EE }; lc=0;//跳转结束
#define DelayX(b)settimer(&lc,__LINE__,b); return ; case __LINE__: //任务内延时等待“函数”
#define RunTask(a,b) currid=b; if (timers==0){timers=-1; a();} //运行顶层任务
#define CallSub(x)DelayX(0);x(); if (timers!=-1) return; //调用子任务
void settimer(char *lc,charline,unsigned char d){//设置定时器
*lc=line;timers=d;
}
/****************小小调度器结束*** (我很短,但用起来很爽)******************************/
{:biggrin:}{:biggrin:}好思路哦,谢谢啦!呵呵
eddia2012
发表于 2012-12-3 22:31:46
希望看到楼主的下一个版本,呵呵
smset
发表于 2012-12-4 12:16:50
哦,但没看到有其他编译环境的案例呢。
chenjnh
发表于 2012-12-4 16:23:23
关注一下
topdog
发表于 2012-12-4 17:01:07
smset 发表于 2012-11-27 18:43 static/image/common/back.gif
嗯,我可以设置个监控机制,如果某个任务占用时间过长,可以暂停掉这个任务一段时间。
而死循环调试程 ...
放個狗看一下不行嗎?
xsh2005105326
发表于 2012-12-4 17:27:58
holts2 发表于 2012-11-29 13:22 static/image/common/back.gif
试插一下,真的好用哈
试试,还没用过void main()
gallle
发表于 2012-12-4 17:32:11
回头研究一下!{:smile:}
trey21ic
发表于 2012-12-4 17:34:06
这种方法的鼻祖应该是protothread,已用于LWIP中,freeRTOS中的协程也是基于这种原理
PaulDE
发表于 2012-12-4 20:53:34
本帖最后由 PaulDE 于 2012-12-4 20:56 编辑
Mark 调度器
难道我上次没有按爪吗??
这么好的帖子
minier
发表于 2012-12-4 21:54:48
protothrea+时间触发的合作模式
minier
发表于 2012-12-4 21:55:06
protothrea+时间触发的合作模式
minier
发表于 2012-12-4 21:56:25
若采用GCC,可以有比switch更好的机制,快速任务阻塞、跳转和切换
dujuan8693
发表于 2012-12-4 22:12:42
学习一下!
smset
发表于 2012-12-4 23:08:23
本帖最后由 smset 于 2012-12-5 09:54 编辑
利用了Pt的语法,并非简单照搬,而是改造了原Pt的延时模式,大幅节省任务所需资源,从原Pt任务的10B Ram到现在的2B Ram.原Pt任务每状态35~40 ROM消耗字节到现在的13字节,一切都为了追求更小巧自然。
其实这个调度器的重点并不真正在于与Pt的语法,而是对节省CPU资源的极致追求。
以前,裸奔之所以一直存在,是因为,裸奔对资源的要求几乎小于所有嵌入式操作系统。
在设计这个调度器之前,一直在想一个问题: 状态机有多“便宜”?,有没有比“状态机”更便宜的?如果有比状态机更“便宜”的编程方法,那裸奔还有什么意义么?
另外,设计一个调度器,不仅仅是框架本身对资源的要求要小,还有一个方面就是任务函数内部的处理过程,对资源的要求也要小。
我以前用ProtoThread来做了多种产品,确实也算很省RAM, 但是我发现了ProtoThread的一个最大的问题: 任务函数内每个状态消耗的字节太高,比状态机还高,也就是说编译出来的CODE比用状态机方式要大。
对于ROM资源紧张的单片机来说(比如2K,4K或8K字节Flash),这个可能是一个不小的问题。
传统状态机的优点在于: 当状态很简单时,确实是最省ROM的。比如一个LED闪烁,只需10多个字节就可以了。另外一个优点是,高度可移植性,与cpu无关,任何cpu编程,都可以用状态机来做。
睡着任务的复杂化,状态增多时,状态机的ROM消耗就会变大。
所以我在本调度器里面,保留了两种语法:
一种是传统状态机,用于简单的任务。比如LED闪烁等。
另一种就是经过改良的PT语法,经过我实际测试,改良的PT语法,一个状态的平均消耗是13字节,当状态量达到4个左右时,改良的PT语法所消耗的ROM就会小于传统状态机语法了,
而且任务越复杂,状态量越多,改良的PT语法比传统状态机语法苏所节省资源越多。
那么,这就实现了一个逆转!在复杂任务面前,传统状态机语法“输了”! 改良的PT语法不仅仅是写起来更自然,更易懂,而且还更“便宜”,而且同样与cpu无关,具备高度移植性。
基于大部分产品而言,任务不会简单到只闪烁一个LED,从总体来讲,使用本调度器,确实是比裸奔更省资源了。
这个才是本调度器的真正意义所在。
eddia2012
发表于 2012-12-5 08:29:30
/*****************小小调度器部分开始********************************************/
#define_SS static char lc=0; switch(lc){ case 0: lc=0;
#define_EE }; lc=0;
#defineWaitX(a,b)settimer(&lc,__LINE__,a,b); return ; case __LINE__:
struct TASK {
char td;
void (*fp)();
};
#define MAXTASKS 5
struct TASK tasks;
//设置定时器
void settimer(char *lc,charline,chartmrid,int d){
*lc=line;
tasks.td=d;
}
//逻辑定时器处理,在定时器中断里调用
void dectimers() {
unsigned char i;
for (i=0;i<MAXTASKS;i++){
if (tasks.td>0)tasks.td--;
}
}
//任务调度函数,在main里面运行
void runtasks() {
unsigned char i;
for(i=0;i<MAXTASKS;i++)
{
if (tasks.fp!=0){
if (tasks.td==0){
tasks.td=-1;
tasks.fp();
}
}
}
}
/****************小小调度器部分结束*******************************************************/
lc 的数据类型是 char,而lc是用来保持任务的—LIN—,这个数最是可以超过255的,比如这个__LINE__ = 256 = 0x100,那case __LINE__时,这个值就是 case 0: 这样 __SS中定义的 lc = 0 就一样了,一个switch语句中有可能出现两个case 0;
smset
发表于 2012-12-5 09:18:47
eddia2012 发表于 2012-12-5 08:29 static/image/common/back.gif
/*****************小小调度器部分开始********************************************/
#define_SS st ...
{:smile:} 对,你分析得很细哈。之所以这样,是为了节省RAM,如果不想省这个字节,用unsigned int也可以的。
遇到这个情况,编译器会报告重复的 case,你在WaitX()前加一行回车就解决了。
smset
发表于 2012-12-5 09:20:13
或改下宏也可以的: #defineWaitX(a,b)settimer(&lc,__LINE__+(!__LINE__),a,b); return ; case __LINE__+(!__LINE__):
smset
发表于 2012-12-5 09:22:22
topdog 发表于 2012-12-4 17:01 static/image/common/back.gif
放個狗看一下不行嗎?
也行,你一定是个放狗高手,从你的昵称就知道了。{:lol:}
microsoho
发表于 2012-12-5 09:46:44
mark 学习
eddia2012
发表于 2012-12-5 11:45:17
我发一个在楼主上面改好的例程一个是C51,一个是sonix MCU下的
先发下C51,并贴上全文:
/*********************************
Titel :pTask.h
Mcu :8-32 bit
RAM :bytes: 5 * (D_TASKS_MAX)+6
ROM :bytes: < 0.5K
Complier :Support of c compiler
Author :Eddie
Version:V1.3
Updata :2012-12-05
**********************************/
/*
Note:
Note:
(1).add task multithreading mode(PTM)
(2).add taks Time-triggered mode(TTM)
(3).change: ptm to pt/tt Mixed-mode
(4).debug:Task_tick()
(5).Optimization;
(6).add func: void Task_start(u8 tid)
(7).add subcall()
*/
#ifndef _pTask_h_
#define _pTask_h_
//--------------------user define------------------
#define D_TASKS_MAX 3
#define lc_type u8
#define ENI() EA = 1
//---------------data type------------------------
#define u8 unsigned char
#define u16unsigned int
#define u32unsigned long
//------------------------------------------------
//---------------task constant define-------------
#define D_Task0_ID 0
#define D_Task1_ID 1
#define D_Task2_ID 2
#define D_Task3_ID 3
#define D_Task4_ID 4
#define D_Task5_ID 5
#define D_Task6_ID 6
#define D_Task7_ID 7
#define D_Task8_ID 8
//------------------------------------------------
#define D_Delay_ever ((u8)-1)
#define D_period_ever ((u8)-1)
#define D_wait_ever ((u8)-1)
//-----------------function define----------------
void ptk_set_timer(lc_type *lc,lc_typeline,u8 timeover);
void Task_create(void (*pFunc)() ,u8 tid);
voidTask_start(u8 tid);
//-----------------------------------------------
struct
{
void (* pTask)(void);
}func;
u8 taskSleep;
u8 taskID,taskEvenRdy;
u8 tIndex,eIndex;
bit task_Wait_flag;
/******************************************************
Micro : PTK_BEGIN
Note : 启动任务处理,放在函数开始处
Updata : 2012-12-03
*******************************************************/
#define PTK_BEGIN \
static lc_type lc=0; switch(lc){ case 0:
/******************************************************
Micro : PTK_END
Note : 结束任务,放在函数的最后
Updata : 2012-12-03
*******************************************************/
#define PTK_END } lc=0;
/************************************************
Function : ptk_set_lc
Stacks :
Note : 线程任务lc设定
Updata : 2012-12-03
************************************************/
#define ptk_set_lc() \
*lc = (lc_type)__LINE__
/******************************************************
Micro : Task_ReInit
Stacks :
Note : 重新初始化进程.
Updata : 2012-12-03
*******************************************************/
#define Task_ReInit() *lc = 0; return
/************************************************
Micro : Task_setsleep
Stacks :
Note : 设置指定的进程为休眠状态
Updata : 2012-12-04
************************************************/
#define Task_setsleep(tid, timeover) \
taskSleep = timeover
/******************************************************
Micro : Task_sleep
Stack : 1
Note : 进程立即进入休眠
Updata : 2012-12-03
*******************************************************/
#define Task_sleep(timeover) \
do{ \
ptk_set_timer(&lc,(lc_type)__LINE__,timeover); \
case (lc_type)__LINE__: \
if(taskSleep)return; \
}while(0)
/************************************************
Micro : Task_delay
Stacks :
Note : 进程内延时
Updata : 2012-12-04
************************************************/
#define Task_delay(timeover) \
Task_sleep(timeover)
/************************************************
Micro : Task_period
Stacks :
Note : 进程运行周期
Updata : 2012-12-04
************************************************/
#define Task_period(timeover) \
Task_sleep(timeover)
/******************************************************
Micro : Task_condic_wait
Stacks :
Note : 等待条件或超时
Updata : 2012-12-04
*******************************************************/
#define Task_condic_wait(condiction,timeover) \
do{ \
ptk_set_timer(&lc,(lc_type)__LINE__,timeover); \
case (lc_type)__LINE__: \
if((!(condiction))&& taskSleep) return;\
task_Wait_flag = (condiction)? 1:0; \
}while(0)
/******************************************************
Micro : Task_event_wait
Stacks :
Note : 等待事件或超时
Updata : 2012-12-03
*******************************************************/
#define Task_event_wait(timeover) \
do{ \
ptk_set_timer(&lc,(lc_type)__LINE__,timeover); \
case (lc_type)__LINE__: \
if((!(taskEvenRdy & (1<<taskID)))&& taskSleep) \
return; \
task_Wait_flag = (taskEvenRdy & (1<<taskID))? 1:0;\
taskEvenRdy &= 0xff ^ (1<<taskID); \
}while(0)
/************************************************
Micro : Ints_event_send
Stacks :
Note : 中断或进程向进程传事件消息
Updata : 2012-12-04
************************************************/
#define Ints_event_send(tid) \
do{ \
taskEvenRdy |= (1<<tid); \
taskSleep = 0; \
}while(0)
/************************************************
Micro : Ints_even_clear
Stacks :
Note : 清除进程传事件消息
Updata : 2012-11-21
************************************************/
#define Ints_even_clear() \
taskEvenRdy &= 0xff ^ (1<<taskID)
/************************************************
Micro : Task_event_send
Stacks :
Note : 向进程传事件消息,并切换到等待此事件的任务
Updata : 2012-12-04
************************************************/
#define Task_event_send(tid) \
do{ \
taskEvenRdy |= (1<<tid); \
taskID = tid; taskSleep = 0; \
ptk_set_lc(); return; \
case (lc_type)__LINE__: \
taskID = taskID; \
}while(0)
/******************************************************
Micro : Task_switch
Stacks :
Note : 任务切换
Updata : 2012-12-04
*******************************************************/
#define Task_switch() \
do{ \
ptk_set_lc();return; \
case (lc_type)__LINE__: \
taskID = taskID; \
}while(0)
/************************************************
Micro : Task_setsuspend
Stacks :
Note : 设置指定的进程为休眠状态.
Updata : 2012-11-19
************************************************/
#define Task_setsuspend(tid) \
taskSleep = D_Delay_ever
/************************************************
Micro : task_suspend
Stacks :
Note : 进程立即进入休眠
Updata : 2012-12-04
************************************************/
#define Task_suspend() \
do{ \
ptk_set_timer(&lc,(lc_type)__LINE__,D_Delay_ever); \
case (lc_type)__LINE__: \
if(taskSleep) return; \
}while(0)
/************************************************
Micro : Task_resume
Stacks :
Note : 唤醒指定的进程.
Updata : 2012-11-22
************************************************/
#define Task_resume(tid) \
do{ \
if(tid != taskID) \
taskSleep = 0; \
}while(0)
/*******************************************************
Micro : Task_subCall
Stacks :
Note : 调用子任务
Updata : 2012-12-03
*******************************************************/
#define Task_subCall(subTask) \
do{ \
ptk_set_timer(&lc,(lc_type)__LINE__,0); return ;\
case (lc_type)__LINE__:subTask(); \
if(taskSleep) return; \
}while(0)
/************************************************
Micro : Task_tick
Stacks :
Note : 更新进程定时器
Updata : 2012-12-03
************************************************/
#define Task_tick() \
do{ \
for(tIndex = 0; tIndex < D_TASKS_MAX; tIndex++) \
{ \
if(taskSleep != D_Delay_ever) \
{ \
if(taskSleep){ \
taskSleep--;} \
} \
} \
}while(0)
/************************************************
Micro : Task_schedule
Stacks :
Note : 进程调度,事件触发优先
Updata :2012-12-04
************************************************/
#defineTask_schedule() \
do{ \
for(eIndex = 0; eIndex < D_TASKS_MAX; eIndex++) \
{ \
if(taskEvenRdy & (1<<eIndex)) \
{ \
taskID = eIndex; \
goto L_Sch; \
} \
} \
if(taskSleep == 0) \
{ \
L_Sch:(*func.pTask)(); \
} \
if(++taskID >= D_TASKS_MAX){taskID = 0;} \
}while(0)
/************************************************
Function : ptk_set_timer
Stacks :
Note : 线程任务定时设定
Updata : 2012-12-03
************************************************/
void ptk_set_timer(lc_type *lc,lc_typeline,u8 timeover)
{
*lc=line;taskSleep = timeover;
}
/************************************************
Function : Task_create
Stacks :
Note : 初始化任务
Updata : 2012-11-26
************************************************/
void Task_create(void (*pFunc)() ,u8 tid)
{
func.pTask = pFunc;
}
/************************************************
Function : Task_start
Stacks :
Note : 从指定任务开始运行
Updata : 2012-11-26
************************************************/
voidTask_start(u8 tid)
{
u8 i;
for(i = 0;i < D_TASKS_MAX;i++)
{
taskSleep = 1+i;
}
taskID = tid;
ENI();
}
//-----------------------End of file---------------
#endif
#include <STC89C51.h>
#include "pTask.h"
sfr IAP_CONTR = 0xC7;
sfr WDT_CONTR = 0xC1;
sbit KEY = P3^2;
sbit LED1= P2^4;
u8 code numtab={ 0x24,0x6F,0xE0,0x62,
0x2B,0x32,0x30,0x67,
0x20,0x22,0x21,0x38,
0xB4,0x68,0xB0,0xB1
};
u8 keycount = 0;
/************************************************
Function : WDTC
Input :
Output :
Return :
Stacks : 1
Note :
Updata : 2012-12-04
************************************************/
void WDTC()
{
WDT_CONTR =0x3C;
}
/************************************************
Function : Init_IO
Input :
Output :
Return :
Stacks : 1
Note :
Updata : 2012-12-04
************************************************/
void Init_IO()
{
P3M0 = 0x00;
P3M1 =0x00;
P1 = 0xff; //关LED数码管显示
KEY = 1;
}
/************************************************
Function : Init_TMR0
Input :
Output :
Return :
Stacks : 1
Note : 初始化定时器,产生10ms中断
Updata : 2012-12-04
************************************************/
void Init_TMR0()
{
TMOD = 0x21;
IE |= 0x82;
TL0 = 0Xff;
TH0 = 0Xb7;
TR0 = 1;
}
/************************************************
Function : INTT0 interrupt
Input :
Output :
Return :
Stacks : 1
Note : 定时器中断处理函数
Updata : 2012-12-04
************************************************/
void INTT0(void) interrupt 1 using 1
{
TL0=0Xff;
TH0=0Xb7;
Task_tick();
}
/************************************************
Function : Task0_led
Input :
Output :
Return :
Stacks :
Note : 任务一,
LED1引脚接在发光管负极,
LED1=0 为亮,LED1=1为灭
Updata : 2012-12-04
************************************************/
void Task0_led()
{
PTK_BEGIN
while(1)
{
LED1 = !LED1;
if (LED1)
Task_delay(45);
else
Task_delay(5);
}
PTK_END
}
/************************************************
Function : Task0_led
Input :
Output :
Return :
Stacks :
Note : 任务二
Updata : 2012-12-04
************************************************/
void Task1_key()
{
static bit SameKey_F = 0;
PTK_BEGIN
while(1)
{
if(KEY)
{
if((++keycount >= 20)&&(!SameKey_F))
{
IAP_CONTR = 0x60;
SameKey_F = 1;
}
}
else
{
keycount = 0;
SameKey_F = 0;
}
Ints_event_send(D_Task2_ID);
Task_delay(5);
}
PTK_END
}
/************************************************
Function : subtask
Input :
Output :
Return :
Stacks :
Note : 这是一个子任务函数
Updata : 2012-12-04
************************************************/
voidsubtask()
{
static char i;
PTK_BEGIN
while(1)
{
for(i=0;i<=5;i++)
{
P1=numtab;
Task_event_wait(D_wait_ever);
}
}
PTK_END
}
/************************************************
Function : Task2_display
Input :
Output :
Return :
Stacks :
Note : 任务三,“线程”写法,复杂任务请用这种
方式来写,比传统状态机写法更简单,
更自然,而且更省ROM!
顶层任务的任何地方都可以调用子任务
Updata : 2012-12-04
************************************************/
voidTask2_display()
{
static char i;
PTK_BEGIN
while(1)
{
for(i=0;i<=9;i++) //先从0--9快速显示,间隔200mS
{
P1=numtab;
Task_delay(20);
}
for(i=0;i<=9;i++) //然后从0--9慢速显示,间隔500mS
{
P1=numtab;
Task_event_wait(50);
if(task_Wait_flag)
{
Task_subCall(subtask);
}
}
}
PTK_END
}
/*************************************************************
main program zone
*************************************************************/
void main()
{
Init_IO();
Init_TMR0();
Task_create(Task0_led, D_Task0_ID);
Task_create(Task1_key, D_Task1_ID);
Task_create(Task2_display,D_Task2_ID);
Task_start(D_Task0_ID);
while(1)
{
WDTC();
Task_schedule();
}
}
eddia2012
发表于 2012-12-5 11:48:44
下面是用在sonix 上的一个智能家居控制上的例子:
/********************************************
Title : main
McuBody : SN8F26E611
RAM : 128*8Bit
ROM : 2K*16Bit
STACKS : 8 level
I/O PORT: 11
PWM PORT: 3(P17/16/P15)
T0 : 8bit base timer
T1 : 16bit
TC0-2 : 3* 8bit timer/count with pwm/cout_out(auto load)
EXINT : 2(INT0/INT1)
ADC : 8 channel(12bit)
INTS : 11(INT0/T0/T1/TC0/TC1/TC2/CMP/URX/UTX/SIO/WAKEUP)
OPTION : Security-------Enable
High Fcpu------Fosc/2
High_clk-------IHRC_16M
Low Fcpu-------FLosc/1
Watchdog-------Enable
LVD------------LVD_L
Resetpin-------P02
WDT_CLK--------Flosc/4
WDT TIME: about 512ms_3v/256ms_5v
WORK_VCC: 3.3V
IDE : SN8 C Studio_V146(572.015)
Author : Eddie
Updata : 2012-12-04
Verison : A/01
********************************************/
/*
Note:
(1).debug:Confirm Communication() 0x02 to 0x03
(2).change: nTask.h to pTask.h
;--------------------------------------------
;P00 ----- TEST1
;P01 ----- TEST2
;P02 ----- NC2
;P10 ----- UTX
;P11 ----- URX
;P12 ----- URTS
;P13 ----- UCTS
;P14 ----- NC3
;P15 ----- NC4
;P16 ----- NC5
;P17 ----- TRIG_IN
;--------------------------------------------
*/
#include <SN8F26E611.h>
#include "SN26E611_USER.h"
#include "typedef.h"
#include "pTask.h"
//====================================================================
//---------------------------uart rx/tx------------------------------
volatile u8 RxBuf,TxBuf,RxIndex,TxCnt,TxWaitT2ms,WdtT2ms;
volatile u8 __ROM *TxPrt;
volatile u8 TxCodeNum;
volatile bit RxPackageOK_F,TxPackage_F;
volatile bit RxConnectOK_F;
volatile bit Task0Runing_F,Task1Runing_F,Task2Runing_F;
volatile bit beTrig_F;
/********************************************************************************
Interrupts Program Zone
********************************************************************************/
//===============================================================================
void __interrupt ISR_WakeInt(void){}
void __interrupt ISR_INT0 (void){}
void __interrupt ISR_T0 (void){}
void __interrupt ISR_TC1 (void){}
void __interrupt ISR_TC2 (void){}
void __interrupt ISR_T1 (void){}
void __interrupt ISR_CM0 (void){}
void __interrupt ISR_SIO (void){}
//===============================================================================
void __interrupt ISR_TC0(void)
{
static u8 T60msBase = 10;
static bit TrigInOld_F;
FTC0IRQ = 0u;
//---------------------------------------
TxWaitT2ms++;
WdtT2ms++;
//-------------trig in check------------
if(!(--T60msBase))
{
T60msBase = 30;
if(!beTrig_F)
{
if(TrigInOld_F && (!TRIG_IN))
{
beTrig_F = 1;
Ints_event_send(D_Task1_ID);
}
}
TrigInOld_F = TRIG_IN;
}
//------------task time check------------
Task_tick();
}
void __interrupt ISR_UART_RX(void)
{
u8 FccSum ,i;
//-------------------------Uart process-------------------------
//if((FUFMER == 0)&&(RxPackageOK_F == 0))
if(RxPackageOK_F == 0)
{
RxBuf = URXD;
if(RxIndex > 12) {RxIndex = 0;} //rx burrer size max as 12
else
{
if(RxBuf == D_Frame_STX)
{
if((RxBuf == 0x00)&&(RxBuf >=0x6)&&(RxBuf <= 0x0A)&&(RxIndex == RxBuf+2))
{
FccSum = 0x00;
for(i = 1;i < RxIndex;i++) {FccSum += RxBuf;}
if(FccSum == 0)
{
Disable_Rx();
RxIndex = 0;
RxPackageOK_F = 1;
Ints_event_send(D_Task0_ID);
}
else {RxIndex = 0;}
}
}
else {RxIndex = 0;}
}
}
//---------Clear signs on the last-----------
FURXIRQ=0;
//-------------------------------------------
}
void __interrupt ISR_UART_TX(void)
{
FUTXIRQ = 0;
if(TxCnt > 0)
{
UTXD = *TxPrt;
TxPrt++;
TxCnt--;
}
else
{
TxPackage_F = 0;
} //TxCnt == 0 mains the last byte trans completed}
}
/********************************************************************************
Sub Program Zone
********************************************************************************/
/************************************************
Function : IO_Init
Input :
Output :
Return :
Stacks : 1
Note : IO initalization
"1"----output
"0"----input
Updata : 2012-11-07
************************************************/
void IO_Init(void)
{
P0CR = (1<<P_TEST1)|(1<<P_TEST2);
P1CR = (0<<P_URX)|(1<<P_UTX)|(0<<P_URTS)|(1<<P_UCTS)|(0<<P_TRIG_IN);
//---------------
P0PHCR = 0xffu; //
P1PHCR = 0xffu ^ (1<<P_TRIG_IN);
//---------------
PORT0 = (0<<P_TEST1)|(0<<P_TEST2);
PORT1 = (1<<P_UTX)|(0<<P_UCTS); //disable Uart sent frist
}
/************************************************
Function : Timer_Init
Input :
Output :
Return :
Stacks : 1
Note : Fcpu =HIRC(16MHz)/2 = 8MHz
tc0 timeout period as 2ms
Updata : 2012-11-06
************************************************/
void Timer_Init(void)
{
//disable all interrutps first,and clr all irq flag
DISI();
//--------------enable t0 for delay()-------------
T0CR = T0Prescale_128; //t0clk period as 8us
FT0IEN = 0; //disable t0 interrupt
FT0ENB = 1;
//--------------enable tc1 timerover interrupt-------
TC0CR = (TCxPrescale_128 | AS_TIMER | TCxCLK_AS_FCPU | DS_TCxOut | DS_PWMx);
TC0 = TC0R = D_TC0_Preset;
FTC0IEN = 1; //enable tc0 interrupt
FTC0ENB = 1; //enable use tc0
}
/************************************************
Function : Uart_Init
Input :
Output :
Return :
Stacks : 1
Note : Fhosc =HIRC(16MHz)
Fcpu = Fhosc/2 = 8MHz
9.6K baud rate
Updata : 2012-11-08
************************************************/
void Uart_Init(void)
{
FUTXPEN = 0; // Disable UART TX parity bit check function
FURXPEN = 0; // Disable UART RX parity bit function.
URRX = D_URS_BR_9600;
URCR = D_URC_BR_9600; // Set UART baud rate as 9600bps.
FUTXEN = 1; // Enable UART TX
FURXEN=1; // Enable UART RX
FUTXIEN=1; // Enable UART TX interrupt function.
FUTXIRQ= 0; // Clear UART TX interrupt flag.
FURXIEN = 1; // Enable RX interrupt
FURXIRQ =0; // clear RX interrupt request flag
}
/************************************************
Function : Delay2Ms
Input :
Output :
Return :
Stacks : 2
Note : Fosc = 16MHz
Fcpu = Fosc/1=16MHz
Updata : 2012-11-05
************************************************/
void Delay2Ms(u8 ms)
{
while(ms--)
{
WDTC();
T0 = 0x06;
while(T0);
}
}
/************************************************
Function : Commun_Response
Input :
Output :
Return :
Stacks : 1
Note : fire alerm
Updata : 2012-12-04
************************************************/
u8 __ROMCommun_Response = { //0x02,
0x00,
0x0a,
0x43,
0x4e,
0x4e,
0x54,
0x0b,
0x03,
0x00,
0x00,
0xb6};
/************************************************
Function : State_Normal
Input :
Output :
Return :
Stacks : 1
Note :
Updata : 2012-10-08
************************************************/
u8 __ROMState_Normal={ //0x02, //STX
0x00, //LenghtH
0x08, //LenghtL
'R', //0x52
'G', //0x47
'A', //0x41
'L', //0x4C
'N', //0x4E
'A', //0x41
0x43}; //fcc
/************************************************
Function : State_Ringing
Input :
Output :
Return :
Stacks : 1
Note :
Updata : 2012-11-05
************************************************/
u8 __ROMState_Ringing ={ //0x02, //STX
0x00, //LenghtH
0x08, //LenghtL
'R', //0x52
'G', //0x47
'A', //0x41
'L', //0x4C
'O', //0x4F
'N', //0x4E
0x35}; //fcc
/************************************************
Function : State_RxError
Input :
Output :
Return :
Stacks : 1
Note :
Updata : 2012-10-08
************************************************/
u8 __ROMState_RxError = { //0x02, //STX
0x00, //LenghtH
0x08, //LenghtL
'R', //0x52
'G', //0x47
'A', //0x41
'L', //0x4C
'E', //0x45
'1', //0x31
0x5C}; //fcc
/************************************************
Function : Prefix_Body_Check
Input :
Output :
Return :
Stacks : 1
Note : prefix_body bytes
Updata : 2012-11-07
************************************************/
u8 Prefix_Body_Check(char __ROM *string,u8 length)
{
u8 i;
length = length +3;
for(i = 3;i < length;i++)
{
if(RxBuf != (u8)*string) break;
string++;
}
if(i < length){i = 0x00;}
return i;
}
/************************************************
Function : TrigInLevelChk
Input :
Output :
Return :
Statcks: 1
Note :
Updata : 2012-11-07
************************************************/
u8 TrigInLevelChk(u8 times)
{
u8 i = 0;
while(times--)
{
if(!TRIG_IN) i++;
}
return i;
}
/************************************************
Function : Tx_SenMsg
Input :
Output :
Return :
Stacks : 1
Note :
Updata : 2012-11-08
************************************************/
void Tx_SenMsg(u8 CodeNum)
{
switch(CodeNum)
{
case 0:
{
TxPrt = Commun_Response;
TxCnt = 11;
break;
}
case 1:
{
TxPrt = State_Ringing;
TxCnt = 9;
break;
}
case 2:
{
TxPrt = State_Normal;
TxCnt = 9;
break;
}
case 3:
{
TxPrt = State_RxError;
TxCnt = 9;
break;
}
}
//---------------trans code-----------
if(CodeNum < 4)
{
TxWaitT2ms = 0;
while((URTS == 0)||(TxPackage_F == 1)) //wait reqest to send singal
{
if(TxWaitT2ms >= 150) return; //timeover as 300ms
}
TxPackage_F = 1;
UTXD = D_Frame_STX; //STX
}
//------------------------------------
}
/************************************************
Function : Task_Start
Input :
Output :
Return :
Stacks : 2
Note :
Updata : 2012-12-04
************************************************/
void Task_Init(void)
{
Delay2Ms(250);
Enable_Rx();
}
/************************************************
Function : Task0_Rxdecoded
Input :
Output :
Return :
Stacks : 2
Note :
Updata : 2012-12-04
************************************************/
void Task0_Rxdecoded(void)
{
PTK_BEGIN
while(1)
{
Task_event_wait(D_wait_ever);
//-----------Confirm Communication-------
if(Prefix_Body_Check("CNNT",4))
{
Enable_Rx();
TxCodeNum = D_Commun_Response;
Tx_SenMsg(TxCodeNum);
RxConnectOK_F = 1;
}
//-----------Command send from RF---------
else if(Prefix_Body_Check("SGAL0000",8))
{
Enable_Rx();
if(TrigInLevelChk(20) >= 5)
{
TxCodeNum = D_State_As_Ringing;
Tx_SenMsg(TxCodeNum);
}
else
{
TxCodeNum = D_State_As_Normal;
Tx_SenMsg(TxCodeNum);
}
}
//-----------Command Reply from RF---------
else if(Prefix_Body_Check("CGWLOK",6))
{
Enable_Rx();
}
else if(Prefix_Body_Check("CGWLE1",6))
{
Enable_Rx();
Tx_SenMsg(TxCodeNum);
}
//------------Communication Error ---------
else
{
Enable_Rx();
Tx_SenMsg(D_State_RxError);
}
}
PTK_END
}
/************************************************
Function : Task1_TxTrigsigle
Input :
Output :
Return :
Stacks : 2
Note : task perid as 50ms
Updata : 2012-12-04
************************************************/
void Task1_TxTrigsigle(void)
{
PTK_BEGIN
while(1)
{
Task_event_wait(25);
if(task_Wait_flag)
{
beTrig_F = 0;
TxCodeNum = D_State_As_Ringing;
Tx_SenMsg(TxCodeNum);
}
}
PTK_END
}
/********************************************************************************
Main Program Zone
********************************************************************************/
void main(void)
{
DISI();
WDTC();
IO_Init();
Uart_Init();
Timer_Init();
Task_Init();
Task_create(Task0_Rxdecoded,D_Task0_ID);
Task_create(Task1_TxTrigsigle,D_Task1_ID);
Task_start(D_Task0_ID);
//----------------------------main loop-----------------------------------
while(1)
{
Task_schedule();
WDT_Clear();
}
}
eddia2012
发表于 2012-12-5 11:52:28
下面是源码:
eddia2012
发表于 2012-12-5 11:52:50
attach://74370.rar
eddia2012
发表于 2012-12-5 11:53:21
没上传好,再传
smset
发表于 2012-12-5 12:10:27
本帖最后由 smset 于 2012-12-5 12:13 编辑
eddia2012 ,很好啊,你这么快就应用起来了。
eddia2012
发表于 2012-12-5 12:36:58
{:smile:}谢谢楼主! 还是看过楼主的"推荐protothread多任务,很适合lgt" 才接触到 protothread的,也是在看过你的新作后,在你的上面稍加修改,然后用在项目上了,
已用它开发两个小项目了,呵呵
tangguanglun
发表于 2012-12-5 12:51:43
感谢楼主分享了
tangguanglun
发表于 2012-12-5 20:30:43
本帖最后由 tangguanglun 于 2012-12-5 20:33 编辑
我/*
配置为通用定时器定时10ms
*/
void TimerCfgtiming(unsigned long ms)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//72M
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = ms * 10; // 1/f * 10 * ms
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
TIM_PrescalerConfig(TIM1, 7200, TIM_PSCReloadMode_Immediate);//定时器时钟72M / 7200 = 10K = f
TIM_ARRPreloadConfig(TIM1, DISABLE);//禁止ARR预装载缓冲器
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //使能定时器为溢出中断
TIM_Cmd(TIM1, ENABLE);
}
/*
配置为定时器定时溢出中断
*/
void TimerNVICCfg(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void task1()
{
_SS
while (1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_1);
DelayX(100);
}
_EE
}
voidtask2()
{
_SS
while(1)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_1);
DelayX(100);
}
_EE
}
void main()
{
GPIOCfgIO();
TimerCfgtiming(10);
TimerNVICCfg();
while(1)
{
RunTask(task1, 0); //task1任务放
RunTask(task2, 1); //task2任务放
}
}我像这样写了,下载到STM32的板子里面,仿真时任LED灯并没有出现预期的间隔1s闪烁的情况. 这个延时到底是怎么回事呢。
qq1806765274
发表于 2012-12-5 20:31:18
学习了{:smile:}
smset
发表于 2012-12-5 21:31:04
本帖最后由 smset 于 2012-12-5 21:35 编辑
tangguanglun 发表于 2012-12-5 20:30 static/image/common/back.gif
我我像这样写了,下载到STM32的板子里面,仿真时任LED灯并没有出现预期的间隔1s闪烁的情况. 这个延时到底是 ...
task1,task2同时在执行,同时控制同一个LED,不带这么奢侈的啊。
一个LED闪烁一个任务就搞定啊:
void task1()
{
_SS
while (1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_1);
DelayX(100);
GPIO_ResetBits(GPIOC, GPIO_Pin_1);
DelayX(100);
}
_EE
}
tangguanglun
发表于 2012-12-5 21:43:50
smset 发表于 2012-12-5 21:31 static/image/common/back.gif
task1,task2同时在执行,同时控制同一个LED,不带这么奢侈的啊。
一个LED闪烁一个任务就搞定啊:
我只是测试能否实现在规定时间之内调度其他任务。 但是我测试的结果却是否定的
dr2001
发表于 2012-12-5 21:58:27
tangguanglun 发表于 2012-12-5 21:43 static/image/common/back.gif
我只是测试能否实现在规定时间之内调度其他任务。 但是我测试的结果却是否定的 ...
代码的问题可能在于要看到效果的话,需要两个任务启动的时候岔开一定的时间,否则LED操作了也不一定能显示。
dr2001
发表于 2012-12-5 22:09:33
smset 发表于 2012-12-4 23:08 static/image/common/back.gif
利用了Pt的语法,并非简单照搬,而是改造了原Pt的延时模式,大幅节省任务所需资源,从原Pt任务的10B Ram到 ...
ProtoThread的Switch方法可以在continuation上消耗的字节数很少,但是生成的代码会是一个序列比较链,当间断点多的时候,整体效率会低。
这个使用Labels as Values的扩展可以直接解决,如果使用GCC,Keil MDK等编译器,效果会好很多。当然,基于标准C也有代码不那么优雅的方法,但是可以让编译器进行跳转表优化。
这个就看怎么取舍了,代码美观,执行效率高,编译器依赖,三者。
smset
发表于 2012-12-5 22:22:27
dr2001 发表于 2012-12-5 21:58 static/image/common/back.gif
代码的问题可能在于要看到效果的话,需要两个任务启动的时候岔开一定的时间,否则LED操作了也不一定能显 ...
对,任务一刚开灯,任务二就关灯啊。所以看不到灯亮。 把时间错开。
smset
发表于 2012-12-5 22:23:52
dr2001 发表于 2012-12-5 22:09 static/image/common/back.gif
ProtoThread的Switch方法可以在continuation上消耗的字节数很少,但是生成的代码会是一个序列比较链,当 ...
对,我比较看重的是与编译器无关。
张小盒
发表于 2012-12-6 00:05:31
顶楼,期待结果。
eddia2012
发表于 2012-12-6 08:12:10
楼主:
能把抢占式调度加进来吗?
flyfox8
发表于 2012-12-6 08:43:33
smset 发表于 2012-11-27 10:07 static/image/common/back.gif
嗯,是的,可以自己改,无需函数指针也完全可以,这样每个任务只需1到2个字节。
我已经在此基础上,继续 ...
学习,持续关注。
zengyunming
发表于 2012-12-6 11:57:30
楼主我有个疑问,如下红色部分,你这个参数从哪来的。
#define_SS static char lc=0; switch(lc){ case 0: lc=0;
#define_EE }; lc=0;
#defineWaitX(a,b)settimer(&lc,__LINE__,a,b); return ; case __LINE__:
smset
发表于 2012-12-6 12:05:00
__LINE__就是当前行号啊,编译器自动转为行号。
zengyunming
发表于 2012-12-6 12:40:48
smset 发表于 2012-12-6 12:05 static/image/common/back.gif
__LINE__就是当前行号啊,编译器自动转为行号。
不太理解,你这样做的用意是什么。
YS126
发表于 2012-12-6 12:55:59
学习了,记好~~
flor
发表于 2012-12-6 13:43:40
竟然可以做成任务形式不用状态机,这c语法逆天了。。。
flor
发表于 2012-12-6 13:49:21
问下楼主,多成嵌套的task能否处理?
smset
发表于 2012-12-6 13:57:48
flor 发表于 2012-12-6 13:49 static/image/common/back.gif
问下楼主,多成嵌套的task能否处理?
可以的,102楼的版本已经支持调用子任务了。
topdog
发表于 2012-12-6 14:26:40
本帖最后由 topdog 于 2012-12-6 14:50 编辑
很好,在PIC16单片机上试过暂未发现bug。编译器picc;IDE: mplab ide v8.8。
完全测试好后,把工程发出来,呵呵。
nds_shenzhen
发表于 2012-12-6 14:29:47
先收藏再学习
flor
发表于 2012-12-6 14:30:54
那个例子嵌套了一个任务,如果嵌套多层呢?
另外一个问题:c51局部变量覆盖问题存在吗?这两个问题解决了做复杂应用就很方便了
xiaolaba
发表于 2012-12-6 22:29:54
smset 发表于 2012-11-29 09:56 static/image/common/back.gif
数码管不论是动态还是静态扫描,都支持。 这是一个时间多任务调度器。
我把文件作为附件传上来,以此文件为 ...
其實很想試一下 MC68HC908QT1, 可是編譯語法分歧太多了, 編譯不過啦, 因為源碼語法都是套C51的比較多.
不知道俺試的結論如何, 是俺不會玩嗎 ?
例如
eddia2012
发表于 2012-12-6 22:52:58
MC68HC908 有这个C51的语法吗:sbit KEY = P3 ^ 2; 肯定没有,所以是编译不过的,你要修改成你现在编译器的语法才行的。
xiaolaba
发表于 2012-12-6 23:03:49
本帖最后由 xiaolaba 于 2012-12-6 23:19 编辑
eddia2012 发表于 2012-12-6 22:52 static/image/common/back.gif
MC68HC908 有这个C51的语法吗:sbit KEY = P3 ^ 2; 肯定没有,所以是编译不过的,你要修改成你现在编译器的 ...
對呀, 不同的MCU移植也要花些功夫
所以試了 AT89C2051, 結果找到網上一個 STC89C51.h (http://read.pudn.com/downloads140/doc/604049/CC100A/%E5%AE%9E%E9%AA%8C%E4%BE%8B%E7%A8%8B/SY_000_include/stc89c51.h__.htm)
編譯又說沒有 P3M0, P3M1 定義, 到底少了一些資料, 用的是 KEIL C
後來慢慢再看了12樓的 定时器触发调度N.zip, 抄裡面的 STC89C51.h, 再加上 130樓的 mian.c, 編譯才過
STC89C51.h
/* After is STC additional SFR */
/* sfrAUXR= 0x8e; */
/* sfrAUXR1 = 0xa2; */
/* sfrIPH = 0xb7; */
sfrP4= 0xe8;
sbit P43 = P4^3;
sbit P42 = P4^2;
sbit P41 = P4^1;
sbit P40 = P4^0;
sfrXICON = 0xc0;
//sfrWDT_CONTR = 0xe1;
sfr ISP_DATA= 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr ISP_CMD = 0xe5;
sfr ISP_TRIG= 0xe6;
sfr ISP_CONTR = 0xe7;
/* Above is STC additional SFR */
/*--------------------------------------------------------------------------
REG51F.H
Header file for 8xC31/51, 80C51Fx, 80C51Rx+
Copyright (c) 1988-1999 Keil Elektronik GmbH and Keil Software, Inc.
All rights reserved.
Modification according to DataSheet from April 1999
- SFR's AUXR and AUXR1 added for 80C51Rx+ derivatives
--------------------------------------------------------------------------*/
/*BYTE Registers*/
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
sfr PSW= 0xD0;
sfr ACC= 0xE0;
sfr B = 0xF0;
sfr SP = 0x81;
sfr DPL= 0x82;
sfr DPH= 0x83;
sfr PCON = 0x87;
sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0= 0x8A;
sfr TL1= 0x8B;
sfr TH0= 0x8C;
sfr TH1= 0x8D;
sfr IE = 0xA8;
sfr IP = 0xB8;
sfr SCON = 0x98;
sfr SBUF = 0x99;
sfr P0M0 = 0x93;
sfr P0M1 = 0x94;
sfr P1M0 = 0x91;
sfr P1M1 = 0x92;
sfr P2M0 = 0x95;
sfr P2M1 = 0x96;
sfr P3M0 = 0xB1;
sfr P3M1 = 0xB2;
/*80C51Fx/Rx Extensions*/
sfr AUXR = 0x8E;
sfr AUXR1= 0xA2;
sfr SADDR= 0xA9;
sfr IPH = 0xB7;
sfr SADEN= 0xB9;
sfr T2CON= 0xC8;
sfr T2MOD= 0xC9;
sfr RCAP2L = 0xCA;
sfr RCAP2H = 0xCB;
sfr TL2 = 0xCC;
sfr TH2 = 0xCD;
/* PCA SFR
sfr CCON = 0xD8;
sfr CMOD = 0xD9;
sfr CCAPM0 = 0xDA;
sfr CCAPM1 = 0xDB;
sfr CCAPM2 = 0xDC;
sfr CCAPM3 = 0xDD;
sfr CCAPM4 = 0xDE;
sfr CL = 0xE9;
sfr CCAP0L = 0xEA;
sfr CCAP1L = 0xEB;
sfr CCAP2L = 0xEC;
sfr CCAP3L = 0xED;
sfr CCAP4L = 0xEE;
sfr CH = 0xF9;
sfr CCAP0H = 0xFA;
sfr CCAP1H = 0xFB;
sfr CCAP2H = 0xFC;
sfr CCAP3H = 0xFD;
sfr CCAP4H = 0xFE;
*/
/*BIT Registers*/
/*PSW */
sbit CY = PSW^7;
sbit AC = PSW^6;
sbit F0 = PSW^5;
sbit RS1= PSW^4;
sbit RS0= PSW^3;
sbit OV = PSW^2;
sbit P = PSW^0;
/*TCON*/
sbit TF1= TCON^7;
sbit TR1= TCON^6;
sbit TF0= TCON^5;
sbit TR0= TCON^4;
sbit IE1= TCON^3;
sbit IT1= TCON^2;
sbit IE0= TCON^1;
sbit IT0= TCON^0;
/*IE */
sbit EA = IE^7;
sbit EC = IE^6;
sbit ET2= IE^5;
sbit ES = IE^4;
sbit ET1= IE^3;
sbit EX1= IE^2;
sbit ET0= IE^1;
sbit EX0= IE^0;
/*IP */
/* sbit PPC= IP^6;*/
sbit PT2= IP^5;
sbit PS = IP^4;
sbit PT1= IP^3;
sbit PX1= IP^2;
sbit PT0= IP^1;
sbit PX0= IP^0;
/*P3*/
sbit RD = P3^7;
sbit WR = P3^6;
sbit T1 = P3^5;
sbit T0 = P3^4;
sbit INT1 = P3^3;
sbit INT0 = P3^2;
sbit TXD= P3^1;
sbit RXD= P3^0;
/*SCON*/
sbit SM0= SCON^7; // alternatively "FE"
sbit FE = SCON^7;
sbit SM1= SCON^6;
sbit SM2= SCON^5;
sbit REN= SCON^4;
sbit TB8= SCON^3;
sbit RB8= SCON^2;
sbit TI = SCON^1;
sbit RI = SCON^0;
/*P1*/
/* PCA
sbit CEX4 = P1^7;
sbit CEX3 = P1^6;
sbit CEX2 = P1^5;
sbit CEX1 = P1^4;
sbit CEX0 = P1^3;
sbit ECI= P1^2;
*/
sbit T2EX = P1^1;
sbit T2 = P1^0;
/*T2CON*/
sbit TF2 = T2CON^7;
sbit EXF2= T2CON^6;
sbit RCLK= T2CON^5;
sbit TCLK= T2CON^4;
sbit EXEN2 = T2CON^3;
sbit TR2 = T2CON^2;
sbit C_T2= T2CON^1;
sbit CP_RL2= T2CON^0;
/*CCON*/
/*PCA
sbit CF = CCON^7;
sbit CR = CCON^6;
sbit CCF4= CCON^4;
sbit CCF3= CCON^3;
sbit CCF2= CCON^2;
sbit CCF1= CCON^1;
sbit CCF0= CCON^0;
*/
页:
1
[2]
3
4
5
6
7
8
9
10
11