4

啊,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 等都无济于事 - 我总是在屏幕上看到垃圾。

救我!

4

2 回答 2

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;

然后 glyph 现在指向与 相同的地址fontInfo->data[charOffset]

接下来要知道的是;

C 中的 a[b] 只是写 *(a + b) 的一种奇特方式

所以 glyph 是一个指针,当这样使用时glyph[indexIntoGlyph],它与 相同*(glyph + indexIntoGlyph),并且取消引用运算符*意味着我们在该地址获取数据。

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

如果变量在 PROGMEM 中,则使用 pgm_read_byte() 作为取消引用运算符 * 的替代。对于 RAM 中的“普通”变量,您始终可以编写 *(&a) 而不仅仅是 a 来返回变量 a 的值;所以要从 progmem 返回一个 8 位宽的变量,你可以编写 pgm_read_byte(&x)。

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

于 2011-11-28T02:32:53.107 回答
0

我在 AVRfreaks.net 获得了一些大力支持,并认为我会在此处发布答案以供该社区将来参考。谢谢'周'!

'wek' 根据我提供的信息确定了我​​需要从&fontInfo->data[charOffset]in开始发送多个字节drawCharBitmap()

如果变量在 PROGMEM 中,则可以pgm_read_byte()用作取消引用运算符的替代品*。对于 RAM 中的“正常”变量,您始终可以编写*(&a)而不是仅仅 a 来返回变量的值a;所以要从你编写的程序中返回一个 8 位宽的变量pgm_read_byte(&x)

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

我仍在尝试理解此处的链接,但这是一个很好的答案,值得放在此处。感谢所有花时间看这个的人。

于 2011-11-28T00:33:02.273 回答