本例子为用汇编在普中单片机上实现一个简单的秒表功能,加一个清零按键。
新建keil工程,新建.asm文件并加入工程,不添加startup.a51文件
在写代码之前,讲一些后面写51汇编必要的基础知识,因为汇编与硬件息息相关,这些不知道就没法写
1、单片机上电后的大致运行过程
单片机内部有自带的检测烧写程序,当上电后在一定引脚上检测到一定信号,则接收串口发来的数据烧写到程序存储器中(从0000H开始),
再执行烧写好的程序,否则执行上一次烧写的程序。
单片机执行的第一条指令是程序存储器的0000H里内容,一般在这里写一个跳转指令到主程序起始地址(比如1000H之类的,只是举个例子,不一定这里)
在执行主程序时,若发生中断,会跳到程序存储器的固定地址(比如T0会跳到000BH处),一般在这写个跳转指令,使程序跳转到中断处理程序处
这里的固定地址就是所谓的中断向量。所以我们写51汇编程序首先得在这些地址处写好跳转指令
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
MOV DPTR,#disBuf
MOV A,00H;代表读取disBuf的第一个,01H则读第二个
MOVC A,@A+DPTR;从rom取数据
这里我还有点不懂的地方,DB这样的伪指令在单片机里难道是只能用来定义常量(在rom里)的吗?8086中好像是变量
我试了几次也查了下没找到不错的回答,最后定义变量是直接 ‘变量名 EQU 内部ram的地址 ‘来实现的
数据存储器即ram区,分为片内和片外,访问用到的指令不一样,片内直接MOV就行,片外ram只能通过A寄存器来读取或访问(具体指令看后面附上的表)
这里可以发现51单片机数据存储区和代码存储区是分开的,从这点来看它是哈佛结构的,但是取指和读数据又是分时的,网上有人说这是冯诺伊曼结构的特点。。。所以有争论
4、需要掌握的调试技巧
汇编毕竟直接操作存储器,所以debug使用非常重要,下面稍微提一下关键的几个使用
第一块地方从左到右分别是:重置(丛头开始)、全速运行、停止、单步运行(进入子程序)、单步运行(子程序不进去单步运行)
第二块能看到常用的寄存器的值,这里的R0是指第一组的R0,想看其他组得用第三块的功能
第三块用于查看存储器里的值,如下:
在Memory窗口中输入地址值,得到的结果是程序代码区的内容。要查看各种内存区域的内容,只要在Address框内输入“字母:地址”即可显示相应的内存值。其中字母可以是C、D、I、X,分别代表的意义是:
C:代码存储空间
D:直接寻址片内存储空间</