51头文件reg51.h详解

我们在用c语言编程时往往第一行就是头文件,51单片机为reg51.h或reg52.h,51单片机相对来说比较简单,头文件里面内容不多,像飞思卡尔、ARM系列的单片机头文件往往内容就非常多,尽管如此,对一些初次接触单片机的朋友来说,51的头文件还是搞不太清楚,今天具体来说明一下。

寄存器地址及位地址声明的原因

reg51.h里面主要是一些特殊功能寄存器的地址声明,对可以位寻址的,还包括一些位地址的声明,如果如sfr P1=0x80; sfr IE=0xA8;sbit EA=0xAF等。 sfr P1 = 0x90这句话表示:P1口所对应的特殊功能寄存器P1在内存中的地址为0x80,sbit EA=0xAF这句话表示EA这一位的地址为0xAF。

注意这里出现了一个使用很频繁的sfr和sbit。 sfr 表示特殊功能寄存器的意思,它并非标准C语言的关键字,而是Keil 为能直接访问80C51中的SFR 而提供了一个新的关键词,其用法是:sfr 特殊功能寄存器名=地址值(注意对于头文件里“特殊功能寄存器名”,用户实际上也可以修改的,如P1=0 x80,也可改为A1=0x80,但sfr 和地址值则不能更改,否者会编译出错。)

sbit 表示位的意思,它也是非标准C 语言的关键字,编写程序时如需操作寄存器的某一位(可位寻址的寄存器才能用)时,需定义一个位变量,此时就要要到sbit,如sbit deng=P1^0,sbit EA = 0xAF;需要注意的是,位定义时有些特殊, 用法有三种:

第一种方法:sbit 位变量名=寄存器位地址值

第二种方法:sbit 位变量名=SFR 名称^寄存器位值(0-7)

第三种方法:sbit 位变量名=SFR 地址值^寄存器位值

具体内容如下:

/*--------------------------------------------------------------------------
REG51.H             //REG 就是 Register(寄存器)的意思,对51单片机的操作就是对寄存器的操作

Header file for generic 80C51 and 80C31 microcontroller.
Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
All rights reserved.
--------------------------------------------------------------------------------------------

51单片机是8位地址的,用十六进制来表示就是两位十六进制数,所以下面看到的都是两位十六进制的地址

关于位寻址及操作,有个简便方法判断,将字节地址换成10进制后能否被“8”整除,能被“8”整除的就
能进行位操作,不能被“8”整除就不能,如P1地址为90H,10进制为144 144/8=18,能被整除,所以可以位
操作。再如TMOD地址为89H, 10进制为137 137/8=17.125,不能被整除,所以不可以位操作。

--------------------------------------------------------------------------------------------*/

#ifndef __REG51_H__ //如果没有定义__REG51_H__,那么定义它
#define __REG51_H__

/*  BYTE Register  */ 

/*  -------------------------------------------------
   sfr 是 special function register,特殊功能寄存器  
    -------------------------------------------------*/

sfr P0   = 0x80;    // P0口
sfr P1   = 0x90;    // P1口
sfr P2   = 0xA0;    // P2口
sfr P3   = 0xB0;    // P3口
sfr PSW  = 0xD0;    // Program Status Word,程序状态字
sfr ACC  = 0xE0;    // 累加器
sfr B    = 0xF0;    // 乘除法辅助寄存器
sfr SP   = 0x81;    // Stack Point,堆栈指针
sfr DPL  = 0x82;    // 数据指针(低8位)
sfr DPH  = 0x83;    // 数据指针(高8位)
sfr PCON = 0x87;    // Power Control,电源控制和波特率选择
sfr TCON = 0x88;    // Timer Controller  定时器控制
sfr TMOD = 0x89;    // Timer Mode    定时器方式控制寄存器,不可寻址
sfr TL0  = 0x8A;    // 定时器0低8位
sfr TL1  = 0x8B;    // 定时器1低8位
sfr TH0  = 0x8C;    // 定时器0高8位
sfr TH1  = 0x8D;    // 定时器1高8位
sfr IE   = 0xA8;    // Interrupt Enable  中断使能
sfr IP   = 0xB8;    // Interrupt Priority  中断优先级控制
sfr SCON = 0x98;    // Seriel Controller 串行口控制寄存器,监视和控制51 芯片串行口的工作状态
sfr SBUF = 0x99;    // Serial Buffer,串行数据收/发缓冲器


/*  BIT Register  */


/*  PSW     Program Status Word   程序状态字  */

/* ---------------------------------------------------------------------------------------------
    sbit定义特殊功能寄存器的位变量,映射到IO口(P1^1这种IO口的“位”)
    bit和int char差不多,只不过char=8位, bit=1位而已。都是变量,编译器在编译过程中分配地址。
    除非指定,否则这个地址是随机分配的。这个地址是整个可寻址空间,RAM+FLASH+扩展空间。bit只
    有0和1两种值,和Windows下VC中的BOOL类似。
   ---------------------------------------------------------------------------------------------*/

sbit CY   = 0xD7;   /* PSW.7,carry,进位标志,在执行加减运算指令时,如果运算结果的最高位(D7)
               发生了进位或借位,则CY由硬件自动置1。*/
sbit AC   = 0xD6;   /* PSW.6,assistant carry,半进位标志位,也称为辅助标志位。在执行加减运算指令时,如
               果运算结果的低半字节(D3)发生了向高半字节进位或借位,则AC由硬件自动置1。*/    
sbit F0   = 0xD5;   /* PSW.5,用户标志位。用户可以根据需要对F0、F1赋予一定的含义,由用户置1和清0,作为软件标 

               志。 */
sbit RS1  = 0xD4;   /* PSW.4,工作寄存器组选择控制位。通过对这两位设定,可以从4个工作寄存器组中选择一组作为当   

                   前工作寄存器。 */
sbit RS0  = 0xD3;   // PSW.3
sbit OV   = 0xD2;   /* PSW.2,overflow,溢出标志位,有两种情况影响该位。一是执行加减运算时,如果D7或
               D6任一位,并且只一位发生了进位或借位,则OV自动置1 */
/* sbit F1 = 0xD1 */    //这个原来的头文件是没有的,自己加上去的,和 F0 作用一样
sbit P    = 0xD0;   /* PSW.1,奇偶标志位。每条指令执行完后,该位都会指示当前累加器A中1的个数。如果A中有奇数       

                       个1,则P自动置1。*/

/*  TCON    Timer Controller  定时器控制  */

sbit TF1  = 0x8F;   // Timer1 Flag,T1中断标志位
sbit TR1  = 0x8E;   // Timer1 Run,T1运行控制位
sbit TF0  = 0x8D;   // Timer0 Flag,T0中断标志位
sbit TR0  = 0x8C;   // Timer0 Run,T0运行控制位
sbit IE1  = 0x8B;   // Interrupt1 Exterior,外部中断1中断标志位
sbit IT1  = 0x8A;   // Interrupt1 Touch,外部中断1 触发方式选择位
sbit IE0  = 0x89;   // Interrupt0 Exterior,外部中断0中断标志位
sbit IT0  = 0x88;   // Interrupt0 Touch,外部中断0触发方式选择位

/*  IE      Interrupt Enable  中断使能  */

sbit EA   = 0xAF;   // IE.7,Enable All Interrupt,中断总允许位
sbit ES   = 0xAC;   // IE.4,Enable Serial,串行口中断允许位 
sbit ET1  = 0xAB;   // IE.3,Enable Timer 1,T1中断允许位
sbit EX1  = 0xAA;   // IE.2, Enable Exterior 1,外部中断1中断允许位
sbit ET0  = 0xA9;   // IE.1,Enable Timer 0,T0中断允许位
sbit EX0  = 0xA8;   // IE.0,Enable Exterior 0,外部中断0中断允许位

/*  IP      Interrupt Priority  中断优先级控制  */ 

sbit PS   = 0xBC;   // IP.4,Priority Serial    串口优先级标志位
sbit PT1  = 0xBB;   // IP.3,Priority Timer 1    定时器1优先级标志位
sbit PX1  = 0xBA;   // IP.2,Priority Exterior 1    外部中断1优先级标志位
sbit PT0  = 0xB9;   // IP.1,Priority Timer 0    定时器0优先级标志位
sbit PX0  = 0xB8;   // IP.0,Priority Exterior 0    外部中断0优先级标志位

/*  P3  */

sbit RD   = 0xB7;   // Read Data,读数据
sbit WR   = 0xB6;   // Write Data,写数据
sbit T1   = 0xB5;   // Timer 1,定时器1,由TMOD的高四位控制
sbit T0   = 0xB4;   // Timer 0,定时器0,由TMOD的低四位控制
sbit INT1 = 0xB3;   // Interrupt 1,中断1
sbit INT0 = 0xB2;   // Interrupt 0,中断0
sbit TXD  = 0xB1;   // Receive Data,串口接收端
sbit RXD  = 0xB0;   // Transmit Data,串口发送端

/*  SCON    Seriel Controller 串行口控制  */

sbit SM0  = 0x9F;   // SM0和SM1组成4种工作方式,对应有不同特性
sbit SM1  = 0x9E;   //
sbit SM2  = 0x9D;   /* 多机通信控制位。多机通信是工作于方式2和方式3,SM2位主要用于方式2和方式3。
               接收状态,当串行口工作于方式2或3,以及SM2=1时,只有当接收到第9位数据(RB8)
               为1时,才把接收到的前8位数据送入SBUF,且置位RI发出中断申请,否则会将接受
               到的数据放弃。当SM2=0时,就不管第位数据是0还是1,都难得数据送入SBUF,并发
               出中断申请。工作于方式0时,SM2必须为0。*/
sbit REN  = 0x9C;   // Receive Enable,使能接收
sbit TB8  = 0x9B;   // 发送接收数据位8
sbit RB8  = 0x9A;   // 接收数据位8
sbit TI   = 0x99;   // 发送中断标志位
sbit RI   = 0x98;   // 接收中断标志位

#endif

bit与sfr用法类似,只是sbit是位操作,用于将某个sfr中具体位赋值给一个变量,这样后面程序就可用通过该变量为该位清0或置1。
 

sfr用于将一个单片机的特殊功能寄存器(special function register)赋值给一个变量,这样在后面的程序中就可以中这个变量指引(refer to)该寄存器。

sbit与sfr用法类似,只是sbit是位操作,用于将某个sfr中具体位赋值给一个变量,这样后面程序就可用通过该变量为该位清0或置1。

STC该系列单片机的特殊功能寄存器布局如下:

6597809737983524400.gif

看过上图这么多特殊功能寄存器之后可能会产生一些困扰,我们用sfr P0 = 0×80表示P0,用sfr SP = 0×81表示SP,这个没有歧义。

有困扰的是:假如用sbit P0_1 = 0×81表示P0口的第一位,那么我想表示SP寄存器的第0位怎么办呢?如果也是定义成sbit SP_0 = 0×81那么明显会有二义性,编译器理解不了。其实这个问题是不存在的,从图1中可以看出,SFR又可以分为两个区域:可位寻址区和不可位寻址区。可位寻址区的寄存器地址能够被8整除,而不可位寻址区的寄存器地址不满足这一要求。因此例子中的sbit SP_0 = 0×81对于SP寄存器这是无效的应该写成sfr SP=0x81。

例如:sbit P0^1=0x81;sfr SP=0x81;

它们虽然都引用了同一个地址0×81,但是对于编译器来说,这两者的含义完全不同,前者因为有sbit关键字,所以是位寻址。后者因为是sfr关键字,所以是字节地址,表示的是一个特殊功能寄存器赋值。

51单片机一般直接操作寄存器(很少会用到指针;难道用的是直接寻址?具体待查阅)。

  • 6
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值