查看原文
其他

【MCU】一种单片机节省内存的方法(补充)

bug菌 最后一个bug 2022-07-15


1、聊一聊

    以前听这首曲子内心会变得格外平静,然而现在却五味陈杂!

    今天主要跟大家分享一个MCU省内存的办法,同时也欢迎大家在文末问答留言讨论。

2、读前必备

    对于MCU节省内存办法大合集bug菌在很早之前就总结分享给大家了,如果还没来得及阅读的小伙伴点击下方链接先学习一波。


单片机开发之节省内存大法(C语言版本)



3、本文补充省内存办法

1

const的使用
    关于const的用法应该是老生常谈的知识点了,如果还有不是特别清楚的小伙伴可以参考<一文搞定C语言const关键字>一文,bug菌就不重复造轮子了,直接以stm32单片机为例看看const变量的的存储方式。
参考demo:
1#include "led.h"
2#include "delay.h"
3#include "usart.h"
4
5#define DEV_NUM_MAX   (3)
6#define DEV_PARAM_MAX (2)
7
8typedef struct _tag_DevParam
9{
10    char* Name;                     //设备名称
11    uint32_t Param[DEV_PARAM_MAX];  //设备参数
12}sDevParam;
13
14
15 const sDevParam stDevParam[DEV_NUM_MAX] = {
16                                {"Uart1",57600,0},
17                                {"Uart2",57600,1},
18                                {"CAN",1000000,0},
19                                };
20/***************************************
21 * Fuction:const内存分配测试
22 * Author :bug菌                                
23 **************************************/

24 int main(void)
25 {
26    uint8_t t = 0;
27    uint8_t devCnt = 0;
28
29    delay_init();            //延时函数初始化    
30    uart_init(115200);   //串口初始化
31
32    printf("\n*******************const Test*******************\r\n");
33
34    for(devCnt = 0 ;devCnt < DEV_NUM_MAX;devCnt++)
35    {
36        printf("DevName = %s,Param1 = %d,Param2 = %d\r\n",stDevParam[devCnt].Name,\
37                                                      stDevParam[devCnt].Param[0],\
38                                                      stDevParam[devCnt].Param[1]);
39    }
40    printf("stDevParam Size : %d \r\n",sizeof(stDevParam));
41    printf("stDevParam Addr : 0x%X \r\n",stDevParam);
42    printf("\n***********欢迎关注公众号:最后一个bug************\n");
43    while(1)
44    {
45        delay_ms(10); 
46        if(++t > 150){LED0=0;}else{LED0=1;}
47    }    
48 }
运行结果:

分析一下:
  • 对于stm32的所有存储映像都在对应工程所编译生成的.map文件中,对.map文件(其文件在工程目录中)的熟悉度就在一定程度上彰显你对stm32单片机的熟练程度。

  • 程序编译成功以后,就可以直接在map文件中查找const修饰的数组名,从而得到如下结果:


  • 从上图我们了解到其stDevParam变量位置0x080016b8数据区且位于(.contdata段--只读数据段)并占用了36个字节,与我们串口输出结果是相符合的。


2

const数据的存储
    通过上面的测试程序显示了const数据的存储位置,那么我们看一下该位置位于stm32的哪块存储区域,是RAM还是FLASH?
    因为我们节省内存主要就是通过占用更小的RAM来实现相同的项目需求,那么对于MCU而言最好就是的借助Flash,通过时间来置换空间,拿出对应的数据手册看看这些存储范围是如何分配的。

上图来源于ST手册Memory Mapping
    很明显前一节测试的const stDevParam变量位置0x080016b8处,正好处于FLASH存储位置,所以其并没有占用RAM资源。

3

const数据使用
    很多写单片机程序的小伙伴都喜欢把一些只读的变量用全局变量来保存,然而这些变量基本上只保存一些参数,这对于单片机的RAM资源是非常浪费的。
    bug菌曾经接手过一个前同事项目,怎么说呢?可能这个项目他也是接手别人的,该项目MCU还外部扩展了一个16M的SDRAM,大家都觉得反正RAM大,变量随便定,也不去管数据范围,动不动就float,double,真的是牛。
    直到bug菌接手内存占用率已高达95%,后面稍微添加一些需求感觉RAM就要爆掉了,没办法这样下去终究会出问题,于是申请了代码重构,通过优化代码结构、设计等RAM占用率直接降到了50%左右,可以想象一下之前的开发人员是多么的任性。
    所以一句话说得好"前人栽树,后人乘凉;前人挖坑,后人入fen"。前面我们分析了stm32的const数据位于Flash上,一般Flash都会比RAM打上好几倍:(如下图所示:)

上图来源于ST官网

    这样对于一些预先设置好的参数等等都可以整理以后统一放到类似于前面demo中这样的结构体数组中,从而可以大大减少对RAM的占用。
    注意一点的是 : 访问RAM一般来说会比访问Flash要快一些,然而大部分项目对于这样的差异影响非常之小,后面bug菌会为大家再带来一篇文章讲讲这块的知识。
    

4、最后小结

    那单片机使用const节省内存先为大家讲到这里,如果大家还有什么好的方法欢迎在文末的问答区分享留言。

    好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。

推荐好文  点击蓝色字体即可跳转

【收藏】get这些技巧,HardFault_Handler排查只需要几分钟

【C进阶】这种地方别再强制类型转化了,来告诉你个小技巧!

【算法】高效"KMP"字符匹配算法就这么简单

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存