最近,我们在课上讲了几个小例子,在此再把Proteus图及程序的详细解释列出来,供大家参考。 - 应用查询方式,对连接在P1.4管脚上的按键次数进行计数,每5次在P1.0上连接的红色LED亮或不亮。
本题考虑点: - 应用查询方式,即读和检测P1.4管脚的状态,是1或0;
- 每5次翻转一次,因此可设一个寄存器作为计数器,看是否到了5次,5次后清零;
- P1.0上的LED亮或不亮,即状态翻转,CPL P1.0。
Proteus图 应用元器件:单片机80C51(或80C52)、按键Button、电阻Res、LED 图1 找元器件的方法 单片机属于微处理器库里面的,因此,应再点击Microprocessor ICS,后同。 图2. 1题图 程序: ORG 0H ;程序从程序存储器的0单元开始存放 MAIN: MOV R0,#0 ;设R0为计数器,赋初始值0,注意,在这儿不赋值0,单片机一上电R0也等于0 LOOP: JB P1.4,$ ;若P1.4为高,表明没键按下,等待 JNB P1.4,$ ;若P1.4为低,表明有键按下,等待该键的弹起 INC R0 ;按键弹起后,表明按键一次,计数器加1 CJNE R0,#6,LOOP ;若R0不等于6,表明还没按够5次,继续查询按键信息 MOV R0,#0 ;若R0=6,表明已经被按下5次,计数器清零 CPL P1.0 ;P1.0翻转,即LED的状态转换 AJMP LOOP ;进入下一个循环 END ;程序结束 图3 调试状态
- 应用定时器,控制从P1.0和P1.1输出周期为300us和600us的方波程序。
本题考虑点: 首先明确为应用定时器,且输出波形为方波,周期300us和600us,也就是说,如果用这两个管脚输出波形的话,其翻转的时间分别为150us和300us。 然后确定应用定时器的工作方式,对于6MHz的晶振来说,对于12分频的单片机的机器周期为2us,即对机器周期的计数分别为75和150,都小于256,因此,可用8位定时器,并且300us是150us的整数倍,因此可用一个定时器解决。在此选用自动装入的8位定时器,即工作方式2,设用T0。 则TMOD的取值为: 先看TMOD的各位: GATE C\T M1 M0 GATE C\T M1 M0 因为用T0来计时,且在本题目中T1不用,因此,TMOD的取值可为:00000010B , 16进制:02H 初始值的计算,应用公式: 计算得:X=106,16进制为6AH,即TH0和TL0的赋值都为6AH(因方式2位自动装入模式) Proteus图: 图4 题2图及调出示波器的位置 程序及解释: ORG 0H ;程序从程序存储器的0单元开始存放 AJMP MAIN ;跳转至以MAIN为标号的主程序
ORG 0BH ;0B是定时器0的中断子程序入口 AJMP T0INT ;跳转到以T0INT为标号的中断子程序
ORG 30H ;主程序从30H单元开始存放 MAIN: MOV TMOD,#20H ;设置定时器的工作方式,采用工作方式2即自动装入的8位 MOV TH0,#8AH ;给TH0赋初值 MOV TL0,#8AH ;给TL0赋初值 SETB EA ;打开总中断 SETB ET0 ;打开T0的中断 SETB TR0 ;让T0开始工作 SJMP $ ;踏步,等待中断
T0INT: CPL P1.0 ;时间到,翻转P1.0 INC R0 ;因为300us正好是150us的整数倍,因而可用一个定时器 CJNE R0,#2,GOON ;用R0作为中断几次的计数器,若中断2次既达到150us的两倍 MOV R0,#0 ;若达到了两倍,翻转,计数器清零 CPL P1.1 ;P1.1翻转 GOON: RETI ;中断子程序返回
END ;程序结束
图5 波形图 - 应用164带3只数码管,显示从000-999的单个跳数;
本题考虑点: 164是移位寄存器,因此最好直接用串口,与164连接; 3位数,可把三位数设为一个计数器,设从30H-32H,其中30H为最低位,31H为中间位,32H为最高位,然后从30H开始加1,当30H加到10后,30H清零,31H再加1,31H为10后,变为零,32H再加1,当32H为10后,清零。 把显示部分编写为一个子程序,30-32H内的数每改变一次,调用一次显示; 由于人的视力跟不上单片机一条指令的运算时间,因此需要延时。 因此,在软件设计上可分为三部分:一是加数部分,一是显示部分,一是延时部分。 Proteus图: 图6 题3图 (注意RXD、TXD的接法,以及后两只164的接法) 程序: ORG 0H ;程序从程序存储器的0单元开始存放 AJMP MAIN ;跳转到主程序
ORG 30H ;主程序从程序存储器的30H单元开始存放 MAIN: MOV 30H,#0 ;给30H单元赋初始值0 MOV 31H,#0 ;给31H单元赋初始值0 MOV 32H,#0 ;给32H单元赋初始值0
LOOP: INC 30H ;30H单元内的数加1 MOV R1,30H ;将30H单元内的数赋值给R1,以便应用 CJNE Rn,#DATA,REL语言判断并跳转 CJNE R1,#10,NEXT ;若30H内的数不是10则跳转到调用显示 MOV 30H,#0 ;若30H内的数是10,则清零 INC 31H ;上位30H的数等于10时,下一位31H加1 MOV R1,31H ;将31H内的数赋值给R1 CJNE R1,#10,NEXT ;间接地判断31H内的数是否等于10,如不是,转显示 MOV 31H,#0 ;若31H等于10,则清零,将32H加1 INC 32H ;32H加1(此为最高位) MOV R1,32H ;判断32H的数值 CJNE R1,#10,NEXT ;间接判断32H内的数是否等于10,不是转显示 MOV 32H,#0 ;若是32H清零 NEXT: ACALL DISPLAY ;调用显示子程序 ACALL DELAY ;调用延时子程序 SJMP LOOP ;跳转到加1部分,循环
DISPLAY:MOV R0,#30H ;将显示数据的存放首单元赋值给R0,以便调用循环将数值赋值给A MOV DPTR,#TAB ;将显示码的首地址赋值给DPTR DISLOP:MOV A,@R0 ;将以R0内的数30H内的数值赋值给A MOVC A,@A+DPTR ;查表语句,将显示码赋值给A MOV SBUF,A ;将显示码通过串行口送出去 JNB TI,$ ;如果TI不等于1,表明还没送出去,等待 CLR TI ;若TI=1表明数据已经送走,将送走的标志位TI清零,以便进行下次输送 INC R0 ;指向下一单元 CJNE R0,#33H,DISLOP ;判断是否将3个单元(30H,31H,32H)的数据都送完 RET ;子程序返回
DELAY: MOV R7,#0 ;延时子程序,给R7赋值0(相当于256) DEL1: MOV R6,#0 ;给R6赋值0 DJNZ R6,$ ;若R6-1不等于0,在此语句循环 DJNZ R7,DEL1 ;如R0=0则判断R7-1是否为零,不为零则跳转到DEL1,给R6重新赋值 RET ;子程序返回
TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH ;显示码表 END ;程序结束 图7 运行状态图
- 应用双机通讯,实现在A机上的数码管数字加到按另一键时的将该数发送到B机的数码管上显示。
本题考虑点: 双机通讯,串行口的通讯方式设置; 设采用串行口方式1,则需要设置波特率,应用T1的工作方式2; 双机都带一只数码管; 主机带3只按键。 Proteus图: 此处由于用P0口带数码管,因此因在P0各管脚上加上拉电阻,此处用排阻respack-8;公共端接高。 图8 题4图 编程考虑: 波特率生成器用T1的工作模式2,波特率选用9600,晶振6MHz,则TH1和TL1的赋值为0F4H,SCON选用工作模式1,且可接收。 TMOD= #20H
SCON=50H
编程: 主机程序: ORG 0H ;程序从程序存储器的0单元开始存放 AJMP MAIN ;跳转到以MAIN为标号的程序去 ORG 30H ;以下程序从程序存储器的30H开始存放 MAIN: MOV TMOD,#20H ;选用定时器2工作模式,即自动赋初始值的8位定时器 MOV TH1,#0F4H ;给TH1赋值0F4H; MOV TL1,#0F4H ;给TL1赋值0F4H; SETB EA ;打开总中断允许位; SETB ET1 ;打开定时器1的中断允许位; SETB TR1 ;使定时器1运行 MOV SCON,#50H ;设置串行口的工作模式,采用模式1
MOV DPTR,#TAB ;赋值显示码表的首地址 MOV R0,#0 ;设置R0为显示数字的计数器 MOV R1,#0 ;R1设置为讯显示码的中转寄存器
KEYSCAN:JB P1.0,KEY1 ;若按键1没有被按下,转去查询键2 JNB P1.0,$ ;如键1被按下,则等待键1弹起 INC R0 ;键1弹起后,显示数加1 CJNE R0,#10,NEXT ;如显示数等于10,则从0开始 MOV R0,#0 ;清零 NEXT: MOV A,R0 ;将显示的数给A MOVC A,@A+DPTR ;查表取显示的码值 MOV R1,A ;将码值给R1暂存 MOV P0,A ;将显示码值给P0显示 key1: JB P1.1,KEYSCAN ;检测第二个按键按下没有 JNB P1.1,$ ;按下了等待弹起 MOV A,R1 ;将显示码给A MOV SBUF,A ;将显示码送去串行口 JNB TI,$ ;若TI不等于1,表明正在发送中 CLR TI ;TI=1,则表明已经发送完毕,将标志位清零,以便下次发送 SJMP KEYSCAN ;继续检测有按键是否被按下
TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH ;显示码 END ;程序结束
从机程序: ORG 0H ;程序从程序存储器的0单元开始存放 AJMP MAIN ;跳转到以MAIN为标号的程序去 ORG 30H ;以下程序从程序存储器的30H开始存放 MAIN: MOV TMOD,#20H ;选用定时器2工作模式,即自动赋初始值的8位定时器 MOV TH1,#0F4H ;给TH1赋值0F4H; MOV TL1,#0F4H ;给TL1赋值0F4H; SETB EA ;打开总中断允许位; SETB ET1 ;打开定时器1的中断允许位; SETB TR1 ;使定时器1运行 MOV SCON,#50H ;设置串行口的工作模式,采用模式1
LOOP: JNB RI,$ ;若RI不等于1,表明无数据通过串行口送入 CLR RI ;如RI=1,表明有数据送入,将RI清零,以便下次接收 MOV A,SBUF ;将串行口接收到的数据给A MOV P0,A ;A将接收到的数据传送给P0,显示 SJMP LOOP ;继续等待接收到数据
END ;程序结束 图9 题4运行状态图
- 应用外部中断,对连接在P3.2管脚上的按键次数进行计数,每5次在P1.0上连接的绿色LED亮或不亮。
本题考虑点: 要求应用外部中断,则必须应用中断子程序,且在子程序内计数,满5次让P1.0翻转。 Proteus图: 图10 题5图 编程: ORG 0H ;程序从程序存储器的0单元开始存放 AJMP MAIN ;跳转到以标号为MAIN处
ORG 03H ;外部中断0的9子程序入口 AJMP INT0 ;调用外部中断子程序INT0
ORG 30H ;主程序从程序存储器的30H单元开始存放 MAIN: SETB EA ;打开总中断 SETB EX0 ;打开外部中断0的中断 SETB IT0 ;将外部中断0的触发信号设置为下降沿 SJMP $ ;在此等待中断发生
INT0: INC R0 ;用R0作为计数器,每中断一次加1 CJNE R0,#5,NEXT ;若没中断5次返回,等待下一次 MOV R0,#0 ;将计数器清零 CPL P1.0 ;将P1.0翻转 NEXT: RETI ;中断子程序返回
END ;程序结束
图11 题5运行状态图
- 应用计数器,对连接在P3.4管脚上的按键次数进行计数,每5次在P1.0上连接的黄色LED亮或不亮。
本题考虑点: 题意用计数器,且在P3.4管脚上,即应用计数器T0; 未说明用查询还是中断方式,本题选用中断方式。 Proteus图: 图12 题6图 程序: ORG 0H ;主程序入口 AJMP MAIN ;跳转到以MAIN为标号的程序
ORG 0BH ;计数器中断0的子程序入口 AJMP INT0 ;调用外部中断子程序INT0
ORG 30H ;主程序从程序存储器的30H单元开始存放 MAIN: MOV TMOD,#06H ;设置计数器为8位自动装入模式 MOV TH0,#251 ;设置TH0初始值为256-5=251 MOV TL0,#251 ;设置TL0同上 SETB EA ;打开总中断 SETB ET0 ;打开计数器0的中断 SETB TR0 ;将计数器0打开 MOV R0,#0 ;给R0赋值0 SJMP $ ;在此等待中断发生
INT0: CPL P1.0 ;将P1.0翻转 NEXT: RETI ;中断子程序返回
END ;程序结束
|