信盈达—您身边的嵌入式&人工智能专家
全国免费咨询热线:400-8788-909
您现在的位置在: 首页> 学习经验>

时间:2019-05-24 00:00:00 来源:信盈达 作者:信盈达

最近看到几个寻求单片机入门的帖子,一时心血来潮,把自己的一些入门心得写了下来,希望能对初学者有所帮助吧。
可能很多人学习单片机的开始都是一章一章的的去阅读教程,我也这样做过,结果就是没多久就昏昏欲睡了。对于初学者来说,什么随机存储器啊,只读存储器啊,寄存器啊,寻址方式啊,周期啊,指令啊。。。等等等等,简直就跟看天书一样。其实,我认为对于初学者来说,没必要了解这么多,学习总是一个循序渐进的过程,不要妄想着能一下子就把单片机的理解透了,然后再去动手做实验,做项目,这是很不现实的。
学习单片机的时候,要想着单片机能做什么我就学什么,我想要做什么就学什么,不懂,就翻书,再不行,就上网找。那么首先单片机能做些什么呢?单片机能做的事情很多很多,恐怕说个几天几夜都说不完。可能很多人会这么说,这么多的功能,这么多的例子,究竟从何学起啊!但是在我看来,单片机能做的只有两件事而你要做的也只有这两件事情:第一,输出高低电平;第二,接收高低电平的输入。假如单片机没有输入输出功能,那么程序编得在怎么超凡脱俗,也没有任何意义。因为,没有了跟外围器件的通信,单片机还有什么用呢!那么跟外围器件的通信靠的是什么呢?高电平(+3.3V或+5V)和低电平(0V)。那么我们的目的就很明确了,学习单片机的目的就是让单片机的各个管脚输入或输出高或低电平。在程序上代表高低电平的就是数字量1和0。也就是说,程序的最终目的就是在各个管脚上输入或输出1或0。所有的程序都是为了达成这个目的而设计的。换句话来说,只要能在你想要的管脚输入或输出你想要实现的高或低电平,那么你的目的就已经达到了,不要去管你的程序有多么的臃肿或是不堪入目,这个会随着你学习的深入和经验的积累而逐渐改善,不需要着急。
举个最简单的例子,在单片机的P1.0的管脚上接一个LED灯,要让LED灯点亮,就是在P1.0管脚上输出高电平,要让LED灯熄灭,就是在P1.0脚上输出低电平。那么怎么样才能在P1.0脚上输出高或低电平呢?不知道,那就去翻书一条一条的去找指令。哦,找到一条SETB置位指令,置位P1.0那不就是把1赋给P1.0吗,P1.0置1,不就是输出高电平了吗?至于是不是,谁试谁知道。不过,先不要着急,既然找到了输出高电平的指令,那么顺便找找输出低电平的指令。好了,没错,就是你了CLR。那么现在就可以编程序了:
             ORG        0000H
             JMP         MAIN
             OGR        0030H               ;如果不能理解这几条指令的意思,那就直接套用就可以了
MAIN:
             SETB       P1.0                  ;输出高电平,点亮LED灯
             CLR         P1.0                  ;输出低电平,熄灭LED灯
             END
好了,程序完成,很简单吧。可是,这个只是一亮一灭,我要它不停的闪烁怎么办?简单!多加一句跳转指令就行了,跳转指令上面就有JMP,那好吧,再改一下程序
             ORG        0000H
             JMP         MAIN
             OGR        0030H
MAIN:
             SETB       P1.0
             CLR         P1.0
             JMP         MAIN
             END
大功告成
可是,程序运行之后,看不到LED灯一亮一灭啊!怎么回事?这是当然了,单片机CUP的运行速度是以微秒来计的,人的眼睛是反应不过来的。那要怎么办呢?让CPU停一下等个一两秒再执行下一条指令?那显然不行,地球人都知道。那就找点事情给CPU去忙吧,不管它干什么都行,只要再这段时间内不要去碰P1.0管脚就行了。那么让它去做什么呢,国际上-_-!!!通常让它去数数,因为CPU每数一个数的时间都是一样的,比如说1微秒,那么数1 000个数,就是1毫秒,数1 000 000个数就是一秒。那么怎么样让CPU去数数呢?继续找指令表,我找。。。找到一个INC,每执行一次,操作数加1,那我要数到1 000 000的时候停止呢,怎么办?不知道。不知道!那要你干什么,一边去吧你,顺便把你兄弟DEC也带走,我不想再见到你们!我再找。。。这个好像有点用JZ,累加器A中为0就跳转,好像可以啊,我先让CPU跳一边去然后给A一个数1 000 000,让A从1 000 000减到0,A为0时再跳转回来不就行了?不过累加器A是什么?不知道?那就再翻书。。。哦,好像A最大只能到255,到不了1 000 000,怎么办?255就255吧,先试试再说,看能不能看出变化。那么怎么给A送数呢?MOV呗!好了,那谁谁谁,你给我回来,DEC别看了,说的就是你!嗯,再改一下程序
             ORG        0000H
             JMP         MAIN
             OGR        0030H
MAIN:
             SETB       P1.0
             MOV        A,#255            ;给A一个数,让CPU去数
             JMP         WAIT               ;CPU给我一边数数去
LED_OFF:
             CLR         P1.0
             MOV        A,#255            ;
             JMP         WAIT1             ;再来一个
LED_ON:
             JMP         MAIN
WAIT:
             DEC        A                     ;A-1
             JZ           LED_OFF         ;等于0就跳回去
             JMP         WAIT              ;不等于0就继续减
WAIT1:
             DEC        A                     ;A-1
             JZ           LED_ON          ;等于0就跳回去
             JMP         WAIT1            ;不等于0就继续减
             END
编译,,排错,运行,大功告成
好了,程序编完了,也能运行了,不过现在高兴是不是太早了,你在JMP来JMP去的,JMP的我头都晕了,那我要是要再延长一点时间,你岂不是要JMP个没完没了了?!难道就没有别的方法了吗?那好吧,我在翻翻书。真是书到用时方恨少啊。。。咦,这个看起来有点意思,CALL,是不是跟打电话一样,不管你在哪里,一个CALL,就能找到你啊。不过这个ACALL和LCALL又有神马不同呢,难道还有国内长途和国际长途之分?不管了,就用你了LCALL,反正不用花钱。
             ORG        0000H
             JMP         MAIN
             OGR        0030H
MAIN:
             SETB       P1.0
             MOV        A,#255
             LCALL     WAIT               ;我CALL
             LCALL     WAIT               ;我再CALL
             LCALL     WAIT               ;
             LCALL     WAIT               ;
             LCALL     WAIT               ;我CALL,CALL,CALL。。。
             CLR         P1.0
             LCALL     WAIT
             LCALL     WAIT
             LCALL     WAIT
             LCALL     WAIT              ;哈哈哈。。。CALL个够,爽
             JMP         MAIN
WAIT:  
             DEC        A                     ;A-1
             JNZ         WAIT              ;没数完,继续。。。
             RET                               ;数完了,那我挂电话了,有时间再CALL你啊
             END
好了,这回看起来舒服多了。不过累加器A,看起来你有点意见?A:“废话!你不知道老子很忙的吗!分分钟几十万上下,你叫我给你数数?你确定,你的脑袋没被驴给踢过?老子纵横机湖几十年,阅人无数,就没见过你这么白的程序员!”好吧,大哥,你牛,我惹不起你我躲的起。我再翻书,幸好这不是在考试,我想怎么翻就怎么翻。。。有了!就是你了DJNZ,减1不为0就跳转。咦,怎么没有减1为0跳转的呢?也不知道创造汇编的那位大神是怎么想的。好吧,这不是我们这些小菜鸟该管的,还是改我的程序比较靠谱一点
             ORG        0000H
             JMP         MAIN
             OGR        0030H
MAIN:
             SETB       P1.0
             MOV        R0,#255         ;那就换一个呗
             LCALL     WAIT               ;我CALL
             LCALL     WAIT               ;我再CALL
             LCALL     WAIT               ;
             LCALL     WAIT               ;
             LCALL     WAIT               ;我CALL,CALL,CALL。。。
             CLR         P1.0
             LCALL     WAIT
             LCALL     WAIT
             LCALL     WAIT
             LCALL     WAIT              ;哈哈哈。。。
             JMP         MAIN
WAIT:  
             DJNZ       R0,WAIT        ;没数完,继续
             RET                               ;数完了,那我挂电话了,有时间再CALL你啊
             END
好了,终于终于终于编完了,其实单片机也不怎么难嘛,呵呵。
最后,再介绍一句,其实
DJNZ       R0,WAIT
这句,还可以换成
DJNZ       R0,$
这样,减1不为0就等待,其实我想介绍的是这一句
JMP         $
这是个死循环,原地跳步,用来调试程序是非常好用的。不知道创造这句的大神是不是要告诉全世界的程序员,美元的魅力连CPU也挡不住,看到它,谁也跑不动。好了,言归正传,这一句其实用来调试程序是非常好用的,不知道怎么用,就先记住吧,或许以后有用,或许永远也没用,一家之言,每个人有每个人的方法。
  • 上一篇:
  • 下一篇: