文章目录

  • 其它文章链接,独家吐血整理
  • 实验现象
  • 主程序
  • 内存池初始化程序
  • 代码讲解

其它文章链接,独家吐血整理

(实验3)单片机,STM32F4学习笔记,代码讲解【按键输入实验】【正点原子】【原创】
(实验4)单片机,STM32F4学习笔记,代码讲解【串口实验】【正点原子】【原创】
(实验5)单片机,STM32F4学习笔记,代码讲解【外部中断实验】【正点原子】【原创】
(实验6,实验7)单片机,STM32F4学习笔记,代码讲解【看门狗实验】【正点原子】【原创】
(实验8)单片机,STM32F4学习笔记,代码讲解【定时器实验】【正点原子】【原创】
(实验9)单片机,STM32F4学习笔记,代码讲解【PWM输出实验】【正点原子】【原创】
(实验10)单片机,STM32F4学习笔记,代码讲解【输入捕获实验】【正点原子】【原创】
(实验11)单片机,STM32F4学习笔记,代码讲解【电容触摸按键实验】【正点原子】【原创】
(实验12)单片机,STM32F4学习笔记,代码讲解【OLED显示实验】【正点原子】【原创】
(实验13)单片机,STM32F4学习笔记,代码讲解【TFTLCD彩屏显示实验】【正点原子】【原创】
(实验15)单片机,STM32F4学习笔记,代码讲解【RTC实时时钟实验】【正点原子】【原创】
(实验17)单片机,STM32F4学习笔记,代码讲解【待机唤醒实验】【正点原子】【原创】
(实验23)单片机,STM32F4学习笔记,代码讲解【DMA实验】【正点原子】【原创】
(实验25)单片机,STM32F4学习笔记,代码讲解【SPI实验】【正点原子】【原创】
(实验34)单片机,STM32F4学习笔记,代码讲解【FLASH模拟EEPROM实验】【正点原子】【原创】
(实验36)单片机,STM32F4学习笔记,代码讲解【外部SRAM实验】【正点原子】【原创】
(实验37)单片机,STM32F4学习笔记,代码讲解【内存管理实验】【正点原子】【原创】
(实验38)单片机,STM32F4学习笔记,代码讲解【SD卡实验】【正点原子】【原创】
(实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】
(实验46)单片机,STM32F4学习笔记,代码讲解【FPU测试实验】【正点原子】【原创】
(实验47)单片机,STM32F4学习笔记,代码讲解【DSP-FFT测试实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验-RTC时钟实验】【正点原子】【原创】
(实验55)单片机,STM32F4学习笔记,代码讲解【网络通信实验】【正点原子】【原创】

实验现象

本实验开机后,显示提示信息,等待外部输入。KEY0用于申请内存,每次申请2K字节内存。KEY1用于写数据到申请到的内存里面。KEY2用于释放内存。KEY_UP用于切换操作内存区(内部SRAM内存/外部SRAM内存/CCM内存)。 DS0用于指示程序运行状态。本章我们还可以通过USMART调试,测试内存管理函数。

主程序

int main(void)
{        u8 key;         u8 i=0;       u8 *p=0;u8 *tp=0;u8 paddr[18];                //存放P Addr:+p地址的ASCII值u8 sramx=0;                 //默认为内部sramNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2delay_init(168);  //初始化延时函数uart_init(115200);       //初始化串口波特率为115200LED_Init();                    //初始化LED LCD_Init();                    //LCD初始化  KEY_Init();                   //按键初始化 FSMC_SRAM_Init();           //初始化外部SRAM  my_mem_init(SRAMIN);       //初始化内部内存池my_mem_init(SRAMEX);      //初始化外部内存池my_mem_init(SRAMCCM);     //初始化CCM内存池POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); LCD_ShowString(30,70,200,16,16,"MALLOC TEST");    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,110,200,16,16,"2014/5/15");   LCD_ShowString(30,130,200,16,16,"KEY0:Malloc  KEY2:Free");LCD_ShowString(30,150,200,16,16,"KEY_UP:SRAMx KEY1:Read"); POINT_COLOR=BLUE;//设置字体为蓝色 LCD_ShowString(30,170,200,16,16,"SRAMIN");LCD_ShowString(30,190,200,16,16,"SRAMIN  USED:   %");LCD_ShowString(30,210,200,16,16,"SRAMEX  USED:   %");LCD_ShowString(30,230,200,16,16,"SRAMCCM USED:   %");while(1){    key=KEY_Scan(0);//不支持连按    switch(key){case 0://没有按键按下 break;case KEY0_PRES:   //KEY0按下p=mymalloc(sramx,2048);//申请2K字节if(p!=NULL)sprintf((char*)p,"Memory Malloc Test%03d",i);//向p写入一些内容break;case KEY1_PRES:  //KEY1按下       if(p!=NULL){sprintf((char*)p,"Memory Malloc Test%03d",i);//更新显示内容      LCD_ShowString(30,270,200,16,16,p);             //显示P的内容}break;case KEY2_PRES: //KEY2按下      myfree(sramx,p);//释放内存p=0;           //指向空地址break;case WKUP_PRES:    //KEY UP按下 sramx++; if(sramx>2)sramx=0;if(sramx==0)LCD_ShowString(30,170,200,16,16,"SRAMIN ");else if(sramx==1)LCD_ShowString(30,170,200,16,16,"SRAMEX ");else LCD_ShowString(30,170,200,16,16,"SRAMCCM");break;}if(tp!=p){tp=p;sprintf((char*)paddr,"P Addr:0X%08X",(u32)tp);LCD_ShowString(30,250,200,16,16,paddr);   //显示p的地址if(p)LCD_ShowString(30,270,200,16,16,p);//显示P的内容else LCD_Fill(30,270,239,266,WHITE);    //p=0,清除显示}delay_ms(10);   i++;if((i%20)==0)//DS0闪烁.{LCD_ShowNum(30+104,190,my_mem_perused(SRAMIN),3,16);//显示内部内存使用率LCD_ShowNum(30+104,210,my_mem_perused(SRAMEX),3,16);//显示外部内存使用率LCD_ShowNum(30+104,230,my_mem_perused(SRAMCCM),3,16);//显示CCM内存使用率LED0=!LED0;}}
}

内存池初始化程序

//内存池(32字节对齐)
__align(32) u8 mem1base[MEM1_MAX_SIZE];                                                 //内部SRAM内存池
__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));                 //外部SRAM内存池
__align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000)));                 //内部CCM内存池
//内存管理表
u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                                 //内部SRAM内存池MAP
u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE)));  //外部SRAM内存池MAP
u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000+MEM3_MAX_SIZE)));  //内部CCM内存池MAP
//内存管理参数
const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE};    //内存表大小
const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE,MEM3_BLOCK_SIZE};                  //内存分块大小
const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE,MEM3_MAX_SIZE};                           //内存总大小//内存管理控制器
struct _m_mallco_dev mallco_dev=
{my_mem_init,                       //内存初始化my_mem_perused,                      //内存使用率mem1base,mem2base,mem3base,          //内存池mem1mapbase,mem2mapbase,mem3mapbase,//内存管理状态表0,0,0,                            //内存管理未就绪
};//复制内存
//*des:目的地址
//*src:源地址
//n:需要复制的内存长度(字节为单位)
void mymemcpy(void *des,void *src,u32 n)
{  u8 *xdes=des;u8 *xsrc=src; while(n--)*xdes++=*xsrc++;
}
//设置内存
//*s:内存首地址
//c :要设置的值
//count:需要设置的内存大小(字节为单位)
void mymemset(void *s,u8 c,u32 count)
{  u8 *xs = s;  while(count--)*xs++=c;
}
//内存管理初始化
//memx:所属内存块
void my_mem_init(u8 memx)
{  mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零  mymemset(mallco_dev.membase[memx], 0,memsize[memx]);    //内存池所有数据清零  mallco_dev.memrdy[memx]=1;                                //内存管理初始化OK
}
//获取内存使用率
//memx:所属内存块
//返回值:使用率(0~100)
u8 my_mem_perused(u8 memx)
{  u32 used=0;  u32 i;  for(i=0;i<memtblsize[memx];i++)  {  if(mallco_dev.memmap[memx][i])used++; } return (used*100)/(memtblsize[memx]);
}
//内存分配(内部调用)
//memx:所属内存块
//size:要分配的内存大小(字节)
//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
u32 my_mem_malloc(u8 memx,u32 size)
{  signed long offset=0;  u32 nmemb;   //需要的内存块数  u32 cmemb=0;//连续空内存块数u32 i;  if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化 if(size==0)return 0XFFFFFFFF;//不需要分配nmemb=size/memblksize[memx];    //获取需要分配的连续内存块数if(size%memblksize[memx])nmemb++;  for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区  {     if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加else cmemb=0;                                //连续内存块清零if(cmemb==nmemb)                         //找到了连续nmemb个空内存块{for(i=0;i<nmemb;i++)                    //标注内存块非空 {  mallco_dev.memmap[memx][offset+i]=nmemb;  }  return (offset*memblksize[memx]);//返回偏移地址  }}  return 0XFFFFFFFF;//未找到符合分配条件的内存块
}
//释放内存(内部调用)
//memx:所属内存块
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;
u8 my_mem_free(u8 memx,u32 offset)
{  int i;  if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化{mallco_dev.init(memx);    return 1;//未初始化  }  if(offset<memsize[memx])//偏移在内存池内. {  int index=offset/memblksize[memx];         //偏移所在内存块号码  int nmemb=mallco_dev.memmap[memx][index]; //内存块数量for(i=0;i<nmemb;i++)                       //内存块清零{  mallco_dev.memmap[memx][index+i]=0;  }  return 0;  }else return 2;//偏移超区了.
}
//释放内存(外部调用)
//memx:所属内存块
//ptr:内存首地址
void myfree(u8 memx,void *ptr)
{  u32 offset;   if(ptr==NULL)return;//地址为0.  offset=(u32)ptr-(u32)mallco_dev.membase[memx];     my_mem_free(memx,offset);   //释放内存
}
//分配内存(外部调用)
//memx:所属内存块
//size:内存大小(字节)
//返回值:分配到的内存首地址.
void *mymalloc(u8 memx,u32 size)
{  u32 offset;   offset=my_mem_malloc(memx,size);                 if(offset==0XFFFFFFFF)return NULL;  else return (void*)((u32)mallco_dev.membase[memx]+offset);
}
//重新分配内存(外部调用)
//memx:所属内存块
//*ptr:旧内存首地址
//size:要分配的内存大小(字节)
//返回值:新分配到的内存首地址.
void *myrealloc(u8 memx,void *ptr,u32 size)
{  u32 offset;    offset=my_mem_malloc(memx,size);     if(offset==0XFFFFFFFF)return NULL;     else  {                                       mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size);   //拷贝旧内存内容到新内存   myfree(memx,ptr);                                                   //释放旧内存return (void*)((u32)mallco_dev.membase[memx]+offset);               //返回新内存首地址}
}

代码讲解

//内存管理试验,需要用到malloc函数和free函数,返回void*类型的指针,刚好我已经刷完了C语言哈哈
//你学习到的知识,总会在你不知道的情况下,会用到,比如现在我学到这里有一种亲切感,而且很舒服

//内存管理==内存池(n个内存块)+内存管理表(n项),分别一一对应,内存管理表中某一项数值为0时
//代表,此项对应的内存池没有存储数据,也就是该项对应的内存块未被占用
//当该项值为数字时,比如为10,那么包括10项对应的内存块,加上其它内存块共分配了10个连续占用的内存块空间
//这里好像时,只要这个内存块被占用,无论占用了多少数据,它仍会到下一个寻找空内存块****(我理解的)

//内存分配方向是自顶->底访问,就是说先从第n项内存管理表开始找其对应的内存块是否被占用,如果没有
//则开辟10个连续空间内存块,如果被占用,则从n-1项开始查找,依次往下,申请内存空间靠malloc来申请地址
//释放内存用free函数来实现

//因为,内存池和内存管理表一一对应,所以说当内存池越小(就是说假如2个字节作为一个内存池)
//那么相应内存管理表的数量要变多,而且其相应内存管理表也就越大

//F4的内存管理==内存池(n个内存块)+内存管理表(n项),总共分为3个大块
//分别是内部SRAM,外部SRAM,内部CCM内存,三者的内存池其实地址都不同,要分开对待
//比如,我们熟知的DMA存储数据,就不能直接访问CCM内存,或者说不能从里面读取出数据,具体可看开发指南

//p指针用来malloc开辟地址,接收开辟内存里第一个字节的地址,返回void *类型
//tp指针仅仅是为了与p区别,用以显示p指针的地址,其它没有用

//****这里程序好复杂,我看了好一会也没分析明白,主要牵扯到指针,与结构体指针,其它我都没见到的
//****我就是想弄明白啥是“内存泄漏”?
//虽然程序没看懂,但是开发指南说的操作我明白了,就是k0开辟内存,k1用于将数据显示在LCD上(开辟内存块首地址)
//假如此时还想开辟内存块,那么必须k2将前面开辟的内存块释放,否则假如你连续两次开辟内存,这没有错
//但是一旦你连续两次按k2释放,第一次也不会错,第二次就会发生内存泄漏
//kUP用来选择内部SRAM/外部SRAM(就是上个程序)/内部CCM

(实验37)单片机,STM32F4学习笔记,代码讲解【内存管理实验】【正点原子】【原创】相关推荐

  1. 【学习笔记】C++内存管理-侯捷

    文章目录 C++内存管理:从平地到万丈高楼 一.primitives-基础工具 1.内存分配的四个层面 2.new/delete表达式 2.1 new表达式 2.2 delete表达式 学习笔记源自博 ...

  2. 冰冰学习笔记:动态内存管理

    前言: 动态内存管理,顾名思义就是我们可以在具体使用内存空间时,并非一次性的创建完毕,而是根据我们的需求,动态的开辟.申请的空间不够了,开辟一点,空间太大了,那我们就减小一点. 在以前我们开辟空间的办 ...

  3. 正点原子的内存管理_正点原子【STM32-F407探索者】第四十二章 内存管理实验

    1)资料下载:点击资料即可下载 2)对正点原子Linux感兴趣的同学可以加群讨论:935446741 3)关注正点原子公众号,获取最新资料更新 上一章,我们学会了使用 STM32F4 驱动外部 SRA ...

  4. (实验38)单片机,STM32F4学习笔记,代码讲解【SD卡实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 SD卡驱动程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ( ...

  5. (实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 FATFS初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创 ...

  6. (实验55)单片机,STM32F4学习笔记,代码讲解【网络通信实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 LWIP初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ...

  7. (实验4)单片机,STM32F4学习笔记,代码讲解【串口实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 串口中断程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] (实 ...

  8. (实验6,实验7)单片机,STM32F4学习笔记,代码讲解【看门狗实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象(实验六) 主程序(实验六) 独立看门狗初始化程序(实验六) 代码讲解(实验六) 实验现象(实验七) 主程序(实验七) 窗口看门狗初始化程序(实验七) 代 ...

  9. (实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验】【正点原子】【原创】

    文章目录 ❤2023重新理解记录 其它文章链接,独家吐血整理 实验现象 主程序 IAP初始化程序 代码讲解 文章目录 ❤2023重新理解记录 其它文章链接,独家吐血整理 实验现象 主程序 IAP初始化 ...

最新文章

  1. 如何使用Twitter Bootstrap获得中心内容?
  2. 博弈论题表(好少~~~)
  3. BLE-NRF51822教程-RSSI获取
  4. go mysql 数据 json,golang查询数据返回json
  5. vue 实现返回上一页不请求数据keep-alive
  6. Common BeanUtils 简介
  7. AS3图像抖动效果源码。
  8. 宏锦软件 Android 的 ListView 使用详解
  9. 唐山职业技术学院计算机专业分数线,唐山职业技术学院历年分数线 2021唐山职业技术学院录取分数线...
  10. Python递归打印函数
  11. rest接口webservice接口利用http请求方式发送数据
  12. Django中_meta 部分用法
  13. 企业系统软件你知道哪些?
  14. 项目实施过程中的风险控制
  15. 满秩矩阵可以初等变换成单位矩阵吗?
  16. SONET/SDH概述
  17. 人工智能学术论坛参会总结【附PPT】
  18. 征兵系统集合版(登录系统+信息填写及查看功能)
  19. 自定义EL表达式的函数
  20. 《乐高EV3机器人搭建与编程》一2.1 零件储存箱

热门文章

  1. 扩展欧几里德算法详解
  2. Linux 自动结束进程并启动进程方法
  3. ubuntu系统gcc版本切换指导
  4. Android WiFi 权限、广播、连接、踩坑相关记录
  5. esxi显卡给2个虚拟机_利用ESXi实现一拖二和各系统独立运行——基础篇
  6. Python scrapy爬虫爬取伯乐在线全部文章,并写入数据库
  7. Python爬虫爬取伯乐在线网站信息
  8. nextdate函数白盒测试问题 软件测试_nextdate白盒测试用例
  9. Mysql权限系统工作原理(转)
  10. 调程序就恶心,怎么办?