b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

51 MCU组装时钟代码示例

电脑杂谈  发布时间:2020-04-29 03:13:46  来源:网络整理

单片机汇编_单片机汇编编程_单片机hex汇编

此示例使用汇编在Puzhong微控制器上实现简单的秒表功能,并带有一个复位按钮.

创建一个新的keil项目,创建一个新的.asm文件并将其添加到项目中,而无需添加startup.a51文件

在编写代码之前,请先谈谈随后编写51程序集所必需的一些基本知识,因为程序集与硬件密切相关,因此如果不了解它们就无法编写这些程序

1. 单片机上电后的一般操作过程

MCU有自己的检测和编程程序. 上电后在某个引脚上检测到某个信号时,从串口发送的数据将被编程到程序存储器中(从0000H开始),

然后执行编程的程序,否则执行最后的编程程序.

微控制器执行的第一条指令是程序存储器中的0000H内容. 通常,在此处将跳转指令写入主程序的起始地址(例如1000H,例如,不一定要在此处)

当执行主程序时,如果发生中断,它将跳转到程序存储器中的固定地址(例如T0会跳转到000BH),一般在这里写一条跳转指令,以便程序跳转到中断处理程序<

此处的固定地址是所谓的中断向量. 因此我们编写51汇编程序必须首先在这些地址上编写跳转指令

单片机hex汇编_单片机汇编编程_单片机汇编

2. 一些常用的寄存器

将不再提及与微控制器的配置有关的特殊寄存器,例如P0,TMOD等,并且与编写C语言时几乎相同. 工作寄存器更多地参与编写汇编.

还有A,B寄存器,DPTR寄存器,PSW寄存器,SP寄存器等,这里专门提到工作寄存器,其他百度可以.

工作寄存器有4组,每组都是8个工作寄存器R0~R7,通过PSW中的RS1、RS0两位来选择使用哪一组,如果不选,默认是选择第0组。
RS1RS0组合为00时,选中第0组工作寄存器,R0~R7地址为00H~07H;(这里的地址为内部RAM区)
RS1RS0组合为01时,选中第1组工作寄存器,R0~R7地址为08H~0FH;
RS1RS0组合为10时,选中第2组工作寄存器,R0~R7地址为10H~17H;
RS1RS0组合为11时,选中第3组工作寄存器,R0~R7地址为18H~1FH。
进入中断时,可以通过改变RS1RS0来分别使用不同的R0-R7

3、51个单片机的存储器结构

编写汇编代码以确保上面的图片清晰可见,因为汇编直接操作上述内存,并且不同的内存区域可能使用不同的指令.

程序存储器用于在程序编译后保存指令,这些常数只需要读取而无需修改. 读取是通过MOVC命令实现的,示例如下

disBuf: DB 00H,01H,02H,03H,04H,05H,06H,07H

单片机汇编_单片机hex汇编_单片机汇编编程

MOV DPTR,#disBuf

MOV A,00H;表示读取disBuf的第一个,01H读取第二个

MOVC A,@ A + DPTR;从rom获取数据

我还是不明白. 像DB这样的伪指令只能用于在微控制器中定义常量(在ROM中)吗?在8086中似乎是一个变量

我尝试了几次,但没有找到好的答案. 最后,变量定义直接是“变量名EQU内部ram的地址”要实现

数据存储器是RAM区域,分为片内和片外. 用于访问的说明不同. 片上直接MOV就足够了. 片外ram只能通过A寄存器读取或访问(请参见表中的特定附件说明)

在这里您可以发现51单片机的数据存储区和代码存储区是分开的. 从这个角度来看,它是一个哈佛结构,但是获取和读取数据是分时的. 曼结构的特征. . . 因此存在争议

4. 掌握调试技巧

毕竟,汇编程序直接操作内存,因此调试的使用非常重要. 这是一些关键用途

单片机汇编编程_单片机hex汇编_单片机汇编

第一个位置是从左到右: 重置(簇头启动),全速运行,停止,单步运行(输入子程序)单片机汇编,单步运行(子程序不进入单步运行)

第二个块可以看到常用寄存器的值,其中R0指的是R0的第一组,如果要查看其他组,则必须使用第三个块的功能

第三个块用于查看内存中的值,如下所示:

在“存储器”窗口中输入地址值,结果是程序代码区域的内容. 要查看各个存储区的内容单片机汇编,只需在“地址”框中输入“字母: 地址”以显示相应的存储值. 字母可以是C,D,I,X,这表示:

C: 代码存储空间

D: 直接访问片上存储空间

I: 间接寻址片上存储空间

X: 扩展了外部RAM空间

单片机汇编_单片机汇编编程_单片机hex汇编

如果输入“ d: 0x30”,则可以在芯片上显示可直接寻址的30H存储空间的内容.

您还可以使用右键单击“修改内存”选项来修改指定内存的内容.

第四个街区,指定地点的断点

5. 汇编代码说明

我个人容易出错的一点是,当我为寄存器分配一个常量值时,我常常忘记使用#号. 汇编语言和C语言习惯不同. 我必须在常量值前面加上#号,否则它将被视为该值所表示的地址的内容

例如,MOV R0,0x01会将内部RAM地址为0x01的存储单元的内容复制到R0. 要将R0分配为1,应将其写为: MOV R0,#0x01

还有一个代码段,用于手动安排起始位置. 确保分段之间没有重叠(我不知道它是否可以自动排列)

好的,知道了这些之后,您就可以根据此说明开始编写汇编代码,我将其直接粘贴

duan       EQU     P0;
wei        EQU     P2;
key        BIT     P3.7;

ORG   0000H
AJMP  MAIN;绝对转移指令,2kb范围(11位)内跳转 LJMP16位 64kb范围内跳转
;短转移指令的功能是先使程序计数器PC加1两次(即:取出指令码),然后把加2后的地址和rel相加作为目标转移地址。因此,短转移指令是一条相对转移指令,是一条双字节双周期指令

ORG   0030H;指明后面的程序从程序存储器的0030H单元开始存放
DELAY200US:            ;@11.0592MHz
    NOP
    NOP
    NOP
    PUSH 30H
    PUSH 31H
    MOV 30H,#2
    MOV 31H,#179
NEXT:
    DJNZ 31H,NEXT
    DJNZ 30H,NEXT
    POP 31H
    POP 30H
    RET
ORG 0060H
;DISPLAY子程序
DISPLAY:
PUSH ACC;不能写A,此处ACC代表地址,push后跟地址,代表把地址内的内容压入栈中
PUSH 00H;R0
PUSH 06H;R6
PUSH 07H;R7
PUSH 83H;DPH
PUSH 82H;DPL
MOV R6,#01H;位选数据,01指的是缓冲区最低位数据
MOV R7,#08H;循环次数
FLAG:
MOV duan,#0x00;消影
MOV A,R6
CPL A;取反
MOV wei,A;位选
MOV   A,#disBufDat
ADD   A,R7
SUBB  A,#0X08
MOV   R0,A
MOV   A,@R0;读出要显示的数据到A
MOV   DPTR,#disTab
MOVC  A,@A+DPTR;从rom取数据,取出要显示的数据对应的段码    
MOV   duan,A;段选
MOV A,R6
RL A
MOV R6,A;更新下一次位选

LCALL DELAY200US
DJNZ R7,FLAG
POP 82H;DPL
POP 83H;DPH
POP 07H
POP 06H
POP 00H
POP ACC
RET
ORG 0100H
;定时器中断0初始化
T0_INIT:
MOV TMOD,#0X01
MOV TH0,#0X3C
MOV TL0,#0XB0
SETB EA
SETB TR0
SETB ET0
RET
ORG 0130H
;T0中断处理程序
INT_TIMERE0:
PUSH ACC
SETB RS0
MOV TH0,#0X3C
MOV TL0,#0XB0
INC R0
MOV A,R0
SUBB A,#0X14
JB CY,SECFLAG
MOV R0,#0x00
INC sec
SECFLAG:
CLR  RS0
POP ACC
RETI
ORG 000BH ;定时器/计数器T0入口地址
LJMP INT_TIMERE0 ;跳转到定时器/计数器中断服务程序中去    
disTab: DB 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40;0-f,空白,横杠的段选数据
disBufDat EQU 47H;定义显示缓冲数据变量区,8个
disBufDatHead EQU 40H //单片机上显示在最左边
sec EQU 48H
    
    
;主程序
ORG 0180H
MAIN:
MOV SP,#0X60;将0x60到0x7f设为堆栈区
LCALL T0_INIT
MOV disBufDatHead,#0X00
MOV disBufDatHead+1,#0X00 
MOV disBufDatHead+2,#0X11
MOV disBufDatHead+3,#0X11 
MOV disBufDatHead+4,#0X11 
MOV disBufDatHead+5,#0X11 
MOV disBufDatHead+6,#0X11 
MOV disBufDatHead+7,#0X11 
MOV sec,#0X3A
WHILE:
JB key,KEYSCAN
MOV sec,0x00
KEYSCAN:
MOV A,sec
SUBB A,#3CH;超过60s归零
JB   CY,CLEAR
MOV sec,#0X00;clr加ram地址无效
CLEAR:
MOV A,sec
MOV B,#0AH
DIV AB;A/B,商存到A中,余数存B中
MOV disBufDatHead,A
MOV disBufDatHead+1,B
LCALL DISPLAY
LJMP   WHILE;循环
END;
    

总体思路是先初始化T0和显示缓冲区,然后在随后的while循环中将sec变量连续反汇编到显示缓冲区中(如果它大于或等于60 clear),则调用DISPLAY子例程显示,如果按按钮清除秒数

display子例程很难看. 功能是将内部ram40h到47h的8个字节用作显示缓冲区. 这8个字节对应8个数码管,每个数码管在相应的字节中显示内容.

它最初旨在用于外部击键. . . 结果,我停止使用时钟了. 搜索了很长时间后,我没有发现任何问题. 我必须先完成任务,然后再说.

说明说明:


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/dianqi/article-192503-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 李晓华
        李晓华

        中国虽然国大人多

      • 张云云
        张云云

        是要进行民煮选举的

      • 李晓华
        李晓华

        一个让人随便入侵领海领空的国家还谈什么强国

      热点图片
      拼命载入中...