Arduino平台ESP8266数据flash存储模式使用介绍

news/2024/7/9 6:14:53

Arduino平台ESP8266数据flash存储模式使用介绍


  • 📌参考说明文档:https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html

PROGMEM关键字,原基于AVR单片机使用的,为了节省RAM空间,将字符串放入闪存中,然后在需要时将其加载到RAM中。

📑ESP8266使用条件

✨ESP8266作为32位单片机,在检索和操作存储在闪存flash中的字符串时,必须以4字节(32bit)为单位从闪存flash中读取,如果没有使用32位对齐方式访问读取,将会导致分割错误,ESP8266将崩溃。必须从闪存读取32位对齐在用于esp8266的Arduino IDE中,以下函数可以实现从使用program存储的闪存中检索字符串:

int memcmp_P(const void* buf1, PGM_VOID_P buf2P, size_t size);
void* memccpy_P(void* dest, PGM_VOID_P src, int c, size_t count);
void* memmem_P(const void* buf, size_t bufSize, PGM_VOID_P findP, size_t findPSize);
void* memcpy_P(void* dest, PGM_VOID_P src, size_t count);
char* strncpy_P(char* dest, PGM_P src, size_t size);
char* strcpy_P(dest, src)
char* strncat_P(char* dest, PGM_P src, size_t size);
char* strcat_P(dest, src)
int strncmp_P(const char* str1, PGM_P str2P, size_t size);
int strcmp_P(str1, str2P)
int strncasecmp_P(const char* str1, PGM_P str2P, size_t size);
int strcasecmp_P(str1, str2P)
size_t strnlen_P(PGM_P s, size_t size);
size_t strlen_P(strP)
char* strstr_P(const char* haystack, PGM_P needle);
int printf_P(PGM_P formatP, ...);
int sprintf_P(char *str, PGM_P formatP, ...);
int snprintf_P(char *str, size_t strSize, PGM_P formatP, ...);
int vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap);

🔖这里面有很多函数,实际上它们是标准c函数的版本,适合从esp8266 32位对齐的闪存中读取。它们都取a,本质上就是a。在底层,这些函数都使用一个进程来确保读取4个字节,并返回请求字节。(_P ,PGM_P,const char *

ESP8266 PROGMEM相关关键字内部的宏定义

#define PROGMEM   ICACHE_RODATA_ATTR
#define ICACHE_RODATA_ATTR  __attribute__((section(".irom.text")))

#define PGM_P       const char *
#define PGM_VOID_P  const void *
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
//include  WString.h
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
#define F(string_literal) (FPSTR(PSTR(string_literal)))
  • ✨将变量放在flash的.irom.text部分的位置。
  • 🌿在代码块中声明一个存储在flash中的字符串。
void myfunction(void) {
PGM_P xyz = PSTR("Store this string in flash");
const char * abc = PSTR("Also Store this string in flash");
}
  • 🌿声明一个全局字符串存储在flash闪存中。
static const char xyz[] PROGMEM = "This is a string stored in flash. Len = %u";

void setup() {
    Serial.begin(115200); Serial.println();
    Serial.println( FPSTR(xyz) ); // just prints the string, must convert it to FlashStringHelper first using FPSTR().
    Serial.printf_P( xyz, strlen_P(xyz)); // use printf with PROGMEM string
}
  • 🌿使用inline内联函数,存储字符串到Flash闪存中。
void setup() {
    Serial.begin(115200); Serial.println();
    Serial.println( F("This is an inline string")); //
    Serial.printf_P( PSTR("This is an inline string using printf %s"), "hello");
}
  • 🌿使用关键字PROGMEM将数组存储在闪存flash中并读取。
const size_t len_xyz = 30;
const uint8_t xyz[] PROGMEM = {
  0x53, 0x61, 0x79, 0x20, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
  0x74, 0x6f, 0x20, 0x4d, 0x79, 0x20, 0x4c, 0x69, 0x74, 0x74,
  0x6c, 0x65, 0x20, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x00};

 void setup() {
     Serial.begin(115200); Serial.println();
     uint8_t * buf = new uint8_t[len_xyz];
     if (buf) {
      memcpy_P(buf, xyz, len_xyz);
      Serial.write(buf, len_xyz); // output the buffer.
     }
 }
  • 🌿在程序存储空间(PROGMEM)中声明一些数据,并从中提取一个字节。
const size_t len_xyz = 30;
const uint8_t xyz[] PROGMEM = {
  0x53, 0x61, 0x79, 0x20, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
  0x74, 0x6f, 0x20, 0x4d, 0x79, 0x20, 0x4c, 0x69, 0x74, 0x74,
  0x6c, 0x65, 0x20, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x00
};

void setup() {
  Serial.begin(115200); Serial.println();
  for (int i = 0; i < len_xyz; i++) {
    uint8_t byteval = pgm_read_byte(xyz + i);
    Serial.write(byteval); // output the buffer.
  }
}
  • 🌿在PROGMEM中声明字符串数组并从中检索元素。

✨当处理大量文本时,如一个带有液晶显示屏的项目,设置一个字符串数组通常很方便。因为字符串本身就是数组,这实际上是一个二维数组的例子。
这些通常是庞大的结构,所以将它们放入程序内存中往往是可取的。下面的代码说明了这个思路。

// Define Strings
const char string_0[] PROGMEM = "String 0";
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";

// Initialize Table of Strings
const char* const string_table[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 };

char buffer[30]; // buffer for reading the string to (needs to be large enough to take the longest string

void setup() {
  Serial.begin(9600);
  Serial.println("OK");
}

void loop() {
  for (int i = 0; i < 6; i++) {
    strcpy_P(buffer, (char*)pgm_read_dword(&(string_table[i])));
    Serial.println(buffer);
    delay(500);
  }
}

http://lihuaxi.xjx100.cn/news/1470021.html

相关文章

【高级IO】- 多路转接之 poll | epoll

目录 I/O多路转接 - poll poll 函数 poll 服务器 poll 服务器 poll 的优点 poll 的缺点 I/O 多路转接 - epoll epoll 的相关系统调用 epoll_create 函数 epoll_ctl 函数 epoll_wait 函数 epoll 工作原理 epoll 服务器 ​编辑 epoll 的优点&#xff08;与 sele…

常见前端面试之VUE面试题汇总一

1. Vue 的基本原理 当 一 个 Vue 实 例 创 建 时 &#xff0c; Vue 会 遍 历 data 中 的 属 性 &#xff0c; 用 Object.defineProperty &#xff08; vue3.0 使 用 proxy&#xff09; 将 它 们 转 为 getter/setter&#xff0c;并且在内部追踪相关依赖&#xff0c;在属性被访…

【LeetCode-经典面试150题-day8】

11.盛最多水的容器 题意&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&a…

Vue-12.集成postcss.config.js

PostCSS 介绍 PostCSS 是一个用于处理样式的工具&#xff0c;可以通过插件来定制其行为。以下是一些常用的 PostCSS 插件和 API 的介绍&#xff1a; Autoprefixer: 这是一个流行的 PostCSS 插件&#xff0c;用于自动添加浏览器前缀&#xff0c;以确保您的样式在不同浏览器中具…

智能节水灌溉远程监控解决方案

随着经济社会的飞速发展&#xff0c;农业在其中的份量功不可没。农田灌溉是农业生产中的重中之重&#xff0c;但传统农田灌溉管理存在较大弊端&#xff0c;机井分散&#xff0c;不便管理&#xff0c;造成水资源的浪费&#xff0c;地下水严重匮乏&#xff0c;灌溉水利用系数较低…

常见的时序数据库

1.概念 时序数据库全称为时间序列数据库。时间序列数据库指主要用于处理带时间标签&#xff08;按照时间的顺序变化&#xff0c;即时间序列化&#xff09;的数据&#xff0c;带时间标签的数据也称为时间序列数据。 时间序列数据主要由电力行业、化工行业、气象行业、地理信息…

安装Pip

首发博客地址 https://blog.zysicyj.top/ 安装命令 python -m ensurepip --upgrade 本文由 mdnice 多平台发布

如何在PVE中实施密码策略

二级等保要求系统中用户密码策略必须设置口令长度和定期更换&#xff0c;PVE系统是基于DEBIAN开发。 1、修改/etc/login.defs PASS_MAX_DAYS 90&#xff1b; PASS_WARN_AGE 7&#xff1b; PASS_MIN_LEN 8&#xff1b; 2、修改/etc/pam.d/common-password 配置文件设置口令长…