【11】uC/OS-III应用开发————>RAM内存管理(STM32F767)

  1. 简述

  2. 在嵌入式系统中,内存分配应根据系统特点选择使用

  3. 动态内存分配算法:普通业务系统,动态内存上限取决于硬件,使用效率高 1. 静态内存分配算法:可靠性非常高的系统,需要考虑内存上限,使用效率低

    1. uC/OS内存管理是采用内存池的方式进行管理
    2. 静态划分一大块连续空间做为内存管理的空间,内部划分若干块
    3. 使用的时候就从内存池中获取内存块,使用完将其放回
    4. 核心机制:
  4. 内存池的创建 1. 分配 1. 释放

  5. 存储空间分类:

  6. 内部存储空间:RAM(本节所讲)

    1. 外部存储空间:ROM
  7. 运行机制

  8. 内存池(Memory Pool)是一种用于分配大量大小相同的内存对象的技术,可以加快内存分配/释放的速度

    1. 系统编译时,编译器静态划分一个数组做为系统的内存池,将其分成大小相等的内存块,通过链表链接起来
    2. 先创建内存池才能使用内存块,
    3. 内存控制块
  9. 内存池名称 1. 起始地址 1. 空闲内存块列表 1. 大小 1. 内存块数量 1. 空闲内存块数量

  10. 应用场景

  11. 在不确定数组应该有多大的时候,静态方法,会浪费大量的内存空间,有可能会引起下标越界

    1. uC/OS将系统静态分配的大数组做为内存池,然后分配固定大小的内存块
    2. 如果某个任务内存需求很大,只能按照最大的内存块分配
  12. 常用函数

  13. OSMemCreate();  内存创建函数

    1. OSMemGet();  内存申请函数
    2. OSMemPut();  内存释放函数
  14. 例程

  15. 创建

1 //创建内存管理对象 mem 2 OSMemCreate( (OS_MEM *)&mem, //指向内存管理对象 3 (CPU_CHAR *)"mem for test",//命名内存管理对象 4 (void *)ucArray, //内存分区的首地址 5 (OS_MEM_QTY )3, //内存分区中内存块数目 6 (OS_MEM_SIZE )20, //内存块的字节数目 7 (OS_ERR *)&err); //返回错误类型 8

 

11. 申请 2
1/************************************************** 2 * 函数名:static void AppTaskKey(void *p_arg) 3 * 描述 :按键检测 4 * 输入 :无 5 * 输出 :无 6 * 返回 :无 7 * 调用 :内部调用 8 **************************************************/ 9static void AppTaskKey(void *p_arg) 10{ 11 OS_ERR err; 12 13 char * p_mem_blk; 14 uint32_t ulcount = 0; 15 16 (void)p_arg; 17 18 for(;;) 19 { 20 //向mem获取内存块 21 p_mem_blk = OSMemGet( (OS_MEM *)&mem, //指向内存管理对象 22 (OS_ERR *)&err); //返回错误类型 23 24 sprintf(p_mem_blk, "%d", ulcount ++); //向内存块存取计数值 25 26 OSTaskQPost( (OS_TCB *)&AppTaskLedTCB, //目标任务控制块 27 (void *)p_mem_blk, //消息内容的首地址 28 (OS_MSG_SIZE )strlen(p_mem_blk), // 消息长度 29 (OS_OPT )OS_OPT_POST_FIFO, //发送到任务消息队列的入口 30 (OS_ERR *)&err); //返回错误类型 31 32 OSTimeDlyHMSM ( 0, 0, 1, 0, OS_OPT_TIME_DLY, & err ); //每1s发送一次 33 } 34} 35

 

11. 释放 2
1/************************************************** 2 * 函数名:static void AppTaskLed(void *p_arg) 3 * 描述 :led应用 4 * 输入 :无 5 * 输出 :无 6 * 返回 :无 7 * 调用 :内部调用 8 **************************************************/ 9static void AppTaskLed(void *p_arg) 10{ 11 OS_ERR err; 12 13 CPU_INT32U cpu_clk_freq; 14 CPU_TS ts; 15 OS_MSG_SIZE msg_size; 16 char * pMsg; 17 18 (void)p_arg; 19 20 cpu_clk_freq = BSP_CPU_ClkFreq(); //获取系统时钟 21 22 for(;;) 23 { 24 pMsg = OSTaskQPend( (OS_TICK )0, //无期限等待 25 (OS_OPT )OS_OPT_PEND_BLOCKING, //没有消息任务就阻塞 26 (OS_MSG_SIZE *)&msg_size, //返回消息长度 27 (CPU_TS *)&ts, //返回消息被发送的时间戳 28 (OS_ERR *)&err); //返回错误类型 29 30 ts = OS_TS_GET() - ts; //计算时间差 31 LED1_TOGGLE; 32 33 printf("\r\n 接收到的消息内容为: %s,长度是: %d 字节 \r\n", pMsg,msg_size); 34 printf("\r\n 任务消息从被发送到被接收的时间差是: %d us \r\n", ts / (cpu_clk_freq / 1000000)); 35 36 //退还内存块 37 OSMemPut( (OS_MEM *)&mem, //指向内存管理对象 38 (void *)pMsg, //内存块的首地址 39 (OS_ERR *)&err); //返回错误类型 40 } 41} 42

 

  1. 下载验证

  2. 总结

  3. uC/OS的内存分配算法是只允许用户分配固定大小的内存块,使用完将其放回内存池中;

    1. 内存池中的内存块是通过单链表连接起来的,创建的内存块地址是连续的,空闲的内存块地址上不一定连续
    2. uC/OS将系统静态分配的大数组做为内存池,然后分配固定大小的内存块
    3. uC/OS的内存分配只能解决内存利用率的问题
  4. 参考资料:

  5. 正点原子《STM32F767 UCOS开发手册》

    1. 野火《uC/OS-III内核应用与开发》
    2. 《嵌入式实时操作系统 uC/OS-II原理及应用(第二版)》
    3. 官方源码
  6. 硬件平台:

  7. 正点原子阿波罗F767

  8. 软件平台:

  9. MDK5.2.5

  10. 库版本:

  11. TM32Cube_FW_F7_V1.4.0

  12. uC/OS-III版本

  13. UCOSIII 3.04

代码交流 2021