浅谈C51之位变量

2019-07-15 17:48发布

本帖最后由 不是盖的 于 2015-2-18 12:34 编辑

      对于从C51入门学习51单片机的初学者来说,对于位变量很多感到疑惑。位变量的定义对应什么内存,其操作特点是什么,跟普通的变量有什么区别。基于此,个人整理归纳发表此帖,表述不当或有误之处,欢迎批评指正。
        要具体了解位变量,我们还得从51内存结构入手,我们以8051为例。
                            1.png       

      在片内,数据存储区RAM与特殊功能寄存器区SFR统一编址。地址00H 到7FH总共128单元是数据存储区RAM,地址80H到FFH总共128单元是特殊功能寄存器区。
       数据存储区RAM128个单元分为3部分
       其一是通用寄存器区,其地址为00H到1FH,共32字节单元。
       其二是位寻址区,其对应的地址是20H到2FH,共16字节单元,我们定义的bit的位变量或者bdata修饰的变量,其分配的内存就是在这16字节的位寻址区,也就是说,我们最多能定义128(8*16)个位变量。
      其三是用户RAM区,其地址为30H到7FH,我们定义的除了bit和bata其他变量,堆栈等都在这80字节单元内存里分配。
      我们这里重点讲一下位寻址区。位寻址区每个单元除了系统统一编排的地址外,如上面的20H到1FH,还为每个位编排位寻址地址,如下图。

                                 2.jpg
        位寻址区第一单元的地址是20H,从其最低位开始位编址。
      即位寻址区第一单元的最低位的位编址是00H,第二位是01H,第三位是02H  .......最高位即第8位是07H。
      同样道理,寻址区第二单元的8个位对应的8个位编址是  08H,09H,0AH,0BH,0CH,0DH,0EH,0FH。如此类推。
      这样,位寻址区的16字节单元,每个字节有他的地址外,每个字节的每个位也有他对应的位编址。我们可以以字节访问,也可以以位为单元进行访问。除了位寻址区的位有位编址外,特殊功能区,凡是地址为8的倍数的特殊功能寄存器其每一位都有位编址。如下图

                                       3.jpg
                                       4.jpg
       P0寄存器的地址是80H,地址是8的倍数,每一位都有他的位编址,最低位为80H,第二位为81H,第三位为82H, 。。。。
        同样的道理,定时器计数控制寄存器Tcon的地址为88H,他的第一位IT0的位编址是88H,第二位IEO的位编址是89H。。。。
我们看可以在reg51.h看到他们相应的位定义。
/*  BIT Register  */
/*  PSW   */
sbit CY   = 0xD7;
sbit AC   = 0xD6;
sbit F0   = 0xD5;
sbit RS1  = 0xD4;
sbit RS0  = 0xD3;
sbit OV   = 0xD2;
sbit P    = 0xD0;
/*  TCON  */
sbit TF1  = 0x8F;
sbit TR1  = 0x8E;
sbit TF0  = 0x8D;
sbit TR0  = 0x8C;
sbit IE1  = 0x8B;
sbit IT1  = 0x8A;
sbit IE0  = 0x89;
sbit IT0  = 0x88;
/*  IE   */
sbit EA   = 0xAF;
sbit ES   = 0xAC;
sbit ET1  = 0xAB;
sbit EX1  = 0xAA;
sbit ET0  = 0xA9;
sbit EX0  = 0xA8;
/*  IP   */
sbit PS   = 0xBC;
sbit PT1  = 0xBB;
sbit PX1  = 0xBA;
sbit PT0  = 0xB9;
sbit PX0  = 0xB8;
/*  P3  */
sbit RD   = 0xB7;
sbit WR   = 0xB6;
sbit T1   = 0xB5;
sbit T0   = 0xB4;
sbit INT1 = 0xB3;
sbit INT0 = 0xB2;
sbit TXD  = 0xB1;
sbit RXD  = 0xB0;
/*  SCON  */
sbit SM0  = 0x9F;
sbit SM1  = 0x9E;
sbit SM2  = 0x9D;
sbit REN  = 0x9C;
sbit TB8  = 0x9B;
sbit RB8  = 0x9A;
sbit ti   = 0x99;
sbit RI   = 0x98;
     说到这里,总结就一句话,位寻址区与地址为8倍数的特殊功能寄存器的每个字节单元有地址外,每个字节的每一位也有他的位编址。
我们可以以字节为单元进行访问,也可以以1位为单元进行访问。接下来我们来讲位变量操作和他的优点。
     在C51中用bit 和sbit定义位变量,bit 定义的变量是由编译器分配的,如果你想通过该位变量操作特定的内存,就可以用sbit,如我们re g51.h中定义的sbit TF1  = 0x8F;  0x8F就是位编址,通过TF1就能访问0x8F这个位单元。或者我们经常用的
sbit LED =P0^0; 我们编写一段代码帮助理解一下。

                                     代码.jpg
         看一下他对应的汇编,没学过汇编的同学大概了解一下。
                                  汇编.jpg                   

      从汇编代码我们可以知道,bdata 类型的变量bd系统分配的内存单元是20H,bit1分配的单元是21H的第一位,bit2分配的内存单元是21H的第二位,我们通过bd0,bd1访问变量bd的第一位和第二位。代码运行之后,我们查看其内存变化结果。
                               内存.jpg
       大家可以看得到,0x20单元的结果为0XFC,0x21单元运行完之后的结果是0X03,大家自己去理解解释,结果是验证我们之前的论述的。
      那么,位变量优点何在。位变量可以高效操作一个位单元。 如下代码

                                  LED.jpg
      很简单,就一条单周期的指令就完成了。
      如果是普通变量,我们想把第一位置1,怎么做,如下代码
                           普通变量.jpg
       我们查看一下他对应的汇编。
                         普通汇编.jpg       
       普通变量实现单独操作某一位,是要读改写三步实现的。其代码效率与运行效率都远不及位变量操作。   
          运用技巧:在编程中需要诸多标志位,比如8个,一种办法是定义8个unsigned char变量,这个办法简单,但比较笨,也耗内存,运行效率也不高,比如你要操作多个标志,就得一个个去操作。 其二是定义一个unsingned char 变量,8个位每一个位对应一个标志,用或与操作。而对于51这种有位寻址的单片机,自然是首选位操作,简洁又高效。当然,他的缺点也是很明显,移植不便。个人见解,表述不当或有误之处,欢迎批评指正。谢谢!!!!!














   


     

                                      


               
         








LED汇编.jpg
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
2条回答
xouou
1楼-- · 2019-07-15 21:59
 精彩回答 2  元偷偷看……
不是盖的
2楼-- · 2019-07-15 23:15
本帖最后由 不是盖的 于 2015-2-19 12:06 编辑
xouou 发表于 2015-2-18 18:16
#ifndef _C51
#define _bit      unsigned char
#else


#ifndef _C51
typedef    unsigned char   bit
#endif
这样比较简洁吧

一周热门 更多>