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

发布于 2024-12-18 00:45:05 字数 2009 浏览 4 评论 0原文

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

救救我吧!

Ahhh, PROGMEM, pointers, pointers to pointers, addresses of pointers... My head boggles.

I have a data array for the font in question

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

to which I have added PROGMEM

const uint8_t dejaVuSans9ptBitmaps[] PROGMEM =

This is referenced in another structure like so;

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

The structure is defined as;

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;

Am I correct in assuming this needs to change to;

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;

When I do so, it complains that

warning: pointer targets in initialization differ in signedness

For this particular line in the FONT_INFO variable;

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

It is then drawn using the function;

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);
    ...

Which finally draws the glyph;

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);
   ...

I am in over my head :/ Can anyone give me some direction? I have spent hours trying to use PGM_P, and pgm_read_byte etc to no avail - I always get garbage on the screen.

Save me!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无畏 2024-12-25 00:45:05

好吧,我想我明白这是怎么回事了。

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

在函数 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] 相同的地址。

接下来要知道的是;

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

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

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

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

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

OK, I think I understand what is going on here.

First, const uint8_t* data is a pointer to the data stored in PROGMEM.

In the function void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str) we pass a pointer to fontInfo.

To continue, the following is important to understand;

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

are all the same. So ptr_to_fontInfo->data returns the data (not address)

Then using the & operator, we pass the 'address of' this data to the next function

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

This address is stored in the declared pointer variable unint8_t *glyph here;

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

Keeping this in mind;

int *ptr;
int a;

ptr = &a;

Then glyph now points to the same address as fontInfo->data[charOffset].

The next thing to know is;

a[b] in C is just a fancy way for writing *(a + b)

So glyph being a pointer, when used like this glyph[indexIntoGlyph], it is the same as *(glyph + indexIntoGlyph), and the dereferencing operator * means we get the data at that address.

From there, we can use the pgm rules as wex described;

If the variable is in PROGMEM, you use pgm_read_byte() as a
replacement for the dereference operator *. For "normal" variables in
RAM you can always write *(&a) instead of just a to return the value
of the variable a; so to return a 8-bit wide variable from progmem you
write pgm_read_byte(&x).

Hope this explanation is correct and helps people (newbies like me!) understand it a bit better.

你与清晨阳光 2024-12-25 00:45:05

我在 AVRfreaks.net 上得到了一些大力支持,我想我应该在这里发布答案以供该社区将来参考。谢谢“威克”!

“wek”根据我提供的信息确定,我需要发送从 drawCharBitmap() 中的 &fontInfo->data[charOffset] 开始的多个字节。

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

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

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

I got some great support over at AVRfreaks.net, and thought I'd post the answer here for future reference by this community. Thanks 'wek'!

'wek' identified that based on the information I gave, that I needed to send multiple bytes starting from &fontInfo->data[charOffset] in drawCharBitmap().

If the variable is in PROGMEM, you use pgm_read_byte() as a
replacement for the dereference operator *. For "normal" variables
in RAM you can always write *(&a) instead of just a to return the
value of the variable a; so to return a 8-bit wide variable from
progmem you write pgm_read_byte(&x).

Now recall that a[b] in C is just a fancy way for writing *(a + b)
(where a is a pointer pointing to the first member of the array,
thus rules of pointer arithmetics apply). So in drawCharBitmap you
can change glyph[indexIntoGlyph] either into
pgm_read_byte(&(glyph[indexIntoGlyph])), or pgm_read_byte(glyph +
indexIntoGlyph)
.

I'm still trying to understand the links here, but it was such a great answer it deserved to be put on here. Thanks to all who took the time to look at this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文