【正点原子STM32连载】 第四十三章 FLASH模拟EEPROM实验 摘自【正点原子】APM32E103最小系统板使用指南

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

第四十三章 FLASH模拟EEPROM实验

本章将介绍使用APM32E103的片上Flash模拟EEPROM,并对齐进行读写操作。通过本章的学习,读者将学习到闪存存储器控制(FMC)的使用。
本章分为如下几个小节:
43.1 硬件设计
43.2 程序设计
43.3 下载验证

43.1 硬件设计
43.1.1 例程功能

  1. 按下KEY_UP和KEY0按键,分别对Flash进行数据的写入和读取操作,读取到的数据会显示至LCD
  2. 可通过USMART对Flash进行单字数据的读取和写入操作
  3. LED0闪烁,指示程序正在运行
    43.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并口驱动)
    43.1.3 原理图
    本章实验使用的FMC为APM32E103的片上资源,因此没有对应的连接原理图。
    43.2 程序设计
    43.2.1 Geehy标准库的FMC驱动
    APM32E103的片上Flash是可以直接读取的,但Flash无法直接写入,写入Flash前,需要先对其进行擦除操作,该操作需要有FMC来完成,其具体的操作步骤如下:
    ①:解锁访问FMC控制寄存器
    ②:擦除前禁止Flash的数据缓冲
    ③:擦除Flash的指定扇区
    ④:对Flash进行编程
    ⑤:重新使能Flash的数据缓冲
    ⑥:重新上锁访问FMC控制寄存器
    在Geehy标准库中对应的驱动函数如下:
    ①:解锁访问FMC控制寄存器
    该函数用于解锁访问FMC控制寄存器,其函数原型如下所示:
    void FMC_Unlock(void);
    该函数的形参描述,如下表所示:

形参 描述
无 无
表43.2.1.1 函数FMC_Unlock()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表43.2.1.2 函数FMC_Unlock()返回值描述
该函数的使用示例,如下所示:

#include " apm32e10x.h"
#include " apm32e10x _fmc.h"void example_fun(void)
{/* 解锁访问FMC控制寄存器 */FMC_Unlock();
}

②:擦除指定的FMC页面
该函数用于擦除Flash的指定扇区,其函数原型如下所示:
FMC_STATUS_T FMC_ErasePage(uint32_t pageAddr);
该函数的形参描述,如下表所示:
形参 描述
pageAddr 要擦除的页面地址例(在apm32e10x_fmc.h文件中有定义)
表43.2.1.5 函数FMC_Erase Page()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
FMC_STATUS_BUSY 忙
FMC_STATUS_ERROR_PG 编程错误
FMC_STATUS_ERROR_WRP 写保护错误
FMC_STATUS_COMPLETE 操作完成
FMC_STATUS_TIMEOUT 超时错误
表43.2.1.6 函数FMC_EraseSector()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_fmc.h"void example_fun(void)
{FMC_STATUS_T status;/* 擦除Flash的扇区11(系统电压在2.7V~3.6V之间) */status = FMC_ErasePage(pageaddr)if (status == FMC_COMPLETE){/* Do something. */}else{/* Do something. */}
}

③:字编程Flash
该函数用于对Flash进行字编程,其函数原型如下所示:
FMC_STATUS_T FMC_ProgramHalfWord(uint32_t address, uint32_t data);
该函数的形参描述,如下表所示:
形参 描述
address 指定Flash的地址
data 指定的数据
表43.2.1.7 函数FMC_ProgramHalfWord()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
FMC_STATUS_BUSY 忙
FMC_STATUS_ERROR_PG 编程错误
FMC_STATUS_ERROR_WRP 写保护错误
FMC_STATUS_COMPLETE 操作完成
FMC_STATUS_TIMEOUT 超时错误
表43.2.1.8 函数FMC_ProgramHalfWord()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_fmc.h"void example_fun(void)
{FMC_STATUS_T status;/* 编程Flash指定地址0x08000000为0x50505050 */status = FMC_ProgramHalfWord(0x08000000, 0x50505050)if (status == FMC_COMPLETE){/* Do something. */}else{/* Do something. */}
}

④:使能Flash数据缓冲
该函数用于使能Flash的数据缓冲,其函数原型如下所示:
void FMC_EnableDataCache(void);
该函数的形参描述,如下表所示:
形参 描述
无 无
表43.2.1.9 函数FMC_EnableDataCache()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表43.2.1.10 函数FMC_EnableDataCache()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_fmc.h"void example_fun(void)
{/* 使能Flash的数据缓冲 */FMC_EnableDataCache();
}

⑤:上锁访问FMC控制寄存器
该函数用于上锁FMC控制寄存器,其函数原型如下所示:
void FMC_Lock(void);
该函数的形参描述,如下表所示:
形参 描述
无 无
表43.2.1.11 函数FMC_Lock()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表43.2.1.12 函数FMC_Lock()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_fmc.h"void example_fun(void)
{/* 上锁访问FMC控制寄存器 */FMC_Lock();
}

43.2.2 Flash驱动
本章实验的Flash驱动主要负责向应用层提供Flash的读写操作函数。本章实验中,Flash的驱动代码包括apmflash.c和apmflash.h两个文件。
Flash驱动中,读取Flash数据的函数,如下所示:

/*** @brief       从指定地址读出一个半字数据* @param       faddr: 读取地址,必须按2字节对齐* @retval      读取到的一个半字数据*/
uint16_t apmflash_read_halfword(uint32_t faddr)
{return *(volatile uint16_t *)faddr;
}/*** @brief       从指定地址读出指定长度的数据* @param       raddr : 指定读出数据的起始地址* @param       pbuf  : 保存读出数据的起始地址* @param       length: 指定读出数据的长度,单位:半字* @retval      无*/
void apmflash_read(uint32_t raddr, uint16_t *pbuf, uint16_t length)
{uint16_t i;for (i=0; i<length; i++){pbuf[i] = apmflash_read_halfword(raddr);    /* 读出一个半字的数据 */raddr += 2;                                 /* 地址偏移一个半字的长度 */}
}

APM32E103片上Flash的读取十分简单,仅需读取对应地址的数据即可。
Flash驱动中,往Flash写入数据的函数,如下所示:

/*** @brief       向指定地址写入指定长度的数据* @param       waddr : 指定写入数据的起始地址* @param       pbuf  : 保存写入数据的起始地址* @param       length: 指定写入数据的长度,单位:半字* @retval      无*/
void apmflash_write(uint32_t waddr, uint16_t *pbuf, uint32_t length)
{uint32_t addrx;uint32_t endaddr;uint32_t pageaddr;FMC_STATUS_T status = FMC_STATUS_COMPLETE;/* 指定地址小于Flash的起始地址 */
if ((waddr < APM32_FLASH_BASE) ||
/* 指定地址大于Flash的末地址 */(waddr > (APM32_FLASH_BASE + APM32_FLASH_SIZE)) ||
/* 指定地址没有按2字节对齐 */((waddr & 1) != 0)){return;}FMC_Unlock();addrx = waddr;                           /* 数据写入的起始地址 */endaddr = waddr + (length << 1);         /* 数据写入的结束地址 */while (addrx < endaddr)                  /* 擦除写入区域中存在非0xFFFF的扇区 */{   /* 存在非0xFFFF */if (apmflash_read_halfword(addrx) != 0xFFFF){	/* 计算页地址(向下按页大小对齐) */pageaddr = addrx & ~(APM32_PAGE_SIZE - 1);/* 擦除页 */status = FMC_ErasePage(pageaddr);/* 擦除失败 */if (status != FMC_STATUS_COMPLETE){break;}}else                                 /* 擦除成功 */{addrx += 2;}}if (status == FMC_STATUS_COMPLETE)       /* 擦除扇区没有错误 */{while (waddr < endaddr){	/* 写入数据 */if (FMC_ProgramHalfWord(waddr, *pbuf) != FMC_STATUS_COMPLETE){break;}waddr += 2;pbuf++;}}FMC_Lock();                              /* 重新上锁访问FMC控制寄存器 */
}

在写Flash前需要先判断待写入的比特位是否为1,若不为1则需要先进行擦除操作,否则将写入失败,保证待写入位置的比特位全部为0后,方可调用函数FMC_ProgramWord()对Flash进行编程。
43.2.3 实验应用代码
本章实验的应用代码,如下所示:

/* 待写入Flash的数据 */
static const uint8_t g_text_buf[] = {"APM32 FLASH TEST"};
/* 待写入Flash数据的长度 */
#define TEXT_SIZE sizeof(g_text_buf)
/* 写Flash的长度,单位:字,按2字节向上对齐 */
#define SIZE ((TEXT_SIZE >> 1) + (((TEXT_SIZE & 1) != 0) ? 1 : 0))
/* 写Flash的地址,必须大于本代码的大小+Flash的起始地址(0x08000000) */
#define FLASH_SAVE_ADDR 0x08010000int main(void)
{uint8_t t = 0;uint8_t key;uint8_t data[SIZE];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 */lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);lcd_show_string(30, 70, 200, 16, 16, "FLASH EEPROM TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "KEY_UP:Write  KEY0:Read", RED);while (1){t++;key = key_scan(0);if (key == WKUP_PRES)                         /* 写Flash */{lcd_fill(0, 150, 239, 319, WHITE);lcd_show_string(30, 150, 200, 16, 16, "Start Write FLASH....", RED);apmflash_write(FLASH_SAVE_ADDR, (uint16_t *)g_text_buf, SIZE);lcd_show_string(30, 150, 200, 16, 16, "FLASH Write Finished!", RED);}else if (key == KEY0_PRES)                    /* 读Flash */{lcd_show_string(30, 150, 200, 16, 16, "Start Read FLASH.... ", RED);apmflash_read(FLASH_SAVE_ADDR, (uint16_t *)data, SIZE);lcd_show_string(30, 150, 200, 16, 16, "The Data Readed Is:  ", RED);lcd_show_string(30, 170, 200, 16, 16, (char *)data, BLUE);}if (t == 20){LED0_TOGGLE();t = 0;}delay_ms(10);}
}

从本章实验的应用代码中可以看到,在完成相关的初始化工作后,便会不断地等待按键输入,若检测到KEY_UP按键被按下,则会往Flash的指定地址中写入指定的数据,若检测到KEY_0按键被按下,则会从Flash的指定地址中读取数据,并在LCD上进行显示。
43.3 下载验证
在完成编译和烧录操作后,可以看到LCD上显示了本实验相关的信息,此时便可按下KEY_UP按键往Flash的指定地址写入指定数据,然后再按下KEY_0按键从Flash的指定地址将写入的数据读回来在LCD上进行显示,此时便可以看到在LCD上显示了“APM32 FLASH TEST”的提示信息,该提示信息就是从Flash中读回的数据。

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

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

相关文章

自定义shell工具函数之pull_image()

这是一个名为pull_image的Shell脚本函数。让我来解释一下这个函数的功能&#xff1a; function pull_image() {image$1DOCKER_IMAGE_MIRROR$(get_config_or_env DOCKER_IMAGE_MIRROR)if [[ "${DOCKER_IMAGE_MIRROR}" "1" ]]; thenif [[ "$(uname -m…

深入解析ESP32C3(1) - 使用ESP-IDF

乐鑫ESP32系列芯片是性价比非常高的嵌入式平台&#xff0c;不仅外设接口丰富&#xff0c;有较多的存储空间&#xff0c;还支持WIFI/BT等无线连接&#xff0c;同时也支持加密和权限管理等安全功能&#xff0c;这大大拓展了芯片的应用领域&#xff1b;当然&#xff0c;最重要的是…

Python使用pyechart分析疫情确诊人数图(2024)

import json from pyecharts.charts import Map from pyecharts import options as opts# 首先打开文件获取数据 f open("/Desktop/python/Project/数据可视化/疫情.txt", "r", encoding"UTF-8") data f.read()# 字符串转化成json数据 data_js…

Java多线程--创建多线程的基本方式一:继承Thread类

文章目录 一、创建和启动线程&#xff08;1&#xff09;概述&#xff08;2&#xff09;方式1&#xff1a;继承Thread类1、使用步骤2、举例2.1 案例12.2 案例22.3 案例3 3、两个问题3.1 问题13.2 问题2 4、代码及总结 二、练习&#xff08;1&#xff09;方式一&#xff08;2&…

索引的概述和性能分析

索引index&#xff0c;是一种有序的数据结构&#xff0c;可以高效的获取数据&#xff0c;在数据库中维护着满足查找特定算法的数据结构&#xff0c;就是索引 无索引的情况&#xff0c;查询数据时会全表扫描&#xff0c;效率极低 索引结构 &#xff08;1&#xff09;二叉树&…

python解决求二叉树的最长同值路径问题

对于给定的一颗二叉树&#xff0c;需要找到最长的路径&#xff0c;并且该路径上的每个节点具有相同的值的问题&#xff0c;对于寻找到的这条路径可以经过根节点也可以不经过根节点&#xff0c;两个节点之间的路径长度是由他们的变数来表示的&#xff0c;给定如下图的二叉树 添加…

【 Qt 快速上手】-②- Qt 环境搭建

文章目录 1. Qt 开发工具概述1.1 Qt Creator 介绍1.2 Visual Studio 介绍1.3 Eclipse 介绍 2. Qt SDK 的下载与安装2.1 Qt SDK 的下载2.2 Qt SDK 的安装2.3 验证 Qt SDK 安装是否成功2.4 Qt 环境变量配置 1. Qt 开发工具概述 Qt 开发环境需要安装三个部分&#xff1a; C编译器…

小伙频繁发朋友圈引发分手,拼命“晒“生活是否成为一种病态行为?

根据《西湖之声》1月19日的报道&#xff0c;一个小伙子因为一天发十几条朋友圈而引起了他女友的不满&#xff0c;女友甚至提出了分手。现如今&#xff0c;朋友圈已经成为每个人自我形象展示的平台&#xff0c;认真发朋友圈不仅是表达自己的一种方式&#xff0c;也是一种自我释放…

redis缓存和本地缓存的应用设计

数据查询顺序 一级缓存&#xff1a;本地缓存 -》二级缓存&#xff1a;redis缓存 -》数据库 本地缓存和分布式缓存 本地缓存&#xff1a;基于jvm, 意思是程序放在哪&#xff0c;数据就存储在哪&#xff0c;不需要网络请求&#xff0c;特别快&#xff0c;但是需要占用jvm的内存…

Python利用Excel读取和存储测试数据完成接口自动化教程

http_request2.py用于发起http请求 #读取多条测试用例#1、导入requests模块import requests#从 class_12_19.do_excel1导入read_data函数from do_excel2 import read_datafrom do_excel2 import write_datafrom do_excel2 import count_case#定义http请求函数COOKIENonedef ht…

Unity之四元数计算

四元数相乘 #region 四元数相乘 Quaternion q Quaternion.AngleAxis(20, Vector3.up); this.transform.rotation * q; #endregion 四元数乘向量 Vector3 v Vector3.forward; print(v); //四元数乘向量的顺序不能改变&#xff0c;也就是说不能用向量去乘四元数&#xff0c;…

Spring Boot Aop 执行顺序

Spring Boot Aop 执行顺序 1. 概述 在 spring boot 项目中&#xff0c;使用 aop 增强&#xff0c;不仅可以很优雅地扩展功能&#xff0c;还可以让一写多用&#xff0c;避免写重复代码&#xff0c;例如&#xff1a;记录接口耗时&#xff0c;记录接口日志&#xff0c;接口权限&…

C# byte转int:大小端读取

参考&#xff1a;byte[]数组和int之间的转换 文章目录 Byte转为INT小端存储方式转int大端存储方式转int 大端模式和小端模式是计算机存储多字节数据时的两种方式。内存地址从小往大增长。 大端模式&#xff1a;最高有效&#xff08;最高位&#xff09;的字节存放在最小地址上&…

python 自动化模块 - pyautogui初探

python 自动化模块 - pyautogui 引言一、安装测试二、简单使用三、常用函数总结 引言 在画图软件中使用pyautogui拖动鼠标&#xff0c;画一个螺旋式的正方形 - (源码在下面) PyAutoGUI允许Python脚本控制鼠标和键盘&#xff0c;以自动化与其他应用程序的交互。API的设计非常简…

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

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

【设计模式 行为型】策略模式

它允许在运行时根据需要选择算法的行为。该模式通过将算法封装成独立的类&#xff0c;使得它们可以相互替换&#xff0c;而不影响使用算法的客户端代码。 策略模式主要包含以下角色&#xff1a; 环境&#xff08;Context&#xff09;&#xff1a;环境对象持有一个策略对象的引…

基于Abaqus的三种钢筋混凝土梁数值模拟对比研究

混凝土结构抗压强度高&#xff0c;而抗拉强度大约只有其十分之一&#xff0c;在受到竖向荷载&#xff08;包括自重&#xff09;作用下&#xff0c;梁下部会产生拉应力&#xff0c;上部产生压应力&#xff0c;而由于其抗拉强度低&#xff0c;因此很小的荷载即可导致梁下部开裂&a…

pytorch学习(二)、网络的构建和卷积层

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、nn.Module&#xff08;网络的构建&#xff09;二、torch.nn.functional.conv2d&#xff08;卷积运算&#xff09;三、神经网络--卷积层&#xff08;一层卷积…

Mysql中的日志系统

文章目录 1. 慢查询日志&#xff08;Slow Query Log&#xff09;1.1 是否开启慢查询日志1.2 开启慢查询日志&#xff0c;设置时间阈值1.2.1 修改文件my.ini1.2.2 重启mysql后配置生效 1.3 查看慢查询日志1.3.1 直接用文本编辑器打开1.3.2 使用mysqldumpslow进行分析 2. InnoDB …

C语言从入门到实战——文件操作

文件操作 前言一、 为什么使用文件二、 什么是文件2.1 程序文件2.2 数据文件2.3 文件名 三、 二进制文件和文本文件四、 文件的打开和关闭4.1 流和标准流4.1.1 流4.1.2 标准流 4.2 文件指针4.3 文件的打开和关闭4.4 文件的路径 五、 文件的顺序读写5.1 顺序读写函数介绍fgetcfp…