一、i/o引脚的特性
单片机的外部属性就是它有众多的i/o引脚,如40脚封装的51系列,就有32个脚是i/o引脚。它们也叫单片机的并口。
这32个i/o引脚全是数字的(即只会出现或只允许0、1变化)。
这32个i/o引脚分成4组,每组8位(即8根i/o引脚),用p0、p1、p2、p3标注,每组里的各位用px.y区别,如p0口的8位标记为p0.0~p0.7(x=0~3;y=0~7)。
当然,这四个口p0、p1、p2、p3是有区别的,它们都有另外的功能;若只做一般的i/o引脚用,可视它们是一样的(我们这一讲只考虑做一般的i/o引脚用)。
二、i/o引脚的寻址
这四个口p0、p1、p2、p3(共32根引线)在内部映射有4个8位专用寄存器,名字也叫p0、p1、p2、p3,对这4个寄存器进行操作,也就可对32根引线进行操作(它们一一对应),很方便。
这里介绍一下字操作、字节操作、位操作的概念:字是由字节组成的,一个字节为8位二进制。字的位数由cpu的位数(或cpu里寄存器的位数)决定,即字长;若cpu为8位机,则字长为8位,正好等于一个字节;若cpu为16位机,则字长为16位,所以字操作时,一次就对两个字节进行处理,同理,我们就知道当cpu为32位机、64位机时,字操作所处理的字节数了。所谓字节操作,就是一次对8位二进制同时进行操作。说到这里,大家肯定能回答什么叫位操作了,即对一个字节里的某一位进行操作。再次强调一下,以上所讲的操作、处理,就是对i/o引脚的寻址、就是执行指令的过程,执行的结果就是各位变0或1。
有了以上概念,我们就可以告诉大家,这四个口p0、p1、p2、p3即可字节操作,也可位操作。(同学们好好想一想,拿p1口做例,字节操作是怎么回事?位操作又是怎么回事?)再进一步,操作的含义是什么呢?答:输入和输出,即i/o。这32根线,每一根都可以输入和输出,输入是单片机从外部接收数据和命令、感知外部世界的过程;输出是单片机根据设定、经过运算、甚至是智能的对外部世界作出反应,进行控制的过程。从指令的角度看,输入和输出稍有不同,输入稍复杂一些,所以,51单片机的这32个输入和输出口,也叫准双向口。我们下边先讲简单的输 出过程,而把输入过程放在后边的讲座里。
三、i/o引脚的输出
在第一讲里,在最小系统的电路图里,大家已知p1口和p3口接了16只发光二极管,现在我们将这两个口作为输出口用,很明白,当其中的某个脚为1时,该脚所接的led是“灭”的;反之,为0时,则“亮”。如下图所示。可见,这里的亮或灭是由硬件的接法决定的(若换一种接法,亮灭的电平会颠倒的)。
由此我们也看出,学习单片机,软、硬件是分不开的,这是它的显著的特点。
下面给大家介绍几条i/o引脚输出的指令:
先介绍指令格式
【标号:】操作码操作数1,操作数2 【,操作数n】【;注释】
以上的指令格式中,方括号内的内容可有可无,若要的话,一定注意标点符号不能省略;操作码必有,它是简单的英语单词以助记符形式出现,便于记忆,它说明了操作的性质;操作数可有可无,可多可少,中间以逗号分隔,它和操作码之间至少空一格,它说明了操作的具体内容;注释也是可有可无,但规范和专业的做法是要有详细的注释,且不是简单的指令说明,而是其物理的、硬件的、实质性的解释。
字节输出的指令
mov p1,#00000000b ;该指令可使p1口的8个脚(p1.0~p1.7)全部变为低电平,当然,p1口的8只发光管都会点亮;(指令中的操作数2也可写成#0、#0h,前者是10进制写法,后者是16进制写法,均可)
mov p1,#11111111b ;这条指令相反,8只发光管都会灭。
位输出的指令
clr p1.0 ;该指令使p1口的0脚变为低电平,它所接的那只发光管亮,不会影响其他。
而 setb p1.0 这条指令就使p1口的0脚变为高电平。
有了以上这些准备,下面我们就来编一段程序,让p1口和p3口的发光管轮流点亮,每个发光管点亮200ms,轮流不息,俗称“流水灯”。
四、流水灯编程
1.字节方式处理
;****************************************
org 0000h
;org为伪指令,告诉汇编程序,下面的指令从rom的0000h处开始放
main: mov p1,#11111110b
mov p3,#11111110b
;可见,以上两条指令使p1口的p1.0脚和p3口的p3.0脚所接发光管点亮
lcall ys200ms
;上面是一条调用子程序指令,用意是让cpu执行一些其他无关的指令,耗费掉200ms的时间,让刚亮的两只发光管能亮200ms时间,否则,由于cpu执行指令太快,我们将无法分清哪只发光管亮了。
mov p1,#11111101b
mov p3,#11111101b ;很显然,换了两只发光管亮
lcall ys200ms
mov p1,#11111011b
mov p3,#11111011b ;很显然,又换了两只发光管亮
lcall ys200ms
mov p1,#11110111b
mov p3,#11110111b ;很显然,又换了两只发光管亮
lcall ys200ms
mov p1,#11101111b
mov p3,#11101111b ;很显然,又换了两只发光管亮
lcall ys200ms
mov p1,#11011111b
mov p3,#11011111b ;很显然,又换了两只发光管亮
lcall ys200ms
mov p1,#10111111b
mov p3,#10111111b ;很显然,又换了两只发光管亮
lcall ys200ms
mov p1,#01111111b
mov p3,#01111111b ;很显然,又换了两只发光管亮
lcall ys200ms
;到此为止,p1口和p3口的发光管轮流亮了一遍
ljmp main
;我们应该让cpu返回开始处,再次开始亮灯循环,上边这条指令就是无条件跳转指令,命令cpu跳回标号为main处,继续执行指令,永远往复。
以下给出延时子程序,以保持程序的完整性,但不讲解,以后再说。
ys200ms: mov r7,#4
ys0: mov r6,#100
ys1: mov r5,#250
djnz r5,$
djnz r6,ys1
djnz r7,ys0
ret
end
;************************************************************
位处理方式
;**************************************************
org 0000h
main: mov p1,#0ffh
mov p3,#0ffh ;先做准备工作,使所有led全灭
loop: clr p1.0 ;p1.0脚所接发光管点亮
clr p3.0 ;p3.0脚所接发光管点亮
lcall ys200ms
setb p1.0
setb p3.0 ;在点亮下一只前,关掉已点亮的
clr p1.1 ;p1.1脚所接发光管点亮
clr p3.1 ;p3.1脚所接发光管点亮
lcall ys200ms
setb p1.1
setb p3.1 ;在点亮下一只前,关掉已点亮的
clr p1.2 ;p1.2脚所接发光管点亮
clr p3.2 ;p3.2脚所接发光管点亮
lcall ys200ms
setb p1.2
setb p3.2 ;在点亮下一只前,关掉已点亮的
clr p1.3 ;p1.3脚所接发光管点亮
clr p3.3 ;p3.3脚所接发光管点亮
lcall ys200ms
setb p1.3
setb p3.3 ;在点亮下一只前,关掉已点亮的
clr p1.4 ;p1.4脚所接发光管点亮
clr p3.4 ;p3.4脚所接发光管点亮
lcall ys200ms
setb p1.4
setb p3.4 ;在点亮下一只前,关掉已点亮的
clr p1.5 ;p1.5脚所接发光管点亮
clr p3.5 ;p3.5脚所接发光管点亮
lcall ys200ms
setb p1.5
setb p3.5 ;在点亮下一只前,关掉已点亮的
clr p1.6 ;p1.6脚所接发光管点亮
clr p3.6 ;p3.6脚所接发光管点亮
lcall ys200ms
setb p1.6
setb p3.6 ;在点亮下一只前,关掉已点亮的
clr p1.7 ;p1.7脚所接发光管点亮
clr p3.7 ;p3.7脚所接发光管点亮
lcall ys200ms
setb p1.7 ;p1.7脚所接发光管灭
setb p3.7 ;p3.7脚所接发光管灭
ljmp loop ;跳至标号loop处继续反复
;***********************************************************
延时子程序同上,不再重复。
以上我们可看出,完成相同的任务,但编写程序的方法却不一样,其实还有更多的方法完成这一任务。由此,我们的同学们应该领会到,“指令是死的,人是活的”,“条条大道通北京”,只要发挥我们的聪明才智,总是可以达到目的的。
最后强调一下,做这些发光管亮灭实验的意义何在?它的意义就在于:我们能使发光管随心所欲的亮和灭,且有精确的时间控制,就能对任何其他的外部设备进行控制,如彩灯、电动机、车床等,只是变一变相应的电路而已。