c - 访问 Arduino/AVR 上 PROGMEM 中的各个字节

标签 c arduino avr progmem

我已经阅读了几天关于访问 PROGMEM 的内容,并梳理了其他几个问题,但我仍然无法让我的代码工作。任何帮助将不胜感激。

我在下面提供了 Arduino 的完整测试草图。它的大部分工作正常,但是当我循环遍历“alpha”字符的每个字节时,如“alphabytes”所指出的,我只是得到垃圾,所以我显然没有访问正确的内存位置。问题是,我不知道如何访问该内存位置。

我见过其他几个这样的示例,但没有一个在指针数组中具有不同大小的数据数组。

请参阅以“>>>> 问题是...”开头的行

// 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();
}

最佳答案

请注意,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++);
    ...
}

关于c - 访问 Arduino/AVR 上 PROGMEM 中的各个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31100771/

相关文章:

c - 如何计算 C 字符串中字符 '/' 出现的次数?

ios - 如何将 C int 放入 NSArray?

c - 围绕初始化器元素的好方法不是 C 中的常量错误吗?

c - 为什么使用2个指针指向atmega微 Controller 中的寄存器地址?

c - 如何将链接本地地址绑定(bind)到 ipv6 套接字

c++ - 使用Arduino编程ATtiny10( "ld.exe"错误)

audio - 没有音频输出 Teensy 3.2 使用板载 DAC 或 USB 直通

c++ - Arduino 字符串比较不起作用

c - Atmega @ 8MHZ 延迟 8 倍到快

c - fwrite 是否在内部调用任何锁?