消息机制:
消息机制是借助sleep/suspend来实现的,不能算真正的消息机制.但在很多场合下已经足够了,对51这样的芯片来说,资源占用率和执行效率更重要.
定义一个消息向量表,每个表示一个消息,每个项能保存一个task_id
event_vector[MAX_EVENT_VECTOR]
#define EVENT0 0
#define EVENT1 1
#define EVENT2 2
....
#define EVENTn MAX_EVENT_VECTOR - 1
当进程要监听该消息时,将自已的task_id号装入对应的向量中即可.例如要监听EVENT_RF_PULS_SENT,只需:
event_vector[EVENT_RF_PULS_SENT] = task_id;
这个过程称为"消息注册",已写为一个宏 event_replace(eid)
所以上例只需写成
event_replace(EVENT_RF_PULS_SENT);
...
event_clear(EVENT_RF_PULS_SENT);//使用完后消除该消息
如果不确定该消息目前是否有其它过程已在监听,可使用event_reg(eid, reg),将原先的向量保存在参数reg指定的变量中,并在用完消息后用event_restor(eid, reg)还原回来.
static unsigned char old_event_vector;
event_reg(EVENT_RF_PULS_SENT, old_event_vector);
....
event_unreg(EVENT_RF_PULS_SENT, old_event_vector);//使用完后还原该消息
如果监听了消息,在退出任务前必须解除监听,否则会引发错误地唤醒.
当进程处于运行态时是无法收到消息的,因此要等待消息必须进入休眠/延时状态.完整过程:
注册消息
...
进入休眠
...
要唤醒一个等待消息的进程,调用event_push(eid)即可.
如果eid指定的消息无进程监听,则消息被丢弃.
另外要注意的是,由于消息机制是借用休眠机制来完成的,所以如果监听消息的进程未处于休眠/延时中时,进程是无法收到消息的,该消息会被直接丢弃.在这种情况下,应使用task_wait_interrupt()来完成.
这种情况发生于进程监听的消息产生于中断服务程序中.其机制如下:
假定任务A与中断服务A_ISV
A中完成对缓冲区的填写,填完后进入休眠,等待消息MESSAGE_A
A_ISV负责在定时中断发生时将缓冲区中的字节写到P1口,写完后发送MESSAGE_A
通常情况下,这个过程并无问题,但当以下情况发生时,任务A将永远处于等待中:
A填写完缓冲区后,进入休眠前,定时器中断发生了
此时中断服务程序按步就班地将缓冲区处理完,并发送MESSAGE_A消息.如前所说,发送消息的实质是将task_sleep的值置为0
中断服务返回后,也按步就班将task_sleep置值,此刻它一点也不知道,也无从知道中断已经发生过了,于是信息实质上丢失.于是该任务再也不会醒来.
解决的方法是,在写缓冲区前先将任务的task_sleep置值,然后才写缓冲区,然后才进入休眠状态.这样,中断发生时task_sleep必已完成赋值,因而消息不会丢失.
该过程已写为一个宏task_wait_interrupt(缓冲区操作的语句)
写法有点别扭,但工作得很好.如果不习惯这样的风格,可以直接展开该宏书写代码:
task_setsuspend(task_id);
操作缓冲区的语句
task_switch();
|