【问题标题】:Program memory space is being overwritten程序存储空间被覆盖
【发布时间】: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 好的。我会写一个答案

标签: c memory atmel


【解决方案1】:

在标准 C 中,如果你在头文件中有这个:

const char M1_1_1[] = {32,32,32,32,69,110,116,101,114,105,110,103};

并且两个或多个翻译单元包含该头文件,由于同一对象有多个定义,这是未定义的行为。由于编译器/链接器为每个定义或其他任何东西使用内存,这可能表现为高内存使用率。

如果您可以重新排列代码以使定义仅出现在.c 文件中,则可能会解决问题。其他单位可以通过extern const char M1_1_1[];访问数据。

【讨论】:

  • static 一方面有帮助,但另一方面会增加内存占用空间。` extern 对于数组本身没有用(也不会起作用),因为您需要知道大批。要么导出两个常量,要么使用终止符。
  • @0andriy 如果需要,您可以使用枚举或#define 作为数组的大小。我发布的代码确实有效并且很有用,具体取决于要求。您假设调用者需要大小,这可能不是真的。
  • 是的,我知道,但它更容易出错,因为一个人必须更新两个以上的地方而不是一个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多