在第二章介绍了MCS-51单片机的系统结构在第三章、第四章介绍了语言:汇编语言和C51语言在第五章介绍了单片机电路的绘图工具Protel99在第六章介绍了单片机仿真工具Proteus因此,通过前面章节的内容介绍,在硬件和软件上具备了单片机基础应用的知识。基于上述知识,本章采用“用资源、学器件、组系统”的思路,主要对MCS-51单片机的并行I/O口、定时/计数器、外中断、串行口等内部资源进行应用编程,并学习一些常用的电子器件原理和使用方法,构成读者可理解、可学习的小型控制系统。通过实践运用,真正开始单片机的硬软件综合学习。7.1.1.1功能要求P0口接8个绿色发光管。要求:1.发光二极管先由上到下再由下到上来回流动,循环三次;2.发光二极管分别从两边往中间流动,循环三次;3.发光二极管从中间往两边流动,循环三次。7.1.1.2硬件设计7.1.1.3软件设计(一)分析1.发光二极管亮灭控制由发光二极管电路确定,P0口输出低电平时发光二极管亮,P0口输出高电平时发光二极管灭。2.功能及参数分析(1)发光管由上到下再由下到上来回流动,循环三次;最上面发光管接P00引脚,最下面发光管接P07引脚。由上到下流动的初值n=0xFE,二进制形式11111110,然后进行一位左移,形成11111101……最后形成01111111;由下到上流动的初值n=0x7F,二进制形式01111111,然后进行一位右移,形成10111111……最后形成11111110。C51语言左移、右移运算符移位规则:左移()高位移出,低位补0;右移()低位移出,高位补0。例如:11111110左移一位变为11111100;01111111右移一位变为00111111,不符合要求。因此采用变通方式,解决问题。左移问题,采用一个变量n=0x01,其二进制为00000001,取反后为11111110送P0;然后n左移一位,形成00000010,再取反为11111101送P0;如此重复。右移问题同左移问题。7.1.1.3软件设计(2)发光管再分别从两边往中间流动,循环三次;一共8个发光管,最两边的发光管分别接P00和P07。由两边向中间流动过程为:P00、P07所接发光管亮,然后P01、P06所接发光管亮,然后P02、P05所接发光管亮,最后P03、P04所接发光管亮。实现方式很多,本节采用其中一种。先设置两个变量初值为n=0x01、m=0x80,再设置一变量k=n|m,则K=0x81(二进制10000001),取反后(二进制01111110)送P0;然后n左移一位变0x02,m右移一位变0x40,k=0x42(01000010),取反后(10111101)送P0;如此重复。7.1.1.3软件设计(3)发光管再从中间往两边流动,循环三次。同(2),不再复述。7.1.1.3软件设计(二)程序编制#includereg51.h#defineuintunsignedint#defineucharunsignedchar//软件延时voiddelay(void){uinti;for(i=0;i35530;i++);}voidmain(){uinti,j;ucharn,m,k;while(1){//1.发光管由上到下再由下到上来回流动,循环三次;for(i=0;i3;i++){n=0x01;for(j=0;j8;j++){P0=~n;delay();n=n1;}n=0x80;for(j=0;j8;j++){P0=~n;delay();n=n1;}}//2.发光管再分别从两边往中间流动,循环三次;for(i=0;i3;i++){n=0x01;m=0x80;for(j=0;j4;j++){k=n|m;P0=~k;delay();n=n1;m=m1;}}//3.发光管再分别从中间往两边流动,循环三次;for(i=0;i3;i++){n=0x08;m=0x10;for(j=0;j4;j++){k=n|m;P0=~k;delay();n=n1;m=m1;}}}}7.1.14调试与仿真看实践操作7.1.2.1功能要求P0口接一个7段数码管。要求数码管由0到9再由9到0来回计数。通过该例子理解同样的并行I/O口可控制多种外围器件,并且要根据外围器件的要求进行电路设计和程序编制。7.1.2.2硬件设计使用P0口连接单个数码管时,要根据控制要求对引脚进行连接。本例中采用共阳极数码管,并且采用标准连接:即P0.7--dpP0.6--gP0.5--fP0.4—eP0.3--dP0.2--cP0.1--bP0.0--a仿真数码管段选线的左端是a,右端是dp;位选线接高电平(共阳)。如图8.4。7.1.2.3软件设计1.分析1)数码管原理在单片机应用系统中通常使用的是8段式LED数码管显示器,它有共阴极和共阳极两种,如图8.5所示。2)段码原理控制发光管字形显示的二进制编码通常称为字段码。不同的数字与字符字段码不一样,对于同一个数字与字符,共阴极连接和共阳极连接的字段码也不一样。举几个例子:例如:数码管8根引脚和P0口连接(标准连接方式)P0口:P07P06P05P04P03P02P01P007段数码管:dpgfedcba则:想要显示字形“0”,abcdef亮,dp、g灭。“0”共阴极数码管段码:dpgfedcba00111111=0x3F“0”共阳极数码管段码:dpgfedcba11000000=0xC0想要显示“1”,bc亮,其他都灭。“1”共阴极数码管段码:dpgfedcba00000110=0x06“1”共阳极数码管段码:dpgfedcba11111001=0xF9从例子里可以看出,共阴极和共阳极的字段码互为反码。常见的数字和字符的共阴极和共阳极的字段码如表8.1所示:显示字符共阴极段码共阳极段码显示字符共阴极段码共阳极段码03FHC0HC39HC6H106HF9HD5EHA1H25BHA4HE79H86H34FHB0HF71H8EH466H99HP73H8CH56DH92HU3EHC1H67DH82HT31HCEH707HF8HY6EH91H87FH80HL38HC7H96FH90H8.FFH00HA77H88H“灭”00FFHB7CH83H………………3)数码管应用定义一个一维数组:unsignedcharcodeled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数组下标:0123456789//显示字形:“0”“1”“2”“3”…“9”通过数组下标和字形段码的对应关系,可以很方便地使用。由0到9再由9到0的字形显示,只要通过下标变换,输出对应段码即可。2.程序编制#includereg51.h#defineuintunsignedint#defineucharunsignedcharunsignedcharcodeled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//软件延时voiddelay(void){uinti;for(i=0;i35530;i++);}voidmain(){ucharn;while(1){//1.由0到9计数for(n=0;n10;n++){P0=led[n];delay();}//2.由9到0计数此处for循环可以改成for(n=9;n=0;n--)吗?}}7.1.3.1功能要求P0口接8个黄色发光二极管,P1、P2口接两个7段数码管。P3.0、P3.1引脚接二个按键。要求P3.0引脚所接按键起复位作用,复位时灯全灭,数码管灭;P3.1引脚所接按键为二进制加法计数按键,按压一次加一,发光二极管显示其二进制值,数码管显示其十进制值。此例可以很好的演示二进制加法过程。7.1.3.2硬件设计本例采用共阳极数码管,分别由两个不同I/O口控制,位选线都接高电平,静态显示。左边数码管接P2口显示十位数右边数码管接P1口显示个位数按键采用自复式按键,单键方式连接。7.1.3.3软件设计1.分析1)按键控制键盘接口电路是单片机系统设计非常重要的一环,作为人机交互界面里最常用的输入设备,我们可以通过键盘输入数据或命令来实现简单的人机交互。键盘实际上是一组按键开关的集合,平时按键开关总是处于断开状态,当按下键时它才闭合。P1.1VCCGND(a)P1.1VCCGND(b)(1)键值识别:图(a)、(b)是按键电路,按键为输入设备。该按键为自复式按键,压下后松手,自动弹起。按键未压下时:P1.1通过电阻接VCC,为高电平“1”;按键压下时:P1.1接地,为低电平(2)抖动消除键按下后,由于机械接触会产生抖动,松开后也会产生抖动。抖动时间很短,一般为20ms左右。抖动过程中会有很多高低电平变化,不能准确地确定键盘是否按下。所以,在测到P1.1为低电平后,做20ms延时;再次测试P1.1,如还为低电平,则认为按键稳定闭合(用户按下),然后按照要求作出相应功能。断开闭合断开P1.1(c)(3)键盘编程识别编程如下过程:sbitP11=P1^1;//未压,P11自动为1;压下,P11为0;unsignedintkeyscan(){unsignedinti;if(P11==0)//第一次测试,如果为P11低电平{for(i=0;i1000;i++);//软件延时,避过抖动时间,简称消抖(如果有硬件消抖电路,此步不用做)if(P11==0)//消抖后第二次测试,P11还为低电平则说明有键压下。return0;//有键压下返回0}elsereturn1;//无键压下返回1}2.功能及参数分析(1)按压P30连接的复位键,发光二极管全灭,数码管全灭。P0、P1、P2口都给高电平。(2)按压P31连接的计数键,发光二极管、数码管显示相应值。发光二极管表示:灭表示0,亮表示1。二进制数表示发光二极管电平0000000011111111000000011111111000000010111111010000001111111100……1111111100000000二进制数值表示刚好和发光二极管电平相反。用发光二极管显示最大值255,数码管由于只有两位,显示最大值99。(二)程序编制#includereg51.h#defineuintunsignedint#defineucharunsignedcharunsignedcharcodeled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};sbitRet=P3^0;sbitCnt=P3^1;(二)程序编制uintkeyscan(){unsignedinti;if(Ret==0){for(i=0;i2000;i++);if(Ret==0)return1;//有Ret键压下返回1}elseif(Cnt==0){for(i=0;i2000;i++);if(Cnt==0)return2;//有Cnt键压下返回2}elsereturn0;//无键压下,返回0}voidmain(){ucharn;n=0;P0=0xff;//设置初始参数,发光二极管全灭,数码管全灭。P1=0xff;P2=0xff;while(1){if(keyscan()==1)//Ret按下,全灭。{n=0;P0=0xff;P1=0xff;P2=0xff;}elseif(keyscan()==2)//Cnt按下,计数后显示。{n++;P0=~n;P1=led[n%10];//显示个位P2=