【发布时间】:2017-05-08 13:21:51
【问题描述】:
我正在使用 AtmelStudio7 为 Atmel Mega645A 控制器编写固件。我有一堆消息显示在 16x2 字符显示屏上。为了保留 SRAM 空间,我试图将这些消息存储在 ROM 程序存储器中。我的问题是,我似乎正在覆盖已经用于其他代码的程序内存部分。以下是详细信息:
我在主程序开头附近有以下语句:
#include "adht.h"
#include "languages.h"
在 adht.h 我有以下内容:
#include <avr/pgmspace.h>
我相信我的问题的关键在于我创建的头文件languages.h。在languages.h 中,我有数百行代码如下所示:
const char M1_1_1[] PROGMEM = {32,32,32,32,69,110,116,101,114,105,110,103};
const char M1_2_1[] PROGMEM = {32,32,83,116,97,110,100,98,121,32,77,111,100,101};
const char M2_1_1[] PROGMEM = {32,32,70,87,32,82,101,118,105,115,105,111,110};
const char M2_2_1[] PROGMEM = {32,32,32,32,40,110,117,109,98,101,114,41};
const char M3_1_1[] PROGMEM = {32,78,79,46,32,79,70,32,84,72,69,82,65,80,89};
const char M3_2_1[] PROGMEM = {32,32,32,32,83,69,83,83,73,79,78,83,58};
.
.
. etc. etc.
当我用这样的 ~660 行编译时,AtmelStudio 报告以下内容: 程序内存使用:34892 字节 53.2 % 已满 数据存储器使用:2919 字节 71.3 % 已满 EEPROM 内存使用量:170 字节 8.3 % 已满
如果我注释掉大部分“const char ....”行并重新构建,我会得到:
程序内存使用:34896 字节 53.2 % 已满 数据存储器使用:2919 字节 71.3 % 已满 EEPROM 内存使用量:170 字节 8.3 % 已满
...看起来差不多。然而,这两个版本都允许我的程序的其余部分运行没有问题。
这就是我遇到麻烦的地方。进一步在languages.h我有以下代码:
PGM_P const string_table[] PROGMEM =
{
M1_1_1 , M1_1_2 , M1_1_3 , M1_1_4 , M1_1_5 , M1_1_6}; /* ,
M1_2_1 , M1_2_2 , M1_2_3 , M1_2_4 , M1_2_5 , M1_2_6 ,
M2_1_1 , M2_1_2 , M2_1_3 , M2_1_4 , M2_1_5 , M2_1_6 ,
M2_2_1 , M2_2_2 , M2_2_3 , M2_2_4 , M2_2_5 , M2_2_6 ,
M3_1_1 , M3_1_2 , M3_1_3 , M3_1_4 , M3_1_5 , M3_1_6 ,
.
.
. etc. etc.
现在你会注意到在 M1_1_1 的第一行之后...我已经注释掉了 "/" 其余的“指针分配”。请放心,我在作业末尾有一个“/”。如果我只有 6 个指针分配,我的代码可以正常工作。如果我将“/*”向下移动几行以便编译更多代码行,我的程序的其余部分就会开始变得异常,就好像我的程序内存不足一样。我的程序以不同的方式失败,具体取决于编译了多少“指针分配”。 (注意我在这个论坛中输入“星号反斜杠”时遇到问题)。当我用八行未注释掉的代码进行编译时,编译器会报告以下内容:
程序内存使用:35530 字节 54.2 % 已满 数据存储器使用:2919 字节 71.3 % 已满 EEPROM 内存使用量:170 字节 8.3 % 已满
当我取消注释所有这些行时,编译器会报告以下内容:
程序内存使用:44690 字节 68.2 % 已满 数据存储器使用:2919 字节 71.3 % 已满 EEPROM 内存使用量:170 字节 8.3 % 已满
很明显我正在填满程序内存,但还没有接近极限。
为了完整起见,在主程序中,我将消息从 Program Memory 复制到 SRAM 中,如下所示:
char line1[16];
char line2[16];
PGM_P p;
memcpy_P(&p, &string_table[0], sizeof(PGM_P));
strcpy_P(line1, p);
memcpy_P(&p, &string_table[1], sizeof(PGM_P));
strcpy_P(line2, p);
稍后我将 line1 和 line2 发送到显示器。
所以在我看来问题出在我身上
PGM_P const string_table[] PROGMEM =
行。有人可以告诉我如何做到这一点,这样我就不会覆盖我的程序的其余部分吗?
更新:在主程序中,如果我在编译前注释掉以下代码行,程序内存使用率下降(降至 54%),程序的其余部分工作正常:
char line1[16];
char line2[16];
PGM_P p;
memcpy_P(&p, &string_table[0], sizeof(PGM_P));
strcpy_P(line1, p);
memcpy_P(&p, &string_table[1], sizeof(PGM_P));
strcpy_P(line2, p);
当我取消注释这段代码并重新编译时,程序内存使用率回升到 68%,然后当我运行它时,程序的其余部分就崩溃了。那么这些覆盖程序内存的代码行是什么?
更新#2:在上面的代码行中,如果我注释掉这两行:
strcpy_P(line1, p);
strcpy_P(line2, p);
我的程序有效。当然,我仍然无法访问我存储在程序存储器中的数据。请有人告诉我发生了什么事。如何将数据(字符数组,或者 uint_8 数组)放入 RAM 中,以便在 16x2 屏幕上显示?
【问题讨论】:
-
当您说“将这些消息存储在 ROM 程序存储器中”时,您是指在 EEPROM 中吗?以连续动态方式使用 EEPROM 不是一个好主意,因为写入周期的数量是有限的。
-
在 C 中,您不能在头文件中包含
const char M1_1_1[] = {32,32,32,32,69,110,116,101,114,105,110,103};等,这将导致跨翻译单元的多个定义,这是未定义的行为。我不确定 PROGMEM 是否对此有任何影响,但假设它没有(并假设您在至少 2 个单位中包含语言.h)可以解释您的问题。 -
@M.M.我将languages.h中的所有代码移到主程序[在main()之前],它似乎正在工作。谢谢。
-
@JeffG 好的。我会写一个答案