你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【安富莱】【RTX操作系统教程】第18章 内存管理

[复制链接]
baiyongbin2009 发布时间:2016-2-3 13:27
【安富莱】【RTX操作系统教程】第18章     内存管理 【RTX操作系统教程】第18章 内存管理.pdf (969.74 KB, 下载次数: 43)
收藏 评论8 发布时间:2016-2-3 13:27

举报

8个回答
baiyongbin2009 回答时间:2016-2-3 14:50:52
18.2  内存管理API函数
    使用如下7个函数可以实现RTX的内存管理:
_declare_box
_declare_box8
_init_box
_init_box8
_alloc_box
_calloc_box
_free_box
关于这7个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件
18.2.png
                              
这里我们重点的说一下函数_declare_box,_declare_box8,_init_box,_init_box8,_alloc_box和_free_box。

18.2.1  函数_declare_box
函数原型:
  1. #define _declare_box( \
  2.     pool,      \    /* 内存池变量名 */
  3.     size,      \    /* 内存块大小,单位字节 */
  4.     cnt )      \    /* 内存池中内存块的个数 */
  5.     U32 pool[((size+3)/4)*(cnt) + 3]
复制代码

函数描述:
函数_declare_box用于定义一块内存池。
(1)第1个参数填写内存池的变量名。
(2)第2个参数填写内存块的大小,单位字节。
(3)第3个参数填写内存池中内存块的个数。

使用这个函数要注意以下问题:
1.     宏定义中通过操作(size+3)/4保证了每个内存块大小是4字节的倍数,从而也就保证了每个内存块的首地址是4字节对齐的(4字节对齐的含义是地址对4求余等于0)。这里初学者也要注意数据类型的字节对齐问题。
    基本数据类型的字节对齐问题
    这个问题在MDK5安装目录里面的文档DUI0375G_02_mdk_armcc_user_guide.pdf里面有详细的说明,简单的说明,数据类型有几个字节,那么这个数据类型的变量就是几字节对齐,比如32位的int型有4个字节,那么此int型定义的变量就是4字节对齐,对于初学者要牢牢的记住这个知识点。
18.3.png
2.     内存池中额外定义的12个字节用于将内存块做指针链表,方便动态的申请和释放。
使用举例:
  1. #include <rtl.h>

  2. #define PoolBlocks           10
  3. #define PoolPerBlockSize     8

  4. /* 声明一个内存池,10块,每块大小8字节 */
  5. _declare_box(mpool, PoolPerBlockSize, PoolBlocks);
复制代码


18.2.2 函数_declare_box8
函数原型:
  1. #define _declare_box8( \
  2.     pool,      \    /* 内存池变量名 */
  3.     size,      \    /* 内存块大小,单位字节 */
  4.     cnt )      \    /* 内存池中内存块的个数 */
  5.     U64 pool[((size+7)/8)*(cnt) + 2]
复制代码

函数描述:
函数_declare_box用于定义一块内存池。
(1)第1个参数填写内存池的变量名。
(2)第2个参数填写内存块的大小,单位字节。
(3)第3个参数填写内存池中内存块的个数。

使用这个函数要注意以下问题:
1.     宏定义中通过操作(size+7)/8保证了每个内存块大小是8字节的倍数,从而也就保证了每个内存块的首地址是8字节对齐的(8字节对齐的含义是地址对8求余等于0)。这里初学者也要注意数据类型的字节对齐问题。
2.     内存池中额外定义的16个字节用于将内存块做指针链表,方便动态的申请和释放。
使用举例:
  1. #include <rtl.h>

  2. #define PoolBlocks           10
  3. #define PoolPerBlockSize     8

  4. /* 声明一个内存池,10块,每块大小8字节 */
  5. _declare_box8(mpool, PoolPerBlockSize, PoolBlocks);
复制代码


18.2.3 函数_init_box
函数原型:
  1. int _init_box  (
  2.     void* box_mem,       /* 内存池首地址 */
  3.     U32   box_size,      /* 内存池大小,单位字节 */
  4.     U32   blk_size );    /* 内存块大小,单位字节 */
复制代码

函数描述:
函数_init_box用于内存池的初始化,初始化时用到的参数都是源自于_declare_box。
(1)第1个参数填写内存池的首地址。
(2)第2个参数填写内存池的大小,单位字节。
(3)第3个参数填写内存块大小,单位字节。

使用这个函数要注意以下问题:
1.     强烈建议跟函数_declare_box一起使用。用户不要自己去初始化这个函数,用_declare_box声明的才是最保险的。
2.     如果用户没有使用函数_declare_box进行定义,那么要保证内存池首地址是4字节对齐的。
3.     如果用户没有使用函数_declare_box进行定义,那么要保证内存池的大小box_size至少有12个字节,因为这个12个字节是用于将内存块做成指针链表,方便动态申请和释放。
使用举例:
  1. #include <rtl.h>

  2. #define PoolBlocks           10
  3. #define PoolPerBlockSize     8

  4. /* 声明一个内存池,10块,每块大小8字节 */
  5. _declare_box(mpool, PoolPerBlockSize, PoolBlocks);

  6. /*
  7. *********************************************************************************************************
  8. *         函 数 名: AppObjCreate
  9. *         功能说明: 创建任务通信机制
  10. *         形    参: 无
  11. *         返 回 值: 无
  12. *********************************************************************************************************
  13. */
  14. static void AppObjCreate (void)
  15. {        
  16. /* 初始化内存池,4字节对齐,*/
  17. _init_box (mpool, sizeof (mpool), PoolPerBlockSize);
  18. }
复制代码


18.2.4 函数_init_box8
函数原型:
  1. int _init_box  (
  2.     void* box_mem,       /* 内存池首地址 */
  3.     U32   box_size,      /* 内存池大小,单位字节 */
  4.     U32   blk_size );    /* 内存块大小,单位字节 */
复制代码

函数描述:
函数_init_box8用于内存池的初始化,初始化时用到的参数都是源自于_declare_box8。
(1)第1个参数填写内存池的首地址。
(2)第2个参数填写内存池的大小,单位字节。
(3)第3个参数填写内存块大小,单位字节。

使用这个函数要注意以下问题:
1.     强烈建议跟函数_declare_box8一起使用。用户不要自己去初始化这个函数,用_declare_box声明的才是最保险的。
2.     如果用户没有使用函数_declare_box8进行定义,那么要保证内存池首地址是8字节对齐的。
3.     如果用户没有使用函数_declare_box8进行定义,那么要保证内存池的大小box_size至少有16个字节,因为这个16个字节是用于将内存块做成指针链表,方便动态申请和释放。
使用举例:
  1. #include <rtl.h>

  2. #define PoolBlocks           10
  3. #define PoolPerBlockSize     8

  4. /* 声明一个内存池,10块,每块大小8字节 */
  5. _declare_box8(mpool, PoolPerBlockSize, PoolBlocks);

  6. /*
  7. *********************************************************************************************************
  8. *         函 数 名: AppObjCreate
  9. *         功能说明: 创建任务通信机制
  10. *         形    参: 无
  11. *         返 回 值: 无
  12. *********************************************************************************************************
  13. */
  14. static void AppObjCreate (void)
  15. {        
  16. /* 初始化内存池,4字节对齐,*/
  17. _init_box8 (mpool, sizeof (mpool), PoolPerBlockSize);
  18. }
复制代码


18.2.5 函数_alloc_box
函数原型:
  1. void *_alloc_box (
  2.     void* box_mem );    /* 内存池的首地址 */
复制代码

函数描述:
函数_alloc_box用于从首地址是box_mem的内存池中申请一个内存块。
(1)第1个参数填写内存池的首地址。

使用这个函数要注意以下问题:
1.     调用此函数前,一定要使用函数_init_box或者_init_box8进行初始化。
2.     函数_alloc_box支持重入,而且是线程安全的,也即是说用户可以没有限制的在主函数和中断中调用此函数。
使用举例:
  1. #include <rtl.h>

  2. #define PoolBlocks           10
  3. #define PoolPerBlockSize     8

  4. /* 声明一个内存池,10块,每块大小8字节 */
  5. _declare_box(mpool, PoolPerBlockSize, PoolBlocks);

  6. /*
  7. *********************************************************************************************************
  8. *         函 数 名: AppObjCreate
  9. *         功能说明: 创建任务通信机制
  10. *         形    参: 无
  11. *         返 回 值: 无
  12. *********************************************************************************************************
  13. */
  14. static void AppObjCreate (void)
  15. {        
  16. /* 初始化内存池,4字节对齐,*/
  17. _init_box (mpool, sizeof (mpool), PoolPerBlockSize);
  18. }


  19. /*
  20. *********************************************************************************************************
  21. *    函 数 名: AppTaskUserIF
  22. *    功能说明: 按键消息处理     
  23. *    形    参: 无
  24. *    返 回 值: 无
  25. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  26. *********************************************************************************************************
  27. */
  28. __task void AppTaskUserIF(void)
  29. {
  30.      uint8_t  *pucMsg;
  31.      uint8_t ucKeyCode, ucCount = 0;

  32.     while(1)
  33.     {
  34.          ucKeyCode = bsp_GetKey();
  35.         
  36.          if (ucKeyCode != KEY_NONE)
  37.          {
  38.               switch (ucKeyCode)
  39.               {
  40.                    /* K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据 */
  41.                    case KEY_DOWN_K2:
  42.                        /* 申请一个内存块用于8位整形变量 */
  43.                        pucMsg  = _alloc_box (mpool);
  44.                        *pucMsg = ucCount++;
  45.                   
  46.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  47.                        if(os_mbx_send (&mailbox, pucMsg, 100) != OS_R_OK)
  48.                        {
  49.                             /* 发送失败,即使等待了100个时钟节拍 */
  50.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  51.                             _free_box (mpool, pucMsg);
  52.                        }
  53.                        else
  54.                        {
  55.                             /* 发送成功 */
  56.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");   
  57.                             _free_box (mpool, pucMsg);
  58.                        }
  59.                        break;  

  60.                    /* 其他的键值不处理 */
  61.                    default:                    
  62.                        break;
  63.               }
  64.          }
  65.         
  66.          os_dly_wait(20);
  67.      }
  68. }
复制代码


18.2.6 函数_free_box
函数原型:
  1. int _free_box (
  2.     void* box_mem,    /* 内存池首地址 */
  3.     void* box );      /* 要释放的内存块首地址 */
复制代码

函数描述:
函数_free_box用于释放使用函数_alloc_box申请的内存块。
(1)第1个参数填写内存池的首地址。
(2)第2个参数填写要释放的内存块首地址。

使用这个函数要注意以下问题:
1.     此函数的第二个参数必须要填写正确,也就是用户使用的时候最好配套_alloc_box一起使用。
2.     函数_alloc_box支持重入,而且是线程安全的,也即是说用户可以没有限制的在主函数和中断中调用此函数。
使用举例:
  1. #include <rtl.h>

  2. #define PoolBlocks           10
  3. #define PoolPerBlockSize     8

  4. /* 声明一个内存池,10块,每块大小8字节 */
  5. _declare_box(mpool, PoolPerBlockSize, PoolBlocks);

  6. /*
  7. *********************************************************************************************************
  8. *         函 数 名: AppObjCreate
  9. *         功能说明: 创建任务通信机制
  10. *         形    参: 无
  11. *         返 回 值: 无
  12. *********************************************************************************************************
  13. */
  14. static void AppObjCreate (void)
  15. {        
  16. /* 初始化内存池,4字节对齐,*/
  17. _init_box (mpool, sizeof (mpool), PoolPerBlockSize);
  18. }


  19. /*
  20. *********************************************************************************************************
  21. *    函 数 名: AppTaskUserIF
  22. *    功能说明: 按键消息处理     
  23. *    形    参: 无
  24. *    返 回 值: 无
  25. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  26. *********************************************************************************************************
  27. */
  28. __task void AppTaskUserIF(void)
  29. {
  30.      uint8_t  *pucMsg;
  31.      uint8_t ucKeyCode, ucCount = 0;

  32.     while(1)
  33.     {
  34.          ucKeyCode = bsp_GetKey();
  35.         
  36.          if (ucKeyCode != KEY_NONE)
  37.          {
  38.               switch (ucKeyCode)
  39.               {
  40.                    /* K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据 */
  41.                    case KEY_DOWN_K2:
  42.                        /* 申请一个内存块用于8位整形变量 */
  43.                        pucMsg  = _alloc_box (mpool);
  44.                        *pucMsg = ucCount++;
  45.                   
  46.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  47.                        if(os_mbx_send (&mailbox, pucMsg, 100) != OS_R_OK)
  48.                        {
  49.                             /* 发送失败,即使等待了100个时钟节拍 */
  50.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  51.                             _free_box (mpool, pucMsg);
  52.                        }
  53.                        else
  54.                        {
  55.                             /* 发送成功 */
  56.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");   
  57.                             _free_box (mpool, pucMsg);
  58.                        }
  59.                        break;  

  60.                    /* 其他的键值不处理 */
  61.                    default:                    
  62.                        break;
  63.               }
  64.          }
  65.         
  66.          os_dly_wait(20);
  67.      }
  68. }
复制代码


baiyongbin2009 回答时间:2016-2-3 15:38:39
18.3 实验例程说明(4字节对齐)
18.3.1 STM32F103开发板实验
配套例子:
    V4-417_RTX实验_内存管理(4字节对齐)
实验目的:
    1.     学习RTX的内存管理(4字节对齐)。
    2.     函数_declare_box和_init_box用于4字节对齐的内存池初始化。这里4字节对齐的含义
  a.内存池的首地址是4字节对齐(4字节对齐就是地址对4求余等于0)。
  b.每个内存块大小也得是4字节的倍数,这样才能保证每申请到的一个内存块的首地址也是4字节对齐。
  c.4字节对齐是由RTX系统完成的。
实验内容:
    1. K1按键按下,串口打印。
    2. K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。
    3. K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。
    4. 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。
    5. 各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
   RTX配置向导详情如下:
                              
18.4.png
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
18.5.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
18.6.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码

内存管理的初始化和消息邮箱的创建:
  1. #define PoolBlocks           10
  2. #define PoolPerBlockSize     8

  3. /* 声明一个支持10个消息的消息邮箱 */
  4. os_mbx_declare (mailbox, 10);

  5. /* 声明一个内存池,10块,每块大小8字节 */
  6. _declare_box(mpool, PoolPerBlockSize, PoolBlocks);

  7. /*
  8. *********************************************************************************************************
  9. *    函 数 名: AppObjCreate
  10. *    功能说明: 创建任务通信机制
  11. *    形    参: 无
  12. *    返 回 值: 无
  13. *********************************************************************************************************
  14. */
  15. static void AppObjCreate (void)
  16. {
  17.      /* 创建消息邮箱 */
  18.       os_mbx_init (&mailbox, sizeof(mailbox));
  19.    
  20.      /* 初始化内存池,4字节对齐,*/
  21.      _init_box (mpool, sizeof (mpool), PoolPerBlockSize);
  22. }
复制代码

四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t  *pucMsg;
  13.      uint16_t *pusMsg;
  14.      uint32_t *pulMsg;
  15.      uint8_t ucKeyCode, ucCount = 0;

  16.     while(1)
  17.     {
  18.          ucKeyCode = bsp_GetKey();
  19.         
  20.          if (ucKeyCode != KEY_NONE)
  21.          {
  22.               switch (ucKeyCode)
  23.               {
  24.                    /* K1键按下,打印调试说明 */
  25.                    case KEY_DOWN_K1:
  26.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  27.                        break;  

  28.                    /* K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据 */
  29.                    case KEY_DOWN_K2:
  30.                        /* 申请一个内存块用于8位整形变量 */
  31.                        pucMsg  = _alloc_box (mpool);
  32.                        *pucMsg = ucCount++;
  33.                   
  34.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  35.                        if(os_mbx_send (&mailbox, pucMsg, 100) != OS_R_OK)
  36.                        {
  37.                             /* 发送失败,即使等待了100个时钟节拍 */
  38.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  39.                             _free_box (mpool, pucMsg);
  40.                        }
  41.                        else
  42.                        {
  43.                             /* 发送成功 */
  44.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");   
  45.                             _free_box (mpool, pucMsg);
  46.                        }
  47.                        break;  

  48.                    /* K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据 */
  49.                    case KEY_DOWN_K3:
  50.                        /* 申请一个内存块用于16位整形变量 */
  51.                        pusMsg  = _alloc_box (mpool);
  52.                        *pusMsg = ucCount++;
  53.                   
  54.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  55.                        if(os_mbx_send (&mailbox, pusMsg, 100) != OS_R_OK)
  56.                        {
  57.                             /* 发送失败,即使等待了100个时钟节拍 */
  58.                             printf("K3键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  59.                             _free_box (mpool, pusMsg);
  60.                        }
  61.                        else
  62.                        {
  63.                             /* 发送成功 */
  64.                             printf("K3键按下,向消息邮箱发送数据成功\r\n");   
  65.                             _free_box (mpool, pusMsg);
  66.                        }
  67.                        break;  
  68.                   
  69.                    /* 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据 */
  70.                    case JOY_DOWN_OK:
  71.                        /* 申请一个内存块用于32位整形变量 */
  72.                        pulMsg  = _alloc_box (mpool);
  73.                        *pulMsg = ucCount++;
  74.                   
  75.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  76.                        if(os_mbx_send (&mailbox, pulMsg, 100) != OS_R_OK)
  77.                        {
  78.                             /* 发送失败,即使等待了100个时钟节拍 */
  79.                             printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  80.                             _free_box (mpool, pulMsg);
  81.                        }
  82.                        else
  83.                        {
  84.                             /* 发送成功 */
  85.                             printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");   
  86.                             _free_box (mpool, pulMsg);
  87.                        }
  88.                        break;

  89.                    /* 其他的键值不处理 */
  90.                    default:                    
  91.                        break;
  92.               }
  93.          }
  94.         
  95.          os_dly_wait(20);
  96.      }
  97. }

  98. /*
  99. *********************************************************************************************************
  100. *    函 数 名: AppTaskLED
  101. *    功能说明: LED闪烁。
  102. *    形    参: 无
  103. *    返 回 值: 无
  104. *   优 先 级: 2
  105. *********************************************************************************************************
  106. */
  107. __task void AppTaskLED(void)
  108. {
  109.      const uint16_t usFrequency = 200; /* 延迟周期 */
  110.    
  111.      /* 设置延迟周期 */
  112.      os_itv_set(usFrequency);
  113.    
  114.     while(1)
  115.     {
  116.          bsp_LedToggle(2);
  117.          bsp_LedToggle(3);

  118.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  119.          os_itv_wait();
  120.     }
  121. }

  122. /*
  123. *********************************************************************************************************
  124. *    函 数 名: AppTaskMsgPro
  125. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
  126. *    形    参: 无
  127. *    返 回 值: 无
  128. *   优 先 级: 3
  129. *********************************************************************************************************
  130. */
  131. __task void AppTaskMsgPro(void)
  132. {
  133.      uint8_t *pMsg;
  134.      OS_RESULT xResult;
  135.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  136.    
  137.     while(1)
  138.     {
  139.          xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
  140.         
  141.          switch (xResult)
  142.          {
  143.               /* 无需等待接受到消息邮箱数据 */
  144.               case OS_R_OK:
  145.                    printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
  146.                    break;  

  147.               /* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
  148.               case OS_R_MBX:
  149.                    printf("因为消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
  150.                    break;

  151.               /* 超时 */
  152.               case OS_R_TMO:
  153.                    bsp_LedToggle(1);
  154.                    bsp_LedToggle(4);
  155.                    break;
  156.             
  157.               /* 其他值不处理 */
  158.               default:                    
  159.                    break;
  160.          }   
  161.     }
  162. }

  163. /*
  164. *********************************************************************************************************
  165. *    函 数 名: AppTaskStart
  166. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
  167. *    形    参: 无
  168. *    返 回 值: 无
  169. *   优 先 级: 4
  170. *********************************************************************************************************
  171. */
  172. __task void AppTaskStart(void)
  173. {
  174.      /* 创建任务 */
  175.      AppTaskCreate();
  176.    
  177.      /* 创建任务通信机制 */
  178.      AppObjCreate();
  179.    
  180.     while(1)
  181.     {
  182.          /* 按键扫描 */
  183.          bsp_KeyScan();
  184.         os_dly_wait(10);
  185.     }
  186. }
复制代码



baiyongbin2009 回答时间:2016-2-3 15:43:10
18.3.2   STM32F407开发板实验
配套例子:
    V5-417_RTX实验_内存管理(4字节对齐)
实验目的:
    1.     学习RTX的内存管理(4字节对齐)。
    2.     函数_declare_box和_init_box用于4字节对齐的内存池初始化。这里4字节对齐的含义
  a.内存池的首地址是4字节对齐(4字节对齐就是地址对4求余等于0)。
  b.每个内存块大小也得是4字节的倍数,这样才能保证每申请到的一个内存块的首地址也是4字节对齐。
  c.4字节对齐是由RTX系统完成的。
实验内容:
    1. K1按键按下,串口打印。
    2. K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。
    3. K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。
    4. 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。
    5. 各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
18.7.png
                              
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
18.8.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
18.9.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码

内存管理的初始化和消息邮箱的创建:
  1. #define PoolBlocks           10
  2. #define PoolPerBlockSize     8

  3. /* 声明一个支持10个消息的消息邮箱 */
  4. os_mbx_declare (mailbox, 10);

  5. /* 声明一个内存池,10块,每块大小8字节 */
  6. _declare_box(mpool, PoolPerBlockSize, PoolBlocks);

  7. /*
  8. *********************************************************************************************************
  9. *    函 数 名: AppObjCreate
  10. *    功能说明: 创建任务通信机制
  11. *    形    参: 无
  12. *    返 回 值: 无
  13. *********************************************************************************************************
  14. */
  15. static void AppObjCreate (void)
  16. {
  17.      /* 创建消息邮箱 */
  18.       os_mbx_init (&mailbox, sizeof(mailbox));
  19.    
  20.      /* 初始化内存池,4字节对齐,*/
  21.      _init_box (mpool, sizeof (mpool), PoolPerBlockSize);
  22. }
复制代码

四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t  *pucMsg;
  13.      uint16_t *pusMsg;
  14.      uint32_t *pulMsg;
  15.      uint8_t ucKeyCode, ucCount = 0;

  16.     while(1)
  17.     {
  18.          ucKeyCode = bsp_GetKey();
  19.         
  20.          if (ucKeyCode != KEY_NONE)
  21.          {
  22.               switch (ucKeyCode)
  23.               {
  24.                    /* K1键按下,打印调试说明 */
  25.                    case KEY_DOWN_K1:
  26.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  27.                        break;  

  28.                    /* K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据 */
  29.                   case KEY_DOWN_K2:
  30.                        /* 申请一个内存块用于8位整形变量 */
  31.                        pucMsg  = _alloc_box (mpool);
  32.                        *pucMsg = ucCount++;
  33.                   
  34.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  35.                        if(os_mbx_send (&mailbox, pucMsg, 100) != OS_R_OK)
  36.                        {
  37.                             /* 发送失败,即使等待了100个时钟节拍 */
  38.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  39.                             _free_box (mpool, pucMsg);
  40.                        }
  41.                        else
  42.                        {
  43.                             /* 发送成功 */
  44.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");   
  45.                             _free_box (mpool, pucMsg);
  46.                        }
  47.                        break;  

  48.                    /* K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据 */
  49.                    case KEY_DOWN_K3:
  50.                        /* 申请一个内存块用于16位整形变量 */
  51.                        pusMsg  = _alloc_box (mpool);
  52.                        *pusMsg = ucCount++;
  53.                   
  54.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  55.                        if(os_mbx_send (&mailbox, pusMsg, 100) != OS_R_OK)
  56.                        {
  57.                             /* 发送失败,即使等待了100个时钟节拍 */
  58.                             printf("K3键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  59.                             _free_box (mpool, pusMsg);
  60.                        }
  61.                        else
  62.                        {
  63.                             /* 发送成功 */
  64.                             printf("K3键按下,向消息邮箱发送数据成功\r\n");   
  65.                             _free_box (mpool, pusMsg);
  66.                        }
  67.                        break;  
  68.                   
  69.                    /* 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据 */
  70.                    case JOY_DOWN_OK:
  71.                        /* 申请一个内存块用于32位整形变量 */
  72.                        pulMsg  = _alloc_box (mpool);
  73.                        *pulMsg = ucCount++;
  74.                   
  75.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  76.                        if(os_mbx_send (&mailbox, pulMsg, 100) != OS_R_OK)
  77.                         {
  78.                             /* 发送失败,即使等待了100个时钟节拍 */
  79.                             printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  80.                             _free_box (mpool, pulMsg);
  81.                        }
  82.                        else
  83.                        {
  84.                             /* 发送成功 */
  85.                             printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");   
  86.                             _free_box (mpool, pulMsg);
  87.                        }
  88.                        break;

  89.                    /* 其他的键值不处理 */
  90.                    default:                    
  91.                        break;
  92.               }
  93.          }
  94.         
  95.          os_dly_wait(20);
  96.      }
  97. }

  98. /*
  99. *********************************************************************************************************
  100. *    函 数 名: AppTaskLED
  101. *    功能说明: LED闪烁。
  102. *    形    参: 无
  103. *    返 回 值: 无
  104. *   优 先 级: 2
  105. *********************************************************************************************************
  106. */
  107. __task void AppTaskLED(void)
  108. {
  109.      const uint16_t usFrequency = 200; /* 延迟周期 */
  110.    
  111.      /* 设置延迟周期 */
  112.      os_itv_set(usFrequency);
  113.    
  114.     while(1)
  115.     {
  116.          bsp_LedToggle(2);
  117.          bsp_LedToggle(3);

  118.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  119.          os_itv_wait();
  120.     }
  121. }

  122. /*
  123. *********************************************************************************************************
  124. *    函 数 名: AppTaskMsgPro
  125. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
  126. *    形    参: 无
  127. *    返 回 值: 无
  128. *   优 先 级: 3
  129. *********************************************************************************************************
  130. */
  131. __task void AppTaskMsgPro(void)
  132. {
  133.      uint8_t *pMsg;
  134.      OS_RESULT xResult;
  135.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  136.    
  137.     while(1)
  138.     {
  139.          xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
  140.         
  141.          switch (xResult)
  142.          {
  143.               /* 无需等待接受到消息邮箱数据 */
  144.               case OS_R_OK:
  145.                    printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
  146.                    break;  

  147.               /* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
  148.               case OS_R_MBX:
  149.                    printf("因为消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
  150.                    break;

  151.               /* 超时 */
  152.               case OS_R_TMO:
  153.                    bsp_LedToggle(1);
  154.                    bsp_LedToggle(4);
  155.                    break;
  156.             
  157.               /* 其他值不处理 */
  158.               default:                    
  159.                    break;
  160.          }   
  161.     }
  162. }

  163. /*
  164. *********************************************************************************************************
  165. *    函 数 名: AppTaskStart
  166. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
  167. *    形    参: 无
  168. *    返 回 值: 无
  169. *   优 先 级: 4
  170. *********************************************************************************************************
  171. */
  172. __task void AppTaskStart(void)
  173. {
  174.      /* 创建任务 */
  175.      AppTaskCreate();
  176.    
  177.      /* 创建任务通信机制 */
  178.      AppObjCreate();
  179.    
  180.     while(1)
  181.     {
  182.          /* 按键扫描 */
  183.          bsp_KeyScan();
  184.         os_dly_wait(10);
  185.     }
复制代码


baiyongbin2009 回答时间:2016-2-3 15:59:57
18.4 实验例程说明(8字节对齐)
18.4.1 STM32F103开发板实验
配套例子:
    V4-418_RTX实验_内存管理(8字节对齐)
实验目的:
    1.     学习RTX的内存管理(8字节对齐)。
    2.     函数_declare_box8和_init_box8用于8字节对齐的内存池初始化。这里8字节对齐的含义:
   a.     内存池的首地址是8字节对齐(8字节对齐就是地址对8求余等于0)。
   b.    每个内存块大小也得是8字节的倍数,这样才能保证每申请到的一个内存块的首地址也是8字节对齐。
   c.     8字节对齐是由RTX系统完成的。
实验内容:
    1.K1按键按下,串口打印。
    2.K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。
    3.K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。
    4.摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。
    5.摇杆UP键按下,申请一个内存块用于64位整形变量,然后向消息邮箱发送数据。
    6.各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
                              
18.10.png
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
18.11.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
18.12.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码

内存管理的初始化和消息邮箱的创建:
  1. #define PoolBlocks           10
  2. #define PoolPerBlockSize     8

  3. /* 声明一个支持10个消息的消息邮箱 */
  4. os_mbx_declare (mailbox, 10);

  5. /* 声明一个内存池,10个块,每块大小8字节 */
  6. _declare_box8(mpool, PoolPerBlockSize, PoolBlocks);

  7. /*
  8. *********************************************************************************************************
  9. *    函 数 名: AppObjCreate
  10. *    功能说明: 创建任务通信机制
  11. *    形    参: 无
  12. *    返 回 值: 无
  13. *********************************************************************************************************
  14. */
  15. static void AppObjCreate (void)
  16. {
  17.      /* 创建消息邮箱 */
  18.       os_mbx_init (&mailbox, sizeof(mailbox));
  19.    
  20.      /* 初始化内存池,8字节对齐,*/
  21.      _init_box8 (mpool, sizeof (mpool), PoolPerBlockSize);
  22. }
复制代码

四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t  *pucMsg;
  13.      uint16_t *pusMsg;
  14.      uint32_t *pulMsg;
  15.      uint64_t *pullMsg;
  16.    
  17.      uint8_t ucKeyCode, ucCount = 0;

  18.     while(1)
  19.     {
  20.          ucKeyCode = bsp_GetKey();
  21.         
  22.          if (ucKeyCode != KEY_NONE)
  23.          {
  24.               switch (ucKeyCode)
  25.               {
  26.                    /* K1键按下,打印调试说明 */
  27.                    case KEY_DOWN_K1:
  28.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  29.                        break;  

  30.                    /* K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据 */
  31.                    case KEY_DOWN_K2:
  32.                        /* 申请一个内存块用于8位整形变量 */
  33.                        pucMsg  = _alloc_box (mpool);
  34.                        *pucMsg = ucCount++;
  35.                   
  36.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  37.                        if(os_mbx_send (&mailbox, pucMsg, 100) != OS_R_OK)
  38.                        {
  39.                             /* 发送失败,即使等待了100个时钟节拍 */
  40.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  41.                             _free_box (mpool, pucMsg);
  42.                        }
  43.                        else
  44.                        {
  45.                             /* 发送成功 */
  46.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");   
  47.                             _free_box (mpool, pucMsg);
  48.                        }
  49.                        break;  

  50.                    /* K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据 */
  51.                    case KEY_DOWN_K3:
  52.                        /* 申请一个内存块用于16位整形变量 */
  53.                        pusMsg  = _alloc_box (mpool);
  54.                        *pusMsg = ucCount++;
  55.                   
  56.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  57.                        if(os_mbx_send (&mailbox, pusMsg, 100) != OS_R_OK)
  58.                        {
  59.                             /* 发送失败,即使等待了100个时钟节拍 */
  60.                             printf("K3键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  61.                             _free_box (mpool, pusMsg);
  62.                        }
  63.                        else
  64.                        {
  65.                             /* 发送成功 */
  66.                             printf("K3键按下,向消息邮箱发送数据成功\r\n");   
  67.                             _free_box (mpool, pusMsg);
  68.                        }
  69.                        break;  
  70.                   
  71.                   /* 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据 */
  72.                    case JOY_DOWN_OK:
  73.                        /* 申请一个内存块用于32位整形变量 */
  74.                        pulMsg  = _alloc_box (mpool);
  75.                        *pulMsg = ucCount++;
  76.                   
  77.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  78.                        if(os_mbx_send (&mailbox, pulMsg, 100) != OS_R_OK)
  79.                        {
  80.                             /* 发送失败,即使等待了100个时钟节拍 */
  81.                             printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  82.                             _free_box (mpool, pulMsg);
  83.                        }
  84.                        else
  85.                        {
  86.                             /* 发送成功 */
  87.                             printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");   
  88.                             _free_box (mpool, pulMsg);
  89.                        }
  90.                        break;

  91.                    /* 摇杆UP键按下,申请一个内存块用于64位整形变量,然后向消息邮箱发送数据 */
  92.                    case JOY_DOWN_U:
  93.                        /* 申请一个内存块用于32位整形变量 */
  94.                        pullMsg  = _alloc_box (mpool);
  95.                        *pullMsg = ucCount++;
  96.                   
  97.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  98.                        if(os_mbx_send (&mailbox, pulMsg, 100) != OS_R_OK)
  99.                        {
  100.                             /* 发送失败,即使等待了100个时钟节拍 */
  101.                             printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  102.                             _free_box (mpool, pullMsg);
  103.                        }
  104.                        else
  105.                        {
  106.                             /* 发送成功 */
  107.                             printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");   
  108.                             _free_box (mpool, pullMsg);
  109.                        }
  110.                        break;

  111.                    /* 其他的键值不处理 */
  112.                    default:                    
  113.                        break;
  114.               }
  115.          }
  116.         
  117.          os_dly_wait(20);
  118.      }
  119. }

  120. /*
  121. *********************************************************************************************************
  122. *    函 数 名: AppTaskLED
  123. *    功能说明: LED闪烁。
  124. *    形    参: 无
  125. *    返 回 值: 无
  126. *   优 先 级: 2
  127. *********************************************************************************************************
  128. */
  129. __task void AppTaskLED(void)
  130. {
  131.      const uint16_t usFrequency = 200; /* 延迟周期 */
  132.    
  133.      /* 设置延迟周期 */
  134.      os_itv_set(usFrequency);
  135.    
  136.     while(1)
  137.     {
  138.          bsp_LedToggle(2);
  139.          bsp_LedToggle(3);

  140.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  141.          os_itv_wait();
  142.     }
  143. }

  144. /*
  145. *********************************************************************************************************
  146. *    函 数 名: AppTaskMsgPro
  147. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
  148. *    形    参: 无
  149. *    返 回 值: 无
  150. *   优 先 级: 3
  151. *********************************************************************************************************
  152. */
  153. __task void AppTaskMsgPro(void)
  154. {
  155.      uint8_t *pMsg;
  156.      OS_RESULT xResult;
  157.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  158.    
  159.     while(1)
  160.     {
  161.          xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
  162.         
  163.          switch (xResult)
  164.          {
  165.               /* 无需等待接受到消息邮箱数据 */
  166.               case OS_R_OK:
  167.                    printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
  168.                    break;  

  169.               /* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
  170.               case OS_R_MBX:
  171.                    printf("因为消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
  172.                    break;

  173.               /* 超时 */
  174.               case OS_R_TMO:
  175.                    bsp_LedToggle(1);
  176.                    bsp_LedToggle(4);
  177.                    break;
  178.             
  179.               /* 其他值不处理 */
  180.               default:                    
  181.                    break;
  182.          }   
  183.     }
  184. }
复制代码



baiyongbin2009 回答时间:2016-2-3 16:03:50
18.4.2   STM32F407开发板实验
配套例子:
    V5-418_RTX实验_内存管理(8字节对齐)
实验目的:
    1.     学习RTX的内存管理(8字节对齐)。
    2.     函数_declare_box8和_init_box8用于8字节对齐的内存池初始化。这里8字节对齐的含义:
  a.     内存池的首地址是8字节对齐(8字节对齐就是地址对8求余等于0)。
  b.    每个内存块大小也得是8字节的倍数,这样才能保证每申请到的一个内存块的首地址也是8字节对齐。
  c.     8字节对齐是由RTX系统完成的。
实验内容:
    1.K1按键按下,串口打印。
    2.K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。
    3.K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。
    4.摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。
    5.摇杆UP键按下,申请一个内存块用于64位整形变量,然后向消息邮箱发送数据。
    6.各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
18.13.png
                              
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
18.14.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
18.15.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码

内存管理的初始化和消息邮箱的创建:
  1. #define PoolBlocks           10
  2. #define PoolPerBlockSize     8

  3. /* 声明一个支持10个消息的消息邮箱 */
  4. os_mbx_declare (mailbox, 10);

  5. /* 声明一个内存池,10个块,每块大小8字节 */
  6. _declare_box8(mpool, PoolPerBlockSize, PoolBlocks);

  7. /*
  8. *********************************************************************************************************
  9. *    函 数 名: AppObjCreate
  10. *    功能说明: 创建任务通信机制
  11. *    形    参: 无
  12. *    返 回 值: 无
  13. *********************************************************************************************************
  14. */
  15. static void AppObjCreate (void)
  16. {
  17.      /* 创建消息邮箱 */
  18.       os_mbx_init (&mailbox, sizeof(mailbox));
  19.    
  20.      /* 初始化内存池,8字节对齐,*/
  21.      _init_box8 (mpool, sizeof (mpool), PoolPerBlockSize);
  22. }
复制代码

四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t  *pucMsg;
  13.      uint16_t *pusMsg;
  14.      uint32_t *pulMsg;
  15.      uint64_t *pullMsg;
  16.    
  17.      uint8_t ucKeyCode, ucCount = 0;

  18.     while(1)
  19.     {
  20.          ucKeyCode = bsp_GetKey();
  21.         
  22.          if (ucKeyCode != KEY_NONE)
  23.          {
  24.               switch (ucKeyCode)
  25.               {
  26.                    /* K1键按下,打印调试说明 */
  27.                    case KEY_DOWN_K1:
  28.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  29.                        break;  

  30.                    /* K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据 */
  31.                    case KEY_DOWN_K2:
  32.                        /* 申请一个内存块用于8位整形变量 */
  33.                        pucMsg  = _alloc_box (mpool);
  34.                        *pucMsg = ucCount++;
  35.                   
  36.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  37.                        if(os_mbx_send (&mailbox, pucMsg, 100) != OS_R_OK)
  38.                        {
  39.                             /* 发送失败,即使等待了100个时钟节拍 */
  40.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  41.                             _free_box (mpool, pucMsg);
  42.                        }
  43.                        else
  44.                        {
  45.                             /* 发送成功 */
  46.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");   
  47.                             _free_box (mpool, pucMsg);
  48.                        }
  49.                        break;  

  50.                    /* K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据 */
  51.                    case KEY_DOWN_K3:
  52.                        /* 申请一个内存块用于16位整形变量 */
  53.                        pusMsg  = _alloc_box (mpool);
  54.                        *pusMsg = ucCount++;
  55.                   
  56.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  57.                        if(os_mbx_send (&mailbox, pusMsg, 100) != OS_R_OK)
  58.                        {
  59.                             /* 发送失败,即使等待了100个时钟节拍 */
  60.                             printf("K3键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  61.                             _free_box (mpool, pusMsg);
  62.                        }
  63.                        else
  64.                        {
  65.                             /* 发送成功 */
  66.                             printf("K3键按下,向消息邮箱发送数据成功\r\n");   
  67.                             _free_box (mpool, pusMsg);
  68.                        }
  69.                        break;  
  70.                   
  71.                    /* 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据 */
  72.                    case JOY_DOWN_OK:
  73.                        /* 申请一个内存块用于32位整形变量 */
  74.                        pulMsg  = _alloc_box (mpool);
  75.                        *pulMsg = ucCount++;
  76.                   
  77.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  78.                        if(os_mbx_send (&mailbox, pulMsg, 100) != OS_R_OK)
  79.                        {
  80.                             /* 发送失败,即使等待了100个时钟节拍 */
  81.                             printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  82.                             _free_box (mpool, pulMsg);
  83.                        }
  84.                        else
  85.                        {
  86.                             /* 发送成功 */
  87.                             printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");   
  88.                             _free_box (mpool, pulMsg);
  89.                        }
  90.                        break;

  91.                    /* 摇杆UP键按下,申请一个内存块用于64位整形变量,然后向消息邮箱发送数据 */
  92.                    case JOY_DOWN_U:
  93.                        /* 申请一个内存块用于32位整形变量 */
  94.                        pullMsg  = _alloc_box (mpool);
  95.                        *pullMsg = ucCount++;
  96.                   
  97.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  98.                        if(os_mbx_send (&mailbox, pulMsg, 100) != OS_R_OK)
  99.                        {
  100.                             /* 发送失败,即使等待了100个时钟节拍 */
  101.                             printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  102.                             _free_box (mpool, pullMsg);
  103.                        }
  104.                        else
  105.                        {
  106.                             /* 发送成功 */
  107.                             printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");   
  108.                             _free_box (mpool, pullMsg);
  109.                        }
  110.                        break;

  111.                    /* 其他的键值不处理 */
  112.                    default:                    
  113.                        break;
  114.               }
  115.          }
  116.         
  117.          os_dly_wait(20);
  118.      }
  119. }

  120. /*
  121. *********************************************************************************************************
  122. *    函 数 名: AppTaskLED
  123. *    功能说明: LED闪烁。
  124. *    形    参: 无
  125. *    返 回 值: 无
  126. *   优 先 级: 2
  127. *********************************************************************************************************
  128. */
  129. __task void AppTaskLED(void)
  130. {
  131.      const uint16_t usFrequency = 200; /* 延迟周期 */
  132.    
  133.      /* 设置延迟周期 */
  134.      os_itv_set(usFrequency);
  135.    
  136.     while(1)
  137.     {
  138.          bsp_LedToggle(2);
  139.          bsp_LedToggle(3);

  140.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  141.          os_itv_wait();
  142.     }
  143. }

  144. /*
  145. *********************************************************************************************************
  146. *    函 数 名: AppTaskMsgPro
  147. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
  148. *    形    参: 无
  149. *    返 回 值: 无
  150. *   优 先 级: 3
  151. *********************************************************************************************************
  152. */
  153. __task void AppTaskMsgPro(void)
  154. {
  155.      uint8_t *pMsg;
  156.      OS_RESULT xResult;
  157.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  158.    
  159.     while(1)
  160.     {
  161.          xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
  162.         
  163.          switch (xResult)
  164.          {
  165.               /* 无需等待接受到消息邮箱数据 */
  166.               case OS_R_OK:
  167.                    printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
  168.                    break;  

  169.               /* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
  170.               case OS_R_MBX:
  171.                    printf("因为消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
  172.                    break;

  173.               /* 超时 */
  174.               case OS_R_TMO:
  175.                    bsp_LedToggle(1);
  176.                    bsp_LedToggle(4);
  177.                    break;
  178.             
  179.               /* 其他值不处理 */
  180.               default:                    
  181.                    break;
  182.          }   
  183.     }
  184. }
复制代码


baiyongbin2009 回答时间:2016-2-3 16:04:25
18.5 总结
    本章节主要为大家讲解了RTX内存管理的实现方法,关于嵌入式内存管理的方案还有很多,有兴趣的同学可以查阅相关资料了解一下。

stary666 回答时间:2016-2-3 16:09:47
看看,,,,,,,,,,,,
看不透说不穿 回答时间:2019-3-24 12:58:13
有个问题请教下,RTX 邮箱传递的是数据地址,上面的例子动态生成一个内存,数据邮箱发送完后释放了内存,邮箱的接收端收到地址,但是如果数据没有来得及处理会不会用的不是真实数据,因为地址已经被释放,可能其他地方的风险。

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版