定数データをプログラム領域(フラッシュメモリー)に書き込む、読み出す

pp.381ff.

avr/pgmspace.hライブラリーを使う。定数データをフラッシュメモリーへ書き込むときはPROGMEMマクロを、そのデータを読み出すときはpgm_read_byte()pgm_read_word()を使う。

  • const 型 変数名 PROGMEM = 値;と記述すると、値はRAMには格納されずにプログラム領域(フラッシュメモリー)に格納される。
  • 1バイトデータはpgm_read_byte(アドレス);で読み出す。
  • 2バイトデータはpgm_read_word(アドレス);で読み出す。

PROGMEMは不揮発性であり、プログラムメモリーに存在し続ける。だからどのサブルーチンからでも利用できる。したがってPROGMEMはグローバル変数であり、グローバル名前空間で宣言すべきである。すなわちPROGMEM変数は、函数定義の外側で宣言すべきである。そうすれば、PROGMEM変数のスコープが何か特定の函数に限定されていないことと、PROGMEM変数に格納されたデータへはどの函数からでもアクセスできることとがコンパイラーに知らせられる。

著者によれば、PROGMEMのデータは全部別のヘッダーファイルに定義するのが一番簡単との由。

#define F_CPU 1000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#include "USART.h"

// 長い文字列定数をフラッシュメモリーに格納してみる。
const char myVeryLongString[] PROGMEM = "\n\"It\'s very reasonable. We agreed on the rate before I started the job. And if anything, it\'s an underestimate. If you feel dissatisfied, I suggest you go to another agency or the Better Business people and ask whether they feel the rate is unreasonable for the job.\" How long did she think eighty-two dollars kept a private detective going? With an office to hire. With a daughter to feed.\n";

int main(){
    initUSART();
    char oneLetter;
    
    while(1){
        
        for(uint16_t i=0; i<sizeof(myVeryLongString); i++){
            oneLetter = pgm_read_byte(&(myVeryLongString[i])); // 文字列を1文字ずつ表示する。pgm_read_byte()の引数はアドレス。
            transmitByte(oneLetter);
            _delay_ms(10);
        }
        _delay_ms(1000);
        
    }
    
    return 0;
}

f:id:ti-nspire:20200221095545p:plain:w500