0. 寻址方式
寻址方式在汇编中是很重要的,汇编所有的操作都是和和内存或者寄存器打交道的,在80C51里面一共7种寻址方式。
1. 立即寻址:
这个没什么好说的,就是往寄存器或者内存里面写立即数,在80C51汇编里面立即数前面带一个#(这个和Intel其他汇编和AT&T的都是不一样的)。
MOV A, #00H ;把数字0放入寄存器A中
2. 直接寻址:
在80C51汇编中,如果数字前面不带#,就表明这个是一个地址,而且是绝对地址
MOV A, 20H ;把20H对应的内存的一个字节的内容传送到A中
MOV C, 20H ;把20H对应的内存的一个字的内容传送到C中(位寻址)
(注意P口也是内存地址,可能会出判断题判断MOV P0, #02H,是否合法类似的。)
3. 寄存器寻址:
在80C51中,RX表示寄存器(要记住寄存器是有4组的)
比如(R0) = 44H
MOV A, R0 ;把44H放入A寄存器中
4. 寄存器间接寻址:
在8086中我们很熟悉这个东西,比如在8086这种寻址方式就是 mov ax, [bx],但是80c51这个东西就很特别,在80c51中,如果要使用寄存器间接寻址:
:片内RAM(采用Ri(R0和R1,只能这两个),SP)
:片外RAM(采用Ri,DPTR)
比如(R0) = 44H (44H) = 30H
MOV A, @R0 ;把R0里面的内容对应的内存(44H)的内容(30H)放入A寄存器中
5. 变址寻址:
这种方式是拿来访问ROM的(而且也只能访问ROM)
MOVC A, @A+DPTR ;把A+DPTR的内存对应的内容放入A中
6. 相对寻址:
这个是专门针对相对跳转指令来说的,这些指令等下看。要注意的是这个相对转移的偏移值的大小是-128~127的。
目的地址 = PC + rel = 当前指令存储地址 + 指令的字节数 + rel
(要注意的是80C51的PC值是不断+1的(80C51有个部件叫PC Incremter),也就是8位8位移动(因为80C51是个8位的芯片,不能像80386那样移动四个字节或者两个字节),也就是说80C51看到跳转指令的时候是让自己再获取PC对应的操作数(8位),然后继续+1的)
7. 位寻址:
可位寻址的地方就是上一个文章所说的那个用户低128位的那16字节地址(20H~30H),以及特殊寄存器的一些可以叫出名字的一些地方。
位寻址的四种表示方式:
1. 直接操作地址:00H
2. 点操作符(有点像C的结构体的操作) 20H.1 PSW.6
3. 位名字,如IT0
4. 自定义: NAME BIT PSW.5 ;把PSW.5这个位地址给一个名字NAME
1. 汇编指令
书上废话太多,总结一下。
0. 传输指令(MOV)
格式(目的:源)
A :#data,direct,@Ri,Rn
Rn :#data,direct,A (R寄存器不能操作R寄存器)
direct :#data,direct,@Ri,Rn,A
@Ri :#data,direct,A (R寄存器不能操作R寄存器)
DPTR :#data16 (注意这个是MOV指令,不是MOVC或者MOVX,MOV只能是16位操作数到DPTR)
1. 特殊传输指令:
0. MOVC:(查表指令)
格式(目的:源)
A :@A+DPTR,@A+PC(都是在ROM里面查东西)
1. MOVX:(外部内存操作,扩展的时候非常需要用到)
格式(目的:源)
A :@A+Ri,@DPTR(读外部内容)
@Ri :A (写外部内容,注意这个只能寻址到256位,如果RAM寻址比8位还高,还需要给P2口提供高8位)
@DPTR :A (写外部内容,外部64KB的内容都可以访问到,DPH由P2输出,DPL由P0输出)
2. PUSH:(压栈指令):
PUSH direct
3. POP: (弹栈指令):
POP direct (注意PUSH和POP只能操作内存,有一种情况是需要我们压入A的内容,则要使用POP/PUSH ACC)
4. XCH:(字节交换指令):
格式(目的:源)
A :direct,@Ri,Rn
5. XCHD:(半字节交换指令):
格式(目的:源)
A :@Ri(这个指令比较奇葩,只能操作@Ri,是把Ri的内容指向的内存的低四位和A的低四位互换)
6. SWAP:(自交换):
SWAP A(不解释了。。)
2. 算术指令:
0. 不带进位加法指令(ADD)
格式(目的:源)
A :#data,direct,@Ri,Rn
1. 十进制调整指令(DA)
DA A
2. 带进位的加法指令(ADDC)
格式(目的:源)
A :#data,direct,@Ri,Rn
3. INC(自增指令)
格式(目的:源)
INC direct,@Ri,Rn,A, DPTR
4. SUBB(带借位的减法指令)
格式(目的:源)
A :#data,direct,@Ri,Rn(注意减法指令没有不带借位的)
5. DEC(自减指令)
格式(目的:源)
DEC direct,@Ri,Rn,A(没了DPTR)
6. MUL(无符号相乘指令,一定要记得是无符号的!)
MUL AB (A*B)(低8位在A上,高8位在B上,如果A溢出,OV = 1,B有结果,否则0V = 0,结果只在A中,进位CY总是会被清零,P的值按A的值来决定)
7. DIV(无符号除法指令)
DIV AB (A/B)(A是商,B是余数,OV的值只与除数是否为0有关,如果除数是0,那么OV = 1,否则0V = 0,CY会被清零,P的值按A的值来决定)。
2. 逻辑运算指令:
1. ANL(按位与),ORL(按位或),XRL(按位异或)
格式(目的:源)
A :#data,direct,@Ri,Rn
direct :#data,A
C :bit(可位寻址)
bit(可位寻址) :C
2. CLR(清零),CPL(取反),RL(循环左移),RLC(带CY位的循环左移),RR(循环右移),RRC(带CY位的循环右移)
操作A和位,注意带CY位的循环移动是把最高位放到CY位上,然后最低位是根据上一个CY位来的。
3. 跳转指令:
这些指令相当好记,因为只用记英文就知道这些指令是干嘛的了。
1. LJMP(long jump,长转移指令):
可以跳转到一个16位的绝对地址
2. AJMP(短转移指令):
可以跳转到一个11位的绝对地址
3. SJMP(相对转移指令):
rel是目标地址相对PC的偏移值(这里应该这样理解,处理器一看到SJMP指令,要先指向SJMP指令的下一条指令,所以先PC + 2(当然了其实一个一个加的,先遇到SJMP的8位操作码,然后再识别8位操作数,问题就是这个8位的操作数,这个8位的操作数实际上是编译的时候已经算好的了,是按照目标地址 - (SJMP的汇编地址 + 2)来算的 )
比如当我执行SJMP $的时候,$在这里是助记符而已,表明的当前地址,所以在编译的时候,会在SJMP的目的操作数上替换成-2,所以等SJMP执行时就自动跳转到本身了。
4. JMP(散转移指令):
这个指令是为了实现跳转表的,跳转表就是我们经常写的C的那个switch在汇编层实现的东西,具体格式就是JMP @A+DPTR(A + DPTR里面的内容是要跳转到的位置的据对地址)。
5. 条件转移指令(JZ,JNZ,CJNE,DJNZ,JC,JNC,JB,JNB,JBC):
这些指定都加多了一些条件,然后进行的都是相对转移(比如JZ,就是JUMP IS ZERO(当结果为0的时候就进行转移(和8086看ZF位不一样,80C51是看的A的值是否为0,如果A的内容为0,则转移,否则不转移)),JNZ刚好相反)
CJNE是比较不相等才转移(注意这个指令只能用于无条件数,有条件数是不适用的,因为它只看CY)。
格式:
CJNE A, #data, rel
CJNE A, direct, rel
CJNE Rn, #data, rel
CJNE @Ri, #data, rel
DJNZ是最常用的拿来做循环的指令(曾几何时我没用这个指令被老师说我程序写的太复杂),这个指令很容易拿来实现for,这个指令最大的特点就是可以边比较边把寄存器或者目的地址内容减1,直到减到0为止。
格式:
DJNZ Rn, rel
DJNZ direct, rel
JB,JBC,JNB指令都是看对应的位地址的情况然后跳转,JB是目的位地址是1则跳,否则不跳,JNB功能刚好和JB的相反,JBC除了能比较位为1然后跳转意外,还能把对应的位地址清零
JC和JNC则是看的是CY标记位。
ACALL和LCALL这两个指令就不用说了,一个短调用一个是长调用,这两个命令都要和RET指令一起用。RETI是和中断一起用的,RETI除了会把压入栈的地址弹出来外还会把80C51内部的挂起的中断请求给撤销掉,以响应下次中断(和8086的IRQ是一样的)。
2. C51
C51虽然长得和C差不多,写的时候和C也差不多,但是毕竟不是正统的CS的产物,有一点奇奇怪怪的东西还是需要注意一下的。
首先C51的整形(unsigned int和int都是16位的(并不是32位),而且我建议大家写程序的时候不要去定义一个什么宏uchar来表示什么unsigned char,这种做法简直是在侮辱编辑器,要是keli写的不够爽可以换VScode或者Notepad++)。而unsigned long 和long都是32位的,float是32位的,同时C51有bit型,这个是C没有的东西。
特殊功能寄存器型(sfr,sfr16),分别可以指向8位特殊寄存器(当然必须是可寻址的那些了),16位特殊寄存器。
比如sfr FUCK = 0x90; 我们就定义了FUCK这个变量指向0x90这个地址对应的特殊功能寄存器(当然我们知道这个是P1,是8位的)
sbit可以定义一个可位寻址,这个可以定义内部RAM的位寻址空间以及特殊功能寄存器,
比如可以sbit papa = P0^0,这样papa这个变量就是P0^0了。
C51另一个特色是可以自定义存储类型,这个在外部拓展写代码的时候是很重要的。

比如我可以定义一个指针unsigned char xdata *ptr = 0x7fff,这个指针指向外部内存0x7ffff地址。
另外我们也可以在C51中定义存储模式,C51定义了三种存储模式,SMALL(默认存储类型是data,存在片内RAM,速度快),COMPACT(pdata(紧凑模式),存储于片外分片RAM),LARGE(xdata大模式,存储于片外64KB的RAM,速度慢)。
注意在C51里面,中断子程序的写法是这样的void Fun()interrupt m uisng n(没有返回值和没有参数,并且后面带着interrupt(使用哪个中断(中断从0-4分别为外部中断0,定时器中断0,外部中断1,定时器中断1,串口中断))和using(80c51一共4个工作寄存器组))。
3. 一些题目
选了一些题目,有一些是书上作业,有一些是老师布置过的题目
1. 将R1的内容传送到R0(注意80c51MOV指令不能寄存器对寄存器)
2. 将内部RAM单元10H的内容送到外部RAM单元1000H(注意1000H已经比256要大了,不能用@Ri,要用DPTR)
MOV A,10H
MOV DPTR,#1000H
MOVX @DPTR, A
3. 将外部ROM内容1000H的内容传送到R5(注意MOVC的格式只有@A + DPTR或者@A + PC,不能少A)
MOV DPTR,#1000H
MOV A, #00H
MOVC A, @A+DPTR
MOV R5 ,A
4. 将外部RAM单元2000H的内容传送到外部RAM单元2001H(注意MOVX的格式)
MOV DPTR, #2000H
MOVX A, @DPTR
MOV DPTR, #2001H
MOVX @DPTR, A
5. 现外部RAM 2000H和内部RAM20H有内容,设计程序实现将这两个单元内容相加,将其结果的十位和各位送到外部RAM的2000H,百位送到F0位
MOV R0, #2000H
MOVX A, @R0 ;注意是外部内容
ADD A, 20H
DA A ;DA一定要放在ADD之后
MOVX @R0, A ;A包括了十位和个位
MOV F0,C
6. 屏蔽20H的高4位(注意逻辑指令是可以直接操作内存的,不要傻乎乎地转A)
7. 将E0H的低4位取反,高4位不变(注意这个世界有异或运算这种东西)
8. 将31H:30H和11H:10H的内容实现16位数相加((31H:30H) + (11H:10H)),把结果存在30H中(51是高端字节序)
MOV A, 31H ;高端字节序,低位在高字节
ADD A, 11H
MOV A, 30H
ADDC A, 10H
MOV 30H, A
(PS如果是减法,由于减法是没有不带借位减法的,所以在第一步必须CLR C,其他只要把ADD和ADDC换成SUBB就可以了)
9. 设X变量在内存10H内,Y在内存20H内,编写程序实现:(完整实现) Y = { 80H x>0; 50 x ==0 ; 0FFH x<0 }
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN:
MOV A,10H
CLR C
JB ACC. LESS ;注意这里不要用SUBB,题目没有告诉我们这是无符号数,SUBB的话要看OV和CY
GREAT:
JZ EQUAL
MOV Y,#80H
AJMP OUT
EQUAL:
MOV Y,#50H
AJMP OUT
LESS:
MOV Y,0FFH
OUT:
...
10. 在内部RAM21H单元开始存储了有一组单字节的不带符号数,数据长度是30H,要求求出最大的数放入BIG单元
MOV R6, #30H ;R6存放有多少个数
MOV R1, #21H ;数组开始
MOV R0, #00H ;R0放的是最大的数
LOOP:
CLR C
MOV A, R0
SUBB A, @R1
JNC CONTINUE
MOV A, @R1
MOV R0, A
CONTINUE:
INC R1
DJNZ R6,LOOP
MOV R3, BIG ;R3指向了BIG单元
MOV A, R0
MOV @R3, A
- 单片微机原理P0:80C51结构原理
本来我真的不想让51的东西出现在我的博客上的,因为51这种东西真的太low了,学了最多就所谓的垃圾科创利用一下,但是想一下这门课我也要考试,还是写一点东西顺便放博客上吧. 这一系列主要参考<单片 ...
- 单片微机原理P3:80C51外部拓展系统
外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC. 0. IO接口电路概念与存储器拓展 1. 为什 ...
- 单片微机原理P2:80C51外部中断与定时器系统
0. 外部中断 书上的废话当然是很多的了,对于中断我想大家应该早就有一个很直观的认识,就是"设置断点,执行外部外码,然后返回断点"这样的三个过程.中断给系统提供了一个良好的响应模式 ...
- 单片微机原理P4:80C51串口与串行总线拓展
0. 串口通讯 0. 串口通讯的数据传输方式:单工(单向传输数据),半双工(非同时双向传输),全双工(同时,双向传输) 1. 根据通信方式的不同又分为同步通讯和异步通讯. 同步通讯:所有设备都使用同一 ...
- 80x86/Pentium微机原理及接口技术-微处理器-学习笔记
80x86/ Pentium微机原理及接口技术 1. 计算机基础... 1 1.1常用术语... 1 1.2计算机中数与编码的表示方法... 1 1.2.1进制表示及进制转换... 1 1.2 ...
- 002-创建型-03-单例模式(Singleton)【7种】、spring单例及原理
一.概述 保证一个类仅有一个实例,并提供一个全局访问点 私有构造器.线程安全.延迟加载.序列化和反序列化安全.反射攻击 1.1.适用场景 1.在多个线程之间,比如servlet环境,共享同一个资源或者 ...
- html基本标签表单实现交互原理,单选框,复选框,下拉框介绍
表单是什么?表单是前端和服务器做交互的一种机制,表单收集用户输入信息,之后发送或者提交给服务器.用户在输入的信息称之为内容,内容的文本分为普通和密码型,用户通过单选框.复选框.下拉框(也就是下拉菜单) ...
- 单片机的基本构成、工作原理 LET′S TRY“嵌入式编程”: 1 of 6
单片机的基本构成.工作原理 LET′S TRY“嵌入式编程”: 1 of 6 本连载讲解作为嵌入式系统开发技术人员所必需具备的基础知识.这些基础知识是硬件和软件技术人员都应该掌握的共通技术知识.有了电 ...
- AngularJS进阶(三)HTML:让表单、文本框只读,不可编辑的方法
HTML:让表单.文本框只读,不可编辑的方法 有时候,我们希望表单中的文本框是只读的,让用户不能修改其中的信息,如使<input type="text" name=" ...
随机推荐
- hdoj1789【贪心】
题意: 已知有n个作业,每个作业呢,都是一天可以做完,每个作业都有一个截止日期,每个作业如果超过他的截止日期会扣分,最后让你求一个怎么安排求得一个最小扣的分数. 比如现在有3个作业 截止日期:3 3 ...
- 【HDU - 1257】最少拦截系统(贪心)
最少拦截系统 Descriptions: 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的 ...
- TensorFlow多线程输入数据处理框架(四)——输入数据处理框架
参考书 <TensorFlow:实战Google深度学习框架>(第2版) 输入数据处理的整个流程. #!/usr/bin/env python # -*- coding: UTF-8 -* ...
- Ascall码的故事
没事发个ascall码表,二进制值得研究呦 sub al,30h; and al,00001111b ;字符ascall转数字or al,00110000b; sub al,32; and al,11 ...
- python三行代码实现快速排序
def quick_sort(array): if len(array) < 2: return array return quick_sort([lt for lt in array[1:] ...
- 洛谷 P1445 [Violet]樱花
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> usin ...
- CF 602 D. Lipshitz Sequence 数学 + 单调栈 + 优化
http://codeforces.com/contest/602/problem/D 这题需要注意到的是,对于三个点(x1, y1)和(x2, y2)和(x3, y3).如果要算出区间[1, 3]的 ...
- D. Tavas and Malekas DFS模拟 + kmp + hash || kmp + hash
http://codeforces.com/contest/535/problem/D 如果真的要把m个串覆盖上一个串上面,是可以得,不会超时. 要注意到一点,全部覆盖后再判断时候合法,和边放边判断, ...
- qconshanghai2016
http://2016.qconshanghai.com/schedule 大会日程 2016年10月20日 星期四 07:45 开始签到 09:00 开场致辞 专题 前端技术实践 主题演讲 业务上云 ...
- jQuery在$(function(){})中調用函數
任務太緊,很少記筆記,記下一篇jQuery中調用函數的例子: 該方法是在載入頁面的時候,判斷 ModelName 不為空,則獲取Model信息加載到Table中: 另外,在點擊半成品編號文本框時,也調 ...