51单片机学习(汇编语言)
51单片机学习(汇编语言版)
注:本笔记参考疯狂的石头单片机——51篇 汇编版
一、点LED灯
我们先要看电路图(注意这个图和下面的电路板照片是反着的)
可以看到最上面是IO口,1对应P0的0口,8对应P0的7口,灯是绿色的,想要让灯点亮,下面VCC是正极高电平,上面的IO口应该为负极低电平,这样电路才能导通,我们想要让第一个灯即D8亮,就需要让P0的0口为低电平
1 |
|
这就是效果
我们可以改进一下,比如说把二进制改成十六进制
1 |
|
我们现在想要让高四位的四个灯全部点亮,低四位的四个灯不亮
1 |
|
我们还可以把代码精简一下,不需要用到累加器A,直接把值传到P0口
1 |
|
0F0H就是11110000即低四位的灯亮
我们还有另一种方法点亮灯
CLR是清除位的意思,就是清0寄存器
1 |
|
再看一个
1 |
|
这个的意思就是说把P0的7口清零
接下来我们试一试让灯间隔着亮,即一个亮一个不亮
1 |
|
其实上面的程序都不是一个完整的程序,那么什么样的程序是一个完整的程序呢?
1 |
|
二、让LED灯闪烁
用到延时
要学到循环结构和寄存器的使用
下面的程序可以先不用理解,注释也先不看,先看后面的解释之后再来看代码
注意一下,代码中加了冒号的前面内容(绿色的)都是函数名,是可以随便取的,可以取MAIN也可以取START这些都没事,只是自定义的函数名
1 |
|
程序的效果是:
最右边的灯是一亮一灭的
这里解释一下DJNZ指令,DJNZ Rn,REL是一条转移指令,先将工作寄存器Rn中的数减”1”判断结果是否为”0”,不为”0”程序就跳转到行标为REL的地方执行,否则,为”0”就不转移,继续执行下一条指令。
需要注意的是每执行一次DJNZ指令时,工作寄存器中的数会先减去1后,再判断是否返回。例如如果Rn中原来是2,则执行两次DJNZ后,Rn中就是0了,DJNZ运行的机器周期为2。
还有一个JNZ指令(或JNE)刚好和DJNZ指令相反,结果不为零(或不相等)则转移
这里还要说明一下指令周期的意思——即CPU执行一条指令所需要的时间称为指令周期。它是以机器周期为单位的
时钟周期——也叫振荡周期,一个时钟周期=晶振的倒数。
51单片机的一个机器周期=6个状态周期=12个时钟周期
51单片机的指令有单字节,双字节和三字节的,他们的指令周期不尽相同,一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占用时间为12*(1/12000000)=1us
这里通过一个c语言程序讲解一下延时程序的原理
1 |
|
这个程序是传入一个参数z比如为50,然后x=50开始,y从110一直减到0,然后x=49,y再从110减到0,一共减了50*110次。注意第一个for循环后面没有分号,意思是接下来执行下面的for循环。
这样一个程序就达到了延时的效果,因为这个程序执行完需要一定的时间,如果一次1毫秒,那就是50*110毫秒
接下来我们看一下用汇编写的50ms延时子程序:
1 |
|
计算精准延时时间:1 + (1 * 200) +(2 * 125 * 200) + (2 * 200) + 2
=(2 * 125 + 3 ) * 200 + 3
=50603us
=50ms
可以由上面的式子整理出公式即:
延时时间=(2 * 内循环+3) * 外循环 + 3
现在我们来详细说明一下怎么计算延时时间:
第一句:MOV R7,#200 在整个子程序中只被执行一次,且为单周期指令,所以耗时1us
第二句:MOV R6,#125 因为第四句如果为0则会跳回这里执行,那么就数一共跳回了多少次,因为R7是200,所以要减200次R7才能为0,所以跳转了200次,也就是第二句执行了200次
第三句:DJNZ R6,DEL2 本身内循环了R6次,但是又有外循环R7次,所以就是125*200次,注意DJNZ这个指令是双周期指令,所以需要再乘2
第四句:就是R7次,即200次,但是因为DJNZ是双周期指令,所以是2*200
第五句:这个就要2us,固定的
我们再看另一个例子,1秒延时子程序
1 |
|
延时时间:1 + (1 * 10) + (1 * 200 * 10) + (2 * 248 * 200 * 10) + (2 * 200 * 10) + (2 * 10) + 2
=998033us = 1s
已经很好理解了,需要注意的就是R7,R6,R5的顺序
公式可以归纳为((2 * 最内循环 + 3) * 内循环 + 3) * 外循环 +3
这里我再补充一下51单片机内的寄存器R0-R7
R0-R7在数据存储器里的实际地址是由特殊功能寄存器PSW里的RS1、RS0位决定的
我们只要知道通常情况下R0-R7在数据存储区里的实际地址是00H-07H,如果我们需要08H-0FH的地址,我们是需要对PSW寄存器进行设置才可以使R0-R7在数据存储区里的实际地址变为08H-0FH,这个我们以后再讲,因为不常用
好了全部讲完了,现在再回去看最开始的代码,会发现非常的简单,主函数START先让灯亮,然后调用延时函数,让程序停一下,然后在让灯灭,再调用延时函数,让程序停一下,这样就可以实现灯的闪烁了。
三、流水灯
单片机P1口接八个LED,每次点亮两只,先从右边向左移动点亮,再从左边向右边移动点亮,然后闪烁两次,重复循环
1 |
|
代码其实已经很简单了,完全看得懂,效果就是灯从右往左依次点亮,不断循环下去。
我们现在把程序变得复杂一点
1 |
|
程序的效果是:灯先从右往左依次亮起,然后所有灯亮,灭,亮,灭,再从右到左依次亮起
现在我们讲一下这个程序,因为c语言里面我们可以写带参数的函数,如果要循环几次就传多少的参数,在汇编语言里面不行,那么我们就是在上一句的结尾先用寄存器存好,为接下来调用做准备。
四、数码管(显示数字)
我们看一下数码管的原理
一共有八个led灯,比如我们想让它显示1,那么就让b,c亮起来就可以了,如果想要它显示0,那么就a,b,c,d,e,f亮,g,h不亮。这里的h代表小数点
这里讲的是共阳极数码管的编程
下面编写一个程序来驱动一位共阳极数码管从0-F显示
1 |
|
现在我们来讲一下DPTR是什么
它是一个16位的寄存器
我们看第五行,@符号是寄存器间接寻址前缀
其实就当指针来理解就好了,现在DPTR里面存了一个TABLE数组,数组里面刚好有16个元素,DPTR也刚好是16位寄存器,然后DPTR的指针地址刚开始是0,0指向0xc0,一直到16,16指向0x8e,A+DPTR,如果A是1,那么加了之后就是1了,那么就指向0xf9,@符号就是取值,所以第五行就是把0xf9这个值存到A里面。
然后我们还要知道这个TABLE数组里面的值其实就是数码管对应亮起的值,比如0xc0就代表数码管亮0
好了,这个程序肯定已经看懂了
五、四位共阳极数码管(显示四个数字)
这里做的效果就是拿一个可以显示四个数字的数码管显示1234
看一下这个电路图,从P0一直接到了P13
1 |
|
这样一个程序的效果就是依次显示1,2,3,4并不是常亮1,2,3,4
这里就要用到动态扫描
最简单的方法就是缩短延时
把第36行的#100改成10之后,就会发现几乎可以常亮,但是还是可以肉眼看到一点闪烁
六、独立按键
独立按键就是输入,就是我们按下按键的时候会有什么样的操作
这里我们把独立按键接到P2口上
1 |
|
这个简单的程序就是实现按第几个键第几个灯就会亮
七、外部中断
中断的概念
所谓“中断”,是指CPU执行正常程序时,系统出现特殊请求,CPU暂时中止当前的程序,转去处理更紧急的事件(执行中断服务程序),处理完毕(中断服务完成)后,CPU自动返回原程序的过程
好处:提高CPU效率(实时响应外界信息)、实现并行工作
通俗理解非常简单,比如你正在打王者,这时候微信来了消息,我们就会先把王者挂后台,然后去回微信,这就是执行中断服务程序。然后微信回复完之后又在后台点击王者这个app,然后继续游戏(注意,这时候并没有杀后台,王者不需要重新登陆,直接就可以继续刚刚的游戏),这就是中断服务完成,CPU返回原程序
外部中断:
从外部引脚P3.2或者P3.3引脚接收到的信号称为中断源(比如在看书时,敲门声和电话声就是两种中断源)
外部中断信号由两种类型(敲门门铃,直接手敲门)
电平触发:低电平有效
边缘触发:高电平变为低电平有效
中断申请寄存器IE介绍
八、定时器中断
定时和计数功能最终都是通过计数实现的,若计数的事件源是周期固定的脉冲,则可以实现定时功能,否则只能实现计数功能。因此可以将定时和计数功能由一个部件实现。
实现定时和计数的方法一般有定时、专用硬件电路和可编程定时器/计数器三种方法。
软件定时:执行一个循环程序进行时间延迟。定时准确,不需要外加硬件电路,但增加CPU开销。
专用硬件电路定时:可实现精确的定时和计数,但参数调节不便。
可编程定时器/计数器:不占用CPU时间,能与CPU并行工作,实现精确的定时和计数,又可以通过编程设置其工作方式和其它参数,因此使用方便
51单片机有三个16位的定时器——定时器0、定时器1和定时器2。
定时器0、1各具有四种工作模式;定时器2有两种工作模式
定时器0、1和定时器2的任何一种工作模式均可通过程序对相应寄存器进行设置来选择。
定时器T0和T1都是两个16位加法计数器
51中断入口地址
INTO:0003H
T0:000BH
INT1:0013H
以下程序是用数码管显示的秒表,可以显示到0-9秒(一位共阳极数码管)
1 |
|
九、矩阵按键
他和独立按键最大的区别就是独立按键8个io口只能控制8个按键,而矩阵按键就可以用8个io口控制8*8个按键了,大大提高了效率
比如说控制s2就需要1和7
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!