在 Arduino/AVR 上访问 PROGMEM 中的单个字节
Accessing individual bytes in PROGMEM on Arduino/AVR
我已经阅读了几天关于访问 PROGMEM 的内容,并梳理了其他几个问题,但我的代码仍然无法正常工作。任何帮助将不胜感激。
我在下面包含了 Arduino 的完整测试草图。它的大部分工作正常,但是当我循环遍历 "alpha" 字符的每个字节时,正如 "alphabytes" 所指出的那样,我只是得到了垃圾,所以我显然没有访问正确的内存位置.问题是,我不知道如何访问该内存位置。
我见过其他几个这样工作的例子,但是 none 在指针数组中有不同大小的数据数组。
请查看以“>>>> 问题是...”开头的行
// 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();
}
经过大量研究(坦率地说,经过大量试验和错误),我找到了一个有效的解决方案。我不知道这是最正确还是最优雅的解决方案,但它确实有效。
column_byte = pgm_read_byte(pgm_read_byte(&alphabytes[a]) + b);
对 pgm_read_byte() 的内部调用:
pgm_read_byte(&alphabytes[a])
returns 一个值,它是正在评估的字符的地址(注意前导 "address-of" 运算符“&”)。
外部 pgm_read_byte 在偏移量 "b" 处读取该内存。
这个解决方案也可以分为两部分:
int memory_loc = pgm_read_byte(&alphabytes[a]);
column_byte = pgm_read_byte(memory_loc + b);
我的 C 技能不足以真正解释 "memory_loc" 是否需要是一个 int(我试过它作为 "char" 并且它也有效)。
注意alphabytes它是数组,每个元素包含一个REFERENCE(即地址),其中存储了相应的字符。因此,您应该分两步访问它。
第一步是了解所需项目在程序中的地址。地址为 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++);
...
}
我已经阅读了几天关于访问 PROGMEM 的内容,并梳理了其他几个问题,但我的代码仍然无法正常工作。任何帮助将不胜感激。
我在下面包含了 Arduino 的完整测试草图。它的大部分工作正常,但是当我循环遍历 "alpha" 字符的每个字节时,正如 "alphabytes" 所指出的那样,我只是得到了垃圾,所以我显然没有访问正确的内存位置.问题是,我不知道如何访问该内存位置。
我见过其他几个这样工作的例子,但是 none 在指针数组中有不同大小的数据数组。
请查看以“>>>> 问题是...”开头的行
// 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();
}
经过大量研究(坦率地说,经过大量试验和错误),我找到了一个有效的解决方案。我不知道这是最正确还是最优雅的解决方案,但它确实有效。
column_byte = pgm_read_byte(pgm_read_byte(&alphabytes[a]) + b);
对 pgm_read_byte() 的内部调用:
pgm_read_byte(&alphabytes[a])
returns 一个值,它是正在评估的字符的地址(注意前导 "address-of" 运算符“&”)。
外部 pgm_read_byte 在偏移量 "b" 处读取该内存。
这个解决方案也可以分为两部分:
int memory_loc = pgm_read_byte(&alphabytes[a]);
column_byte = pgm_read_byte(memory_loc + b);
我的 C 技能不足以真正解释 "memory_loc" 是否需要是一个 int(我试过它作为 "char" 并且它也有效)。
注意alphabytes它是数组,每个元素包含一个REFERENCE(即地址),其中存储了相应的字符。因此,您应该分两步访问它。
第一步是了解所需项目在程序中的地址。地址为 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++);
...
}