MCS51单片机讲义C语言编程清华大学出版社第二章.docx
《MCS51单片机讲义C语言编程清华大学出版社第二章.docx》由会员分享,可在线阅读,更多相关《MCS51单片机讲义C语言编程清华大学出版社第二章.docx(18页珍藏版)》请在冰豆网上搜索。
MCS51单片机讲义C语言编程清华大学出版社第二章
第二章MCS-51系列单片机结构
2.1MCS-51单片机基本结构
在学习单片机的内部结构之前,先了解下现在正在使用的计算机的几大组成部,计算机有五个组成部份:
运算器:
用于实现算术和逻辑运算。
计算机的运算和处理都在这里进行;
控制器:
是计算机的控制指挥部件,使计算机各部份能自动协调的工作;
存储器:
用于存放程序和数据,又分为内存储器和外存储器;
输入设备:
用于将程序和数据输入到计算机;
输出设备:
用于把计算机数据,计算或加工的结果以用户需要的形式显示或保存;
通常把运算器和控制器合在一起称为中央处理器(CentralProcessingUnit),简称CPU。
而把外存储器、输入设备和输出设备合在一起称之为计算机的外部设备。
2.1.1MCS-51单片机结构简介
单片机(Microcontroller,又称微控制器)是在一块硅片上集成了各种部件的微型计算机。
这些部件包括中央处理器CPU、数据存储器RAM、程序存储器ROM、定时器/计数器和多种I/O接口电路。
典型的MCS-51系列单片机由下图2.1所示的器件组成:
图2.1MCS-51单片机结构框图
●中央处理器:
中央处理器(CPU)是整个单片机的核心部件,是8位数据宽度的处理器,能处理8位二进制数据或代码,CPU负责控制、指挥和调度整个单元系统协调的工作,完成运算和控制输入输出功能等操作。
●数据存储器(RAM):
8051内部有128个8位用户数据存储单元和128个专用寄存器单元,它们是统一编址的,专用寄存器只能用于存放控制指令数据,用户只能访问,而不能用于存放用户数据,所以,用户能使用的的RAM只有128个,可存放读写的数据,运算的中间结果或用户定义的字型表。
●程序存储器(ROM):
8051共有4096个8位掩膜ROM,用于存放用户程序,原始数据或表格。
●定时/计数器:
8051有两个16位的可编程定时/计数器,以实现定时或计数产生中断用于控制程序转向。
●并行输入输出(I/O)口:
8051共有4组8位I/O口(P0、P1、P2或P3),用于对外部数据的传输。
●全双工串行口:
8051内置一个全双工串行通信口,用于与其它设备间的串行数据传送,该串行口既可以用作异步通信收发器,也可以当同步移位器使用。
●中断系统:
8051具备较完善的中断功能,有两个外中断、两个定时/计数器中断和一个串行中断,可满足不同的控制要求,并具有2级的优先级别选择。
●时钟电路:
8051内置最高频率达12MHz的时钟电路,用于产生整个单片机运行的脉冲时序,但8051单片机需外置振荡电容。
2.1.2MCS-51单片机内部结构
单片机的结构有两种类型,一种是程序存储器和数据存储器分开的形式,即哈佛(Harvard)结构,另一种是采用通用计算机广泛使用的程序存储器与数据存储器合二为一的结构,即普林斯顿(Princeton)结构。
INTEL的MCS-51系列单片机采用的是哈佛结构的形式,而后续产品16位的MCS-96系列单片机则采用普林斯顿结构。
图2.2是MCS-51系列单片机的内部结构示意图。
图2.2MCS-51系列单片机的内部结构图
MCS-51系列单片机的基本性能完全相同,其特点如下:
●8位CPU;
●片内振荡器及时钟电路;
●32根I/O线;
●外部存储器寻址范围ROM、RAM各64K;
●2个16位的定时器/计数器;
●5个中断源,2个中断优先级;
●全双工串行口;
●布尔处理器。
2.2MCS-51单片机引脚功能
MCS-51是标准的40引脚双列直插式集成电路芯片,引脚分布如图2.3:
图2.3MCS-51单片机引脚分布图
引脚的功能简要说明如下:
1.电源引脚VCC和GND
VCC(40):
电源端,+5V输入。
GND(20):
接地端。
2.时钟电路引脚XTAL1和XTAL2
XTAL1(19):
片内振荡电路的输入端。
XTAL2(18):
片内振荡电路的输出端。
8051的时钟有两种方式,一种是片内时钟方式,需在18和19脚外接石英晶体(2-12MHz)和振荡电容,振荡电容的值一般取10pF-30Pf;另外一种是外部时钟方式,即将XTAL1接地,外部时钟信号从XTAL2脚输入;如图2.4
a.内部时钟方式b.外部时钟方式
图2.48051的时钟方式
3.控制信号引脚RST、ALE、PSEN和EA
RESET/Vpd(9)复位信号复用端:
当8051通电,时钟电路开始工作,在RESET引脚上出现24个时钟周期以上的高电平,系统即初始复位。
初始化后,程序计数器PC指向0000H,P0-P3输出口全部为高电平,堆栈指钟写入07H,其它专用寄存器被清“0”。
RESET由高电平下降为低电平后,系统即从0000H地址开始执行程序。
然而,初始复位不改变RAM(包括工作寄存器R0-R7)的状态。
8051的复位方式可以是自动复位,也可以是手动复位,见图2.5。
a.上电自动复位b.手动复位
图2.58051复位电路
此外,RESET/Vpd还是一复用脚,Vcc掉电期间,此脚可接上备用电源,以保证单片机内部RAM的数据不丢失。
ALE/PROG(30)地址锁存允许信号端:
ALE/PROG当访问外部程序器时,ALE(地址锁存)的输出用于锁存地址的低位字节。
而访问内部程序存储器时,ALE端将有一个1/6时钟频率的正脉冲信号,这个信号可以用于识别单片机是否工作,也可以当作一个时钟向外输出。
更有一个特点,当访问外部程序存储器,ALE会跳过一个脉冲。
如果单片机带有片内EPROM,在编程其间,将用于输入编程脉冲。
PSEN(29)程序存储允许输出信号端:
当访问外部程序存储器时,此脚输出负脉冲选通信号,PC的16位地址数据将出现在P0和P2口上,外部程序存储器则把指令数据放到P0口上,由CPU读入并执行。
EA/Vpp(31)内外部程序存储器选通端:
EA/Vpp,8051和8751单片机,内置有4kB的程序存储器,当EA为高电平并且程序地址小于4kB时,读取内部程序存储器指令数据,而超过4kB地址则读取外部指令数据。
如EA为低电平,则不管地址大小,一律读取外部程序存储器指令。
显然,对内部无程序存储器的8031,EA端必须接地。
在对片内ROM编程时,EA/Vpp脚还需加上21V的编程电压。
4.输入输出口
8051有4组8位I/O口:
P0、P1、P2和P3口,P1、P2和P3为准双向口,P0口则为双向三态输入输出口,下面分别介绍这几个口线:
1>P0端口(P0.0-P0.7):
P0口是8位双向三态输入/输出接口,如图2.6(a),P0口其中一位的电路图。
P0口既可作地址/数据总线使用,又可作通用I/O口用。
连接外部存储器时,P0口一方面作为8位数据输入/输出口,另一方面用来输出外部存储器的低8位地址。
作输出口时,输出漏极开路,驱动NMOS电路时应外接上拉电阻;作输入口之前,应先向锁存器写1,使输出的两个场效应管均关断,引脚处于“浮空”状态,这样才能做到高阻输入,以保证输入数据的正确。
正是由于该端口用作I/O口,输入时应先写1,故称为准双向口。
当PO口作地址/数据总线使用时,就不能再把它当通用I/O使用。
(a)P0口位结构(b)P1口位结构
(c)P2口位结构(d)P3口位结构
图2.6输入输出口位结构图
2>P1端口(P1.0-P1.7):
P1口是8位准双向口,作通用输入/输出口使用,如图2.6(b)所示。
在输出驱动部分,P1口有别于P0口,它接有内部上拉电阻。
P1口的每一位可以独立地定义为输入或者输出,因此,P1口既可以作为8位并行输入/输出口,又可作为8位输入/输出端。
CPU既可以对P1口进行字节操作,又可以进行位操作。
当作输入方式时,该位的锁存器必须预写1。
3>P2端口(P2.0-P2.7):
P2口是8位准双向输入/输出接口,如图2.6(c)所示。
P2口可作通用I/O口使用,与P0口相同,当外接程序存储器时,P2口给出地址的高8位,此时不能作通用I/O口。
当外接数据存储时,若RAM小于256B,用R0、R1作间接寄存器,只需P0口送出地址低8位,P2口可以用作通用I/O口;若RAM大于256B,必须用16位寄存器DPTR作间址寄存器,则P2口只能在一定限度内作一般I/O使用。
4>P3端口(P3.0-P3.7):
P3口也是一个8位的准双向输入/输出接口,如图2.6(d)所示。
它具有多种功能。
一方面与P1口一样作为一般准双向输入/输出接口,具有字节操作和位操作二种工作方式;另一方面8条输入/输出线可以独立地作为串行输入/输出口和其它控制信号线。
P3端口用于一些特殊功能,具体的第二功能定义表2-1。
表2-1P3端口引脚第二功能表
口线
第二功能
信号名称
P3.0
RXD
串行数据接收
P3.1
TXD
串行数据发送
P3.2
INT0
外中断0
P3.3
INT1
外中断1
P3.4
T0
定时/计数器0计数输入
P3.5
T1
定时/计数器1计数输入
P3.6
WR
外部数据存储器写选通
P3.7
RD
外部数据存储器读选通
5>P0—P3端口的负载能力及接口要求
P0口的每一位输出可驱动8个LSTTL输入,但把它当通用口使用时,输出级是开漏电路,故用它驱动NMOS输入时需外接上拉电阻;把它当地址/数据总线时,则无需接外部上拉电阻。
P1—P3口的输出级接有内部上拉电阻,它们的每一位输出可驱动4个LSTTL输入。
CHMOS端口只能提供几毫安的输出电流,故当作为输出口去驱动一个普通晶体管的基极时,应在端口与晶体管基极间串联一个电阻,以限制高电平输出时的电流。
2.3输入/输出实例
流水灯硬件电路描述如下:
8051单片机的P1口的P1.0—P1.7分别接有LED(D1—D8),当某一端口输出为“0”时,相应的LED点亮,P0.2、P0.3、P0.4、P0.5分别接有四个按钮K1--K4,按下按钮时,相应引脚被接地。
现要求编写可键控的流水灯程序,当K1按下时,开始流动,K2按下时停止流动,全部灯灭,K3使灯由D1往D8流动,K4使灯由D8往D1流动。
2.3.1硬件设计分析
通过对流水灯题目要求的分析,LED阳极连接正向电压,阴极连接P1端口。
当P1端口输出“0”时,LED上为正向电压,LED点亮;当P1端口输出“1”时,LED上无压差,LED熄灭;为了防止LED过流烧毁,需串联限流电阻,限流电阻越小LED越亮,也容易烧毁。
按钮连接在P0口上,当查询按钮状态时,如果按钮按下,其状态为“0”;如果按钮未按下,由于P0口无内部上拉电阻,端口悬浮,其状态不确定,所以在电路中,需要外部上拉电阻。
复位电路采用手动复位电路,时钟电路采用内部时钟电路。
根据流水灯题目要求硬件电路设计如图2.7所示
图2.7流水灯硬件电路
2.3.2程序功能与实现
下面首先给出程序,然后再进行分析。
键控流水灯的程序
#include"reg51.h"
#include"intrins.h"
#defineucharunsignedchar
voidmDelay(unsignedintDelayTime)
{//延时函数
unsignedintj=0;
for(;DelayTime>0;DelayTime--)
for(j=0;j<125;j++);
}
ucharKey()
{//按键判断函数,无按键按下返回0,否则返回键值。
ucharKeyV;
uchartmp;
P0=P0|0x3c;//四个按键所接位置
KeyV=P0;
if((KeyV|0xc3)==0xff)//无键按下
return(0);
mDelay(10);//延时,去键抖
KeyV=P0;
if((KeyV|0xc3)==0xff)
return(0);
else
{
for(;;)
{
tmp=P0;
if((tmp|0xc3)==0xff)
break;
}
return(KeyV);
}
}
voidmain()
{
unsignedcharOutData=0xfe;
bitUpDown=0;
bitStart=0;
ucharKValue;
for(;;)
{
KValue=Key();
switch(KValue)
{
case0xfb:
//P0.2=0,Start
{
Start=1;
break;
}
case0xf7:
//P0.3=0,Stop
{
Start=0;
break;
}
case0xef:
//P0.4=0Up
{
UpDown=1;
break;
}
case0xdf:
//P0.5=0Down
{
UpDown=0;
break;
}
}
if(Start)
{
if(UpDown)
OutData=_crol_(OutData,1);
else
OutData=_cror_(OutData,1);
P1=OutData;
}
else
P1=0xff;//否则灯全灭
mDelay(1000);
}
}
2.3.3程序分析
1.“文件包含”处理
#include"reg51.h"
#include"intrins.h"
程序的第一行是一个“文件包含”处理。
所谓“文件包含”是指一个文件将另外一个文件的内容全部包含进来,所以这里的程序虽然只有2行,但C编译器在处理的时候却要处理几十或几百行。
这里程序中包含REG51.h文件的目的是为了要使用P1这个符号,即通知C编译器,程序中所写的P1是指80C51单片机的P1端口而不是其它变量。
打开reg51.h可以看到这样的一些内容:
/*-------------------------------------------------------------------
REG51.H
Headerfileforgeneric80C51and80C31microcontroller.
Copyright(c)1988-2001KeilElektronikGmbHandKeilSoftware,Inc.
Allrightsreserved.
-------------------------------------------------------------------*/
/*BYTERegister*/
sfrP0=0x80;
sfrP1=0x90;
sfrP2=0xA0;
sfrP3=0xB0;
sfrPSW=0xD0;
sfrACC=0xE0;
sfrB=0xF0;
sfrSP=0x81;
sfrDPL=0x82;
sfrDPH=0x83;
sfrPCON=0x87;
sfrTCON=0x88;
sfrTMOD=0x89;
sfrTL0=0x8A;
sfrTL1=0x8B;
sfrTH0=0x8C;
sfrTH1=0x8D;
sfrIE=0xA8;
sfrIP=0xB8;
sfrSCON=0x98;
sfrSBUF=0x99;
/*BITRegister*/
/*PSW*/
sbitCY=0xD7;
sbitAC=0xD6;
sbitF0=0xD5;
sbitRS1=0xD4;
sbitRS0=0xD3;
sbitOV=0xD2;
sbitP=0xD0;
/*TCON*/
sbitTF1=0x8F;
sbitTR1=0x8E;
sbitTF0=0x8D;
sbitTR0=0x8C;
sbitIE1=0x8B;
sbitIT1=0x8A;
sbitIE0=0x89;
sbitIT0=0x88;
/*IE*/
sbitEA=0xAF;
sbitES=0xAC;
sbitET1=0xAB;
sbitEX1=0xAA;
sbitET0=0xA9;
sbitEX0=0xA8;
/*IP*/
sbitPS=0xBC;
sbitPT1=0xBB;
sbitPX1=0xBA;
sbitPT0=0xB9;
sbitPX0=0xB8;
/*P3*/
sbitRD=0xB7;
sbitWR=0xB6;
sbitT1=0xB5;
sbitT0=0xB4;
sbitINT1=0xB3;
sbitINT0=0xB2;
sbitTXD=0xB1;
sbitRXD=0xB0;
/*SCON*/
sbitSM0=0x9F;
sbitSM1=0x9E;
sbitSM2=0x9D;
sbitREN=0x9C;
sbitTB8=0x9B;
sbitRB8=0x9A;
sbitTI=0x99;
sbitRI=0x98;
这里都是一些符号的定义,即规定符号名与地址的对应关系。
注意其中有sfrP1=0x90;这样的一行(上文中用黑体表示),即定义P1与地址0x90对应,P1口的地址就是0x90(0x90是C语言中十六进制数的写法,相当于汇编语言中写90H)。
从这里还可以看到频繁出现的词:
sfr、sbit。
2.sfr、sfr16
sfr并非标准C语言的关键字,而是Keil为能直接访问80C51中的SFR(特殊功能寄存器)而提供了一个新的关键词,同样提供sfr16,sfr16占用两个内存单元,值域为0~65535。
sfr16和sfr一样用于操作特殊功能寄存器,所不同的是它用于操作占两个字节的寄存器。
其用法是:
sfr变量名=地址值
sfr16变量名=地址值
3.sbit
在C语言里,如果直接写P1_0,C编译器并不能识别,而且P1_0也不是一个合法的C语言变量名,所以必须给它们建立联系,这里使用了KeilC的关键字sbit来定义,sbit是C51中的一种扩充数据类型,利用它可以访问芯片内部的RAM中的可寻址位或特殊功能寄存器中的可寻址位。
sbit的用法有三种:
第一种方法:
sbit位变量名=地址值
第二种方法:
sbit位变量名=SFR名称^变量位地址值
第三种方法:
sbit位变量名=SFR地址值^变量位地址值
如定义PSW中的OV可以用以下三种方法:
sbitOV=0xd2
(1)说明:
0xd2是OV的位地址值
sbitOV=PSW^2
(2)说明:
其中PSW必须先用sfr定义好
sbitOV=0xD0^2(3)说明:
0xD0就是PSW的地址值
因此这里用sbitP1_0=P1^0;就是定义用符号P1_0来表示P1.0引脚,也可以起P10一类的名字,只要下面程序中也随之更改就行了。
关于特殊功能寄存器内容详细内容见下章。
4.bit位标量
bit位标量是C51编译器的一种扩充数据类型,利用它可定义一个位标量,但不能定义位指针,也不能定义位数组。
它的值是一个二进制位,不是0就是1,类似一些高级语言中的Boolean类型中的True和False。
5._crol_()、_cror_()
_crol_()、_cror_()分别为字节左移和字节右移函数,使用它们需包含头文件intrins.h。
详情参阅C51库函数。