单片机DPTR(DPH,DPL)和SP特殊寄存器C语言中应用?这三个特殊寄存器对C程序员来说是透明的,不用C程序员操作,编译的时候会自动运用这三个寄存器,ACC寄存器和B寄存器也类似
编译器把C译成指令序列时,会根据具体情况处理SP,相对于C的使用者是透明的。https://bbs.21ic.com/icview-42986-1-1.html
指针
汇编语言里面 这样操作 MOVX A, @ DPTR 或者 MOVC A, @A + DPTR
C语言里面不需要程序员操作DPTR,编译器会自动操作的https://zhidao.baidu.com/question/346722123.html
C语言出现数组的地方会编译中会自动用DPTR指针。
调用子程序和中断程序的地方采用到堆栈SP
源程序单片机例程中的2402
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define NOP4() {_nop_();_nop_();_nop_();_nop_();}
sbit SCL=P1^0;
sbit SDA=P1^1;
sbit SPK=P3^0;
//标准音符频率对应的延时表
uchar code HI_LIST[]={0,226,229,232,233,236,238,240,241,242,244,245,246,247,248};
uchar code LO_LIST[]={0,4,13,10,20,3,8,6,2,23,5,26,1,4,3};
//待写入24C04的音符
uchar code Song_24C04[]={1,2,3,1,1,2,3,1,3,4,5,3,4,5};
uchar sidx; //读取音符索引
//延时
void DelayMS(uint ms)
{
uchar i;
while(ms--) for(i=0;i<120;i++);
}
//IIC开始
void Start()
{
SDA=1;SCL=1;NOP4();SDA=0;NOP4();SCL=0;
}
//IIC停止
void Stop()
{
SDA=0;SCL=0;NOP4();SCL=1;NOP4();SDA=1;
}
//读取应答
void RACK()//应该是判断从机的应答啊?怎么此函数是单片机输出应答呢?2019.12.18
{
SDA=1;NOP4();SCL=1;NOP4();SCL=0;
}
//发送非应答信号
void NO_ACK()
{
SDA=1;SCL=1;NOP4();SCL=0;SDA=0;
}
//向24C04中写一个字节数据
void Write_A_Byte(uchar b)
{
uchar i;
for(i=0;i<8;i++)
{
b<<=1;SDA=CY;_nop_();SCL=1;NOP4();SCL=0;
}
RACK();
}
//向指定地址写数据
void Write_IIC(uchar addr,uchar dat)
{
Start();
Write_A_Byte(0xa0);Write_A_Byte(addr);Write_A_Byte(dat);
Stop();
DelayMS(10);
}
//从24C04中读一个字节数据
uchar Read_A_Byte()
{
uchar i,b;
for(i=0;i<8;i++)
{
SCL=1;b<<=1;b|=SDA;SCL=0;
}
return b;
}
//从当前地址读取数据
uchar Read_Current()
{
uchar d;
Start();
Write_A_Byte(0xa1);d=Read_A_Byte();NO_ACK();
Stop();
return d;
}
//从任意地址读取数据
uchar Random_Read(uchar addr)
{
Start();
Write_A_Byte(0xa0);Write_A_Byte(addr);
Stop();
return Read_Current();
}
//定时器0中断
void T0_INT() interrupt 1
{
SPK=~SPK;
TH0=HI_LIST[sidx];
TL0=LO_LIST[sidx];
}
//主程序
void main()
{
uint i;
IE=0x82;
TMOD=0x00;
for(i=0;i<14;i++) //向24C04写入音符表
{
Write_IIC(i,Song_24C04[i]);
}
while(1) //反复读取音符并播放
{
for(i=0;i<15;i++) //从24C04中读取音符
{
sidx=Random_Read(i); //从指定地址读取
TR0=1; //播放
DelayMS(300);
}
}
}
反汇编
126: ?C_STARTUP: LJMP STARTUP1
127:
128: RSEG ?C_C51STARTUP
129:
130: STARTUP1:
131:
132: IF IDATALEN <> 0
C:0x0000 020166 LJMP STARTUP1(C:0166)
C:0x0003 00 NOP
C:0x0004 00 NOP
C:0x0005 00 NOP
C:0x0006 00 NOP
C:0x0007 00 NOP
C:0x0008 00 NOP
C:0x0009 00 NOP
C:0x000A 00 NOP
C:0x000B 020088 LJMP T0_INT(C:0088)
94: void main()
95: {
96: uint i;
97: IE=0x82;
C:0x000E 75A882 MOV IE(0xA8),#DPL(0x82)
98: TMOD=0x00;
C:0x0011 E4 CLR A
C:0x0012 F589 MOV TMOD(0x89),A
99: for(i=0;i<14;i++) //向24C04写入音符表
C:0x0014 F508 MOV 0x08,A
C:0x0016 F509 MOV 0x09,A
100: {
101: Write_IIC(i,Song_24C04[i]);
C:0x0018 AF09 MOV R7,0x09
C:0x001A EF MOV A,R7
C:0x001B 90007A MOV DPTR,#Song_24C04(0x007A)
C:0x001E 93 MOVC A,@A+DPTR
C:0x001F FD MOV R5,A
C:0x0020 1200EE LCALL Write_IIC(C:00EE)
102: }
C:0x0023 0509 INC 0x09
C:0x0025 E509 MOV A,0x09
C:0x0027 7002 JNZ C:002B
C:0x0029 0508 INC 0x08
C:0x002B C3 CLR C
C:0x002C 940E SUBB A,#0x0E
C:0x002E E508 MOV A,0x08
C:0x0030 9400 SUBB A,#0x00
C:0x0032 40E4 JC C:0018
103: while(1) //反复读取音符并播放
104: {
105: for(i=0;i<15;i++) //从24C04中读取音符
C:0x0034 E4 CLR A
C:0x0035 F508 MOV 0x08,A
C:0x0037 F509 MOV 0x09,A
106: {
107: sidx=Random_Read(i); //从指定地址读取
C:0x0039 AF09 MOV R7,0x09
C:0x003B 12014B LCALL Random_Read(C:014B)
C:0x003E 8F0A MOV sidx(0x0A),R7
108: TR0=1; //播放
C:0x0040 D28C SETB TR0(0x88.4)
109: DelayMS(300);
C:0x0042 7F2C MOV R7,#0x2C
C:0x0044 7E01 MOV R6,#0x01
C:0x0046 1200D8 LCALL DelayMS(C:00D8)
110: }
C:0x0049 0509 INC 0x09
C:0x004B E509 MOV A,0x09
C:0x004D 7002 JNZ C:0051
C:0x004F 0508 INC 0x08
C:0x0051 C3 CLR C
C:0x0052 940F SUBB A,#0x0F
C:0x0054 E508 MOV A,0x08
C:0x0056 9400 SUBB A,#0x00
C:0x0058 40DF JC C:0039
C:0x005A 80D8 SJMP C:0034
C:0x005C 00 NOP
C:0x005D E2 MOVX A,@R0
C:0x005E E5E8 MOV A,0xE8
C:0x0060 E9 MOV A,R1
C:0x0061 EC MOV A,R4
C:0x0062 EE MOV A,R6
C:0x0063 F0 MOVX @DPTR,A
C:0x0064 F1F2 ACALL C:07F2
C:0x0066 F4 CPL A
C:0x0067 F5F6 MOV 0xF6,A
C:0x0069 F7 MOV @R1,A
C:0x006A F8 MOV R0,A
C:0x006B 00 NOP
C:0x006C 04 INC A
C:0x006D 0D INC R5
C:0x006E 0A INC R2
C:0x006F 14 DEC A
C:0x0070 03 RR A
C:0x0071 08 INC R0
C:0x0072 06 INC @R0
C:0x0073 021705 LJMP C:1705
C:0x0076 1A DEC R2
C:0x0077 0104 AJMP C:0004
C:0x0079 03 RR A
C:0x007A 0102 AJMP C:0002
C:0x007C 03 RR A
C:0x007D 0101 AJMP C:0001
C:0x007F 020301 LJMP C:0301
C:0x0082 03 RR A
C:0x0083 04 INC A
C:0x0084 0503 INC 0x03
C:0x0086 04 INC A
C:0x0087 05C0 INC 0xC0
C:0x0089 E0 MOVX A,@DPTR
C:0x008A C083 PUSH DPH(0x83)
C:0x008C C082 PUSH DPL(0x82)
89: SPK=~SPK;
C:0x008E B2B0 CPL SPK(0xB0.0)
90: TH0=HI_LIST[sidx];
C:0x0090 E50A MOV A,sidx(0x0A)
C:0x0092 90005C MOV DPTR,#HI_LIST(0x005C)
C:0x0095 93 MOVC A,@A+DPTR
C:0x0096 F58C MOV TH0(0x8C),A
91: TL0=LO_LIST[sidx];
C:0x0098 E50A MOV A,sidx(0x0A)
C:0x009A 90006B MOV DPTR,#LO_LIST(0x006B)
C:0x009D 93 MOVC A,@A+DPTR
C:0x009E F58A MOV TL0(0x8A),A
92: }
C:0x00A0 D082 POP DPL(0x82)
C:0x00A2 D083 POP DPH(0x83)
C:0x00A4 D0E0 POP ACC(0xE0)
C:0x00A6 32 RETI
C:0x00A7 1200C0 LCALL Write_A_Byte(C:00C0)
C:0x00AA AF05 MOV R7,0x05
C:0x00AC 1200C0 LCALL Write_A_Byte(C:00C0)
27: void Stop()
28: {
29: SDA=0;SCL=0;NOP4();SCL=1;NOP4();SDA=1;
C:0x00AF C291 CLR SDA(0x90.1)
C:0x00B1 C290 CLR SCL(0x90.0)
C:0x00B3 00 NOP
C:0x00B4 00 NOP
C:0x00B5 00 NOP
C:0x00B6 00 NOP
C:0x00B7 D290 SETB SCL(0x90.0)
C:0x00B9 00 NOP
C:0x00BA 00 NOP
C:0x00BB 00 NOP
C:0x00BC 00 NOP
C:0x00BD D291 SETB SDA(0x90.1)
30: }
31: //读取应答
32: void RACK()//应该是判断从机的应答啊?怎么此函数是单片机输出应答呢?2019.12.18
33: {
34: SDA=1;NOP4();SCL=1;NOP4();SCL=0;
35: }
36: //发送非应答信号
37: void NO_ACK()
38: {
39: SDA=1;SCL=1;NOP4();SCL=0;SDA=0;
40: }
41: //向24C04中写一个字节数据
C:0x00BF 22 RET
42: void Write_A_Byte(uchar b)
43: {
44: uchar i;
45: for(i=0;i<8;i++)
C:0x00C0 E4 CLR A
C:0x00C1 FE MOV R6,A
46: {
47: b<<=1;SDA=CY;_nop_();SCL=1;NOP4();SCL=0;
C:0x00C2 EF MOV A,R7
C:0x00C3 25E0 ADD A,ACC(0xE0)
C:0x00C5 FF MOV R7,A
C:0x00C6 9291 MOV SDA(0x90.1),C
C:0x00C8 00 NOP
C:0x00C9 D290 SETB SCL(0x90.0)
C:0x00CB 00 NOP
C:0x00CC 00 NOP
C:0x00CD 00 NOP
C:0x00CE 00 NOP
C:0x00CF C290 CLR SCL(0x90.0)
48: }
C:0x00D1 0E INC R6
C:0x00D2 BE08ED CJNE R6,#0x08,C:00C2
49: RACK();
50: }
51: //向指定地址写数据
C:0x00D5 02013C LJMP RACK(C:013C)
16: void DelayMS(uint ms)
17: {
18: uchar i;
19: while(ms--) for(i=0;i<120;i++);
C:0x00D8 EF MOV A,R7
C:0x00D9 1F DEC R7
C:0x00DA AA06 MOV R2,0x06
C:0x00DC 7001 JNZ C:00DF
C:0x00DE 1E DEC R6
C:0x00DF 4A ORL A,R2
C:0x00E0 600B JZ C:00ED
C:0x00E2 E4 CLR A
C:0x00E3 FD MOV R5,A
C:0x00E4 ED MOV A,R5
C:0x00E5 C3 CLR C
C:0x00E6 9478 SUBB A,#0x78
C:0x00E8 50EE JNC DelayMS(C:00D8)
C:0x00EA 0D INC R5
C:0x00EB 80F7 SJMP C:00E4
20: }
C:0x00ED 22 RET
52: void Write_IIC(uchar addr,uchar dat)
C:0x00EE AC07 MOV R4,0x07
53: {
54: Start();
C:0x00F0 12012B LCALL Start(C:012B)
55: Write_A_Byte(0xa0);Write_A_Byte(addr);Write_A_Byte(dat);
C:0x00F3 7FA0 MOV R7,#PPAGE_SFR(0xA0)
C:0x00F5 1200C0 LCALL Write_A_Byte(C:00C0)
C:0x00F8 AF04 MOV R7,0x04
56: Stop();
C:0x00FA 1200A7 LCALL C:00A7
57: DelayMS(10);
58: }
59: //从24C04中读一个字节数据
C:0x00FD 7F0A MOV R7,#sidx(0x0A)
C:0x00FF 7E00 MOV R6,#0x00
C:0x0101 0200D8 LJMP DelayMS(C:00D8)
60: uchar Read_A_Byte()
61: {
62: uchar i,b;
63: for(i=0;i<8;i++)
C:0x0104 E4 CLR A
C:0x0105 FE MOV R6,A
64: {
65: SCL=1;b<<=1;b|=SDA;SCL=0;
C:0x0106 D290 SETB SCL(0x90.0)
C:0x0108 EF MOV A,R7
C:0x0109 25E0 ADD A,ACC(0xE0)
C:0x010B FF MOV R7,A
C:0x010C A291 MOV C,SDA(0x90.1)
C:0x010E E4 CLR A
C:0x010F 33 RLC A
C:0x0110 4207 ORL 0x07,A
C:0x0112 C290 CLR SCL(0x90.0)
66: }
C:0x0114 0E INC R6
C:0x0115 BE08EE CJNE R6,#0x08,C:0106
67: return b;
68: }
69: //从当前地址读取数据
C:0x0118 22 RET
70: uchar Read_Current()
71: {
72: uchar d;
73: Start();
C:0x0119 12012B LCALL Start(C:012B)
74: Write_A_Byte(0xa1);d=Read_A_Byte();NO_ACK();
C:0x011C 7FA1 MOV R7,#0xA1
C:0x011E 1200C0 LCALL Write_A_Byte(C:00C0)
C:0x0121 120104 LCALL Read_A_Byte(C:0104)
C:0x0124 120159 LCALL NO_ACK(C:0159)
75: Stop();
C:0x0127 1200AF LCALL Stop(C:00AF)
76: return d;
77: }
78: //从任意地址读取数据
C:0x012A 22 RET
22: void Start()
23: {
24: SDA=1;SCL=1;NOP4();SDA=0;NOP4();SCL=0;
C:0x012B D291 SETB SDA(0x90.1)
C:0x012D D290 SETB SCL(0x90.0)
C:0x012F 00 NOP
C:0x0130 00 NOP
C:0x0131 00 NOP
C:0x0132 00 NOP
C:0x0133 C291 CLR SDA(0x90.1)
C:0x0135 00 NOP
C:0x0136 00 NOP
C:0x0137 00 NOP
C:0x0138 00 NOP
C:0x0139 C290 CLR SCL(0x90.0)
25: }
26: //IIC停止
27: void Stop()
28: {
29: SDA=0;SCL=0;NOP4();SCL=1;NOP4();SDA=1;
30: }
31: //读取应答
C:0x013B 22 RET
32: void RACK()//应该是判断从机的应答啊?怎么此函数是单片机输出应答呢?2019.12.18
33: {
34: SDA=1;NOP4();SCL=1;NOP4();SCL=0;
C:0x013C D291 SETB SDA(0x90.1)
C:0x013E 00 NOP
C:0x013F 00 NOP
C:0x0140 00 NOP
C:0x0141 00 NOP
C:0x0142 D290 SETB SCL(0x90.0)
C:0x0144 00 NOP
C:0x0145 00 NOP
C:0x0146 00 NOP
C:0x0147 00 NOP
C:0x0148 C290 CLR SCL(0x90.0)
35: }
C:0x014A 22 RET
79: uchar Random_Read(uchar addr)
C:0x014B AD07 MOV R5,0x07
80: {
81: Start();
C:0x014D 12012B LCALL Start(C:012B)
82: Write_A_Byte(0xa0);Write_A_Byte(addr);
C:0x0150 7FA0 MOV R7,#PPAGE_SFR(0xA0)
83: Stop();
C:0x0152 1200A7 LCALL C:00A7
84: return Read_Current();
C:0x0155 120119 LCALL Read_Current(C:0119)
85: }
C:0x0158 22 RET
37: void NO_ACK()
38: {
39: SDA=1;SCL=1;NOP4();SCL=0;SDA=0;
C:0x0159 D291 SETB SDA(0x90.1)
C:0x015B D290 SETB SCL(0x90.0)
C:0x015D 00 NOP
C:0x015E 00 NOP
C:0x015F 00 NOP
C:0x0160 00 NOP
C:0x0161 C290 CLR SCL(0x90.0)
C:0x0163 C291 CLR SDA(0x90.1)
40: }
C:0x0165 22 RET
133: MOV R0,#IDATALEN - 1
C:0x0166 787F MOV R0,#0x7F
134: CLR A
C:0x0168 E4 CLR A
135: IDATALOOP: MOV @R0,A
C:0x0169 F6 MOV @R0,A
136: DJNZ R0,IDATALOOP
C:0x016A D8FD DJNZ R0,IDATALOOP(C:0169)
185: MOV SP,#?STACK-1
186:
187: ; This code is required if you use L51_BANK.A51 with Banking Mode 4
188: ;<h> Code Banking
189: ; <q> Select Bank 0 for L51_BANK.A51 Mode 4
190: #if 0
191: ; <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
192: EXTRN CODE (?B_SWITCH0)
193: CALL ?B_SWITCH0 ; init bank mechanism to code bank 0
194: #endif
195: ;</h>
C:0x016C 75810A MOV SP(0x81),#sidx(0x0A)
196: LJMP ?C_START
C:0x016F 02000E LJMP main(C:000E)
C:0x0172 00 NOP
C:0x0173 00 NOP
C:0x0174 00 NOP