51单片机学习过程中的常见疑惑

一、什么是51单片机?AT89C51、STC89C51、BF7615BM28这些都是51单片机吗?

        答:51单片机是兼容Intel 8051指令系统的单片机的总称,与具体生产厂商和单片机型号没有直接关联。上述单片机都使用了Intel 8051指令系统(含自主增加指令的增强型),所以都是51单片机。

二、MCS-51和8051是否是相同的意思?

答:MCS是Intel公司单片机的系列符号,有MCS-48、MCS-51、MCS-96等系列,而经典的MCS-51系列包含三个基本型80C31、8051、8751,以及对应的低功耗型号80C31、8051、87C51,因而MCS-51特指Intel的这几种型号。由于2007年后Intel停止了MCS系列单片机的生产,所以准确来说,后面其他厂商生产的AT89C51等单片机不属于MCS-51系列。

        8051一般是指Intel 8051指令系统(指令集),只要单片机仍使用Intel 8051指令系统,那么仍可称为8051单片机,简称51单片机。

---参考资料《MCS51和8051是否相同?》

三、8051经典内部结构是怎样的?

 四、AT89C51是51单片机,那么AT89C52是52单片机吗?

        答:不是,51单片机是指使用了Intel 8051指令系统(指令集)的单片机,一般没有52单片机的说法。之所以存在AT89C52这一型号的单片机,是因为在早期AT89C51单片机的基础上额外增加了一个定时器/计数器T2,并且升级了RAM和ROM的内存,所以AT89C52可以视作为AT89C51的强化版。

 五、学生时代,国内常见的51单片机为STC公司产的STC89C52RC,编程时需要注意什么?

        答:STC89C52RC是STC(宏晶科技)公司基于8051内核推出的一款51单片机,编程前需要通过STC推出的ISP下载软件将器件包注入Keil软件安装目录下,准确选择单片机型号。

        当然,由于都使用了8051指令系统,单片机型号选择为AT89C52也可以编译,但是STC多出的部分特殊功能寄存器无法直接使用(头文件未声明部分寄存器),需要自行使用SFR声明。

 六、时常看见程序开头有内置头文件,#include<REG51.h>和#include<REG52.h>有何不同?

        答:其实头文件中写的很明白,相关描述如下:

        REG51.h:Header file for generic 80C51 and 80C31 microcontroller.

        REG52.h:Header file for generic 80C52 and 80C32 microcontroller.

        通过WinMerge对比分析这两个文件,我们可以清晰地发现    REG52.h在REG51.h的基础上增加了对定时器/计数器T2相关寄存器的声明。也就是说,如果在程序中使用了定时器/计数器T2相关寄存器,#include<REG51.h>时就需要自行对相关寄存器声明,否则编译器就会报错。头文件REG52.h中已经对相关寄存器做出声明,在程序中可直接使用。

 七、#include<REG51.h>和#include"REG52.h"有何不同?

        答:尖括号包含的头文件是编译器自带的头文件,这一类文件通常放在编译器安装目录下。英文双引号包含的头文件一般是自己编写的头文件,通常放在工程文件目录下,当程序编译时找不到该文件时也会到编译器安装目录下找一遍,但是还是建议按照规范编程。

 八、为什么有时候程序中看不到#include<REG51.h>或#include"REG52.h",这样的程序也可以运行吗?

        答:头文件不是必要的,如果不嫌麻烦,在程序中自行声明自己用到的寄存器也可以。

 九、为什么有时候程序中会见到#include <STC89C5xRC.H>,却没有#include<REG52.h>?

        答:STC89C5xRC.H其实是STC(宏晶科技)自己在REG51F.H的基础上增添了部分自行设计的特殊功能寄存器,内置STC89C5xRC.H时就无需再声明STC自行增添的寄存器。简单来说,REG51F.H是STC89C5xRC.H的真子集。

 十、如果厂商对每一款单片机都有定义头文件,但是我不知道名字该如何添加到程序中呢?

        答:其实只需在程序中单击右键,就能看到插入头文件的相关提示了。 

十一、新建工程时,会有提示将标准8051启动文件代码到工程中,这个是必要的文件吗?

        答:是的,单片机上电时候一般需要对堆栈、引脚等初始化,这些都需要依靠使用汇编编写的启动代码来执行。

11.1 启动文件添加提示
11.2 缺失启动文件生成的汇编指令
11.3 添加启动文件生成的汇编指令

 十二、源文件底下的头文件是如何添加进去的呢?

        答:在源文件中使用#include"xxx.h"就可以添加进去,不过在编译之前得让编译器知道这个头文件在哪儿,这就需要添加头文件路径,方式如图12.1所示:

12.1 添加头文件路径

         注:使用编译器自带的头文件(即:#include<xxx.h>)无需执行此操作。

  十三、sfr、sfr16、sbit 这3个关键字作用是什么?

        答:sfr、sfr16、sbit 这3个关键字并不属于C99规范,只在Keil C51中可以使用。研究过8051存储结构的都知道,8051特殊功能寄存器和内部RAM区的0x80~0xff共用相同的地址(但是物理存储单元各自独立),这在执行读写时就需要通过寻址方式做出区分。根据规定,特殊功能寄存器读写使用直接寻址(部分可位寻址),内部RAM区的0x80~0xff只能使用间接寻址。

13.1 存储结构

        sfr、sfr16、sbit 这3个关键字就承担起特殊功能寄存器区变量的声明,sfr用于声明8位变量,sfr声明16位变量,sbit用于声明位变量。特殊功能寄存器中,地址为8的整数倍的变量支持位寻址(如:0x80、0x88),也就是说支持用sbit声明位变量,具体如图13.2所示。

13.2 位寻址区

   十四、sbit 和bit有什么不同之处?

         答:sbit是用于对支持位寻址的特殊功能寄存器变量进行声明的,bit则是用于定义位变量的,定义的位变量存储在内部通用RAM区(内部RAM地址址区(0x20~0x2f)支持位寻址)。如果还不理解,下面通过生成的汇编指令解答疑惑。

sbit 常用用法:

C语言:sbit P0_0 = P0^0;        P0_0=1;//P0已通过sfr声明,其地址为0x80
汇编指令:SETB     P0_0(0x80.0)

sbit 常用用法:

C语言:bit P0_0;    P0_0=1;//为了演示效果,变量特意重名
汇编指令:SETB     P0_0(0x20.0)

        可以看出,bit定义的变量存储在低128字节内部RAM中(地址0x20.0,注意.0不可忽视),sbit声明的变量存储在SFRs区且地址为8的整数倍(如示例中的0x80)。

        为了验证sbit只能在地址为8的整数倍的SFRs区声明,下面通过实际具体加以验证。通过图13.3可知,基地址确实不能任意给定。

14.1 sbit基地址报错

    十五、可以通过指针访问特殊功能寄存器区吗?

        答:我试了一下,结果是不可以。不排除有其他办法,欢迎批评指正。

相关代码对比如下:

15.1使用指针变量访问时:

C语言:unsigned char *P0=0x80;*P0=0x0C;
汇编指令:    
//    12:         unsigned char *P0=0x80; 
C:0x0003    7B00     MOV      R3,#0x00
C:0x0005    7A00     MOV      R2,#0x00
C:0x0007    7980     MOV      R1,#P0(0x80)
C:0x0009    8B08     MOV      0x08,R3
C:0x000B    8A09     MOV      0x09,R2
C:0x000D    890A     MOV      0x0A,R1
//    13:         *P0=0x0C; 
C:0x000F    AB08     MOV      R3,0x08
C:0x0011    AA09     MOV      R2,0x09
C:0x0013    A90A     MOV      R1,0x0A
C:0x0015    740C     MOV      A,#0x0C
C:0x0017    120020   LCALL    C?CSTPTR(C:0020)

                 C?CSTPTR:
C:0x0020    BB0106   CJNE     R3,#0x01,C:0029
C:0x0023    8982     MOV      DPL(0x82),R1
C:0x0025    8A83     MOV      DPH(0x83),R2
C:0x0027    F0       MOVX     @DPTR,A
C:0x0028    22       RET      
C:0x0029    5002     JNC      C:002D
C:0x002B    F7       MOV      @R1,A
C:0x002C    22       RET      
C:0x002D    BBFE01   CJNE     R3,#0xFE,C:0031
C:0x0030    F3       MOVX     @R1,A
C:0x0031    22       RET           

15.2使用SFR访问时:

C语言:sfr P0 = 0x80;  P0 = 0x0c;
汇编指令:
//    12:         P0=0x0C; 
C:0x000F    75800C   MOV      P0(0x80),#0x0C    

15.3内置ABSACC.H,使用绝对地址访问时:

头文件部分:
#define CBYTE ((unsigned char volatile code  *) 0)
#define DBYTE ((unsigned char volatile data  *) 0)
#if !defined (__CX2__)
#define PBYTE ((unsigned char volatile pdata *) 0)
#endif
#define XBYTE ((unsigned char volatile xdata *) 0)

#define CWORD ((unsigned int volatile code  *) 0)
#define DWORD ((unsigned int volatile data  *) 0)
#if !defined (__CX2__)
#define PWORD ((unsigned int volatile pdata *) 0)
#endif

C语言用户代码:
DBYTE[0x80]=0x0c;

其实没有验证的必要,code指向代码FLASH区,data指向通用RAM区(0x00~0xff),
xdata指向片内拓展通用RAM区(0x0000~0xffff),pdata指向片外拓展64K内存区,都不指向SFRs

    十六、可以在多处使用sfr对特殊功能寄存器声明吗?

        答:不可以,会提示重复定义( redefinition)。

    十七、sbit对特殊功能寄存器声明时为何存在多种写法?

        答:解释如下,常见的写法如下:

方式1:sbit P0_2 = P0^2;        //前提:P0已通过sfr声明
方式2:sbit P0_2 = 0x80^2;      //0x80就是特殊功能寄存器中支持位寻址的寄存器
方式3:sbit P0_2 = 0x82;        //此0x82为直接寻址中的位地址,需要和直接寻址中的字节地址区分开

注:^ 叫异或,可以了解一下他的运算规则

    十八、51单片机支持DEBUG(仿真)吗?

        答:支持。keil C51支持虚拟仿真(simulator)和实物仿真,STC的IAP系列还能抛开仿真器进行片上仿真,实际方法见其他博主的《宏晶STC单片机片上仿真法》

    十九、Keil C51中相较于C99标准,多出哪些扩展关键词?

        答:多出部分如下表所示:

_at_  alien  bdata     bit     code   compac     data
far   idata  interrupt  large   pdata   _priority_   reentrant
sbit   sfr    sfr16     small  _task_  usingxdata

------参考资料《KeilC51基本关键字》

    二十、Keil C51中可以观察程序的运行时间嘛?

        答:可以,在仿真模式下观察Register一栏中sec的变化量(单位为秒)即可。

二十一、Keil C51中可以观察引脚电平的变化嘛?

        答:可以,在仿真模式下,右击变量名称,将需要观察的变量添加到逻辑分析仪即可。

         配置好要查看的变量名称、显示类型、数值范围、位于操作、左移位数,点击程序运行按钮即可观察到变量变化情况。

二十二、Keil C51中可以观察变量变化情况嘛?

        答:可以,在仿真模式下,将需要查看的变量添加到watch窗口即可。

二十二、可以查看某个地址下面的具体值嘛?

        答:可以,通过Memory窗口查看,根据查看的物理地址分区不同,需要输入的前缀也不同。

代码区(CODE)输入C:绝对地址(如:C:0X20)
低128字节通用RAM区(DATA)输入D:绝对地址(如:D:0X20)
高128字节通用RAM区(IDATA)输入I:绝对地址(如:I:0X80)
内部扩展1024字节通用RAM区(XDATA)输入X:绝对地址(如:X:0X80)

二十三、使用位段(位域)操作和使用为变量实现原理有何不同?

23.1位域实现位操作:

C语言:
#include <STC89C5xRC.H>
#include<absacc.h>

union BYTE
{
	unsigned char byte;
	struct 
	{
		unsigned char bit0:1;
		unsigned char bit1:1;
		unsigned char bit2:1;
		unsigned char bit3:1;
		unsigned char bit4:1;
		unsigned char bit5:1;
		unsigned char bit6:1;
		unsigned char bit7:1;
	}BIT;
};
 
int main()
{
	union BYTE data value;
	value.BIT.bit0 = 1;		  

	return 0;
}
汇编代码:
   126: ?C_STARTUP:     LJMP    STARTUP1 
   127:  
   128:                 RSEG    ?C_C51STARTUP 
   129:  
   130: STARTUP1: 
   131:  
   132: IF IDATALEN <> 0 
C:0x0000    020003   LJMP     STARTUP1(C:0003)
   133:                 MOV     R0,#IDATALEN - 1 
C:0x0003    787F     MOV      R0,#0x7F
   134:                 CLR     A 
C:0x0005    E4       CLR      A
   135: IDATALOOP:      MOV     @R0,A 
C:0x0006    F6       MOV      @R0,A
   136:                 DJNZ    R0,IDATALOOP 
C:0x0007    D8FD     DJNZ     R0,IDATALOOP(C:0006)
   185:                 MOV     SP,#?STACK-1 
   186:  
   187: ; This code is required if you use L51_BANK.A51 with Banking Mode 4 
   188: ;<h> Code Banking 
   189: ; <q> Select Bank 0 for L51_BANK.A51 Mode 4 
   190: #if 0    
   191: ;     <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4. 
   192: EXTRN CODE (?B_SWITCH0) 
   193:                 CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0 
   194: #endif 
   195: ;</h> 
C:0x0009    758108   MOV      SP(0x81),#0x08
   196:                 LJMP    ?C_START 
C:0x000C    02000F   LJMP     main(C:000F)
    20: int main() 
    21: { 
    22:         union BYTE data value; 
    23:         value.BIT.bit0 = 1;             
    24:  
C:0x000F    430801   ORL      0x08,#0x01
    25:         return 0; 
C:0x0012    E4       CLR      A
C:0x0013    7E00     MOV      R6,#0x00
C:0x0015    7F00     MOV      R7,#0x00
    26: }
C:0x0017    22       RET      

23.2位变量实现位操作:

C语言:
#include <STC89C5xRC.H>
#include<absacc.h>

int main()
{
	bit bit0 = 1;
	return 0;
}
  
汇编指令:
 126: ?C_STARTUP:     LJMP    STARTUP1 
   127:  
   128:                 RSEG    ?C_C51STARTUP 
   129:  
   130: STARTUP1: 
   131:  
   132: IF IDATALEN <> 0 
C:0x0000    020003   LJMP     STARTUP1(C:0003)
   133:                 MOV     R0,#IDATALEN - 1 
C:0x0003    787F     MOV      R0,#0x7F
   134:                 CLR     A 
C:0x0005    E4       CLR      A
   135: IDATALOOP:      MOV     @R0,A 
C:0x0006    F6       MOV      @R0,A
   136:                 DJNZ    R0,IDATALOOP 
C:0x0007    D8FD     DJNZ     R0,IDATALOOP(C:0006)
   185:                 MOV     SP,#?STACK-1 
   186:  
   187: ; This code is required if you use L51_BANK.A51 with Banking Mode 4 
   188: ;<h> Code Banking 
   189: ; <q> Select Bank 0 for L51_BANK.A51 Mode 4 
   190: #if 0    
   191: ;     <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4. 
   192: EXTRN CODE (?B_SWITCH0) 
   193:                 CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0 
   194: #endif 
   195: ;</h> 
C:0x0009    758120   MOV      SP(0x81),#0x20
   196:                 LJMP    ?C_START 
C:0x000C    02000F   LJMP     main(C:000F)
    20: int main() 
    21: { 
       
    24:         bit bit0 = 1; 
C:0x000F    D200     SETB     0x20.0
    25:         return 0; 
C:0x0011    E4       CLR      A
C:0x0012    7E00     MOV      R6,#0x00
C:0x0014    7F00     MOV      R7,#0x00
    26: }
C:0x0016    22       RET      

差异:

位域实现原理:ORL      0x08,#0x01
位操作实现原理:SETB     0x20.0

        可以对比,使用位域定义的变量并未存放在支持位寻址地址区,通过ORL将立即数(0x01)与直接地址单元(0x08)进行或操作,指令代码占用3字节,需要耗费24个机器周期(12MHz晶振下需要24us时间)。使用位寻址定义的变量通过SETB直接对地址0x20.0进行置位,指令代码占用2字节,需要耗费12个机器周期(12MHz晶振下需要12us时间)。

        由此可见,二者实现原理并不相同,使用硬件位寻址定义的变量操作起来更快,占用内存更小。位域操作需要先读取变量值进行逻辑操作,再重新存入地址,数据读写过程中受内外因素干扰,存在数据紊乱的可能。

二十四、51单片机有可供使用的RTOS嘛?

        答:51单片机是支持RTOS的,但是他匮乏的硬件资源注定支持的RTOS非常轻量化。在Keil_C51\C51\RtxTiny2下有一个名称叫RTX51的RTOS,但是已经被封装成LIB库了,我们看不到具体的源代码。根据库的精简程度,又分为全功能版的RTX51-FULL和精简功能的RTX51-TINY。RTX51-FULL在RTX51-TINY的基础上支持了任务的优先级设定,相关工程配置可参考其他博主介绍。

24.1 经典12T单片机工程配置:硬件平台为STC89C52RC,软件为Keil C51

24.2 增强1T单片机工程配置:硬件平台为STC15W1K16S,软件为Keil C51

24.3 RTX51-TINY使用手册

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值