按照顺序,今天该到说 指令系统 的时候了,要说 指令系统 就必须说 寻址方式,否则就等于没说。今天说的内容,对于你点亮LED,那就是临门一脚了。
这一篇文章,较少个人原创,多多少少来自各种资料的融合,只是按照我自己的方式和顺序讲,看的时候你可以参考若干份一般51教程看,这里我会在附件里上传一份我随手百度到的 这一部分 的资料,以供参考。
首先解释一个概念,什么叫 寻址方式?
寻址方式就是说,CPU在ROM或者RAM的不同存储区域读写数据以及单片机内部存储器不同位置之间交换数据的方式。(个人理解)
这里简单说一下 51单片机的 指令系统 的基本情况。
51单片机总共有111条指令,它们的集合就叫 指令系统。别看它有111条,也千万不要想着去背,更加不要去背程序......千万不要!
按照基本的功能划分,我们一般将它划分成五大类。
这五大类分别是:
数据传送类指令 29条 ——这一大类是重点,因为下边的所有指令,其实都隐含了数据传送作为第一步
算术运算类指令 24条
逻辑运算及移位类指令 24条
控制转移类指令 17条
位操作指令 17条
至于后四大类,如它名字所言。其中我想需要解释的是 第五类,位操作,考虑到一部分读者未必熟悉数字电路。
前边我们说了,二进制数,一个位只有0和1两个状态,当我们要计数更多的时候,就要用多个位组合表示,这与十进制一样,个位就像我们的两只手,撑死只能到10,两个位了就可以去到99......
我们也说了,二进制位除了表示数目以外,很大程度上它其实是表达一系列二进制状态——比如我们前面说的 红绿灯。
那么有时候,如果我们单单只要操作某些位,那我们就可以不整个二进制数一起运算,而是把它拆成一个一个的位去操作,这个东西很多时候很方便。我先举一个简单例子。
首先我假设你懂的 逻辑运算符 与 或 非(假如你不懂,请百度,解释这个东西太费劲了。)
现在我们有一个二进制数 01010001(0x51),它代表的意思是,8个人里,凡是0就是女士,凡是1就是男士,那么,这8个位我们可以想象是8个人站成一排。现在我们要判断某个位置是男士还是女士,我们该怎么做呢?
比如我要判断第五位是男士?那我就应该看 xx?x xxxx,?表示我们要判断的第五位,我们的判断方法是,用 0010 0000和它去 位与
(请注意 位与 与 普通逻辑与 的差别——比方说,前面说的0x51和这个 0x20,如果是逻辑与,因为两个都非0,所以结果是1,但如果是位与,位与就是说对应的位上的0或者1依次与,这里有8次与操作,于是,结果就是0000 0000).
这里简单提一下,位操作的好处,它可以保留或者去除,判断某一些特定位的数值,而在单片机这种RAM紧张的系统中,我们经常用一个位去表示某个状态,而不如PC程序,直接用一个数去表示。具体我们下边讲。
另外三类:控制转移指令,它的功能其实与一般高级编程语言里的条件判断结构 if很接近。
而 算术运算 和 逻辑运算,如名。
我们重点只讲 第一大类,数据传送指令,为什么呢?
我先说一个个人观点:除去对数据进行运算,单片机对数据的所有操作其实质就是在 移动数据。所以,如果你掌握了它,那单片机已经了然在你胸中。
前边说, 讲 指令系统 就必须讲 寻址方式,这针对的就是 这 数据传送类指令。
前边说了,寻址方式,说白了就是CPU在各个存储器的不同位置之间 读写数据,或者CPU控制存储器中不同位置的数据传送——因为CPU是整个单片机的 CEO,它控制了一些。
先简单说说 51系统的七种寻址方式——以下内容纯COPY:
立即寻址
直接寻址
寄存器寻址
寄存器间接寻址
基址寄存器加变址寄存器的变址寻址
位寻址
不知道为什么,我记得是七种,这里却只有六种,不过不要紧,因为上边我除了想让你知道它们有多么拗口费解的中文名字以外,没打算让你真的去记忆它们。
如果信得过我,请记住一句话:你要知道的,只是记得在单片机中,我们如何传送不同位置的数据即可(这些不同位置 包括 ROM空间,RAM的位寻址区,特殊寄存器SFR区等等。)至于它叫什么名字,鬼才有兴趣记得它,不瞒您说,我就不记得。
看完这些,你会有一个奇怪的问题,好端端的我为什么要分这么多种拗口的方法去存取不同位置的数据呢?
这个问题问得好,我先用一个通俗的方法来说。
坐飞机从广州到北京,要花多少时间呢?最多几个小时吧(不好意思没坐过。)做飞机到美国西海岸,估计也就半天(?更没坐过)。但是呢,我坐火车从广州到北京可能就要两天几夜,而我十一坐长途汽车回家更是因为塞车,活生生坐了大半夜才到两百多公里外的粤北......
当时我也很想坐飞机回去。
为51各种莫名其妙寻址方式而蛋疼的童鞋表示,他也很想统一用某种方式,最好就是MOV X,Y了!
但是为什么我不能坐飞机回韶关呢?
首先,韶关没有民用飞机场,其次,假设有,200多公里的短途,我坐火车38快,坐汽车这次算是黑的可以了,110,但坐飞机估计怎么着人家也要收我3、400,不然我担心它连运营都成问题......
对于51而言,也是类似的问题。
具体来说,我现在只知道几点:
1 它内部安排的地址指针长度不够,比如说,人家一个字节就只有8个位,如果你非要用它去寻找超出255B的片外RAM,你这不是存心让人家难看?
2 在上一个问题的基础上,假设人家就是有256B+,人家就是8个位,人家就是要找......这个时侯它很任性,那怎么办?
凉拌,凉拌还得拌,但8个位就是不够啊,我咋整?没事,两个字节不就16位了吗?这一来事情就麻烦了,首先,人家一个字节,CPU只要读一次,现在要读两次,然后,为了人家方便寻找,你不能高八位在加拿大,第八位就跑到阿富汗吧,于是,人家就只能依次存储这两个字节.......这样一来,至少导致两个问题: 1 速度慢 ; 2 内部存储器碎片多。
我就想到这两个,总之,一句话结论:为啥人家那么蛋疼给了6还是7种寻址方式,其原因就好比我不能坐飞机回韶关一样。
刚才回头看了一下我将要上传的这份资料中,提到了很多挺多余的内容,比如说 指令有多少个长度字节。比如说一条汇编指令的格式应该是怎样的......
这些玩意我全都忘得一干二净了,但是它们基本没啥影响,不管我是用C还是汇编都一样。
我的思维是我们要直接从 用途入手,而不是庖丁解牛,那太累了,我只不过是要吃牛肉吗,怎么宰不是宰.......我一不是达芬奇,要画牛,而不是兽医,没打算研究牛的运动解剖学.......
记住,我们是编程序做应用的人,没人要我们去设计CPU和处理器。
但是我觉得如果我就此结束,有点儿对不起观众,毕竟我懂了,没学过的人还不知道怎么回事,所以我打算用精简的方式讲解一下 6种 寻址方式,它们讲完了,数据传送类29条指令也七七八八了。
1 立即寻址
当初,这个名字让我很蛋疼,什么叫“立即”,难道还有“稍等”?算了,别管他,其实它的意思就是,直接把一个数值赋给某个地址或者某个寄存器(其实本质上,某个寄存器就代表那个特定地址,记得我前边说过的么,RAM就像一本草稿纸,上边有特殊寄存器,有所谓用户自定义区,其实说到底,它们都是一页一页的纸,只不过,那个叫 P1的家伙,它平时不告诉别人自己的地址是0X90。)
但是请记住,并不是每一个地址,每一个寄存器,都可以 直接 赋值成一个具体数字的。具体,请查阅指令表。
2 直接寻址
这同样是个蛋疼的名字。
其实直接寻址的意思就是说,我告诉你一个地址,你直接跑到人家住址哪找人家——不知道是不是语文没学好,我当时经常把 “立即寻址”和 “直接寻址”混淆。
同样的,它的寻址范围也是有限制的。并且下边加上几点说明
1 地址这个东西,有时候也可以是寄存器名字,比如说,前边说了,P1的地址其实是0X90,虽然它总是见人就说我叫P1,但大家其实也知道,至少CPU知道,它其实也是地址0X90。
2 直接寻址,只能找RAM低128位,这就好比,你打了一个什么9032,之类的奇怪号码,人家说,对不起你不允许呼叫此号码,也许这个号码直接通道国家秘密机关单位去,当然不能让你去.......
3 寄存器寻址
请注意区分 这里的 寄存器 和 特殊寄存器,为啥呢?因为这里特指R0到R7。
在RAM里,有一个连续单元,分别存储了4组R0到R7,它们是8个连续的8位存储器,要说它们为啥单独归为一类,那是因为,它们可以和A进行直接联系。
你可以直接把R0中的数据转到A中去,反之亦然。
可是,其实在我看来,同样存在MOV A,P1 和MOV P1,A这样的语句,这个分类是不是有点废话呢?
当然不是,那这有啥特点呢?按照书上的写法,简单点理解是,这四组工作寄存器离CPU比较近,操作起来最快,于是乎——宋江想给皇帝老子说招安的事情,还的去找李师师,为啥,因为李师师就睡在皇帝老子旁边啊~
4 寄存器间接寻址
这个名字,,,,,,好吧,如果用我们前边的草稿纸比喻的话,前边的直接寻址我们可以叫 登门入室,那这个寄存器寻址我们可以说是 拿地址挖人——所以上网的童鞋们,没事千万别学我到处乱留手机号码,虽然我的号码不值钱,就怕哪天有人把我号码满大街乱写,还要外加“办证”两个字。
不过,人家这个寄存器也不是谁都可以做的,这就好比,除了警察叔叔和公安哥哥或者某些人可以随意查到我们身份证户籍等资料别人是没有资格查阅的一样。
而51里,这两个寄存器其实只有两个,R0和R1。
而R0和R1都是8位寄存器,所以,虽然人家可以知道人家闺房的地址,但权限也是有限的。。。。。。。255,以后你会经常看见这样的数字,它很有规律,然后俺想告诉你的是,它能查的只有RAM的256B空间。——届时你会发现,在这六类寻址方式里,基本上都是说的寻RAM的地址,只有一个特殊的,它可以查到ROM里的。
请切记这一点,你到底在查什么地方的数据。千万别做出 跑到 美国 找 阿富汗总统的事情——除了他去访美。
当然了,8位51的内部还有一个唯一的可寻址16位寄存器DPTR,它有十六位,不过其实它只是依次并排的两个连续寄存器单元。有了它,就可以访问到255B以外的更大空间。当然了,鞭长莫及,它就16位,撑死也就64K。
5 变址寻址
前边我说了,寻址绝大多数寻的是RAM,而有一个特别,它可以等效于寻找ROM上的地址——其实这种解释是错误的,因为ROM是不可寻址的。
不过,因为有了变址寻址,事情有了点有趣的变化。
这一类寻址总共有3条指令
JMP @A+DPTR //JMP叫无条件转移,意思就是说,我让你往哪去你就得往哪去,没得讨价还价。后边跟的是地址,不过这个地址有点复杂。下边说第二句话的时候你就懂了。
MOVC A,@A+DPTR
MOVC A,@A+PC
这里有一个寄存器叫PC,请不要把它和你桌上这台 个人电脑的PC混为一谈,它的名字叫 程序计数器,嗯,前边我不是说了么,ROM里存储的程序被分成一条一条的8位字节单元,就像我们那一封一封的信,如果我把每一封信按顺序编号,1234,,然后,我一封一封往下读,当我读到第5封的时候,这个叫PC的东西就会是5(哦,不,严格来说,它指向下一条指令的地址,但是它并不一定是6,因为,我正在读的命令可能要两封信才能看完,于是乎,PC就是7)
PC和DPTR都是16位寄存器,唯一不同的是,DPTRk可以寻址,啥意思,就是说,人家的老巢可以被我找到,我可以随便给它赋值,而PC就厉害了,地球人都找不到他,它很严格的观察着我们下一条命令要读的是哪一个信封。
不好意思,我自己都忘记了,PC呢,是 程序计数器,就是说它指定的内容是在ROM空间里,而DPTR呢,它是一个数据指针,也就是说它指定的内容是在RAM里。
于是乎,我才说,尽管PC是不可寻址的,但是因为有了这个MOVC A, @A+PC这条指令,我们也可以读到ROM里的数据。
6 位寻址
这个没啥好说。前边说了,一个字节8个位,但是很多时候,这8个位,不是你想一个一个读就可以一个一个读的。
就好比有人在大街上卖冰糖葫芦,虽然你可能只想吃一颗,但是不好意思,我一串一串卖,单个不卖。
但是,在RAM里,它还是安排了一部分单元允许你一个一个位读写——只是可怜我上哪找卖一颗冰糖葫芦的地方去~~
这一个特殊位置,在RAM的20H到2FH,总共16个字节,一个字节8位,就是128个位。
另外还有一些RAM是可以位寻址的,它们就是高128位的特殊寄存器区中,地址以0或者8结尾的,比如说前边说的P1,它的地址是0X90。
最后我说一下 位地址的表示方法。
那16个可位寻址的字节单元,总共128个位,它的编号是从 20H的最低位开始编址位00,然后01,02,,,,一直到2FH(字节,字节!!)的最高位,为第127位,也就是7F。
这里要注意的是——千万不要把 字节地址 和 位地址 混淆了——因为CPU对它们有独立的寻址方法,因此可以用重复的数值编址。
那份资料接下来还说了一通的5大类传送指令,我考虑一下,明天是否接着写个4接着说,或者不需要了?不管如何,今晚写得够长够累了,其实这一部分也是最头疼的一部分。
希望我另外组织的 介绍方式 对你有点帮助!谢谢,如有记错或者不到位的地方,欢迎指出!!
说完了PC和DPTR的区别,我们再来看这个@A+DPTR这样形式的地址,它有点像我们前边说的 寄存器间接寻址。
@R0,它读的是什么呢?它读的是R0里的数字,可是这个数字并不是我们要的内容,它是一个地址,那个地址上所指的内容才是我们想要的。
就是说,现在有一封信上的指令写着03,但它的意思并不是让你“往前走一步”,而是说让你去看编号为03的那个信封里的内容,它可能让你帮她买酱油......
[
本帖最后由 辛昕 于 2011-10-9 22:07 编辑 ]