PROGMEMに格納する排列の処理パターン

pp.400-401
複数の排列をPROGMEMに格納する。各排列の先頭アドレス(ポインタ)も別の排列にしてPROGMEMに格納する。この方法だと、[i]番目の排列という形で目的の排列へアクセスできる。
https://github.com/ti-nspire/AVR/tree/master/PROGMEM_demo

#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/pgmspace.h>
#include "USART.h"

// 複数の排列をPROGMEMに格納する。普通はヘッダーファイルに分ける。
const uint8_t TABLE0[] PROGMEM = {1,2,3,4,};
const uint8_t TABLE1[] PROGMEM = {5,6,7,8,9,};
const uint8_t TABLE2[] PROGMEM = {10,11,12,13,14,15,16,17,18,19,20,21,22,23};
const uint8_t TABLE3[] PROGMEM = {255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,};

// 各排列の要素数を取得してPROGMEMに格納する。RAMに格納するのでもよい。
const uint16_t tableLengths[] PROGMEM = {
    sizeof(TABLE0)/sizeof(TABLE0[0]),
    sizeof(TABLE1)/sizeof(TABLE1[0]),
    sizeof(TABLE2)/sizeof(TABLE2[0]),
    sizeof(TABLE3)/sizeof(TABLE3[0]),
};

// 各排列の先頭アドレス(ポインタ)から成る排列をPROGMEMに格納する。
const uint8_t *const tablePointers[] PROGMEM = {
    TABLE0,
    TABLE1,
    TABLE2,
    TABLE3,
};

// 排列数をPROGMEMに格納する。RAMに格納するのでもよい。
const uint16_t numOfTables PROGMEM = sizeof(tablePointers) / sizeof(tablePointers[0]);

uint16_t thisTableLength;
uint8_t *thisTableP;
void selectTable(uint16_t whichTable){
    thisTableLength = pgm_read_word(&tableLengths[whichTable]);                  // 目的の排列の要素数を取得する。
    thisTableP = (uint8_t *)pgm_read_word((uint16_t)&tablePointers[whichTable]); // 目的の排列の先頭アドレス(ポインタ)を取得する。
}

int main(){
    initUSART();

    for(uint16_t n=0; n<numOfTables; n++){               // PROGMEMに格納した排列を全部順番に
        selectTable(n);                                  // 選択して、
        for(uint16_t i=0; i<thisTableLength; i++){
            printHexByte(pgm_read_byte(&thisTableP[i])); // その中身を確認する。
            printString(",");
        }
        printString("\n");
    }
    
    return 0;
}

f:id:ti-nspire:20200226083740p:plain