“reg51.h”头文件详解北方蓝芯科技()我们在学习单片机时,在程序的开始都会包含一个头文件“reg51.h”,初学者一般都对该文件存在一些疑惑。例如在我们实验教程第一个实验“点亮一个发光二极管”中,程序如下:#includereg51.h//包含头文件sbitled=P1^0;//表示用led等效于P1^0,//P1^0就是指头文件里定义的P1寄存器的第0BITvoidmain()//主函数{led=0;//低电平驱动发光二极管while(1)//进入while死循环{}}我们可以看到,程序的第一行便是一个“文件包含”处理。所谓“文件包含”是指一个文件将另外一个文件的内容全部包含进来,这个程序中包含REG51.h头文件的目的是为了要使用P1这个符号,即通知C编译器,程序中所写的P1是指80C51单片机的P1端口而不是其它变量。这是为什么呢?我们可以将鼠标放到包含头文件这行,点击鼠标右键打开REG51.h文件,我们可以看到以下内容。/*BYTERegister*///特殊功能寄存器定义(字节)sfrP0=0x80;//P0口地址定义sfrP1=0x90;//P1口地址定义sfrP2=0xA0;//P2口地址定义sfrP3=0xB0;//P3口地址定义sfrPSW=0xD0;//程序状态字,具体位意义见位定义sfrACC=0xE0;//累加器,程序员最常用的sfrB=0xF0;//寄存器,主要用于乘除sfrSP=0x81;//堆栈指针,初始化为07;先加1后压栈,先出栈再减1,sfrDPL=0x82;//DPTR寄存器的低八位sfrDPH=0x83;//DPTR寄存器的高八位sfrPCON=0x87;//电源控制寄存器,最高位为SMOD位sfrTCON=0x88;//Timer/Counter控制寄存器sfrTMOD=0x89;//Timer/Counter方式控制寄存器sfrTL0=0x8A;//定时器0低8位sfrTL1=0x8B;//定时器1低8位sfrTH0=0x8C;//定时器0高8位sfrTH1=0x8D;//定时器1高8位sfrIE=0xA8;//中断控制寄存器sfrIP=0xB8;//中断优先级控制寄存器sfrSCON=0x98;//串口控制寄存器sfrSBUF=0x99;//串口缓冲寄存器/*BITRegister*///位地址寄存器/*PSW*/sbitCY=0xD7;//进位或借位,有就是1,没有就是0sbitAC=0xD6;//辅助进借位sbitF0=0xD5;//没有具体用途,可以由用户决定他的意义sbitRS1=0xD4;//工作寄存器选择位sbitRS0=0xD3;//工作寄存器选择位sbitOV=0xD2;//over!溢出,有是1,没有是0sbitP=0xD0;//奇偶校验,奇数个1是1/*TCON*/sbitTF1=0x8F;//T1溢出中断申请标志sbitTR1=0x8E;//Timer1running,sbitTF0=0x8D;//T0溢出中断申请标志sbitTR0=0x8C;//把上面两个1换成0sbitIE1=0x8B;//外中断1请求标志sbitIT1=0x8A;//外中断1触发方式sbitIE0=0x89;//外中断0请求标志sbitIT0=0x88;//外中断0触发方式/*IE*/sbitEA=0xAF;//使能全部中断sbitES=0xAC;//串口中断使能位sbitET1=0xAB;//定时器1使能位sbitEX1=0xAA;//外中断1使能位sbitET0=0xA9;//定时器0使能位sbitEX0=0xA8;//外中断1使能位/*IP*/sbitPS=0xBC;//串行中断优先级sbitPT1=0xBB;//T1优先级sbitPX1=0xBA;//外部中断1优先级sbitPT0=0xB9;//T0优先级sbitPX0=0xB8;//外部中断0优先级/*P3*///控制寄存器sbitRD=0xB7;//读sbitWR=0xB6;//写sbitT1=0xB5;//T/C1sbitT0=0xB4;//T/C0sbitINT1=0xB3;//外中断1sbitINT0=0xB2;//外中断0sbitTXD=0xB1;//串行发送sbitRXD=0xB0;//串行接收/*SCON*/sbitSM0=0x9F;//sbitSM1=0x9E;//串口工作方式sbitSM2=0x9D;//什么鬼特征位,要用查书,或者等我以后解释,啊哈sbitREN=0x9C;//串行接收允许sbitTB8=0x9B;//收到的第九位sbitRB8=0x9A;//要发的第九位sbitTI=0x99;//哇,熟悉吧,发送完成中断标志sbitRI=0x98;//接收完成中断标志当然,注释是加上去的,这里都是一些符号的定义,即规定符号名与地址的对应关系。下面理解一下sfr和sbit这两个符号:1)sfr注意到sfrP0=0x80;这一行,就是定义P0与地址0x80对应,P0口的地址就是0x80sfr这个词并不是标准C语言的关键字,而是Keil为能直接访问80C51中的SFR(特殊功能寄存器)而提供了一个新的关键词,其用法是:sfrt变量名=地址值。2)sbit注意到sbitEA=0xAF;这一行,就是定义EA与地址0xAF对应,EA中断使能这一位的地址就是0xaf。关于sbit,也不是标准的C关键字。而是Keil为能直接访问80C51寄存器而提供了一个新的关键词,其用法是:sbitX=A^n。其中A是一个可位寻址的变量,而n表示该变量的第几位,而X就是一个位变量,它就是A中的第n位。这里的符号^已经不再是标准C语言中的异或操作符了,这里有它自己独特的意思,只能是这样的写法。例如:sbitP15=P1^5;就是定义用符号P15来表示P1.5引脚,如果你愿意也可以用其它名字,只要下面程序中也随之更改就行了。另外,在培训过程中,发现有不少学生对上面定义存在这样一个疑惑,看下面两行sfrSP=0x81;sbitP0_1=0x81;//P0^1=0x81;这两行共用一个地址,岂不冲突了。解答如下:当然不会冲突,sfr跟sbit是两个不同的意义,sfr是给一个字节的地址起一个变量名,传给变量名的是该字节的首地址,如sfrP0=0x80,P0(8位IO口)已经代表了0x80到0x87整整8位的地址;而sbit定义的仅仅是一个位,如P0_1=0x80,P0_2=0x81„„P0_7=0x87,他们是P0的具体表现,即是给0x80到0x87各起一个变量名。编译器会根据sfr和sbit两个指令来分辨出0x80到底代表的是一个字节的首地址还是一个位。举个通俗一点的例子:假设一果园有很多果树,编号分别从1-100,然后每棵果树上又有很多果子,果子编号也分别从1-100,这时,果树的编号为8和果子编号8一样吗?字节地址和位地址意思和这相似。