Arduino-PROGMEMを使用してフラッシュメモリ(プログラムストレージスペース)にデータを書き込みます

AVRストレージの概要:

AVRシリーズマイクロ
プロセッサ内には、3種類の独立してアドレス指定可能なメモリがあります。1。フラッシュプログラムメモリ(つまり、プログラムストレージスペース、フラッシュメモリ)
2。SRAMデータメモリ(つまり、動的メモリ)
3.EEPROMデータメモリ

シングルチップマイクロメータは、プログラムメモリとデータメモリを分離するためにHaval構造を採用しています。データメモリRAMは通常比較的小さく、プログラムメモリフラッシュは比較的広いスペースがあるため、変更する必要のないデータをより大きなスペースでフラッシュに配置する必要があります。

たとえば、LCD表示テキストをサポートするためにシングルチップマイクロコンピュータが必要な場合、数kbに達する可能性のある巨大なフォントライブラリが必要です。このような大量のデータはRAMに保存するのには適さず、Flashにしか保存できません。

pgmspace.hは、それに関連する読み取りおよび書き込み操作を提供します。

質問ガイド:

Arduinoプログラムをコンパイルすると、次のプロンプトが表示されます。

项目使用了 656 字节,占用了 (0%) 程序存储空间。最大为 253952 字节。
全局变量使用了9字节,(0%)的动态内存,余留8183字节局部变量。最大为8192字节。

コンパイル時によく発生する問題は次のとおりです。

项目使用了 4756 字节,占用了 (15%) 程序存储空间。最大为 30720 字节。
全局变量使用了2246字节,(109%)的动态内存,余留-198字节局部变量。最大为2048字节。
没有足够的内存; 编译时出错。

[プログラムストレージスペース]には空き容量が多く、[ダイナミックメモリ]が足りないため、正常に書き込むことができません。この問題は、「より大きな」データを持つ定数、特に配列が宣言されている場合によく発生します。

解決:

この問題を解決するために、[ダイナミックメモリ]に書き込む必要のある定数を[プログラムストレージスペース]に書き込んで、[ダイナミックメモリ]スペースを節約することができます。

グローバル定数を定義するときは、PROGMEMキーワードを使用するか、PROGMEMデータタイプを使用して、「動的メモリ」に格納するのではなく、「この情報をプログラムストレージスペースに格納する」ようにコンパイラに指示します。

PROGMEMキーワード(またはデータタイプ)で使用されるライブラリ:pgmspace.h

#include <avr/pgmspace.h>

データ定義:

const dataType variableName [] PROGMEM = {data0,data1,data3 ...};
// dataType- 任何变量类型
// variableName- 数据数组的名称
プログラムストレージスペースFLASHは変更できないため、定義するときにキーワードconstを追加することをお勧めします。

1. [グローバル]定数として使用する場合は、PROGMEMキーワードを直接使用できます。PROGMEMキーワードの位置は比較的任意ですが、以前のバージョンのArduinoとの互換性のために、後回しにすることをお勧めします。といった:

const char str1[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"
const PROGMEM char str2[] = "Hi, I would like to tell you a bit about myself.\n"
PROGMEM const char str3[] = "Hi, I would like to tell you a bit about myself.\n"

2. [ローカル]定数として使用する場合は、次のようなstaticキーワードとともに使用する必要があります。

const static char flash_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"

3.別の定義フォームでは、PROGMEMキーワードを使用しませんが、次のようなPROGMEMデータタイプを直接使用します。

const prog_char flash_str[] = "Hi, I would like to tell you a bit about myself.\n"

4.文字列定数の定義

// 全局定义形式:
const char flash_str[] PROGMEM = “Hello, world!”;

// 函数内定义形式:
		/* pgmspace.h提供了一个宏 PSTR 用来申明Flash中的字符串:
		# define PSTR(s) ((const PROGMEM char *)(s))
		所以,函数内可以采用下面的定义形式:*/
const char *flash_str = PSTR(“Hello, world!”);

// 以下为应用示例:
const char flash_str1[] PROGMEM = “全局定义字符串”;
int main(void)
{
	char *flash_str2=PSTR(“函数内定义字符串”);
	printf_P(flash_str1);
	printf_P(flash_str2);
}

データの読み取り:

この時点まで、私たちのプログラムは正しく機能していません。
Flashへのポインタを関数に渡すと、RAMへのポインタであると見なされるため、RAM内のデータを検索し、プログラムエラーを引き起こします。
したがって、Flashへのポインタを処理するには特別な関数が必要です。
データがプログラムストレージスペースに保存された後、それを読み取るために特別なメソッド(関数)が必要です。

1.非配列定数の読み方
char ram_val; //存到 ram 内的变量
const PROGMEM flash_val = 1; // 存到 flash 内的常量
// 读取
ram_val = pgm_read_byte( &flash_val ); // 读 flash 常量值到 RAM 变量,参数使用【地址&】传递。
2.配列定数の読み方
char displayInt;
const char charSet [] RROGMEM = {0,1,2,3,4,5,6,7,8,9};
// 读取
for (int i = 0; i < 10; i++)
  {
    displayInt = pgm_read_byte(charSet + i);   // 第一种方法
    displayInt = pgm_read_byte(&charSet[i]);   // 第二种方法
  }
3.文字列コピー方式

strcpy_P関数は、文字列を[プログラムストレージスペース]から[動的メモリ]のバッファ「バッファ」にコピーする役割を果たします。
注:コピーするときは、バッファーが十分に大きいことを確認してください。

char buffer[30]; 
// 方式一
strcpy_P(buffer,PSTR("dGltQuY29t\r\n"));  
// 方式二
const char string_0[] PROGMEM = "This is a String"; 
strcpy_P(buffer, (char *)pgm_read_word(&string_0)); 

関連する処理機能:

// 数据读取函数
pgm_read_byte(addr)
pgm_read_word(addr)
pgm_read_dword(addr)
pgm_read_float(addr)
pgm_read_ptr(addr)

// 字符串处理函数
void *memcpy_P(void *, const void *, size_t);
char *strcat_P(char *, const char *);
int strcmp_P(const char *, const char *);
char *strcpy_P(char *, const char *);

可以看到,字符串处理函数与标准处理函数一样,只是以_P结尾,它们的功能也是一样的。 
看这一句代码:

strcmp_P("ram item", PSTR("flash item"));

这句代码用来比较两个字符串,第一个字符串”ram item”是申明在RAM中的,第二个字符串”flash item”通过宏PSTR申明在Flash中。

F()マクロの使用について:

通常、シリアルポート出力には次のステートメントを使用します。

Serial.print("Write something on  the Serial Monitor");

ただし、このように、データは呼び出されるたびに[動的メモリ]に保存されます。
長い文字列を出力したい場合、[動的メモリ]のスペースを大量に消費します。
F()を使用するとこの問題を解決でき、F()を使用すると文字列をFLASHに簡単に保存できます。

Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));

データ読み取りについて

1. Flashで配列を処理するために、pgmspace.hはいくつかのマクロも提供します。
pgm_read_byte(addr)
pgm_read_word(addr)
pgm_read_dword(addr)
pgm_read_float(addr)
pgm_read_ptr(add)

これらは、アドレスaddrで1、2、4バイトを読み取り、浮動小数点数を読み取るために使用されます。
このような問題を考慮して、いくつかの文字列がFlashに格納され、各文字列のアドレスが配列の形式でFlashに格納されます。

const char *s1 PROGMEM = "s1";const char *s2 PROGMEM = "s2";const char* strPointer[] PROGMEM = {s1, s2};

s1とs2を比較する方法は?
まず、2つの文字列のアドレスを読み取り、strcmp_P関数を使用して文字列を比較する必要があります。
両方のポインタが8ビットではなく16ビットであることに注意してください。
したがって、コードは次のようになります。

strcmp_P(pgm_read_word(&strPointer[0]),pgm_read_word(&strPointer[1]));

pgm_read_byte()は16ビットの整数を取得するため、コンパイラはそのようなコードに対して警告を出します。関数のプロトタイプから、関数にポインタが必要であることがわかります。この警告を取り除くには、次の2つの方法があります。

(1)強制型変換

strcmp_P(pgm_read_word((char*)&strPointer[0]), (char*)pgm_read_word(&strPointer[1]));

(2)別のマクロを使用する

strcmp_P(pgm_read_ptr(&strPointer[0]), pgm_read_ptr(&strPointer[1]));
2.データの読み取りの問題

前述のように、ポインタは16ビットで、64kBのアドレス空間をアドレス指定できます。
mega2560などの一部のAVRチップでは、フラッシュスペースは256kBです。64kBを超えるスペースはどのように対処されますか?
pgmspace.hは、次の2種類のFlashアドレス指定マクロを提供します。

1つは、最大64kBの16ビットアドレスを使用した短いアドレスアドレス指定です。

pgm_read_byte_near(address_short)
pgm_read_word_near(address_short)
pgm_read_dword_near(address_short)
pgm_read_float_near(address_short)
pgm_read_ptr_near(address_short)

もう1つは、最大4GBのスペースを持つ32ビットアドレスの長いアドレスアドレス指定です。

pgm_read_byte_far(address_short)
pgm_read_word_far(address_short)
pgm_read_dword_far(address_short)
pgm_read_float_far(address_short)
pgm_read_ptr_faraddress_short)

2種類のアドレス指定にはパフォーマンスの違いがあります。短いアドレスアドレス指定の速度ははるかに高速で、64kBで十分であるため、デフォルトで短いアドレスアドレス指定が使用されます。

#define pgm_read_byte(address_short) pgm_read_byte_near(address_short)
#define pgm_read_word(address_short) pgm_read_word_near(address_short)
#define pgm_read_dword(address_short) pgm_read_dword_near(address_short)
#define pgm_read_float(address_short) pgm_read_float_near(address_short)
#define pgm_read_ptr(address_short) pgm_read_ptr_near(address_short)

64kBを超えるスペースをアドレス指定する必要がある場合は、手動で長いアドレスアドレス指定を使用できます。

おすすめ

転載: blog.csdn.net/sdlgq/article/details/88720706
おすすめ