我正在工作中的第一个嵌入式C项目中,我遇到了一种令我困惑的行为。
我是usindKeilsss5IDE,并通过下面的链接uVision找到了如何映射到特殊功能寄存器(SFR)内存空间
我用下面两个文件片段做的
dataStructures.h
typedef unsigned char byte;
typedef struct DAC {
byte loc[15];
} DAC;
extern DAC DAC_MAP; DAC_MAP.a51
PUBLIC DAC_MAP
DAC_MAP DATA 0xB9
END然后我有C代码,它只在使用1的文字值时才能工作。
byte i = 1;
DAC_MAP.loc[i] = value; // Does not write to the SFR
DAC_MAP.loc[1] = value; // Writes to the SFR我真的很想能够按索引写到一个位置,而不必写大的开关用例来解决这个问题。
对为什么会发生这种事有什么想法吗?
DAC_MAP.a51
PUBLIC DAC_MAP
DAC_MAP DATA 0xB9
ENDdriver.c
#include <DP8051XP.H>
typedef unsigned char byte;
typedef struct DAC {
byte loc[15];
} DAC;
extern DAC DAC_MAP;
int main(void) {
byte i = 1;
DAC_MAP.loc[i] = 0xAA; // Does not write to the SFR
DAC_MAP.loc[1] = 0xAA; // Writes to the SFR
return 0;
}当我在KEIL uVision 5调试器中运行这段代码时,您可以在内存映射中看到,当由变量执行索引时,没有任何更改,但是当使用文字时,值会按预期变化。
发布于 2017-06-05 19:16:00
这个问题是因为您试图使用间接寻址访问8051的特殊功能寄存器,这是不支持的。您将不得不强制编译器使用直接寻址。
来自通用SFR接口
8051中的SFRs仅可直接寻址。这意味着地址必须是程序的一部分。没有办法间接解决SFRs问题。所以指针不起作用。看看关于内部数据内存的Intel文档,它应该变得清晰了。 这样做的一种方法是为每个SFR地址定义一个SFR,并使用一个大开关语句,如下所示: sfr SFR_0x80 = 0x80;sfr SFR_0x81 = 0x81;sfr SFR_0x82 = 0x82;。。void write_sfr (无符号字符sfr_address,无符号字符值){ switch (sfr_address) { case 0x80: SFR_0x80 = value;SFR_0x80;case 0x81: SFR_0x81 = value;SFR_0x81;case 0x82: SFR_0x82 = value;SFR_0x82};
因为您的编译器看起来很聪明,可以将DAC_MAP.loc[1]转换成直接地址,所以这个driver.c可能适用于您:
#include <DP8051XP.H>
typedef unsigned char byte;
typedef struct DAC {
byte loc[15];
} DAC;
extern DAC DAC_MAP;
static void write_dac_map(byte i, byte d) {
switch (i) {
case 0: DAC_MAP.loc[0] = d; break;
case 1: DAC_MAP.loc[1] = d; break;
case 2: DAC_MAP.loc[2] = d; break;
case 3: DAC_MAP.loc[3] = d; break;
case 4: DAC_MAP.loc[4] = d; break;
case 5: DAC_MAP.loc[5] = d; break;
case 6: DAC_MAP.loc[6] = d; break;
case 7: DAC_MAP.loc[7] = d; break;
case 8: DAC_MAP.loc[8] = d; break;
case 9: DAC_MAP.loc[9] = d; break;
case 10: DAC_MAP.loc[10] = d; break;
case 11: DAC_MAP.loc[11] = d; break;
case 12: DAC_MAP.loc[12] = d; break;
case 13: DAC_MAP.loc[13] = d; break;
case 14: DAC_MAP.loc[14] = d; break;
default: //error
}
}
int main(void) {
byte i = 1;
write_dac_map(i, 0xAA);
return 0;
}如果查看代码生成的程序集(由stargateur提供),问题在C:0x0806。
9: int main(void) {
10: byte i = 1;
11:
C:0x0800 7F01 MOV R7,#0x01
12: DAC_MAP.loc[i] = 0xAA; // Does not write to the SFR
C:0x0802 74B9 MOV A,#DAC_MAP(0xB9)
C:0x0804 2F ADD A,R7
C:0x0805 F8 MOV R0,A
C:0x0806 76AA MOV @R0,#0xAA
13: DAC_MAP.loc[1] = 0xAA; // Writes to the SFR
14:
C:0x0808 75BAAA MOV 0xBA,#0xAA
15: return 0;
C:0x080B E4 CLR A
C:0x080C FE MOV R6,A
C:0x080D 1F DEC R7
16: }
C:0x080E 22 RET
C:0x080F 787F MOV R0,#0x7F
C:0x0811 E4 CLR A
C:0x0812 F6 MOV @R0,A
C:0x0813 D8FD DJNZ R0,C:0812
C:0x0815 758107 MOV SP(0x81),#0x07
C:0x0818 020800 LJMP main(C:0800)MOV @R0,#0xAA使用间接寻址,并将0xAA写入地址0xBA处的内部RAM (R0设置为0xB9 + 1)。
MOV 0xBA,#0xAA指令在C:0x0808使用直接寻址,并将写0xAA到SFR的地址0xBA。(使用直接寻址时,0x00和0x7F之间的地址指的是SFRs,而不是0x7F中的位置)。
本网站提供了更多关于8051:http://www.8052.com/tutaddr.phtml的不同寻址方式的信息。
https://stackoverflow.com/questions/44372928
复制相似问题