我正在为uController编写一个c程序,我设法用代码填充了32kb。
该程序已满,具有以下"打印"功能:
void print(char *x)
{
while(*x) {
SerialWrite(*x++);}
}
SerialWrite 看起来像:
void SerialWrite(unsigned char c)
{
while(tx_buffer_size>250);
ES=0;
tx_buffer_size++;
if (tx_buffer_empty == 0){
txBuffer[tx_in++] = c;}
else {
tx_buffer_empty = 0;
SBUF = c;}
ES=1;
}
我用字符串文本作为参数调用打印函数,如下所示:
print("Hello World");
我只使用了32kb外部存储器中的2.2kb,所以我的结论是将"Hello World"移到外部存储器,而不是在主程序中对其进行硬编码。
不幸的是,我的尝试实际上使情况变得更糟,我做了以下工作:
char xdata *msg1 = "Hello World"; // <-- this made it worse, and the external memory space was not used at all
print(msg1);
比我尝试:
char xdata msg1[] = "Hello World";
print(msg1);
这确实将外部存储器大小增加了 12,这是正确的,因为字符串包含 11 个字符 + null。但程序内存也增加了3。我尝试了不同的字符串长度,但程序内存不断增加 3 个字节。
如何解决这个问题?
加法: 我正在使用Keil的C编译器,并且我倾向于程序大小进行编译。 uController是一个FPGA芯片,具有模拟的80C51芯片。对于这个虚拟 80c51,我正在编写代码。我有 32kb 内存用于主程序和 32kb 内存用于变量
编辑:*msg[]是一个错字,它必须是*msg
char xdata *msg1 = "Hello World";
char xdata msg1[] = "Hello World";
我认为你不能以这种方式缩短你的程序,因为即使消息将从xdata 访问,它也会首先由 C 运行时复制到那里,从代码(初始化数据(中获取它。
如果你真的有很多"print((",那么你可以通过为其参数声明正确的指针类型来挤压一些字节。我解释说:由于 8051 的奇怪架构,"高级"C "通用"指针需要三个字节 - 两个字节作为偏移量,第三个字节用于指定它是指向 XDATA 还是代码。然后每次调用 print(( 都必须构造这样一个指针。
例如,如果您声明:
无效打印(char xdata *x(
现在 print(( 只接受指向 Xdata 的指针,并且只需要两个字节长的指针。每次调用 print(( 都会更简单。
似乎你的大部分文本都是恒定的,所以它们将在代码中;所以你需要的指针类型不是XDATA,而是CODE(或者其他关键字是正确的(。
一旦你像上面这样声明了print((,你就不能再打印不在代码段中的数据;也许你需要另一个函数,比如
printx(char* what(
它将像以前一样接受来自任何段的 char*,但您只会在需要时调用这个昂贵的 printx((。
希望这有帮助;8051非常奇特,它的编译器很复杂(但Keil很棒(。我建议看看生成的(低级(代码,也许你可以发现一些其他的内存浪费。祝你好运!
补遗:______________
我曾经遇到过一次,几乎没有文本的空间。我通过应用一些文本压缩很好地解决了。鉴于所有文本都是纯ASCII,我使用了超过127个字符的字符来指出文本中常见的重复单词。例如,如果字符串"Hello"重复几次,则可以将"Hello world"替换为0x80 " world"
。当然,打印例程必须检测这些特殊标记并管理减压 - 但这非常容易。
简而言之,将这一行放在源文件的开头:
#pragma STRING (XDATA)
这些页面可以帮助您更好地理解:
http://www.keil.com/support/man/docs/c51/c51_le_const.htm http://www.keil.com/support/man/docs/c51/c51_string.htm
2018/06/25 编辑: 试试这一行:
#pragma O2 STRING (XDATA)
如上面的第二个链接和本页所述,应启用 OMF2 以使用 STRING 指令 http://www.keil.com/support/man/docs/c51/c51_omf2.htm