矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 12428|回复: 29

考拉聊单片机4

[复制链接]
发表于 2010-12-10 23:18:03 | 显示全部楼层 |阅读模式
上回聊了单片机是如何工作的,见:

http://www.crystalradio.cn/bbs/thread-155467-1-1.html

这回聊聊如何指挥单片机干活?也就是说说单片机所能执行的指令种类和主要运算/操作等。

1、认识多少字儿?

一个小孩子我们经常会问他认识多少字儿了?同样这话也应该问问单片机。前面说过要让单片机干活就得用它所能听懂的语言告诉它要作些什么怎么作,这些单片机所能懂的语言的基本单元就是指令。一种单片机所能认识并执行的指令就构成了它的指令集,可以说就是这个躲在芯片里的小宝宝所认识的字数,你要想让它作事,就得用这些字儿来写作事的步骤也就是程序。前面也说过指令集中的指令越多功能就越强,但也说过不要以为指令少的单片机就简单好学,因为复杂的任务你就必须用一段程序(也就是一组简单功能的指令)来完成。例如PIC中档型号是没乘法指令的,你如果需要作乘法就要用加法移位等指令写一段程序来完成。常见单片机指令集大小不一,51是111条,PIC中档系列(如16F84A)是35条,AVR ATMEGA系列是130条

前面也说过单片机的字长,说的是可处理数据的长度。指令实际也有字长,加上前面所说过的因为程序存储空间和数据存储空间分开的因素,指令的字长和数据的字长可以不一样。比如PIC中档型号的长字(数据)是8位,但指令却是14位的。也正因为这个原因,考拉前面在描述存储器容量时一直没用KB这个单位,只说K。因为不同的单片机里程序存储器这个K后面的单位是不一样的,有的是以字节(Byte,也就是8位二进制)来计算的,有的则不是。

指令的字长不光可以和数据的字长不一样,不同的指令的长度也可以不一样。说到这里就不得不提一下CISC和RISC,前者是复杂指令集,后者是精减指令集,详细区别这里就不细说了,只简单介绍一下区别就是了。CISC一般指令条数多,指令长度不一,执行时间也不一样。我们的PC就是CISC的机器,51也是。51的指令最短的1字节,最长的三字节,执行时间最短的一个机器周期(这个概念后面聊单片机时序时再说),最长的四个机器周期。PIC一般叫作类RISC,指令都是相同的字长(中档为14位二进制),执行时间基本是1个机器周期,个别是2个机器周期。AVR号称是RISC,指令基本是相同的字长(除个别是32位外,其他都是16位,也就是2个字节),执行时间1-4个机器周期,多数是1个周期。一般来说RISC的比CISC的速度快一些,但运行速度和单片机的时序设计也有关系,有些51改进时序设计后速度也提高了,这些后面再说。

注意,指令实际也是一串二进制数字,直接用指令写程序叫机器语言,这是唯一单片机所能认识并直接执行的语言。我们常在书上见到的写法比如MOV、ADD等只是助记符,助记符和二进制的指令是对应的。助记符写程序叫汇编语言,可以基本上直接翻译为指令。还有一种语言叫高级语言,比较接近我们平常的表达方式,比如A=B*3,但这个必须经过编译程序翻译成机器语言单片机才能执行。这个翻译过程不象汇编语言那么直接对应,因此效率不如汇编高,但使用方使。由于机器语言难写难记(1100001010010000,这就是前面例程里的clr P1.0,是不是象天书?),般我们写程序都是用汇编语言和高级语言(单片机主要用C,有的也能用BASIC),这两者的区别与优劣后面再说。但如果要学透单片机建议还是先学一下汇编,简单应用汇编也足能应付。

2、多少与黑白

前面虽然很多地方都从侧面提到了,但这里还是需要正式明确一下:计算机只认识二进制数,所以程序数据都得用二进制来表示。啥叫二进制呢?我们常用的十进制每位数字最多可以有10个状态(0~9),逢10进1。同理二进制也就是每位数字只有2个状态的数制,即每一位数字非0即1,逢2进1。由于每一位的计数数量很少,所以表示同样大小的数字二进制要比十进制用更多的位数。比如8位十进制可以表达最大99999999的数字,基本就是1亿了,而8位二进制11111111只相当于十进制的255。而我们现在说的单片机都是8位字长的,也就是一次加法最多也就加出俩二百五(向高位进一位,高位也就是第9位可计数是256,连余下8位一共是俩),所以在进行数学运算时难度相应比我们日常熟悉的方式要大,当数字比较大时汇编语言尤其麻烦(高级语言简单,麻烦事儿编译程序替你干了,但也要当心溢出,啥是溢出后面再说)。后面我们可能经常会提到高位/低位或高x位/低x位这种词,不管哪种数制左边的某位肯定比右边的某位表示的数值大,所以靠左边的就叫高位,靠右边的叫低位。就一个字节的8位二进制来说,最右边的一位是最低位,称为第0位,最左边的一位是最高位,称为第7位。

二进制与十进制的转换这里就不细讲了,一般书上网上都有,自己去查吧(本贴最后会给大家教一个简单实用的办法)。但有时我们也可以不把二进制转换为十进制,而用二进制直接表示十进制,这就是单片机中常用的BCD码。说来也简单,4位2进制可以表示的最大数是15(16个编码,从0开始),10-15这6个编码不用了,只用前10个,也就是每四位二进制数字表示一位十进制。二进制一般的运算也不细说了,但有一条要注意一下,有些地方程序设计用得到,也就是一个二进制乘2相当于整个二进制数左移一位(右边最末一位补0),原理也简单,左边每一位二进制所能表示的数的大小是右边一位的2倍,左移一位就是整个数字放大一倍了。如果只是需要乘二就直接左移一位即可,效率比你作乘法高得多。例:00000011(等于十进制3)左一位是00000110(等于十进制6),相当于乘以2之后的值。

除了十进制和二进制,在玩单片机过程中我们还会碰到另一种数制,叫十六进制。顾名思义这就是一种每一位最多可以有16个状态的数制,每位最大计数是15。怎么表示呢?在0~9十个数外再加几个英文字母就是了,也就是用0~9加上A~F来表示一位16进制数。前面说了单片机只认识二进制数,为什么又要引入16进制呢?答案很简单,就是为了方便!前面我们已经看到二进制数字非常难以书写与记忆,而一位十六进制恰相当于4位二进制,所以在实际使用中经常把二进制写成十六进制来表示。可以说十六进制就是二进制数的缩写。举个例子前面那条清P1.0的指令是1100001010010000,写成16进制就是C290,是不是简单好记多了?为了区别十六进制和其他数制(如果这个数字里恰好没字母,你还真弄不清到底是十进制还是十六进制),一般在书写时会在前面加0x或是在后面加一个大写的H,前者常用在C语言中,后者常用于汇编语言中。

小学生不光要学算术,单片机当然也一样。我们经常要进行一些逻辑上的判断什么的,比如假如温度高就怎么怎么样,假如电压低就怎么怎么样,这就需要用到逻辑运算。逻辑判断有的可以用专门的比较指令完成,有的则要用两个数字进行逻辑运算得出结果。和逻辑运算相关的布尔代数有些深,但目前不需要深究,只需要了解一些最简单的就行,有了这些就可以理解别人的程序并自己干活了。一般的逻辑运算都可以用与、或、非三种运算来表达完成(道理就不说了,有兴趣的去看数字电路或者离散数学),所以我们只要掌握了这三种逻辑运算就能基本达到目的。逻辑运算里一个算式的结果只有两个可能,“真”或“假”,真用1表示,假用0表示,这样逻辑运算就可以用二进制数来实现。

与(表示为∧)可以理解为同时的意思,比如“小张又高又胖”,用逻辑上的语言来说就是“小张高∧小张胖”,只有这两者都是真的是这句话才是真的,任何一个条件不成立就是假的,一个值和1与原值不变,和0与则清0或(表示为∨)可以理解为或者的意思,比如“小张吃的是面条或者米饭”,用逻辑上的语言来说就是“小张吃面条∨小张吃米饭”,只要他吃了任意一种这句话就是真的(当然也可以两种都吃了),除非两者都没吃才是假的,一个值和1或则置1,和0或则原值不变非(一般表示一个逻辑变量顶上加一横线如ā,这里为了简单表示为—)简单的说就是颠倒黑白,原来是真的经过非运算就得到假值,原来是假的经过非运算得到真值,比如“—(小张吃过饭了)”,如果小张没吃饭括号里的话就是假的但经过非运算整个表达式意思是小张没吃过饭,从而是真的。有时还会遇到一个运算叫异或,如果两个参与运算的值一个真一个假结果就是真,只要相同(同真或同假)结果即为假。异或运算也可以用与或非三种运算来表达,但一般为了方便单片机还是提供这种逻辑运算。一个值和1异或相当于取反,和0异或原值不变

逻辑运算有些什么用呢?简单举例说明一下,把两个二进制数看作一串真假值,1表示真,0表示假,就可以按位进行逻辑运算。比如我们有时需要单片的一个I/O(一般是8位)中的某几位输出某些值,但不希望其他的位受影响,就可以用与或逻辑运算来表达,例如51的P1口目前的值是10101010,我们想低4位(右边4位)输出0011,但不想影响高4位(左边4位)的值,就可以这么操作:
    10101010
∧11110000
——————
=10100000
∨00000011
——————
=10100011
先用与运算把其中几位清0,再用或运算在清0的这几位输出需要的值,从而实现部分口线的输出,这个技巧在单片机程序设计中是很常用的。再有就是象前一贴里说的开关LED,可以不用那么麻烦的又是CLR清0又是SETB置1,只每次对P1.0作一次CPL求反(即非运算)就行了。程序可以变得更简单。异或有时可以用来对一个字节的某些位取反,只要想取反的那些位和1异或,不想变的那些位和0异或就行了。

3、都会干哪些活?

一个小宝宝一天到晚只会吃喝拉撒睡加玩,如果一定要对单片机的行为作个分类的话也是几大类,这就是指令的功能分类。单片机的指令各种教科书上分类不大一样,但都是一些小的区别,考拉在这里把这些指令分为六大类,不论什么单片机肯定都可以把指令分到这六类里去:

①数据传送类指令:就是把要处理的数据/地址什么的在单片机的存储器和寄存器还有I/O端口间传来传去,是使用率最高的一类指令,单片机实际大部分时间都在干这些事儿。另外堆栈操作以及交换指令也归入这一类;
②算术运算类指令:简单说就是加减乘除(有些单片机如PIC中档机没乘除指令),此外一些与运算有关的辅助操作如十进制调整指令也归入这一类;
③逻辑运算类指令:就是前面说过的与或非运算,一般还提供异或运算。此外移位指令一般也归入此类;
④控制转移类指令:前面说过如果不修改PC的值程序就会一直顺序执行下去,但为了进行判断以及循环,我们必须让程序进行转移,这些实现转移的指令就归入此类。一般包括无条件转移,条件转移,子程序调用,返回等指令。这类指令直接影响着程序的质量,所以要写好单片机程序尤其是汇编语言程序,就要特别注意这类指令;
⑤位操作类指令:单片机除了可以对一个字长(8位机就是一个字节)操作外,还可以对位进行操作(例如前面提到的CLR P1.0)。位没有算术运算,只有逻辑运算。位操作指令由数据传送、置位/清0、逻辑运算、控制转移等组成;
⑥其他指令:其他一些用于单片机控制的指令,如空操作(这个一般书上列入控制转移类)、休眠、清看门狗等。空操作,啥都不干吗?(设计这个是不是吃饱撑的或用现在流行语说闲的蛋疼?)…………是的,确实啥都不干,但却是非常有用的指令,有时为了精确计时或实现特定时序等用途就需要在程序中插入空操作,呵呵。

好了,到此你应该已经知道这个躲在芯片的小宝宝到底都可以干些啥了,基本就是这几大类功能,不论多复杂的程序,最后也要用这几类中的指令来完成。详细的指令到后面举到实例时再一个个的介绍,现在只要明白单片机这几大类功能的基本概念就行了。

4、手指在哪里?

前面说到不同单片机指令数量不同,多的一百多,少的才不到四十。后面又说不管多少条指令,都可以分到那几大类里去。既然功能分类都差不多,为什么指令条数区别这么大呢?缺少一些功能指令(如乘除)只是一方面,究其根本其实另有原因,看完下面这段你就会明白了。

前面曾经举过小宝宝用手指算算术的例子,现在再来详细的看一下。比如我们让小宝宝算一下2+3等于多少,假设小宝宝先用左手两个手指表示2,再右手三个手指头表示3,然后数手指,最后得出结果5,高兴的伸出左手五个手指给你看,这就是一个完整的计算过程。单片机进行运算的过程实际是类似的,一般的运算分为单目运算(一个数字参加运算,象加1运算和逻辑非运算)和双目运算(两个数字参加运算,象加减乘除与或等),前面小宝宝进行的加法就是双目运算。参加运算的数据我们在单片机里叫操作数。单片机执行指令必须知道指令存在哪里以及下一条指令在哪里,进行数据运算时同样要知道用于运算的操作数在哪里以及运算结果存在哪里。和指令一样,也可以把这些存数据的地址全放在指令里(确实有早期的计算机这么干),但同样会带来指令太长的问题,于是后来计算机一般都是把得出的结果存在其中一个提供运算数据的存储单元里(比如数据存储器某单元、寄存器以及累加器等,最常用的是累加器,这个概念后面说到硬件时再解释),就象小宝宝算完把结果用左手的手指表示一样(左手原来是用来表示其中一个作加法的数字的)。单片机和前面小宝宝作的是一样的,两个数字进行运算时算完的结果放在左面那个数字的存储单元里,因此一般右边的操作数叫源操作数,左边的叫目的操作数

既然进行数据运算时单片机同样要知道数儿存哪儿(也就是小宝宝作算术时要知道手指在哪里),就和指令一样存在一个寻址的问题。程序的寻址是用PC来解决的,而数据的寻址则要复杂的多。寻址方式就象指令条数一样,越多相应单片机功能就越强。可以把指令的功能比作一个名词,则寻址方式就象用来修饰的形容词,同样的功能配上不同的寻址方式就形成了不同的指令。看到这里你就明白了为什么不同单片机指令数量差别那么大了,由于寻址方式的数量不同,虽然基本功能(也就名词)都差不多,但配上数量不同的寻址方式(也就是形容词),指令数量(实际就是词组了)也就差别很大了。

下来看看一些常用的寻址方式。寻址方式虽然挺多,但最基本的其实就三种方式,其他方式都是从这三种基本方式演变出来的。这三种基本方式是:

①立即寻址:操作数就放在指令当中,执行指令时可以立即得到。相当于一个常量;
②直接寻址:操作数的地址放在指令当中,执行指令时直接到那里去取,相当于一个变量;
③间接寻址:存放操作数地址的数据单元地址放在指令中,执行指令时先到那个数据单元去获取操作数地址,再去那个地址取得操作数,也就是要通过这个数据单元间接获得操作数。这个概念稍有点绕,学过C的一定会想到指针,呵呵。这么设计看起来很麻烦,到后面举到实例时就知道其好处了。

关于寻址方式先说这么多,更多的后面再聊,说太多了会消化不了的,嘻嘻。

[ 本帖最后由 cosine 于 2010-12-11 13:52 编辑 ]
 楼主| 发表于 2010-12-10 23:19:20 | 显示全部楼层
5、逻辑电平,数字量与模拟量

根据前面聊的这些,我们已经知道单片机只认识二进制数,也就是每位只有两个状态,0和1。但这是逻辑上的概念,这些状态还是要用电路来实现的,因此就会有一个逻辑概念与物理状态的对应问题。当单片机供电电压为+5V时,最理想的当然是+5V代表1,0V代表0。但实际电路肯定不会这么理想,有一些误差比如进来一个电压是+3V怎么办呢?

小时候我们看电影是要把片中人物分类的,也就是好人和坏蛋。但实际生活中的人不是这样的,电影中也不完全是这样,可对小孩你如何解释呢?一般的作法是如果这个人好的部分占大多数就归入好人,如果坏的占大多数就算坏人。也就是在好和坏的理想状态上加一定的宽容量,表示逻辑状态的电压也可以照此处理,比如0~0.8V算0,2~5V算1,这就是一种表示逻辑状态的电平,叫TTL电平(TTL电平的严格定义请查询相关资料,这里只是个大概解释)。可这样也有一个问题,仍然有一些中间状态无法解释,就象电影上一个人好坏正好一半咋办?面对小孩子我们可能就直接斩钉截铁的说这种情况不存在,对单片机也一样,这种状态不应该存在,要么就是元器件坏了,呵呵。留一个中间状态的原理很简单,两个状态间需要一个分隔区,不然容易造成错误的解释以致出错。所以在实际应用中要注意电平的范围,如果强行把不在定义内的电压接入就会出乱子,单片机看惯了黑猫白猫,今儿来了一只灰猫它也会犯晕出错的。

注意,不要从前面的例子以为高电平一定就是表示1,低电平就一定表示0。不同的电平标准有不同的定义,也就是逻辑状态和不同电平标准的物理状态间的对应关系是不同的。TTL电平是这么表示,不等于其他电平也这么表示,比如232电平,-15~-3V代表1,+15~+3V代表0。因此在电路接口时一定要注意两边各是什么电平,当电平标准不一样时要进行电平转换。象你要给STC的单片机下载程序,PC串口输出的是232电平,而STC的串行口只接受TTL电平,就需要一个电平转换器,也就是一片类似MAX232的芯片来完成这个工作,这也就是所谓的STC下载线的结构及其所完成的功能。

前面说的这种用一定的电平来表示逻辑状态运行的电路就是数字电路。而平时一般所看到的模拟电路比如放大电路等一般输出都是连续的变化的电压,可以看作有很多个输出值(近乎无穷多个)。单片机主要是由数字电路构成的,但生活中不光有好人坏蛋黑猫白猫,还有好坏参半的人以及灰猫,也就是很多连续的模拟量怎么处理呢?常用的有两种方法,一是设置一个门槛值,当高于或低于这个门槛值时给单片机一个信号,也就是一个数字量,单片机依据这个数字量进行动作,象常见的温度水位控制等;另一种是要把模拟量数字化后提供单片机进行处理,也就是进行A/D转换(模拟量/数字量转换)。前者只要用一个电平转换电路或是电压比较器就能实现,后者相对复杂需要A/D转换电路或专门的A/D芯片。单片机有时也要输出模拟量,同理也需要D/A转换。

在一般业余使用中A/D使用的频率比较高,因为需要采集模拟量用于控制,而输出模拟量即D/A使用的频率不高,多数情况用数字量进行一些开关控制就足够了。所以下面对A/D多说几句。虽然单片机只认识0和1,但一串0和1就可以组成一个二进制数字,也就可以有很多个状态来描述模拟量。因此可以根据一个参考电压,把这个电压分成若干等份,每份给一个编号(就是一个二进制数),当输入电压(不能高于参考电压)落到哪个等份里时,就输出这个编号,单片机就能认识和处理这个模拟量了,这就是A/D的基本原理。至于如何识别落到哪个区间,有很多不同的方法,同理也就有很多不同的电路及芯片。D/A的基本原理其实和这个类似,只是方向相反而已。这些到后面聊到的时候再细说。


今天的主要内容就聊完了,最后说说简单的数制转换方法。编制程序时经常要进行数制转换,二-十六进制互相转换还算简单,四位一组转就是了。二-十进制转换可就比较麻烦了,而且容易出错,这里考拉教大家一个简单的办法:

能上网来看这个贴的朋友都有电脑,那么调出你电脑中附件里的计算器,点菜单里的查看选择科学型(默认是标准型),然后就可以看到显示数字栏的下面有几个不同数制的选项,先选择要转换数据的原始数制,然后输入那个数字,再选择要转换到的数制,你就可以直接看到转换结果。详见附图,简单吧!

今天就先说到这里了,最近理论说的多,下次聊聊实际的,上哪里获得单片机以及如何写入程序,且听下回分解。

http://www.crystalradio.cn/bbs/viewthread.php?tid=157414

[ 本帖最后由 cosine 于 2010-12-18 23:27 编辑 ]

原始值十进制250

原始值十进制250

转为二进制

转为二进制

转为十六进制

转为十六进制

评分

1

查看全部评分

回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2010-12-11 12:35:33 | 显示全部楼层
占一层楼备用。

[ 本帖最后由 cosine 于 2010-12-11 14:02 编辑 ]
回复 支持 反对

使用道具 举报

发表于 2010-12-11 14:52:26 | 显示全部楼层
通俗易懂,不像网上其它教程一样死板,让人摸不着边际,太感谢了!
认真学习了1-4篇,感觉正适合我这样一点基础没有的人,版主辛苦啦~ 期待您能完成此教程,也希望俺能一路学习下来。。。
回复 支持 反对

使用道具 举报

     
发表于 2010-12-11 16:45:21 | 显示全部楼层
欢迎继续讲~~~~~~~~~~~~
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-12-11 17:37:42 | 显示全部楼层
有什么意见和建议也请提出来,后面聊的时候会考虑修改.
回复 支持 反对

使用道具 举报

发表于 2010-12-11 18:33:50 | 显示全部楼层
深入浅出 ,讲的好 .感兴趣了 .今天去书店买了书 " c51单片机高效入门 "
回复 支持 反对

使用道具 举报

     
发表于 2010-12-11 21:53:03 | 显示全部楼层
从头看到尾,写的太好了,通俗易懂很适合学习,谢谢版主。
回复 支持 反对

使用道具 举报

     
发表于 2010-12-11 21:53:26 | 显示全部楼层
老师辛苦。
俺还是觉得AT89S52好玩些,至少下载可以ISP,Flash也够大。
回复 支持 反对

使用道具 举报

发表于 2010-12-11 22:19:10 | 显示全部楼层
版主打了这么多字,一定很辛苦,加油。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-12-11 22:56:27 | 显示全部楼层
原帖由 liccil 于 2010-12-11 21:53 发表
老师辛苦。
俺还是觉得AT89S52好玩些,至少下载可以ISP,Flash也够大。


其实不管什么芯片,适合自己就好.S52是比较常见的芯片了,ISP下载也方便,下载线还能同时用于AVR.
回复 支持 反对

使用道具 举报

     
发表于 2010-12-12 00:07:26 | 显示全部楼层
考拉兄辛苦啦!
回复 支持 反对

使用道具 举报

     
发表于 2010-12-12 00:17:02 | 显示全部楼层
哈哈~我给你装订成册~以供以后阅读之用
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-12-12 09:43:35 | 显示全部楼层
对了,有没有什么地方看不明白发晕的?这个贴一直同时在一乐转贴,有两狼昨时表示没全看懂.如果有没看懂的请提出不,我再补充说明,大家再讨论,这样就明白了.
回复 支持 反对

使用道具 举报

     
发表于 2010-12-12 13:11:28 | 显示全部楼层
看不懂时要多看几编
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-4-26 03:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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