2015-06-28 3 views
0

Я прочитал о доступе к PROGMEM в течение нескольких дней и прочел несколько других вопросов, но я все еще не могу заставить работать мой код. Любая помощь будет оценена по достоинству.Доступ к отдельным байтам в PROGMEM на Arduino/AVR

Я включил полный пробный эскиз для Arduino ниже. Большинство из них работает, но когда я прокручиваю каждый байт символа «альфа», как указано «альфа-байтами», я просто получаю мусор, поэтому я, очевидно, не получаю доступ к правильной ячейке памяти. Проблема в том, что я не могу понять, как получить доступ к этой ячейке памяти.

Я видел несколько других примеров этой работы, но ни один из них не имеет разных массивов данных в массиве указателей.

Пожалуйста, смотрите строку, начинающуюся с «>>>> Вопрос ...»

// Include PROGMEM library 
#include <avr/pgmspace.h> 

// Variable to hold an alphabet character row 
char column_byte; 

// Used to hold LED pixel value during display 
char led_val; 

// Used to hold the screen buffer for drawing the screen 
char matrix_screen[64]; 

/* 
    Define Alphabet characters. This should allow for characters of varying byte lengths. 
*/ 
const char alpha_A[] PROGMEM = {0x06, 0x38, 0x48, 0x38, 0x06}; 
const char alpha_B[] PROGMEM = {0x7E, 0x52, 0x52, 0x2C}; 
const char alpha_C[] PROGMEM = {0x3C, 0x42, 0x42, 0x24}; 

/* 
    The "alphabytes" contains an array of references (pointers) to each character array. 
    Read right-to-left, alphabytes is a 3-element constant array of pointers, 
    which points to constant characters 

*/ 
const char* const alphabytes[3] PROGMEM = { 
    alpha_A, alpha_B, alpha_C 
}; 

/* 
    This array is necessary to list the number of pixel-columns used by each character. 
    The "sizeof" function cannot be used on the inner dimension of alphabytes directly 
    because it will always return the value "2". The "size_t" data 
    type is used because is a type suitable for representing the amount of memory 
    a data object requires, expressed in units of 'char'. 
*/ 
const char alphabytes_sizes[3] PROGMEM = { 
    sizeof(alpha_A), sizeof(alpha_B), sizeof(alpha_C) 
}; 

/** 
* Code Setup. This runs once at the start of operation. Mandatory Arduino function 
**/ 
void setup(){ 

    // Include serial for debugging 
    Serial.begin(9600); 
} 

/** 
* Code Loop. This runs continually after setup. Mandatory Arduino function 
**/ 
void loop(){ 

    // Loop through all alphabet characters 
    for(int a = 0; a < 3; a++) { 

    // Reset screen 
    for (int r = 0; r < 64; r++) { 
     matrix_screen[r] = 0; 
    } 

    // This line works to read the length of the selected "alphabyte" 
    int num_char_bytes = pgm_read_byte(alphabytes_sizes + a); 

    for (int b = 0; b < num_char_bytes; b++){ 

     // Based on alphabytes definition, 
     // Examples of desired value for column_byte would be: 
     // 
     // When a=0, b=0 -> column_byte = 0x06 
     // When a=0, b=1 -> column_byte = 0x38 
     // When a=0, b=2 -> column_byte = 0x48 
     // When a=0, b=3 -> column_byte = 0x38 
     // When a=0, b=4 -> column_byte = 0x06 
     // When a=1, b=0 -> column_byte = 0x7E 
     // When a=1, b=1 -> column_byte = 0x52 
     // When a=1, b=2 -> column_byte = 0x52 
     // When a=1, b=3 -> column_byte = 0x2C 
     // When a=2, b=0 -> column_byte = 0x3C 
     // When a=2, b=1 -> column_byte = 0x42 
     // When a=2, b=2 -> column_byte = 0x42 
     // When a=2, b=3 -> column_byte = 0x24 

     // >>>>> Question is... how to I get that? <<<<<<< 
     // column_byte = pgm_read_byte(&(alphabytes[a][b])); // This doesn't work 

     // Thought: calculate offset each time 
     // int offset = 0; 
     // for(int c = 0; c < a; c++){ 
     // offset += pgm_read_byte(alphabytes_sizes + c); 
     // } 
     // column_byte = pgm_read_byte(&(alphabytes[offset])); // This doesn't work 

     // column_byte = (char*)pgm_read_word(&alphabytes[a][b]); // Doesn't compile 
     column_byte = pgm_read_word(&alphabytes[a][b]); // Doesn't work 

     // Read each bit of column byte and save to screen buffer 
     for (int j = 0; j < 8; j++) { 
     led_val = bitRead(column_byte, 7 - j); 
     matrix_screen[b * 8 + j] = led_val; 
     } 

    } 

    // Render buffer to screen 
    draw_screen(); 

    // Delay between frames 
    delay(5000); 

    } 

} 

/** 
* Draw the screen. This doesn't have the correct orientation, but 
* that's fine for the purposes of this test. 
**/ 
void draw_screen(){ 
    for (int a = 0; a < 8; a++) { 
    for (int b = 0; b < 8; b++) { 
     Serial.print((int) matrix_screen[a * 8 + b]); 
     Serial.print(" "); 
    } 
    Serial.println(); 
    } 
    Serial.println(); 
} 

ответ

0

Отметьте, что alphabytes это массив, в котором каждый элемент содержит СПРАВОЧНИК (то есть адрес), где хранятся соответствующие символы. Таким образом, вы должны получить к нему доступ в два этапа.

Первый шаг - знать адрес в прогемой необходимого элемента. Адреса шириной 16 бит (если вы не используете устройство 128 + k).

PGM_VOID_P ptr = (PGM_VOID_P) pgm_read_word(&alphabytes[a]); 

и, если вы хотите получить доступ к этому побайтно, вы можете просто прочитать с помощью этого указателя, а затем увеличить его:

for (int b = 0; b < num_char_bytes; b++) { 
    uint8_t column_byte = pgm_read_byte(ptr++); 
    ... 
} 
+0

Спасибо. Это помогает прояснить ситуацию. Я думаю, что между моим ответом на мой собственный вопрос и с этим, на который это в значительной степени ответил. – MarkRoland

0

После долгих исследований (и довольно откровенно много проб и ошибок), я наткнулся на такое решение, которое является за работой. Я не знаю, является ли это самым правильным или самым изящным решением, но оно работает.

column_byte = pgm_read_byte(pgm_read_byte(&alphabytes[a]) + b); 

Внутренний вызов pgm_read_byte():

pgm_read_byte(&alphabytes[a]) 

возвращает значение, которое является адрес символа оценивается (обратите внимание на ведущие "адрес-" оператора "&").

Внешняя pgm_read_byte считывает эту память со смещением «b».

Это решение также может быть разбита на две части:

int memory_loc = pgm_read_byte(&alphabytes[a]); 
column_byte = pgm_read_byte(memory_loc + b); 

Мои навыки C не достаточно хороши, чтобы действительно объяснить, если «memory_loc» должен быть в Int (я попробовал это, как «полукокса» и он также работал).

Смежные вопросы