将数据数组(字体)保留在AVR GCC的FLASH - PROGMEM中

时间:2011-11-26 04:01:33

标签: string memory avr avr-gcc winavr

啊,PROGMEM,指针,指针指针,指针地址......我的脑袋很难看。

我有一个有问题的字体的数据数组

const uint8_t dejaVuSans9ptBitmaps[] = 
{
    /* @0 ' ' (5 pixels wide) */
    0x00, /*          */
    0x00, /*          */
...

我添加了PROGMEM

const uint8_t dejaVuSans9ptBitmaps[] PROGMEM =

这在另一个结构中被引用,如此;

const FONT_INFO dejaVuSans9ptFontInfo = {
   13,
   ' ',
   '~',
   dejaVuSans9ptDescriptors, 
   dejaVuSans9ptBitmaps,
};

结构定义为;

typedef struct {
   const uint8_t           height;       
   const uint8_t           startChar;    
   const uint8_t           endChar;      
   const FONT_CHAR_INFO*   charInfo;    
   const uint8_t*          data;         
} FONT_INFO;

我认为这需要改变为是正确的;

typedef struct {
   const uint8_t           height;       
   const uint8_t           startChar;    
   const uint8_t           endChar;      
   const FONT_CHAR_INFO*   charInfo;    
   const PGM_P             data;         
} FONT_INFO;

当我这样做时,它会抱怨

warning: pointer targets in initialization differ in signedness

对于FONT_INFO变量中的这一特定行;

const FONT_INFO dejaVuSans9ptFontInfo = {
    13,
    ' ',
    '~',
    dejaVuSans9ptDescriptors, 
--> dejaVuSans9ptBitmaps, <--
};

然后使用函数绘制;

void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str) {
    ...
    drawCharBitmap(currentX, y, color, &fontInfo->data[charOffset], charWidth, fontInfo->height);
    ...

最终绘制字形;

void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const uint8_t *glyph, uint8_t cols, uint8_t rows) {
   ...
      if (glyph[indexIntoGlyph] & (0X80)) drawPixel(currentX, currentY, color);
   ...

我在我的头上:/任何人都可以给我一些方向吗?我花了好几个小时尝试使用PGM_P,而pgm_read_byte等无济于事 - 我总是在屏幕上看到垃圾。

救救我!

2 个答案:

答案 0 :(得分:1)

好的,我想我明白这里发生了什么。

首先,const uint8_t* data是指向存储在PROGMEM中的数据的指针。

function void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str)我们传递指向fontInfo的指针。

要继续,以下内容非常重要;

fontInfo.data
(*ptr_to_fontInfo).data
ptr_to_fontInfo->data

都是一样的。所以ptr_to_fontInfo->data返回数据(不是地址)

然后使用&运算符,我们将此数据的'地址'传递给下一个函数

drawCharBitmap(currentX, y, color, 
  &fontInfo->data[charOffset], charWidth, fontInfo->height)

此地址存储在此处声明的指针变量unint8_t *glyph中;

void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, 
  uint16_t color, const uint8_t *glyph, uint8_t cols, uint8_t rows)

牢记这一点;

int *ptr;
int a;

ptr = &a;

然后,字形现在指向与fontInfo->data[charOffset]相同的地址。

接下来要知道的是;

  

a中的[b]只是编写*(a + b)

的一种奇特方式

所以字形是一个指针,当像glyph[indexIntoGlyph]一样使用时,它与*(glyph + indexIntoGlyph)相同,解引用运算符*表示我们在该地址获取数据。

从那里,我们可以像wex描述的那样使用pgm规则;

  

如果变量在PROGMEM中,则使用pgm_read_byte()作为   替换解除引用运算符*。对于“正常”变量   RAM你可以随时写*(&amp; a)而不只是a来返回值   变量a;所以从progmem返回一个8位宽的变量你   写pgm_read_byte(&amp; x)。

希望这个解释是正确的,并帮助人们(像我这样的新手!)更好地理解它。

答案 1 :(得分:0)

我在AVRfreaks.net得到了一些很大的支持,并认为我会在这里发布答案以供本社区参考。谢谢'wek'!

'wek'根据我提供的信息确定,我需要从&fontInfo->data[charOffset]的{​​{1}}开始发送多个字节。

  

如果变量在PROGMEM中,则使用drawCharBitmap()作为   替换解除引用运算符pgm_read_byte()。对于“正常”变量   在RAM中你总是可以写*而不是只用a来返回   变量*(&a)的值;所以从中返回一个8位宽的变量   你写的是a

     

现在回想一下,C中的pgm_read_byte(&x)只是写a[b]的一种奇特方式   (其中*(a + b)是指向数组第一个成员的指针,   因此指针算术规则适用)。所以在a你   可以将drawCharBitmap更改为   glyph[indexIntoGlyph]pgm_read_byte(&(glyph[indexIntoGlyph]))

我仍在尝试理解这里的链接,但这是一个非常好的答案,应该放在这里。感谢所有花时间看这个的人。