UCOS 操作系统 问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UCOS 操作系统 问题相关的知识,希望对你有一定的参考价值。

int main(void)


CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);

LED_Init();
__enable_interrupt();
OSInit();
OSTaskCreate(TestTask1,(void *)0,&TestTaskStk1[99],0);
OSStart();

void TestTask1(void *pdata)

char flag=0;
pdata=pdata;

Tim1_Init(); //初始化定时器 10ms一次中断
SetLedON();

while(1)

OSTimeDly(100); //程序在此休眠,进入别的任务,等到调用OSTimeISR中的OSTickTime进行检测是否有优先级更高的任务

if(flag==0)

SetLedOFF();
flag=1;

else

SetLedON();
flag=0;




1:如上代码,为什么在任务中要有一个OSTimeDly(100); 没有这个延时不行吗?
没有延时是不是就不会运行低优先级的任务了?为什么?
2:如果再创建一个任务,是不是写个像void TestTask1(void *pdata) 这样的函数就OK 了,要注意哪些地方代码变化?
求高手指教。

1.ucos建议每个任务都在适当的地方加入延时函数,以避免死在一个任务中系统瘫痪;但不是必须的,如果一个任务通过pend其他任务或isr发送的事件,事件没有被post前会自动挂起,调度其他就绪任务中最高优先级任务执行。

2.新建立一个任务,至少要给他分配一个堆栈,定义任务函数体(类似TestTask1()),并调用OSTaskCreate()创建任务。
参考技术A 1、没有延时也行,但是led变化就看不出来了,低优先级的还会运行的
2、可以这样创建任务,但是要现在main里创建,如:
上面的OSTaskCreate(TestTask1,(void *)0,&TestTaskStk1[99],0);
而且堆栈要先声明。不过一般不用优先级为0的任务

OSTaskCreate(TestTask1, (void *)0, (void *)&TaskStk1[99],6); /*建立任务1 */
OSTaskCreate(TestTask2, (void *)0, (void *)&TaskStk2[99],7); /*建立任务2 */

uCos-II内存管理

ucos 系统由于构思巧妙,结构精简设计,可读性强,同时又具有实时性操作系统大部分的优点,在 物联网开发中应用非常广泛。
之前一直都只是会用ucos 却没有好好研究过它,最近项目中要用到了 ucos-II 所以顺便研究了一番,突然发现 ucos-II 的内存管理写得非常巧妙。
废话不多说,直接上代码:
先看一个内存块结构体
1 typedef struct os_mem {                   /* MEMORY CONTROL BLOCK                                      */
2     void   *OSMemAddr;                    /* Pointer to beginning of memory partition                  */
3     void   *OSMemFreeList;                /* Pointer to list of free memory blocks                     */
4     INT32U  OSMemBlkSize;                 /* Size (in bytes) of each block of memory                   */
5     INT32U  OSMemNBlks;                   /* Total number of blocks in this partition                  */
6     INT32U  OSMemNFree;                   /* Number of memory blocks remaining in this partition       */
7 #if OS_MEM_NAME_EN > 0u
8     INT8U  *OSMemName;                    /* Memory partition name                                     */
9 #endif
10 } OS_MEM;
其中 OSMemAddr 指向一块内存的起始地址;
OSMemFreeList 指向一个可利用的空块的地址;
再看看内存的分配函数
1 OS_MEM  *OSMemCreate (void   *addr,
2                       INT32U  nblks,
3                       INT32U  blksize,
4                       INT8U  *perr)
5 {
6     OS_MEM    *pmem;
7     INT8U     *pblk;
8     void     **plink;
9     INT32U     loops;
10     INT32U     i;
11 #if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
12     OS_CPU_SR  cpu_sr = 0u;
13 #endif
14
15
16
17 #ifdef OS_SAFETY_CRITICAL
18     if (perr == (INT8U *)0) {
19         OS_SAFETY_CRITICAL_EXCEPTION();
20     }
21 #endif
22
23 #ifdef OS_SAFETY_CRITICAL_IEC61508
24     if (OSSafetyCriticalStartFlag == OS_TRUE) {
25         OS_SAFETY_CRITICAL_EXCEPTION();
26     }
27 #endif
28
29 #if OS_ARG_CHK_EN > 0u
30     if (addr == (void *)0) {                          /* Must pass a valid address for the memory part.*/
31         *perr = OS_ERR_MEM_INVALID_ADDR;
32         return ((OS_MEM *)0);
33     }
34     if (((INT32U)addr & (sizeof(void *) - 1u)) != 0u){  /* Must be pointer size aligned                */
35         *perr = OS_ERR_MEM_INVALID_ADDR;
36         return ((OS_MEM *)0);
37     }
38     if (nblks < 2u) {                                 /* Must have at least 2 blocks per partition     */
39         *perr = OS_ERR_MEM_INVALID_BLKS;
40         return ((OS_MEM *)0);
41     }
42     if (blksize < sizeof(void *)) {                   /* Must contain space for at least a pointer     */
43         *perr = OS_ERR_MEM_INVALID_SIZE;
44         return ((OS_MEM *)0);
45     }
46 #endif
47     OS_ENTER_CRITICAL();
48     pmem = OSMemFreeList;                             /* Get next free memory partition                */
49     if (OSMemFreeList != (OS_MEM *)0) {               /* See if pool of free partitions was empty      */
50         OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
51     }
52     OS_EXIT_CRITICAL();
53     if (pmem == (OS_MEM *)0) {                        /* See if we have a memory partition             */
54         *perr = OS_ERR_MEM_INVALID_PART;
55         return ((OS_MEM *)0);
56     }
57     plink = (void **)addr;                            /* Create linked list of free memory blocks      */
58     pblk  = (INT8U *)addr;
59     loops  = nblks - 1u;
60     for (i = 0u; i < loops; i++) {
61         pblk +=  blksize;                             /* Point to the FOLLOWING block                  */
62        *plink = (void  *)pblk;                        /* Save pointer to NEXT block in CURRENT block   */
63         plink = (void **)pblk;                        /* Position to  NEXT      block                  */
64     }
65     *plink              = (void *)0;                  /* Last memory block points to NULL              */
66     pmem->OSMemAddr     = addr;                       /* Store start address of memory partition       */
67     pmem->OSMemFreeList = addr;                       /* Initialize pointer to pool of free blocks     */
68     pmem->OSMemNFree    = nblks;                      /* Store number of free blocks in MCB            */
69     pmem->OSMemNBlks    = nblks;
70     pmem->OSMemBlkSize  = blksize;                    /* Store block size of each memory blocks        */
71     *perr               = OS_ERR_NONE;
72     return (pmem);
73 }
这个函数把addr 指向的一块连续的内存劈成 nblks 个 blksize 大小的内存块。里面利用了一个技巧:在 60-64 行的这个 for 循环里面把每个内存块的首地址保存在它的上一个内存块的首地址空间里面。 67 行把pmem 里面的 OSMemFreeList 指向第一个空块的地址 ( 当前空块的第一个地址保存的是下一个空块的地址) 。
再看看内存获取函数
1 void  *OSMemGet (OS_MEM  *pmem,
2                  INT8U   *perr)
3 {
4     void      *pblk;
5 #if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
6     OS_CPU_SR  cpu_sr = 0u;
7 #endif
8
9
10
11 #ifdef OS_SAFETY_CRITICAL
12     if (perr == (INT8U *)0) {
13         OS_SAFETY_CRITICAL_EXCEPTION();
14     }
15 #endif
16
17 #if OS_ARG_CHK_EN > 0u
18     if (pmem == (OS_MEM *)0) {                        /* Must point to a valid memory partition        */
19         *perr = OS_ERR_MEM_INVALID_PMEM;
20         return ((void *)0);
21     }
22 #endif
23     OS_ENTER_CRITICAL();
24     if (pmem->OSMemNFree > 0u) {                      /* See if there are any free memory blocks       */
25         pblk                = pmem->OSMemFreeList;    /* Yes, point to next free memory block          */
26         pmem->OSMemFreeList = *(void **)pblk;         /*      Adjust pointer to new free list          */
27         pmem->OSMemNFree--;                           /*      One less memory block in this partition  */
28         OS_EXIT_CRITICAL();
29         *perr = OS_ERR_NONE;                          /*      No error                                 */
30         return (pblk);                                /*      Return memory block to caller            */
31     }
32     OS_EXIT_CRITICAL();
33     *perr = OS_ERR_MEM_NO_FREE_BLKS;                  /* No,  Notify caller of empty memory partition  */
34     return ((void *)0);                               /*      Return NULL pointer to caller            */
35 }
这个函数除了红色标出来的这几行代码其它都不重要,在这几行代码里面获取OSMemFreeList 指向的内存块的地址之后把这个地址 return 出去使用。
那么问题来了:为什么没有遍历空块的过程?
原因就在于上面所提到的那种巧妙地方法,每个内存块的前32 位保存的是下一个空块的地址,在获取到OSMemFreeList 后 OSMemFreeList 指针应该要指向下一个空块,而下一个空块就在当前获取到的空块的第一个地址里面,所以在 26 行把 OSMemFreeList 指针指向了当前获取到的内存块的第一个地址所指向的内存块处。
最后就是内存释放函数
1 INT8U  OSMemPut (OS_MEM  *pmem,
2                  void    *pblk)
3 {
4 #if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register           */
5     OS_CPU_SR  cpu_sr = 0u;
6 #endif
7
8
9
10 #if OS_ARG_CHK_EN > 0u
11     if (pmem == (OS_MEM *)0) {                   /* Must point to a valid memory partition             */
12         return (OS_ERR_MEM_INVALID_PMEM);
13     }
14     if (pblk == (void *)0) {                     /* Must release a valid block                         */
15         return (OS_ERR_MEM_INVALID_PBLK);
16     }
17 #endif
18     OS_ENTER_CRITICAL();
19     if (pmem->OSMemNFree >= pmem->OSMemNBlks) {  /* Make sure all blocks not already returned          */
20         OS_EXIT_CRITICAL();
21         return (OS_ERR_MEM_FULL);
22     }
23     *(void **)pblk      = pmem->OSMemFreeList;   /* Insert released block into free block list         */
24     pmem->OSMemFreeList = pblk;
25     pmem->OSMemNFree++;                          /* One more memory block in this partition            */
26     OS_EXIT_CRITICAL();
27     return (OS_ERR_NONE);                        /* Notify caller that memory block was released       */
28 }
同样,最关键的代码在红色部分。首先把要释放的内存块的首地址指向OSMemFreeList 指向的地址 ( 这个地址就是下一个空块的首地址 ) ,之后把 OSMemFreeList 指向刚刚释放的内存块的首地址。只用了一行代码就把一个要释放的内存块插入了空块链表,再调整 OSMemFreeList 指针指向刚释放的内存块,就是这么简单粗暴!!!
一句话总结:ucos-II 的内存管理利用内存块的首地址保存下一个空块的首地址的方式把所有空块链接起来。至少有一个好处,那就是在获取内存块的时候少了一个对整个内存块进行遍历找出空块的过程!
来源:博客园

以上是关于UCOS 操作系统 问题的主要内容,如果未能解决你的问题,请参考以下文章

为啥说操作系统ucos是实时的?ucos是多任务的?

UCOS2系统内核讲述_创建任务

NIOS2随笔——uCOS-II实时操作系统

二代示波器教程第14章 uCOS-III操作系统版本二代示波器实现

ucos实时操作系统学习笔记——任务间通信(信号量)

uCos的多任务实现