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

news2024/11/15 13:40:03

1)实验平台:正点原子APM32E103最小系统板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban

第四十五章 内存管理实验

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

45.1 硬件设计
45.1.1 例程功能

  1. 程序运行后,可通过按下KEY0和KEY_UP按键,分别进行内存的申请和释放操作,操作结果将在LCD上显示
  2. 可通过USMART进行内存申请和释放的操作
  3. LED0闪烁,指示程序正在运行
    45.1.2 硬件资源
  4. LED
    LED0 - PB5
  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
    45.1.3 原理图
    本章实验使用的内存管理库为软件库,因此没有对应的连接原理图。
    45.2 程序设计
    45.2.1 内存管理库的使用
    正点原子提供的内存管理库包含两个文件,分别为:malloc.c和malloc.h,本章实验配套的实验例程中已经提供了这两个文件,并且已经针对正点原子APM32E103最小系统板进行了移植适配,用户在使用时,仅需将这两个文件添加到自己的工程即可,如下图所示:
    在这里插入图片描述

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

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

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

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

#include " apm32e10x.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);
}

45.2.2 实验应用代码
本章实验的应用代码,如下所示:

int main(void)
{
    uint8_t t = 0;
    uint8_t key;
    uint8_t *p_sramin = NULL;
    uint8_t *p_sramex = NULL;
    uint32_t tp_sramin = 0;
    uint32_t tp_sramex = 0;
    uint8_t paddr[32];
    uint16_t memused;
    
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);  /* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    usmart_dev.init(120);                             /* 初始化USMART */
    led_init();                                       /* 初始化LED */
    key_init();                                       /* 初始化按键 */
    lcd_init();                                       /* 初始化LCD */
    sram_init();                                      /* 初始化外部SRAM */
    my_mem_init(SRAMIN);                              /* 初始化内部SRAM内存池 */
    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, "SRAMEX   USED:", BLUE);
    
    while (1)
    {
        t++;
        key = key_scan(0);
        
        switch (key)
        {
            case KEY0_PRES: /* 申请内存 */
            {
                p_sramin = mymalloc(SRAMIN, 2048);    /* 从所有内存池中申请内存 */
                p_sramex = mymalloc(SRAMEX, 2048);    /* 内存申请成功 */
                if ((p_sramin != 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_sramex,
							"SRAMEX: Malloc Test%03d", t + SRAMEX);
                    lcd_show_string(30, 276, 239, 16, 16,
									(char *)p_sramex, BLUE);
                }
                else                                                                    				/* 内存申请失败 */
                {
                    myfree(SRAMIN, p_sramin);                                           				/* 释放申请成功的内存 */
                    myfree(SRAMEX, p_sramex);
                    p_sramin = NULL;
                    p_sramex = NULL;
                }
                break;
            }
            case WKUP_PRES:                                                             			/* 释放内存 */
            {
                myfree(SRAMIN, p_sramin);
                myfree(SRAMEX, p_sramex);
                p_sramin = NULL;
                p_sramex = NULL;
                break;
            }
        }
        
        if ((tp_sramin != (uint32_t)p_sramin) ||
            (tp_sramex != (uint32_t)p_sramex))
        {
            tp_sramin = (uint32_t)p_sramin;
            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,
					"SRAMEX: Addr: 0x%08X",
					(uint32_t)p_sramex);
            lcd_show_string(30, 226, 239, 16, 16,
							(char *)paddr, BLUE);
        }
		/* 内存被释放了 */
        else if ((p_sramin == NULL) || (p_sramex == NULL))
        {
            lcd_fill(30, 210, 239, 319, WHITE);
        }
        
        if ((t % 20) == 0)
        {
            memused = my_mem_perused(SRAMIN);
            sprintf((char *)paddr,
					"%d.%01d%%", memused / 10, memused % 10);
			/* 显示内部SRAM使用率 */
            lcd_show_string(30 + 112, 162, 200, 16, 16,
							(char *)paddr, BLUE);
            
            memused = my_mem_perused(SRAMEX);
            sprintf((char *)paddr,
					"%d.%01d%%", memused / 10, memused % 10);
			/* 显示外部SRAM使用率 */
            lcd_show_string(30 + 112, 178, 200, 16, 16,
							(char *)paddr, BLUE);
            LED0_TOGGLE();
        }
        
        delay_ms(10);
    }
}

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

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

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

相关文章

近期学习文章

DNSlog在渗透测试中的实战技巧 - 网安隐藏源IP,提高溯源难度的几种方案 - 网安FreeBuf网络安全行业门户 【漏洞公告】某平台一个有意思的CSRF // SecTrain安全博客 浅谈Web源码泄漏-安全客 - 安全资讯平台 红队-C2 Server基础构建 - 先知社区FreeBuf网络安全行业…

erlang (OS 操作模块)学习笔记

cmd: env: 返回所有环境变量的列表。 每个环境变量都表示为元组 {VarName,Value},其中 VarName 是 变量和 Value 其值。 例: {VarName,Value} {"ERLANG_HOME","C:\\Program Files\\erl-24.3.4.2\\bin\\erl-24.3.4.2"}…

C语言第三弹---数据类型和变量

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 数据类型和变量 1、数据类型介绍1.1、整型1.2、浮点型1.3、字符型1.4、布尔类型1.5、各种数据类型的长度1.5.1、sizeof操作符1.5.2、数据类型的长度1.5.3、sizeo…

无/自监督去噪(1)——一个变迁:N2N→N2V→HQ-SSL

目录 1. 前沿2. N2N3. N2V——盲点网络(BSNs,Blind Spot Networks)开创者3.1. N2V实际是如何训练的? 4. HQ-SSL——认为N2V效率不够高4.1. HQ-SSL的理论架构4.1.1. 对卷积的改进4.1.2. 对下采样的改进4.1.3. 比N2V好在哪&#xff…

旅游项目day08

1. 旅游日记(游记) 后端:实体类,列表,查看,审核 前端:目的地明细中-游记->带范围条件查询,游记首页,【扩展】游记添加/编辑,【扩展】添加游记时间没登录时…

计算机安全学习笔记(V):UDP和网络扫描

User Datagram Protocol (UDP) UDP是最简单的传输协议。多个程序(服务)可以在主机上侦听,因此操作系统需要知道将流量发送到哪个程序。 在传输协议中,每个程序都与源和目标处的端口相关联,该端口显示为程序的套接字。…

Java入门——开发环境、入门程序(搭建Java开发环境、安装JDK 验证、JDK、编写代码、编译代码、运行代码)

目录 前言 搭建Java开发环境 获取JDK 安装JDK 验证JDK DOS窗口常用命令 入门程序 编写代码 编译代码、运行代码 前言 Java是美国sun公司(Stanford University Network)在1995年推出的一门计算机高级编程语言。Java早期称为Oak(橡树)&#xf…

python里的神奇bug

都知道python里列表必须用逗号分隔开 我再给大家看个神奇的东西 import numpy as npb np.array([2, 1, 2 ,1 ,-1 ,2]); print(b) print(b.shape)b np.array([2, 1, 2 ,1 -1 ,2]); print(b) print(b.shape)结果如下 注意我下面的一个是没有逗号的,而且1和-1之间是…

鸿蒙开发系列教程(四)--ArkTS语言:基础知识

1、ArkTS语言介绍 ArkTS是HarmonyOS应用开发语言。它在保持TypeScript(简称TS)基本语法风格的基础上,对TS的动态类型特性施加更严格的约束,引入静态类型。同时,提供了声明式UI、状态管理等相应的能力,让开…

Jvm相关知识(面试高级必备)

类的实例化顺序 先静态、先父后子 先静态:父静态>子静态 优先级:父类>子类 静态代码块>非静态代码块>构造函数 一个类的实例化过程: ①.父类的static代码块,当前类的static; ②.顺序执行…

python实操之网络爬虫介绍

一、什么是网络爬虫 网络爬虫,也可以叫做网络数据采集更容易理解。它是指通过编程向网络服务器(web)请求数据(HTML表单),然后解析HTML,提取出自己想要的数据。 它包括了根据url获取HTML数据、解…

安捷伦E8362C网络分析仪40GHz

安捷伦E8362C网络分析仪 E8362C 是 Agilent 的 40 GHz 网络分析仪。网络分析仪是一种功能强大的仪器,可以以无与伦比的精度测量射频设备的线性特性。许多行业使用网络分析仪来测试设备、测量材料和监控信号的完整性。 附加功能: 10 MHz 至 20 GHz 123 d…

java-IO

JAVA IO - java io可以让我们用标准的读写操作来完成对不同设备的读写数据工作. - java将IO按照方向划分为输入与输出,参照点是我们写的程序. - 输入:用来读取数据的,是从外界到程序的方向,用于获取数据. - 输出:用来写出数据的,是从程序到外界的方向,用于发送数据. java将…

Dubbo源码解析第一期:如何使用Netty4构建RPC

一、背景 早期学习和使用Dubbo的时候(那时候Dubbo还没成为Apache顶级项目),写过一些源码解读,但随着Dubbo发生了翻天覆地的变化,那些文章早已过时,所以现在计划针对最新的Apache Dubbo源码来进行“阅读理解…

关于eNSP中主机/PC与USG网络不可达的解决方案

check points:主机防火墙、网段、接口配置、ping权限、接口安全域; 1、主机 确认当前在联网络的属性(专用网络/公共网络),本机防火墙有无放通;检查 eNSP内防火墙 接口配置:IP地址是否配置到了正…

浅谈AcrelEMS-CIA机场智慧能源管平台解决方案-安科瑞 蒋静

1 概述 机场智慧能源管平台解决方案对机场范围内变电站内的高低压配电设备 、 发电机、变压器 、UPS、EPS 、广场照明 、 室内照明 、通风及排水等机电设备进行实时分布式监控和集中管理 , 实现无人值守 , 确保高速公路安全畅通 , 提高 自动化管理水平 , 降低机电设备的运行维…

插入排序(一)——直接插入排序与希尔排序

目录 一.前言 二.排序的概念及其运用 1.1排序的概念 1.2 常用排序算法 三.常用排序算法的实现 3.1 插入排序 3.1.1 基本思想 3.1.2 直接插入排序 3.1.3 希尔排序(缩小增量排序) 四.全部代码 sort.c sort.h test.c 五.结语 一.前言 本文我们…

Android.mk和Android.bp的区别和转换详解

Android.mk和Android.bp的区别和转换详解 文章目录 Android.mk和Android.bp的区别和转换详解一、前言二、Android.mk和Android.bp的联系三、Android.mk和Android.bp的区别1、语法:2、灵活性:3、版本兼容性:4、向后兼容性:5、编译区…

【数据结构】快速排序,归并排序

快速排序 1.hoare版本 根据动图的演示,整理的思路如下, 1.定义left,right,key。key默认是左边第一个元素,像两个指针,左边找比key大的,右边找比k小的,找到的话,交换二者,往返这个过…

限流算法之流量控制的平滑之道:滑动时间窗算法

文章目录 引言简介优点缺点样例样例图样例代码 应用场景结论 引言 在互联网应用中,流量控制是一个重要的组件,用于防止系统过载和保护核心资源。常见的限流算法包括固定窗口算法和滑动时间窗算法。本文将重点介绍滑动时间窗算法,并分析其优缺…