找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 29557|回复: 14
收起左侧

几个单片机汇编语言教学例程及详细分析

  [复制链接]
ID:304891 发表于 2018-4-10 09:32 | 显示全部楼层 |阅读模式
最近,我们在课上讲了几个小例子,在此再把Proteus图及程序的详细解释列出来,供大家参考。
  •     应用查询方式,对连接在P1.4管脚上的按键次数进行计数,每5次在P1.0上连接的红色LED亮或不亮。
本题考虑点:
  • 应用查询方式,即读和检测P1.4管脚的状态,是10
  • 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.0P1.1输出周期为300us600us的方波程序。
本题考虑点:
首先明确为应用定时器,且输出波形为方波,周期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 波形图
  •     应用1643只数码管,显示从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
GATE
C\T
M1
M0
GATE
C\T
M1
M0
0
0
1
0
0
0
0
0

SCON=50H
SM0
SM1
SM2
REN
TB8
RB8
TI
RI
0
1
0
1
0
0
0
0

编程:
主机程序:
  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               ;程序结束



完整的Word格式文档51黑下载地址:
近期的几个单片机例程及详细分析 (1).doc (283.5 KB, 下载次数: 93)

评分

参与人数 1黑币 +15 收起 理由
copower + 15 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:352726 发表于 2018-6-15 22:54 | 显示全部楼层
很不错,太棒了
回复

使用道具 举报

ID:416015 发表于 2018-10-26 20:57 | 显示全部楼层
学习一下!!!
回复

使用道具 举报

ID:69115 发表于 2019-2-13 13:48 | 显示全部楼层
都是很好的例子,学习了。
回复

使用道具 举报

ID:255377 发表于 2019-2-19 03:20 来自手机 | 显示全部楼层
在MAIN:MOV  P1,#0FFH  增加此命令
回复

使用道具 举报

ID:219544 发表于 2019-3-22 18:18 | 显示全部楼层
有没有初级学习的 实例教的全套
回复

使用道具 举报

ID:89835 发表于 2019-3-31 23:34 | 显示全部楼层
这些例子很经典,值得认真学习一下
回复

使用道具 举报

ID:336233 发表于 2019-5-30 09:18 | 显示全部楼层

学习一下!!!
回复

使用道具 举报

ID:575629 发表于 2019-7-1 14:21 | 显示全部楼层
程序二有一个小错误,应该是mov tmod #02h
回复

使用道具 举报

ID:475236 发表于 2019-10-10 18:22 | 显示全部楼层
谢谢楼主分享,不错的基础学习资料
回复

使用道具 举报

ID:348676 发表于 2020-1-6 14:15 | 显示全部楼层
谢谢楼主分享,不错的基础学习资料
回复

使用道具 举报

ID:736846 发表于 2020-4-24 11:39 来自手机 | 显示全部楼层
谢谢楼主分享,很好的学习资料。
回复

使用道具 举报

ID:737006 发表于 2020-4-24 14:55 | 显示全部楼层
谢谢分享,学习了。
回复

使用道具 举报

ID:117690 发表于 2020-5-26 16:23 | 显示全部楼层
谢谢分享
回复

使用道具 举报

ID:126173 发表于 2020-6-20 18:09 | 显示全部楼层
这个写得真好,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表