编译工具:MPLAB X IDE v4.15
单片机型号:PIC16F1938
MPLAB开发环境中,包含各种PIC系列单片机的头文件,我在理解头文件中关于寄存器位地址定义时绕了些弯路,所以特意写出来加强记忆。
以LATA寄存器为例:在pic16f1938.h头文件中,关于LATA寄存器的定义如下
// Register: LATA
volatile unsigned char LATA @ 0x10C;
// bit and bitfield definitions
volatile bit LATA0 @ ((unsigned)&LATA*8)+0;
volatile bit LATA1 @ ((unsigned)&LATA*8)+1;
volatile bit LATA2 @ ((unsigned)&LATA*8)+2;
volatile bit LATA3 @ ((unsigned)&LATA*8)+3;
volatile bit LATA4 @ ((unsigned)&LATA*8)+4;
volatile bit LATA5 @ ((unsigned)&LATA*8)+5;
volatile bit LATA6 @ ((unsigned)&LATA*8)+6;
volatile bit LATA7 @ ((unsigned)&LATA*8)+7;
一、代码解析
1. “@”符号
在很多嵌入式编译环境中,"@"符号表示“将符号左边的变量钳制在符号右边的地址” 。
C语言中本来是没有“@”符号的,但在MPLAB编译环境里,“@”相当于汇编中的“EQU”伪指令,即
C语言代码:
LATA @ 0x10C
等价于汇编指令:
LATA EQU 0x10C
用自然语言表述,就是:char型变量LATA的值,存放在字节地址为“0x10C”的内存空间。
2. “LATA0 @ ((unsigned)&LATA*8)+0”语句
① 在C语言中,“unsigned”是“unsigned int”的简写, 在这句代码中的作用是强制类型转换,即:将“&LATA*8”的结果强制类型转换为无符号整型;
② “&LATA*8”语句,由于取地址符“&”的优先级高于乘号“*”,所以这句代码的意思是:取LATA的地址“0x10C”,并将这个值乘以8。从二进制角度来看,就是将“00 0001 0000 1100”左移3位。(其中的二进制数,是由“0x10C”转换而来,由于PIC16F1938的地址总线宽度是14位的,所以该二进制数只能有14位。) 左移之后,结果是“00 1000 0110 0000”(0x860);
于是,“((unsigned)&LATA*8)+0”语句的运算结果就是“0x860”。
用自然语言表述该语句的执行结果:bit型变量LATA0的值,存放在位地址为“0x860”的内存空间。
二、验证
接下来,就该验证一下LATA0的位地址是不是“0x860”了。
既然已经知道了LATA寄存器的字节地址是0x10C,那只要计算一下它的位地址就好:
十六进制(0x10C)—> 十进制(268)
十进制(268 × 8 = 2144) —> 十六进制(0x860)
即LATA0的位地址是“0x860”,和代码的执行结果一致。
至此,位地址定义代码解析结束,重点是要了解位地址的计算方法。