STC单片机自带内部参考电压,单片机生产时内部已经做校准,可分别在ram和rom中读取,
(1)rom中读取
在rom中读取的时候,需要在下载时候勾选下载软件中的 在程序区的结束处添加重要测试参数,如下图所示:
勾选下载后,BandGap电压以mV为单位可以读取。
BGV = (int code *)0xeff7; ROM容量大小不同,地址不同如// STC8A8K60S4A10 是0xeff7
code 是指程序存储(rom)地址
(2)ram中读取
而在ram中不需要勾选(在程序区的结束处添加重要测试参数),放在在idata区域,读取时候用如下程序①(官方例程):
#include "reg51.h"
int *BGV;
unsigned char hi;
unsigned char Low;
void main()
{
BGV = (int idata *)0xef;
Low =(*BGV);
hi = (*BGV) >> 8;
}
疑问1:指针类型为何设置为int?是否可以设置为unsigned int?
????
疑问2:0xef是一个地址,为何可以读取高地址和低地址的数据?
在debug session 中观察汇编代码
6: void main()
7: {
8: BGV = (int idata *)0xef;
9:
C:0x002E 7B00 MOV R3,#0x00
C:0x0030 7A00 MOV R2,#0x00
C:0x0032 79EF MOV R1,#0xEF
C:0x0034 8B0A MOV BGV(0x0A),R3
C:0x0036 8A0B MOV 0x0B,R2
C:0x0038 890C MOV 0x0C,R1
10: Low =(*BGV);
C:0x003A 120003 LCALL C?ILDPTR(C:0003)
C:0x003D AEF0 MOV R6,B(0xF0)
C:0x003F F508 MOV Low(0x08),A
11: hi = (*BGV) >> 8;
12:
13:
C:0x0041 EE MOV A,R6
C:0x0042 FF MOV R7,A
C:0x0043 8F09 MOV hi(0x09),R7
如上调用了函数ILDPTR,ILDPTR汇编的代码如下
C?ILDPTR:
C:0x0003 BB010A CJNE R3,#0x01,C:0010
C:0x0006 8982 MOV DPL(0x82),R1
C:0x0008 8A83 MOV DPH(0x83),R2
C:0x000A E0 MOVX A,@DPTR
C:0x000B F5F0 MOV B(0xF0),A
C:0x000D A3 INC DPTR
C:0x000E E0 MOVX A,@DPTR
C:0x000F 22 RET
C:0x0010 5006 JNC C:0018
C:0x0012 87F0 MOV B(0xF0),@R1
C:0x0014 09 INC R1
C:0x0015 E7 MOV A,@R1
C:0x0016 19 DEC R1
C:0x0017 22 RET
C:0x0018 BBFE07 CJNE R3,#0xFE,C:0022
C:0x001B E3 MOVX A,@R1
C:0x001C F5F0 MOV B(0xF0),A
C:0x001E 09 INC R1
C:0x001F E3 MOVX A,@R1
C:0x0020 19 DEC R1
C:0x0021 22 RET
C:0x0022 8982 MOV DPL(0x82),R1
C:0x0024 8A83 MOV DPH(0x83),R2
C:0x0026 E4 CLR A
C:0x0027 93 MOVC A,@A+DPTR
C:0x0028 F5F0 MOV B(0xF0),A
C:0x002A 7401 MOV A,#0x01
C:0x002C 93 MOVC A,@A+DPTR
C:0x002D 22 RET
此程序功能是:
(1)R3的值等于0x01时,执行如下程序:
C:0x0006 8982 MOV DPL(0x82),R1
C:0x0008 8A83 MOV DPH(0x83),R2
C:0x000A E0 MOVX A,@DPTR
C:0x000B F5F0 MOV B(0xF0),A
C:0x000D A3 INC DPTR
C:0x000E E0 MOVX A,@DPTR
C:0x000F 22 RET
程序功能:读取扩展RAM内的数据并赋值给A,寻址范围0~65535。当数组用xdata定义时如
BGV = (int idata *)0xef;
会跳转到此处。
(2)R3的值小于0x01即等于0x00时,执行如下程序:
C:0x0010 5006 JNC C:0018
C:0x0012 87F0 MOV B(0xF0),@R1
C:0x0014 09 INC R1
C:0x0015 E7 MOV A,@R1
C:0x0016 19 DEC R1
C:0x0017 22 RET
CJNZ操作会影响CY,所以JNC (进位位为0则跳转)
CJNE R3,#0x01,C:0010
上述操作 CJNE R3,#0x01,C:0010 会影响PSW中的借位位,当R3小于#0x01时,CY置1,否则置0.
程序功能:读取单片机内部256字节RAM内的数据并赋值给A,寻址范围0~255。当数组用data或idata定义时,会跳转到此处。如执行BGV = (int idata *)0xef;语句时,即跳转到自处,读取内部RAM地址内的数据。
(3)R3的值不等于0x00或0x01时,通过JNC指令跳转到C:0x0018处,开始与0xFE做比较。R3的值等于0xFE时,执行如下程序:
C:0x0018 BBFE07 CJNE R3,#0xFE,C:0022
C:0x001B E3 MOVX A,@R1
C:0x001C F5F0 MOV B(0xF0),A
C:0x001E 09 INC R1
C:0x001F E3 MOVX A,@R1
C:0x0020 19 DEC R1
C:0x0021 22 RET
程序功能:读取单片机片外RAM内的数据并低位赋值给B,高位赋值给A,寻址范围0~255。当数组用pdata定义时,会跳转到此处。通常8051单片机不使用pdata定义变量或数组。
(4)R3的值不等于0xFE时,即R3的值等于0xFF时,跳转到C:0x0022处执行如下程序:
C:0x0022 8982 MOV DPL(0x82),R1
C:0x0024 8A83 MOV DPH(0x83),R2
C:0x0026 E4 CLR A
C:0x0027 93 MOVC A,@A+DPTR
C:0x0028 F5F0 MOV B(0xF0),A
C:0x002A 7401 MOV A,#0x01
C:0x002C 93 MOVC A,@A+DPTR
C:0x002D 22 RET
程序功能:读取单片机内部ROM内的数据并低位赋值给B,高位赋值给A,寻址范围0~65535。当数组用code定义时,如 BGV = (int code *)0xef;
由此可见,子函数“C?ILDPTR”的作用是,根据数据所在存储空间,用不同的寻址方式读取某地址下的数据。R3用于确定寻址方式,R3的值与对应的寻址方式对应关系为:
1、R3值等于0x00时,片内RAM间接寻址;此时数据用data,idata定义。
2、R3值等于0x01时,片外RAM(扩展RAM)间接寻址;此时数据用xdata定义。
3、R3值等于0xFE时,片外RAM(扩展RAM)低246字节间接寻址;此时数据用pdata定义
4、R3值等于0xFF时,从存储存储器(ROM)进行变址寻址;此时数据用code定义
在Keil C-51编译环境下,指针变量,不管长度是单字节或是双字节,指针变量所占字节数为3字节,R3表示所在存储空间R1和R2表示地址
综上所述,Keil C-51编译环境下,指针是一个占3字节的特殊变量,编译器编译程序时,自动生成判断寻址方式的子函数,并根据根据目标数据所在的物理存储区不同,为指针首字节赋值,根据赋值的不同,进行不同方式的寻址;指针的后2字节,用于存放引用的地址。
回到程序①,使用的是BGV = (int idata *)0xef; 使用的是idata 所以会执行
C:0x0010 5006 JNC C:0018
C:0x0012 87F0 MOV B(0xF0),@R1
C:0x0014 09 INC R1
C:0x0015 E7 MOV A,@R1
C:0x0016 19 DEC R1
C:0x0017 22 RET
程序功能:R1存地址0xEF,MOV B(0xF0),@R1操作后,给R1地址加一变为0xF0,所以疑问二可以读取高低俩个地址。
附录
(1)C?CLDPTR 是操作char指针会调用,与ILDPTR(int 指针)汇编原理类似,不做讨论
如定义 char *BGV1;读取内容可得如下代码
C?CLDPTR:
C:0x00AF BB0106 CJNE R3,#0x01,C:00B8
C:0x00B2 8982 MOV DPL(0x82),R1
C:0x00B4 8A83 MOV DPH(0x83),R2
C:0x00B6 E0 MOVX A,@DPTR
C:0x00B7 22 RET
C:0x00B8 5002 JNC C:00BC
C:0x00BA E7 MOV A,@R1
C:0x00BB 22 RET
C:0x00BC BBFE02 CJNE R3,#0xFE,C:00C1
C:0x00BF E3 MOVX A,@R1
C:0x00C0 22 RET
C:0x00C1 8982 MOV DPL(0x82),R1
C:0x00C3 8A83 MOV DPH(0x83),R2
C:0x00C5 E4 CLR A
C:0x00C6 93 MOVC A,@A+DPTR
C:0x00C7 22 RET
(2)在keil的memory中D:0x0F 表示在ram中的数据,C:0x0F表示在code中的数据
(如单片机内部ram中高128字节,直接寻址是SFRS(特殊功能寄存器),间接寻址是内部数据区,二者物理上是分开的)
C:代码存储空间
D:直接寻址片内存储空间
I :间接寻址片内存储空间
X:扩展的外部RAM空间
(3)for(;;a++,b++) for语句可以加N个++
上一篇:51单片机 | 串口通信实验(模拟串口通信/多机通信实例)
下一篇:手把手教你单片机——串口
- 热门资源推荐
- 热门放大器推荐