【正点原子STM32连载】 第四十八章 内存管理实验 摘自【正点原子】APM32F407最小系统板使用指南

news2024/12/24 3:12:44

1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html##

第四十八章 内存管理实验

本章将介绍正点原子提供的内存管理库的使用,通过使用内存管理库可以提高内存的使用效率,在大型的应用开发中,是必不可少的工具。通过本章的学习,读者将学习到正点原子内存管理库的使用。
本章分为如下几个小节:
48.1 硬件设计
48.2 程序设计
48.3 下载验证

48.1 硬件设计

48.1.1 例程功能

  1. 程序运行后,可通过按下KEY0和KEY_UP按键,分别进行内存的申请和释放操作,操作结果将在LCD上显示
  2. 可通过USMART进行内存申请和释放的操作
  3. LED0闪烁,指示程序正在运行
    48.1.2 硬件资源
  4. LED
    LED0 - PF9
  5. 按键
    KEY0 - PE4
    KEY_UP - PA0
  6. USART1(PA9、PA10连接至板载USB转串口芯片上)
  7. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
  8. 外部SRAM
    48.1.3 原理图
    本章实验使用的内存管理库为软件库,因此没有对应的连接原理图。
    48.2 程序设计
    48.2.1 内存管理库的使用
    正点原子提供的内存管理库包含两个文件,分别为:malloc.c和malloc.h,本章实验配套的实验例程中已经提供了这两个文件,并且已经针对正点原子APM32F407最小系统板进行了移植适配,用户在使用时,仅需将这两个文件添加到自己的工程即可,如下图所示:
    在这里插入图片描述

图48.2.1.1 正点原子内存管理库文件
内存管理库中提供了内存管理初始化、申请内存和释放内存等函数,使用非常方便。
在进行内存申请和释放之前,需要使用内存初始化函数对内存进行初始化,内存管理初始化的使用示例,如下所示:

#include "apm32f4xx.h"
#include "./MALLOC/malloc.h"

void example_fun(void)
{
    /* 初始化内部SRAM内存池 */
    my_mem_init(SRAMIN);
}

初始化内存后,便可以在需要内存的时候申请内存,申请内存函数的使用示例,如下所示:

#include "apm32f4xx.h"
#include "./MALLOC/malloc.h"

void example_fun(void)
{
    uint8_t ptr;
    
    /* 初始化内部SRAM内存池 */
    my_mem_init(SRAMIN);
    
    /* 申请1KB内存 */
    ptr = (uint8_t *)mymalloc(SRAMIN, 1024);
    
    /* Do something. */
}

在内存使用完毕后,需要及时释放内存,否则可能产生内存泄漏,释放内存函数的使用示例,如下所示:

#include "apm32f4xx.h"
#include "./MALLOC/malloc.h"

void example_fun(void)
{
    uint8_t ptr;
    
    /* 初始化内部SRAM内存池 */
    my_mem_init(SRAMIN);
    
    /* 申请1KB内存 */
    ptr = (uint8_t *)mymalloc(SRAMIN, 1024);
    
    /* Do something. */
    
    /* 释放无用内存 */
    myfree(SRAMIN, ptr);
}
48.2.2 实验应用代码
本章实验的应用代码,如下所示:
int main(void)
{
    uint8_t t = 0;
    uint8_t key;
    uint8_t *p_sramin = NULL;
    uint8_t *p_sramccm = NULL;
    uint8_t *p_sramex = NULL;
    uint32_t tp_sramin = 0;
    uint32_t tp_sramccm = 0;
    uint32_t tp_sramex = 0;
    uint8_t paddr[32];
    uint16_t memused;
    
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_3);	/* 设置中断优先级分组为组3 */
    sys_apm32_clock_init(336, 8, 2, 7);					/* 配置系统时钟 */
    delay_init(168);										/* 初始化延时功能 */
    usart_init(115200);									/* 初始化串口 */
    usmart_dev.init(84);								/* 初始化USMART */
    led_init();											/* 初始化LED */
    key_init();											/* 初始化按键 */
    lcd_init();											/* 初始化LCD */
    sram_init();											/* 初始化外部SRAM */
    my_mem_init(SRAMIN);								/* 初始化内部SRAM内存池 */
    my_mem_init(SRAMCCM);								/* 初始化CCM内存池 */
    my_mem_init(SRAMEX);								/* 初始化外部SRAM内存池 */
    
    lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "MALLOC TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEY0:Malloc & WR & Show", RED);
    lcd_show_string(30, 130, 200, 16, 16, "KEY_UP:Free", RED);
    lcd_show_string(30, 162, 200, 16, 16, "SRAMIN   USED:", BLUE);
    lcd_show_string(30, 178, 200, 16, 16, "SRAMCCM  USED:", BLUE);
    lcd_show_string(30, 194, 200, 16, 16, "SRAMEX   USED:", BLUE);
    
    while (1)
    {
    		t++;
    		key = key_scan(0);
    		
    		switch (key)
    		{
    			case KEY0_PRES:/* 申请内存 */
    			{
    				/* 从所有内存池中申请内存 */
    				p_sramin = mymalloc(SRAMIN, 2048);
    				p_sramccm = mymalloc(SRAMCCM, 2048);
    				p_sramex = mymalloc(SRAMEX, 2048);
    				/* 内存申请成功 */
    				if (	(p_sramin != NULL) &&
    						(p_sramccm != NULL) &&
    						(p_sramex != NULL))
    				{
    					/* 使用申请到的内存 */
    					sprintf((char *)p_sramin,
    							"SRAMIN: Malloc Test%03d", 
    							t + SRAMIN);
    					lcd_show_string(30, 260, 239, 16, 16,
    									(char *)p_sramin, BLUE);
    					sprintf((char *)p_sramccm,
    							"SRAMCCM: Malloc Test%03d",
    							t + SRAMCCM);
    					lcd_show_string(30, 276, 239, 16, 16,
    									(char *)p_sramccm, BLUE);
    					sprintf((char *)p_sramex,
    							"SRAMEX: Malloc Test%03d",
    							t + SRAMEX);
    					lcd_show_string(30, 292, 239, 16, 16,
    									(char *)p_sramex, BLUE);
    				}
    				/* 内存申请失败 */
    				else
    				{
    					/* 释放申请成功的内存 */
    					myfree(SRAMIN, p_sramin);
    					myfree(SRAMCCM, p_sramccm);
    					myfree(SRAMEX, p_sramex);
    					p_sramin = NULL;
    					p_sramccm = NULL;
    					p_sramex = NULL;
    				}
    				break;
    			}
    			case WKUP_PRES:/* 释放内存 */
    			{
    				myfree(SRAMIN, p_sramin);
    				myfree(SRAMCCM, p_sramccm);
    				myfree(SRAMEX, p_sramex);
    				p_sramin = NULL;
    				p_sramccm = NULL;
    				p_sramex = NULL;
    				break;
    			}
    		}
    		
    		/* 内存申请成功 */
    		if ((tp_sramin != (uint32_t)p_sramin) ||
    			(tp_sramccm != (uint32_t)p_sramccm) ||
    			(tp_sramex != (uint32_t)p_sramex))
    		{
    			tp_sramin = (uint32_t)p_sramin;
    			tp_sramccm = (uint32_t)p_sramccm;
    			tp_sramex = (uint32_t)p_sramex;
    			
    			/* 显示申请到的内存的首地址 */
    			sprintf((char *)paddr, "SRAMIN: Addr: 0x%08X", (uint32_t)p_sramin);
    			lcd_show_string(30, 210, 239, 16, 16, (char *)paddr, BLUE);
    			sprintf((char *)paddr, "SRAMCCN: Addr: 0x%08X", (uint32_t)p_sramccm);
    			lcd_show_string(30, 226, 239, 16, 16, (char *)paddr, BLUE);
    			sprintf((char *)paddr, "SRAMEX: Addr: 0x%08X", (uint32_t)p_sramex);
    			lcd_show_string(30, 242, 239, 16, 16, (char *)paddr, BLUE);
    		}
    		/* 内存被释放了 */
    		else if ((p_sramin == NULL) || (p_sramccm == NULL) || (p_sramex == NULL))
    		{
    			lcd_fill(30, 210, 239, 319, WHITE);
    		}
    		
    		if ((t % 20) == 0)
    		{
    			/* 显示内部SRAM使用率 */
    			memused = my_mem_perused(SRAMIN);
    			sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
    			lcd_show_string(30 + 112, 162, 200, 16, 16, (char *)paddr, BLUE);
    			
    			/* 显示CCM使用率 */
   			 memused = my_mem_perused(SRAMCCM);
    			sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
    			lcd_show_string(30 + 112, 178, 200, 16, 16, (char *)paddr, BLUE);
    			
    			/* 显示外部SRAM使用率 */
    			memused = my_mem_perused(SRAMEX);
    			sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
    			lcd_show_string(30 + 112, 194, 200, 16, 16, (char *)paddr, BLUE);
    			
    			LED0_TOGGLE();
    		}
    		
    		delay_ms(10);
    }
}

可以看到,本实验的应用代码使用到了三个内存池,分别为内部SRAM、CCM和外部SRAM,在完成内存池初始化后,便在LCD上实时刷新显示三个内存池的使用量,以及检测按键输入,若检测到KEY0按键被按下,则从三个内存池中申请三块内存,并写入测试数据,然后将申请到的三块内存的起始地址即内存中写入的测试数据在LCD上进行显示,若检测到KEY_UP按键被按下,则释放最近一次申请的三块内存回对应的内存池中。
48.3 下载验证
在完成编译和烧录操作后,可以看到LCD上实时地显示了三个内存池的使用情况,此时按下KEY0按键申请内存,可以看到三个内存池的使用量增加,并且LCD上显示了申请到的三个内存的起始地址和内存中写入的测试数据,接着按下KEY_UP按键释放内存,可以看到,LCD上显示的内存信息消失,并且因为内存已经被释放回内存池,因此内存池的使用量较少。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用Java高效地存入一万条数据?这可能是你面试成功的关键!

大家好,我是你们的小米,一个热爱技术、喜欢分享的29岁程序猿。今天我要和大家聊一聊一个常见的面试题:在Java中,当我们需要将一万条数据存储到数据库时,如何能够提高存储效率呢? 在面试过程中,…

生活污水处理一体化处理设备有哪些

生活污水处理一体化处理设备有多种类型,包括但不限于以下几种: 鼓风机:提供曝气系统所需的气流。潜水污水提升泵:将污水从低处提升到高处。旋转式滚筒筛分机:对污水中的悬浮物进行分离和筛选。回旋式格栅:…

以技术创新引领行业发展,飞凌嵌入式获双项省级荣誉

近日,飞凌嵌入式荣获「2023年河北省专精特新示范企业」以及「第五批省级制造业单项冠军企业」两项殊荣。这两项荣誉的获得,是对飞凌嵌入式在专业技术领域与创新能力的高度认可,荣誉的背后,凝聚着飞凌嵌入式无数次的研发探索与对创…

Vite项目的初体验 - 非Vite脚手架版本

开箱即用 (out of box): 无需做任何的配置,就可以用vite来帮助我们处理构建工作。 前提 :node 版本 > 12.0.0,使用 npm 进行依赖管理。 本文的案例,从0到1的,一步一步的体会vite的作用。 本文…

QQ恢复聊天记录,就用这3个方法!

无论是因为误操作、手机丢失、系统崩溃,还是因为更换了新手机,恢复重要的QQ聊天记录都是一件必做的事情。通过聊天记录,用户可以随时查看之前的信息,以便了解事情的经过。 那么,如何恢复丢失的QQ聊天记录呢&#xff1…

【算法】道路与航线(保姆级题解)

题目 农夫约翰正在一个新的销售区域对他的牛奶销售方案进行调查。 他想把牛奶送到 T 个城镇,编号为 1∼T。 (存在T个点) 这些城镇之间通过 R 条道路 (编号为 1 到 R) 和 P 条航线 (编号为 1 到 P) 连接。 (存在R条道路&#…

【Proteus仿真】【Arduino单片机】LCD1602-IIC液晶显示

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器,使用PCF8574、LCD1602液晶等。 主要功能: 系统运行后,LCD1602液晶显示各种效果。 二、软件设计 /* 作者:嗨小…

分享一个使用get_hash_value比对数据脚本

使用get_hash_value获取每个字段的值,再sum起来比对,如果表有lob字段,则会先排除掉lob字段再比对其它字段 这个脚本有两个问题: 1.如果字段所有的值长度加起来超过4000会报错,比对不了,这种情况一般比较少…

【亚马逊云科技产品测评】活动征文|AWS EC2 部署Echarts大屏展示项目

前言 Echarts简介 ECharts是一个使用JavaScript开发的,开源的可视化库。它可以让数据变得生动起来,提供直观,交互性强,可高度个性化定制的数据可视化图表。ECharts支持大部分的浏览器,如IE6、Chrome、Firefox、Safari等…

《QT从基础到进阶·十六》QT实现客户端和服务端的简单交互

QT版本:5.15.2 VS版本:2019 客户端程序主要包含三块:连接服务器,发送消息,关闭客户端 服务端程序主要包含三块:打开消息监听,接收消息并反馈,关闭服务端 1、先打开服务端监听功能 …

烟草5G智慧工厂数字孪生可视化平台,赋能烟草工业数字化智慧转型

随着卷烟工厂提质增效需求增强,信息化建设推进及生产制造系统智能化改革发展,各生产单元逐步升级完善数字化,最终实现智能制造成为必然趋势。因此,5G卷烟加工工厂的数字化转型迫在眉睫。中国烟草制造行业正迈向全新的市场经济时代…

vue-element-admin 集成框架设置中文语言

首先拉取中文版分支代码 https://github.com/PanJiaChen/vue-element-admin/tree/i18n (下载卡的话,下载小羊的压缩包,已上传资源) \src\lang\index.js 改完dangdangdang可以啦

性价比高的照明品牌,五款经济实惠的照明品牌推荐

很多家长有时候会说孩子觉得家里的台灯灯光刺眼,看书看久了就不舒服。这不仅要看光线亮度是否柔和,还要考虑台灯是不是有做遮光式设计。没有遮光式设计的台灯,光源外露,灯光会直射孩子头部,孩子视线较低,很…

Kotlin库实现多线程爬取数据

由于字数限制,以下是一个简化版的爬虫程序示例,使用了Kotlin的网络库kotlinx.coroutines和kotlinx.html。这个程序会爬取一个简单的Python多线程跑数据的网页,并打印出结果。 import kotlinx.coroutines.* import kotlinx.html.* import java…

Word脚注如何插入?1分钟学会!

“最近在写一些文章,引用了一些注释,想为它们增添一些脚注。有没有朋友知道在word里脚注怎么添加呀?” 使用word编写文章时,添加脚注是一项常见的任务,用于引用文献、添加注释或提供额外信息。但可能很多朋友不知道wor…

如何在本地运行稳定扩散模型

推荐基于稳定扩散(stable diffusion) AI 模型开发的自动纹理工具: DreamTexture.js自动纹理化开发包 - NSDT 继 DALL-E 2 和 Imagen 之后,新的深度学习模型 Stable Diffusion 标志着文本到图像领域的巨大飞跃。本月早些时候发布的 Stable Diffusion 承诺…

Java进阶(垃圾回收GC)——理论篇:JVM内存模型 垃圾回收定位清除算法 JVM中的垃圾回收器

前言 JVM作为Java进阶的知识,是需要Java程序员不断深度和理解的。 本篇博客介绍JVM的内存模型,对比了1.7和1.8的内存模型的变化;介绍了垃圾回收的语言发展;阐述了定位垃圾的方法,引用计数法和可达性分析发以及垃圾清…

vue3+antv2.x的画布

报错信息: TypeError: Cannot destructure property component of registry_1.shapeMaps[node.shape] as it is undefined. at VueShapeView.renderVueComponent (http://192.168.10.35:9029/node_modules/.vite/deps/antv_x6-vue-shape.js?v49fbfab0:5569:19…

卷王必看。非肿瘤+WGCNA+单细胞,快来抄作业

今天给同学们分享一篇生信文章“m6A Regulators Is Differently Expressed and Correlated With Immune Response of Esophageal Cancer”,这篇文章发表在Dis Markers期刊上,影响因子为3.464。 结果解读: 食道癌中差异表达基因(D…

第18章 Swing 程序设计

概述 String包的层次结构和继承关系如下 常用的Swing组件如下表 Swing常用窗体 JFrame 窗体 JFrame 类的常用构造方法包括以下两种形式: public JFrame():创建一个初始不可见、没有标题的窗体。 public JFrame(String title)…