⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 21ic ucos+lwip应用心得[社区].htm

📁 44b0+lwip
💻 HTM
📖 第 1 页 / 共 3 页
字号:
            prio)//创建一个新进程<BR>&nbsp;&nbsp;sys_mbox_t 
            sys_mbox_new(void)//创建一个邮箱<BR>&nbsp;&nbsp;void&nbsp;&nbsp;sys_mbox_free(sys_mbox_t 
            mbox)//释放并删除一个邮箱<BR>&nbsp;&nbsp;void&nbsp;&nbsp;sys_mbox_post(sys_mbox_t 
            mbox, void *data) //发送一个消息到邮箱<BR>&nbsp;&nbsp;void 
            sys_mbox_fetch(sys_mbox_t mbox, void 
            **msg)//等待邮箱中的消息<BR>&nbsp;&nbsp;sys_sem_t sys_sem_new(u8_t 
            count)//创建一个信号量<BR>void sys_sem_free(sys_sem_t 
            sem)//释放并删除一个信号量<BR>void sys_sem_signal(sys_sem_t 
            sem)//发送一个信号量<BR>void sys_sem_wait(sys_sem_t 
            sem)//等待一个信号量<BR>&nbsp;&nbsp;void sys_timeout(u32_t msecs, 
            sys_timeout_handler h, void *arg)//设置一个超时事件<BR>&nbsp;&nbsp;void 
            sys_untimeout(sys_timeout_handler h, void 
            *arg)//删除一个超时事件<BR>&nbsp;&nbsp;…<BR>关于操作系统封装层的信息可以阅读lwip的doc目录下面的sys_arch.txt.文件.<BR><BR>2.2 
            Lwip在ucos上的移植.<BR><BR>2.2.1 
            系统初始化<BR><BR>&nbsp;&nbsp;&nbsp;sys_int必须在tcpip协议栈任务tcpip_thread创建前被调用.<BR>&nbsp;&nbsp;#define 
            MAX_QUEUES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;20<BR>#define 
            MAX_QUEUE_ENTRIES&nbsp;&nbsp;&nbsp;20<BR>typedef struct 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OS_EVENT*&nbsp;&nbsp;&nbsp;pQ;//ucos中指向事件控制块的指针<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void*&nbsp;&nbsp;pvQEntries[MAX_QUEUE_ENTRIES];//消息队列<BR>//MAX_QUEUE_ENTRIES消息队列中最多消息数<BR>} 
            TQ_DESCR, *PQ_DESCR;<BR>typedef 
            PQ_DESCR&nbsp;&nbsp;sys_mbox_t;//可见lwip中的mbox其实是ucos的消息队列<BR>static 
            char pcQueueMemoryPool[MAX_QUEUES * sizeof(TQ_DESCR) 
            ];<BR>&nbsp;&nbsp;&nbsp;void 
            sys_init(void)<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;u8_t 
            i;<BR>&nbsp;&nbsp;&nbsp;&nbsp;s8_t&nbsp;&nbsp;&nbsp;ucErr;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;pQueueMem 
            = OSMemCreate( (void*)pcQueueMemoryPool, MAX_QUEUES, 
            sizeof(TQ_DESCR), &amp;ucErr 
            );//为消息队列创建内存分区<BR>&nbsp;&nbsp;&nbsp;&nbsp;//init lwip task prio 
            offset<BR>&nbsp;&nbsp;&nbsp;&nbsp;curr_prio_offset = 
            0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;//init lwip_timeouts for every lwip 
            task<BR>&nbsp;&nbsp;&nbsp;&nbsp;//初始化lwip定时事件表,具体实现参考下面章节<BR>&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i&lt;LWIP_TASK_MAX;i++){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lwip_timeouts[i].next 
            = NULL;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}<BR>2.2.2 
            创建一个和tcp/ip相关新进程:<BR>lwip中的进程就是ucos中的任务,创建一个新进程的代码如下:<BR>#define 
            LWIP_STK_SIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10*1024//和tcp/ip相关任务的堆栈大小.可以根据情况自<BR>//己设置,44b0开发板上有8M的sdram,所以设大<BR>//一点也没有关系:)<BR>//max 
            number of lwip tasks<BR>#define 
            LWIP_TASK_MAX&nbsp;&nbsp;&nbsp;&nbsp;5 //和tcp/ip相关的任务最多数目<BR>//first 
            prio of lwip tasks<BR>#define LWIP_START_PRIO&nbsp;&nbsp;&nbsp;5 
            //和tcp/ip相关任务的起始优先级,在本例中优先级可<BR>//以从(5-9).注意tcpip_thread在所有tcp/ip相关进程中//应该是优先级最高的.在本例中就是优先级5 
            <BR>//如果用户需要创建和tcp/ip无关任务,如uart任务等,<BR>//不要使用5-9的优先级<BR>&nbsp;&nbsp;&nbsp;&nbsp;OS_STK 
            LWIP_TASK_STK[LWIP_TASK_MAX][LWIP_STK_SIZE];//和tcp/ip相关进程<BR>//的堆栈区<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8_t 
            curr_prio_offset ;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys_thread_t 
            sys_thread_new(void (* function)(void *arg), void *arg,int 
            prio)<BR>{<BR>&nbsp;&nbsp;if(curr_prio_offset &lt; 
            LWIP_TASK_MAX){&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;OSTaskCreate(function,(void*)0x1111, 
            &amp;LWIP_TASK_STK[curr_prio_offset][LWIP_STK_SIZE-1],<BR>LWIP_START_PRIO+curr_prio_offset 
            );<BR>&nbsp;&nbsp;&nbsp;&nbsp;curr_prio_offset++; 
            <BR>&nbsp;&nbsp;&nbsp;&nbsp;return 1;<BR>&nbsp;&nbsp;} else 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;// PRINT(" lwip task prio out of range 
            ! error! 
            ");<BR>&nbsp;&nbsp;}<BR>}<BR>从代码中可以看出tcpip_thread应该是最先创建的.<BR>&nbsp;&nbsp;<BR>2.2.3 
            Lwip中的定时事件<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            在tcp/ip协议中很多时候都要用到定时,定时的实现也是tcp/ip协议栈中一个重要的部分.lwip中定时事件的数据结构如下. 
            <BR>struct sys_timeout {<BR>&nbsp;&nbsp;struct sys_timeout 
            *next;//指向下一个定时结构<BR>&nbsp;&nbsp;u32_t 
            time;//定时时间<BR>&nbsp;&nbsp;sys_timeout_handler 
            h;//定时时间到后执行的函数<BR>&nbsp;&nbsp;void 
            *arg;//定时时间到后执行函数的参数.<BR>};<BR>struct sys_timeouts 
            {<BR>&nbsp;&nbsp;struct sys_timeout *next;<BR>};<BR>struct 
            sys_timeouts 
            lwip_timeouts[LWIP_TASK_MAX];<BR>Lwip中的定时事件表的结构如下图,每个和tcp/ip相关的任务的一系列定时事件组成一个单向链表.每个链表的起始指针存在lwip_timeouts的对应表项中.<BR>&nbsp;<BR><IMG 
            src="21IC ucos+lwip应用心得[社区].files/200312221355480.jpg" border=0></P>
            <P>函数sys_arch_timeouts返回对应于当前任务的指向定时事件链表的起始指针.该指针存在lwip_timeouts[MAX_LWIP_TASKS]中.<BR>struct 
            sys_timeouts null_timeouts;<BR>struct sys_timeouts * 
            sys_arch_timeouts(void)<BR>{<BR>&nbsp;&nbsp;u8_t 
            curr_prio;<BR>&nbsp;&nbsp;s16_t err,offset;<BR>OS_TCB 
            curr_task_pcb;<BR>&nbsp;&nbsp;null_timeouts.next = 
            NULL;<BR>&nbsp;&nbsp;//获取当前任务的优先级<BR>&nbsp;&nbsp;err = 
            OSTaskQuery(OS_PRIO_SELF,&amp;curr_task_pcb);<BR>&nbsp;&nbsp;curr_prio 
            = curr_task_pcb.OSTCBPrio;&nbsp;&nbsp;<BR>&nbsp;&nbsp;offset = 
            curr_prio - 
            LWIP_START_PRIO;<BR>&nbsp;&nbsp;//判断当前任务优先级是不是tcp/ip相关任务,优先级5-9<BR>&nbsp;&nbsp;if(offset 
            &lt; 0 || offset &gt;= 
            LWIP_TASK_MAX)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;return 
            &amp;null_timeouts;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;return 
            &amp;lwip_timeouts[offset];<BR>}</P>
            <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            注意:杨晔大侠移植的代码在本函数有一个bug.杨晔大侠的移植把上面函数中的OS_TCB 
            curr_task_tcb定义成了全局变量,使本函数成为了一个不可重入函数.我也是在进行如下测试时发现了这个bug.我的开发板上设置的ip地址是192.168.1.95.我在windows的dos窗口内运行</P>
            <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping 192.168.1.95 –l 2000 
            –t,不间断用长度为2000的数据报进行ping测试,同时使用tftp客户端软件给192.168.1.95下载一个十几兆程序,同时再使用telnet连接192.168.1.95端口7(echo端口),往该端口写数测试echo功能.</P>
            <P>在运行一段时间以后,开发板进入不再响应.我当时也是经过长时间的分析才发现是因为在低优先级任务运行ys_arch_timeouts()时被高优先级任务打断改写了curr_task_tcb的值,从而使sys_arch_timeouts返回的指针错误,进而导致系统死锁.函数sys_timeout给当前任务增加一个定时事件:<BR>void 
            sys_timeout(u32_t msecs, sys_timeout_handler h, void 
            *arg)<BR>{<BR>&nbsp;&nbsp;struct sys_timeouts 
            *timeouts;<BR>&nbsp;&nbsp;struct sys_timeout *timeout, 
            *t;<BR>&nbsp;&nbsp;timeout = 
            memp_malloc(MEMP_SYS_TIMEOUT);//为定时事件分配内存<BR>&nbsp;&nbsp;if (timeout 
            == NULL) 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;return;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;timeout-&gt;next 
            = NULL;<BR>&nbsp;&nbsp;timeout-&gt;h = 
            h;<BR>&nbsp;&nbsp;timeout-&gt;arg = 
            arg;<BR>&nbsp;&nbsp;timeout-&gt;time = 
            msecs;<BR>&nbsp;&nbsp;timeouts = 
            sys_arch_timeouts();//返回当前任务定时事件链表起始指针<BR>&nbsp;&nbsp;if 
            (timeouts-&gt;next == NULL) 
            {//如果链表为空直接增加该定时事件<BR>&nbsp;&nbsp;&nbsp;&nbsp;timeouts-&gt;next = 
            timeout;<BR>&nbsp;&nbsp;&nbsp;&nbsp;return;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;//如果链表不为空,对定时事件进行排序.注意定时事件中的time存储的是本事件<BR>//时间相对于前一事件的时间的差值<BR>&nbsp;&nbsp;if 
            (timeouts-&gt;next-&gt;time &gt; msecs) 
            {&nbsp;&nbsp;&nbsp;&nbsp;<BR>timeouts-&gt;next-&gt;time -= 
            msecs;<BR>&nbsp;&nbsp;&nbsp;&nbsp;timeout-&gt;next = 
            timeouts-&gt;next;<BR>&nbsp;&nbsp;&nbsp;&nbsp;timeouts-&gt;next = 
            timeout;<BR>&nbsp;&nbsp;} else {<BR>&nbsp;&nbsp;&nbsp;&nbsp;for(t = 
            timeouts-&gt;next; t != NULL; t = t-&gt;next) 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout-&gt;time -= 
            t-&gt;time;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (t-&gt;next == 
            NULL ||<BR>&nbsp;&nbsp;&nbsp;t-&gt;next-&gt;time &gt; 
            timeout-&gt;time) {<BR>&nbsp;&nbsp;if (t-&gt;next != NULL) 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;t-&gt;next-&gt;time -= 
            timeout-&gt;time;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;timeout-&gt;next = 
            t-&gt;next;<BR>&nbsp;&nbsp;t-&gt;next = 
            timeout;<BR>&nbsp;&nbsp;break;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;}<BR>}<BR>函数sys_untimeout从当前任务定时事件链表中删除一个定时事件<BR>void 
            sys_untimeout(sys_timeout_handler h, void 
            *arg)<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct sys_timeouts 
            *timeouts;<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct sys_timeout *prev_t, 
            *t;<BR>&nbsp;&nbsp;&nbsp;&nbsp;timeouts = 
            sys_arch_timeouts();//返回当前任务定时事件链表起始指针<BR>&nbsp;&nbsp;&nbsp;&nbsp;if 
            (timeouts-&gt;next == 
            NULL)//如果链表为空直接返回<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;//查找对应定时事件并从链表中删除.<BR>&nbsp;&nbsp;&nbsp;&nbsp;for 
            (t = timeouts-&gt;next, prev_t = NULL; t != NULL; prev_t = t, t = 
            t-&gt;next)<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if 
            ((t-&gt;h == h) &amp;&amp; (t-&gt;arg == 
            arg))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 
            We have a match 
            */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 
            Unlink from previous in list 
            */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if 
            (prev_t == 
            NULL)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeouts-&gt;next 
            = 
            t-&gt;next;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prev_t-&gt;next 
            = 
            t-&gt;next;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 
            If not the last one, add time of this one back to next 
            */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if 
            (t-&gt;next != 
            NULL)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t-&gt;next-&gt;time 
            += 
            t-&gt;time;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memp_free(MEMP_SYS_TIMEOUT, 
            t);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;return;<BR>}<BR>2.2.3&nbsp;&nbsp;“mbox”的实现:</P>
            <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1)mbox的创建<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys_mbox_t 
            sys_mbox_new(void)<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ucErr;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PQ_DESCR&nbsp;&nbsp;&nbsp;&nbsp;pQDesc;&nbsp;&nbsp;&nbsp;&nbsp;<BR>//从消息队列内存分区中得到一个内存块<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pQDesc 
            = OSMemGet( pQueueMem, &amp;ucErr 
            );&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( ucErr == 
            OS_NO_ERR ) 
            {&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//创建一个消息队列<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pQDesc-&gt;pQ=OSQCreate(&amp;(pQDesc-&gt;pvQEntries[0]), 
            MAX_QUEUE_ENTRIES 
            );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( 
            pQDesc-&gt;pQ != NULL ) 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 
            pQDesc;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
            <BR>&nbsp;&nbsp;&nbsp;&nbsp;return SYS_MBOX_NULL;<BR>} </P>
            <P>&nbsp;&nbsp;(2)发一条消息给”mbox”<BR>&nbsp;&nbsp;const void * const 
            pvNullPointer = 0xffffffff;<BR>void sys_mbox_post(sys_mbox_t mbox, 
            void *data)<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;INT8U 
            err;<BR>&nbsp;&nbsp;&nbsp;&nbsp;if( !data ) 
            <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data = 
            (void*)&amp;pvNullPointer;<BR>&nbsp;&nbsp;&nbsp;err= OSQPost( 
            mbox-&gt;pQ, data);<BR>}<BR>在ucos中,如果OSQPost (OS_EVENT *pevent, void 
            *msg)中的msg==NULL 
            会返回一条OS_ERR_POST_NULL_PTR错误.而在lwip中会调用sys_mbox_post(mbox,NULL)发送一条空消息,我们在本函数中把NULL变成一个常量指针0xffffffff.</P>
            <P>(3)从”mbox”中读取一条消息<BR>#define SYS_ARCH_TIMEOUT 0xffffffff<BR>void 
            sys_mbox_fetch(sys_mbox_t mbox, void 
            **msg)<BR>{<BR>&nbsp;&nbsp;u32_t time;<BR>&nbsp;&nbsp;struct 
            sys_timeouts *timeouts;<BR>&nbsp;&nbsp;struct sys_timeout 
            *tmptimeout;<BR>&nbsp;&nbsp;sys_timeout_handler 
            h;<BR>&nbsp;&nbsp;void *arg;<BR>again:<BR>&nbsp;&nbsp;timeouts = 
            sys_arch_timeouts();////返回当前任务定时事件链表起始指针<BR>&nbsp;&nbsp;if 
            (!timeouts || !timeouts-&gt;next) 
            {//如果定时事件链表为空<BR>&nbsp;&nbsp;&nbsp;&nbsp;sys_arch_mbox_fetch(mbox, 
            msg, 0);//无超时等待消息<BR>&nbsp;&nbsp;} else 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;if (timeouts-&gt;next-&gt;time &gt; 0) 
            {<BR>&nbsp;&nbsp;&nbsp;//如果超时事件链表不为空,而且第一个超时事件的time 
            !=0<BR>//带超时等待消息队列,超时时间等于超时事件链表中第一个超时事件的time,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time 
            = sys_arch_mbox_fetch(mbox, msg, 
            timeouts-&gt;next-&gt;time);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//在后面分析中可以看到sys_arch_mbox_fetch调用了ucos中的OSQPend系统调<BR>//用从消息队列中读取消息.<BR>//如果”mbox”消息队列不为空,任务立刻返回,否则任务进入阻塞态.<BR>//需要重点说明的是sys_arch_mbox_fetch的返回值time:如果sys_arch_mbox_fetch<BR>//因为超时返回,time=SYS_ARCH_TIMEOUT,<BR>//如果sys_arch_mbox_fetch因为收到消息而返回,<BR>//time 
            = 
            收到消息时刻的时间-执行sys_arch_mbox_fetch时刻的时间,单位是毫秒<BR>//由于在ucos中任务调用OSQPend系统调用进入阻塞态,到收到消息重新开始执行<BR>//这段时间没有记录下来,所以我们要简单修改ucos的源代码.(后面我们会看到).<BR>&nbsp;&nbsp;&nbsp;&nbsp;} 
            else 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果定时事件链表不为空,而且第一个定时事件的time 
            ==0,表示该事件的定时<BR>//时间到<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time = 
            SYS_ARCH_TIMEOUT;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;if 
            (time == SYS_ARCH_TIMEOUT) 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//一个定时事件的定时时间到<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tmptimeout 
            = 
            timeouts-&gt;next;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeouts-&gt;next 
            = tmptimeout-&gt;next;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;h = 
            tmptimeout-&gt;h;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arg = 
            tmptimeout-&gt;arg;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memp_free(MEMP_SYS_TIMEOUT, 
            tmptimeout);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//从内存中释放该定时事件,并执行该定时事件中的函数<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -