分享

51单片机自学教程(8)

 梅竹修士 2012-07-18

51单片机自学教程(8)

[日期:2008-10-29 ] [来源:net 作者:佚名] [字体: (投递新闻)
程序设计是单片机开发最重要的工作程序设计就是利用单片机的指令系统根据应用系统即

目标产品的要求编写单片机的应用程序其实我们前面已经开始这样做过了这一课我们不是讲如何

来设计具体的程序而是教您设计单片机程序的基本方法不过在讲解之前还是有必要先了解一下单
片机的程序设计语言

一.程序设计语言

    这里的语言与我们通常理解的语言是有区别的它指的是为开发单片机而设计的程序语言如果

您没有学过程序设计可能不太明白我给大家简单解释一下您知道微软的VB VC VB VC 就是为

某些工程应用而设计的计算机程序语言通俗地讲它是一种设计工具只不过这种工具是用来设计计

算机程序的要想设计单片机的程序当然也要有这样一种工具说设计语言更确切些单片机的设计

语言基本上有三类:

1 .完全面向机器的机器语言

    机器语言就是能被单片机直接识别和执行的语言计算机能识别什么以前我们讲过--是数字0

1 所以机器语言就是用一连串的0 1 来表示的数字比如MOV A 40H 用机器语言来表示就是
11100101 0100000
很显然用机器语言来编写单片机的程序不太方便也不好记忆我
们必须想办法
用更好的语言来编写单片机的程序于是就有了专门为单片机开发而设计的语言

2. 汇编语言

汇编语言也叫符号化语言它使用助记符来代替二进制的0 1 比如刚才的MOV A40H 就是汇编语言
指令显然用汇编语言写成的程序比机器语言好学也好记所以单片机的指令普遍采
用汇编指令来编写
用汇编语言写成的程序我们就叫它源程序或源代码可是计算机不能识别和执行用汇编语言写成的程
序啊怎么办当然有办法我们可以通过翻译把源代码译成机器语言这个过程就叫做汇编,汇编工作现在
都是由计算机借助汇编程序自动完成的不过在很早以前它是靠手工来做的.

值得注意的是:汇编语言也是面向机器的,它仍是一种低级语言每一类计算机都有它自己的汇

编语言比如51 系列有它的汇编语言;PIC 系列也有它的汇编语言微机也有它自己的汇编语言它

们的指令系统是各不相同的也就是说不同的单片机有不同的指令系统它们之间是不通用的,这就

是为什么世界上有很多单片机类型的缘故了,为了解决这个问题人们想了很多的办法设计了许多的

高级计算机语言而现在最适合单片机编程的要数C 语言.

3 .C 语言高级单片机语言

C 语言是一种通用的计算机程序设计语言,它既可以用来编写通用计算机的系统程序也可以用

来编写一般的应用程序,由于它具有直接操作计算机硬件的功能所以非常适合用来编写单片机
程序与其他的计算机高级程序设计语言相比它具有以下的特点:

1 .语言规模小使用简单

   在现有的计算机设计程序中C 语言的规模是最小的ANSIC 标准的C 语言一共只有32 个关键字

9 种控制语句然而它的书写形式却比较灵活表达方式简洁使用简单的方法就可以构造出相当复杂

的数据类型和程序结构

2 .可以直接操作计算机硬件

  C 语言能够直接访问单片机的物理空间地址KEIL C51 软件中的C51 编译器更具有直接操作51

单片机内部存储器和I/O 口的能力亦可直接访问片内或片外存储器还可以进行各种位操作

3 .表达能力强表达方式灵活

   C 语言有丰富的数据结构类型可以采用:整型\实型\字符型\数组类型\指针类型\结构类型

\联合类型\枚举类型等多种数据类型来实现各种复杂数据结构的运算,利用C 语言提供的多种运算符

我们可以组成各种表达式还可以采用多种方法来获得表达式的值从而使程序设计具有更大的灵活性,所以
单片机入门后尽量学习C语言。。。。。

二。单片机程序设计的步骤

单片机的程序设计通常包括根据任务绘制程序流程图编写程序及汇编等几个步骤

绘制流程图

所谓流程图就是用各种符号图形箭头把程序的流向及过程用图形表示出来绘制流程图是

单片机程序编写前最重要的工作通常我们的程序就是根据流程图的指向采用适当的指令来编写的下

面的图形和箭头就是我们绘制流程图用的工具,

绘制流程图时首先画出简单的功能流程图粗框图再对功能流程图进行扩充和具体化即对

存储器标志位等单元做具体的分配和说明把功能图上的每一个粗框图转化为具体的存储器或地址单

元从而绘制出详细的程序流程图即细框图下面举个例子给大家演示一下请看下面的程序

主程序

LOOP:SETB P1.0

LCALL DELAY

CLR P1.0

LCALL DELAY

LJMP LOOP

子程序

DELAY MOV R7 #250

D1 MOV R6 #250

D2 DJNZ R6 D2

DJNZ R7 D1

RET END。

下面结合按键在实验板上做一下:

ORG 0000H

LJMP START

ORG 30H

START MOV SP #5FH

MOV P1 #0FFH

MOV P3 #0FFH

L1 JNB P3.2 L2; P3.2 上接有一只按键它按下时P3.5=0

JNB P3.3 L3 ;P3.3 上接有一只按键它按下时P3.6=0

LJMP L1

L2 CLR P1.0 LED1

LJMP L1

L3 SETB P1.0 LED1

LJMP L1

END

2 分支结构程序的设计

  所谓分支结构就是利用条件转移指令使程序执行某一指令后根据所给的条件是否满足来改变

程序执行的顺序也就是本条指令执行完后并不是象顺序结构那样执行下一条指令而是看本条指令

所给的条件是否满足如果满足条件就跳转到其他的指令如果不满足就顺序执行当然也可以是满足

条件顺序执行而不满足条件跳转执行看十五课实验程序中的下面两条

L1 JNB P3.2 L2 ;P3.2 上接有一只按键它按下时P3.2=0

JNB P3.3 L3 ;P3.3 上接有一只按键它按下时P3.3=0

这就是分支结构的程序如果P3.2 0 就转移反之就顺序执行当然也可以改成P3.2=0

顺序执行而P3.2=1 则转移不过此时的程序就要用JB 指令了在51 系列单片机中可以直接用于

分支程序的指令有JB JNB JC JNC JZ JNZ CJNE JBC 等这几条它们可以完成诸如正负判断

大小判断和溢出判断等等在分支结构的指令设计中大家必须注意.执行一条判断指令只可以形成

两路分支如果要形成多路分支就必须进行多次判断也就是多条指令连续判断下面给大家举两个

例子

A 单分支结构的程序实例

假设有两个数在内部RAM 单元的40H 41H 中现在要求找出其中较大的一个数并将较大的数

存入40H 中而将较小的一个数存入41H 中根据程序的要求我们先画出程序的流程图

再根据流程图写出程序的源代码如下

MOV A 40H

CLR C

SUBB A 41H

JNC WAIT

MOV A 41H

XCH A 41H

MOV 40H A

WAIT SJMP WAIT

END

程序的原理请大家自行分析一下接下来再举一个多分支结构的实例看下面的程序

MOV A 20H 取数

JZ ZERO ;A=0 转移A=1 顺序执行

JB ACC 7 STORE ;A 为负数转移

ADD A #3 ;A 为正数则加3

SJMP STORE

ZERO MOV A #20

STORE MOV 21H A

自己画一下本例的流程图这里有一条指令给大家解释一下JB ACC.3 STORE ;ACC.3 表示累加器
中的D3 位这条指令的意思就是看一下累加器中的
D3 位是正还是负D3 是什么呢在这里就是0 20H 
的二进制10000000

3 循环结构程序的设计

循环程序是最常用的程序结构形式在单片机的程序设计中有时要碰到一段程序需要重复执行

多次的情况此时就要用到循环结构程序比如前面的实验--LED 灯闪烁程序的子程序

DELAY MOV R7 #250 ;1

D1 MOV R6 #250 ;2

D2 DJNZ R6 D2 ;3

DJNZ R7 D1 ;4

RET ;5

END

在这段程序中为了延时需要多次执行DJNZ 指令此时若用循环结构程序就可以大大地简化程序

的设计减少程序占用的存储器空间循环结构指令一般有以下四个部分组成

A 初始化部分

初始化部分主要用来设置循环的初始值包括预值数计数器和数据指针的初值比如上例中的

#250 就是预值数初值

B 循环处理部分

循环处理部分是程序的主体部分也称为程序体通过它可以完成程序处理的任务

C 循环控制部分

循环控制部分可以控制程序循环的次数并修改预值数或计数器和指针的值检查该循环是否执

行了足够的次数如果到了足够的次数就采用条件转移指令或判断指令来控制循环的结束比如上例

中的3 4 指令就是当R6 R7 中的值为0 时就转移

C 循环结束部分

循环结束后必须返回一般用RET RETI 指令这里注意.以上四个部分中第一和第四部分

只能执行一次而第二和第三部分可以执行多次

     在循环程序设计中循环控制部分是程序设计的关键环节常用的循环控制方式有计数器控制
和条件控制两种计数器控制就是把要循环的次数即预值数放入计数器中程序每循环一次计数器

的值就减1 一直到计数器的内容为零时循环结束一般用DJNZ 指令而条件控制方式常预先不知

道要循环的次数只知道循环的有关条件此时就可以根据给定的条件标志位来判断程序是否继续一

般参照分支结构方法中的条件来判别指令并执行下面举几个例子来分别解释一下希望大家能以此类推

程序一用计数器控制的单重循环程序

源程序如下

CLR A

MOV R2 20H

MOV R1 22H

LOOP ADD A @R1

INC R1

DJNZ R2 LOOP

MOV 21H A

这段程序的作用是从22H 单元开始存放一个数据块其长度存放在20H 单元中将数据块求和

要求将和存放入21H 单元中和不超过255 下面再举一个条件控制的循环程序

程序二用条件控制的单重循环程序

设字符串存放在内部RAM 21H 开始的单元中以结束作标志要求计算出该字符串的长度并

将其存放在20H 单元中

源程序如下

CLR A

MOV R0 #21H 将地址指针指向21H 单元

LOOP CJNZ @R0 #24H NEXT SJMP COMP 找到结束

NEXT INC A 不为0 计数器加1

INC R0 修改地址指针

SJMP LOOP

COMP MOV 20H A 存放结果

试试看自己把上面两段程序的流程图画出来下面再看一个例子

DELAY MOV R7 #250

D1 MOV R6 #250

D2 DJNZ R6 D2

DJNZ R7 D1

RET

END

 

这是一段约125mS 的延时程序,比较左右两边的

DELAY MOV R7 #250             DELAY MOV R7 #250

D1 MOV R6 #250                D1 MOV R6 #250

D2 DJNZ R6 D2                  D2 MOV R5 #250

DJNZ R7 D1                       D3 DJNZ R5 D3

RET                                DJNZ R6 D2

END                                  DJNZ R7 D1

                                       RET
                                      END

    从这里可以引出一个概念,程序的嵌套:什么是嵌套比如早上我骑自行车从家里到单位去上班

当走到半路上时太太叫我去孩子学校拿点东西到了学校老师又叫我把学校的一台电脑修一下修

好电脑一个朋友又打电话叫我去他那里拿了一本单片机与嵌入式系统杂志完了之后再去上班

这就是生活中的嵌套在单片机的程序设计中也有类似的现象有时为了达到某个目的往往要在一

段循环程序中再加入另一段循环程序这就是单片机的程序嵌套通常我们把一个循环体中不再包含循

环的叫做单重嵌套如果一个循环体中还包括有循环则叫做多重嵌套上面的左边的程序就是

单重嵌套而右边的程序则是多重嵌套另外须注意.在多重嵌套中不允许各个循环体互相交叉

也不允许从外循环跳入内循环否则编译时会出错了解了结构化程序的设计下面再来看子程序的设

计方法

2 子程序的设计方法

  什么是子程序,如何设计子程序要解释这个问题让我们先同样从生活中的一个例子说起请

看下面的数学题目28* 33+65 +47* 33+65 +875* 33+65 在这道题中我们一般是怎么算的

也许大家都知道一般总是先把33+65 =98 代出来然后再用28+47+875 *98 来计算最后的结果

为什么会这样这是因为在这道题中我们多次用到了33+65 这个中间结果在单片机的程序设计

中有时也有这样的情况比如下面的程序

主程序

LOOP:SETB P1.0

LCALL DELAY

CLR P1.0

LCALL DELAY

LJMP LOOP

子程序

DELAY:MOV R7,#250

D1:MOV R6,#250

D2:DJNZ R6,D2

DJNZ R7,D1

RET END

    这是大家非常熟悉的LED 灯延时程序在这段程序中两次调用到了DELAY 这段程序为了简

化程序的设计我们就把DELAY 这段程序单独地列了出来这段列出的程序我们就叫它子程序而调

用子程序的程序我们则叫它主程序LOOP 的程序段在主程序执行时每当要用到子程序时我们

就用LCALL 指令来调用子程序子程序执行完之后必须返回主程序返回就用RET 指令这我们

以前都讲过了这里不再重复

      这里有个问题在子程序的执行过程中有时可能要使用到累加器和某些工作寄存器而在调用

子程序前这些寄存器中可能已经存放有主程序的中间结果它们在子程序返回后仍要使用这样就需

要在进入子程序之前将要使用的累加器和寄存器中的内容预先转移到安全的地方保存起来这叫现场

保护当子程序执行完即将返回主程序之前还要将这些内容先取出来送回到累加器和原来的工作寄

存器中这个过程叫恢复现场保护现场和恢复现场通常使用堆栈即在进入子程序之前将需要保护的
数据压入堆栈在返回之前再将压入的数据弹出到原来的工作单元中恢复原来的状态看下面的例子

LOOP PUSH 03H 03H 单元中的值压入堆栈保护

PUSH ACC 将累加器中的值压入堆栈保护

POP ACC ACC 中的值从堆栈弹出

POP 03H 恢复03H 单元中的内容

RET 从子程序返回

     由于堆栈的操作是后进先出先进后出所以编写指令时必须把后压入堆栈的数据先弹出来

才能保证恢复到原来的状态在实际的程序设计中由于每个应用程序的不同还必须根据具体的情况

来考虑是否需要保护哪些数据需要保护等等这就是单片机的堆栈为什么能够变化的原因关于堆栈

的操作先讲这些1 2 3 4 5也算是对以前的总结吧

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多