嵌入式实时操作系统small RTOS51原理及应用 ----笔记 第七章 任务之间的通信和同步之消息队列

本文深入探讨了SmallRTOS51实时操作系统中的消息队列实现原理与应用,包括循环队列的理解、消息队列的创建、消息的发送与接收机制。通过具体的代码示例,展示了任务间的通信和同步过程。

嵌入式实时操作系统small RTOS51原理及应用 ----笔记 第七章 任务之间的通信和同步之消息队列

Small_RTOS1.12.1\small_rtos\SerialIn

实现方式 类似于 信号量
主要是理解 循环队列

消息队列 应用场景

#define NBYTE           7
#define STARTBYTE1      0xf0
#define STARTBYTE2      0xf1
#define RECIVE_TASK_ID  0

uint8 Buf[NBYTE - 3];

uint8  SerialData[14];
void TaskA(void)
{
    uint8 data temp,temp1;
    uint8 Sum,i;


    OSQCreate(SerialData,14);

	OSQPend(&temp,SerialData,0);
	
        while (1)
        {
            if (OSQPend(&temp1,SerialData,20) == OS_Q_TMO)
            {
                goto start;
            }	
   	      }
 }


void TaskB(void)
{
    while (1)
    {
        OSWait(K_TMO,10);
        OSQPost(SerialData,0xf0);
        OSWait(K_TMO,10);
        OSQPost(SerialData,0xf1);
        OSWait(K_TMO,10);
        OSQPost(SerialData,0xf0);
        OSWait(K_TMO,10);
        OSQPost(SerialData,0xf0);
        OSWait(K_TMO,10);
        OSQPost(SerialData,0x00);
        OSWait(K_TMO,10);
        OSQPost(SerialData,0x00);
        OSWait(K_TMO,10);
        OSQPost(SerialData,0x3f);
    }
}
  

初始化消息队列 OSQCreate

OSQCreate

//输 入: Buf:为队列分配的存储空间地址
//SizeOfBuf:为队列分配的存储空间大小
// 输 出: NOT_OK:参数错误
//         OS_Q_OK:成功
//Buf[0]:队列中字节数,Buf[1]:Buf总长度,Buf[2]:出对端,Buf[3](,Buf[4]):等待队列任务列表

uint8 OSQCreate(uint8  *Buf, uint8 SizeOfBuf)
{
    OS_ENTER_CRITICAL();

    if ((SizeOfBuf >= 5) && (Buf != NULL))
    {
        Buf[0] = 0;                         /* 队列中消息数目           */
        Buf[1] = SizeOfBuf;           /* 消息队列占用内存字节数    */

        Buf[2] = 4;                         /* 将要出队的消息所在位置    */

        Buf[3] = 0;                         /* 消息队列的等待任务列表    */
        Buf[4] = 0;                         /* 任务数大于等于8时为等待任务列表的一部分, */
                                                  /* 否则为消息缓冲区         */

        OS_EXIT_CRITICAL();
        return OS_Q_OK;
    }
    else
    {
        OS_EXIT_CRITICAL();
        return NOT_OK;
    }

}

OSQPend 等待消息队列中的消息

函数名称: OSQPend
功能描述: 等待消息队列中的消息
输 入: Ret:返回的消息
Buf:指向队列的指针
Tick:等待时间
输 出: NOT_OK:参数错误
OS_Q_OK:收到消息
OS_Q_TMO:超时到
OS_Q_NOT_OK:无消息

uint8 OSQPend(uint8 data *Ret, uint8 OS_Q_MEM_SEL *Buf, uint8 Tick)
{
#ifdef __C51__
    uint8 data *cp;
#endif

    OS_ENTER_CRITICAL(); // 关闭中断
    
     /* 设置当前任务的超时时间         */
    OSWaitTick[OSRunningTaskID()] = Tick;      
                                             

/* 使用堆栈是为了使函数具有重入性 */
#ifdef __C51__
    SP++;
    *((uint8 data * data *)SP) = Ret;
#endif

/* 把任务加入等待任务队列 */
Buf[3] |= OSMapTbl[OSRunningTaskID()];

 while (Buf[0] == 0)             /* 消息队列中是否有消息 */
 {
    Buf[0]  =0  表示 没有数据
                
#ifdef __C51__
        SP = SP + sizeof(Buf);
        *((uint8  * data *)(SP + 1 - sizeof(Buf))) = Buf;
#endif

        OSClearSignal(OSRunningTaskID());   /* 任务进入等待状态 */
        OSSched();                          /* 运行下一个任务 */

#ifdef __C51__
        Buf = *((uint8 OS_Q_MEM_SEL * data *)(SP + 1 - sizeof(Buf)));
        SP = SP - sizeof(Buf);
#endif
                /* 任务再次运行,如果超时到,退出循环 */
        if (OSWaitTick[OSRunningTaskID()] == 0)
        {
            break;
        }
    } // end of while (Buf[0] == 0)
    

     /* 将任务从等待队列中清除(可以删除) */
     /*Buf[3]这个字节的每一位,对应一个任务*/
    Buf[3] &= ~OSMapTbl[OSRunningTaskID()];
    //如果是消息队列中,有消息   
    if (Buf[0] > 0)
    {
        /* 有,消息出队 */
        Buf[0]--;           /* 队列的消息数目减一 */
        /* 指向下一个出队位置 */
        Buf[2]++; // 出队消息指针
        
        /* Buf[1]消息队列占用内存字节数 */
        if (Buf[2] >= Buf[1] )
        {

            Buf[2] = 4;
        }
#ifdef __C51__
        cp = (uint8 data *)(*((uint8 data *)SP));
        SP--;
        *cp = Buf[Buf[2]];
#else
        *Ret = Buf[Buf[2]];
#endif
        OS_EXIT_CRITICAL();
        return OS_Q_OK;
    }
    else
    {
                /* 无,返回错误码 */
#ifdef __C51__
        SP--;
#endif

        OS_EXIT_CRITICAL();
        return OS_Q_TMO;
    }
}

OSWait(K_SIG,0) 应用场景

其中 : OSIntSendSignal(1) 和OSWait(K_SIG,0); 是对应的
TaskB 的 任务索引ID 等于 1

void comm(void) interrupt 4
{
    OS_INT_ENTER();
    if (RI == 1)
    {
        RI = 0;
#if EN_OS_Q_INT_POST > 0
        OSQIntPost(SerialData,SBUF);
#endif
#if EN_OS_Q_INT_POST_FRONT > 0
        OSQIntPostFront(SerialData,SBUF);
#endif

    }
    if (TI == 1)
    {
        TI = 0;
        OSIntSendSignal(1);
    }
    OSIntExit();
    
}


void TaskB(void)
{
    while (1)
    {
        OSWait(K_SIG,0);
        SBUF = 'O';
        OSWait(K_SIG,0);
        SBUF = 'K';
        OSWait(K_SIG,0);
        SBUF = '!';
        OSWait(K_SIG,0);
        SBUF = '\n';
        OSWait(K_SIG,0);
    } 
}
Small RTOS(51) 1.20.3v 说明文件 编写动机: 就像在嵌入系统中使用C语言替代汇编一样,在嵌入系统中使用RTOS是大势所趋。原因主要是现在在大多数情况下编程效率比执行效率重要(单片机便宜嘛)。但纵观51RTOS,keil c51 所带的RTX Full 太大(6k多),且需要外部ram,又无源代码,很多时候不实用。RTX Tiny虽然小(900多字节),但是任务没有优先级中断管理,也无源代码,也不太实用。而ucosII虽有源代码,但是它太大,又需要外部ram,所有函数又必须是重入函数,用在51这类小片内RAM的单片机上有点勉强。于是,我借鉴ucosIIRTX Tiny编写了Small RTOS 51,虽然它为51系列编写,但是它还是比较容易移植到其它CPU上。 与作者联系方法: 可以给chenmingji@tom.com(原chenmingji@163.net)写信,或是在www.zlgmcu.com.cn上的论坛ARM与ucosII区提问(目前本人是版主)或是在www.c51bbs.com的论坛上提问(不推荐。c51bbs21ic网名均为cmj)。 版本号定义方式: a.bc.d a:主版本号,一般重大改变时改变它。 bc:次便本号,一般功能增加时改变它。 d:同一版本的修订序号。 版本升级: 1.20.3版 2004年6月8日 修正Os_q.c的一个BUG,造成FIFO发送数据时,在队列中有大量数据且队列较大时,可能会出错。 1.20.2版 2004年2月4日 修正for Keil c51的Os_cpu_c.c的StkDelB函数的BUG,它会影响任务删除的正确执行。 1.20.1版 2004年2月4日 修改OSWait(K_SIG | K_TMO, x) 只能通过信号唤醒的bug。 1.20.0版 2003年8月3日 支持任务动态建立与删除。函数功能向一般的RTOS靠拢。支持C51的重入函数(用关键字reentrant定义的函数)。支持动态内存分配(使用动态内存分配的任务必须使用重入栈)。 1.12.1版 2003年2月5日 修正OS_MAX_TASKS为8、16时的bug。同时修正一些小bug。 1.12.0版 2003年1月24日 OS_MAX_TASKS就是用户任务数量。同时修正一些小bug。 1.11.0版 2002年12月2日 各个任务具有自己的关中断计数器,不在互相影响(这意味着如果一个任务任务放弃CPU前关了中断,当它再次进入运行态时中断还是关的)。优先级最低的任务作为系统保留任务不再需要用户编写,同时节约一些内存。增加一些注释。更正在Keil C51下Memory Model为非Small 模式的Bug。 1.10.5版 2002年10月26日 更正许多小Bug。 1.10.4版 2002年10月6日 合并Os_cpu_a.asmOS_CPU_A_task16.ASM。统一了一下代码风格 1.10.3版 2002年9月16日 修改了Os_cpu_a.asmOS_CPU_A_task16.ASM的LoadCtx代码使之执行更快,代码更小 1.10.2版 2002年9月9日 更正OSWait()的Bug,在极端情况下,这个Bug可能造成可能锁死任务。 修改OSQIntPost()的Keil C51特殊代码,它会造成阅读障碍。 1.10.1版 2002年9月4日 更正OSTimeTick的Bug,它在keil c51中不会有问题,但移植的其它系统可能出错。 1.10版 2002年9月1日 增加Small RTOS消息队列(简化的)信号量的支持;改变了开关中断的方式;增加可移植的变量定义;修正一些Bug。 1.00版 2002年6月20日 使用户可以进行更多的配置,可以禁止中断管理,51系列支持软的非屏蔽中断,并调整目录结构等. 0.60版 2002年5月10日 修改OS_CORE.c使之在keil c51可以重入。不再需要禁止覆盖分析。 0.52版
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值