浅析8051模块化编程技巧

发布者:那是一条路都最新更新时间:2014-10-27 来源: 21ic关键字:模块化编程  C51 手机看文章 扫描二维码
随时随地手机看文章
程序设计就是用计算机所能接受的语言把解决问题的步骤描述出来,也就是把计算机指令或语句组成一个有序的集合。一个好的应用程序不仅是执行效率高,而且还要结构清晰、便于调试。所以人们都采用结构化程序设计方法来编制应用程序。对于每一个初学者来说更应该养成习惯,从简单的程序编制开始就采用这种模块化结构。

目前在8051 单片机应用开发中主要有两种编程语言:汇编语言和C51 语言。C51 语言是一种结构化的编程语言,采用C51 编写的应用程序结构清晰、模块化程度高、可读性强、并容易移植。但C51 语言也有缺点,就是编译后生成的目标代码空间要比汇编的大。

而且目前单片机的教材还是侧重于汇编语言。因此学习用单片机汇编语言程序进行结构化设计还是很有必要的。我们知道C51 语言是函数式语言,其程序由函数构成,每一个源程序有且只有一个主函数main() 和若干个函数组成。其中每一个函数都用于完成某一特定任务。也就是说,一个项目若具有几个功能,实现这些功能就会需要由若干个任务来完成,那么它的源程序中就会有若干个或以上的函数。而在汇编语言中,源程序中只有程序和子程序。那么我们能否以子程序为基本单位,用一个子程序实现一种功能来做到模块化编程呢?实践证明是可行的。但在编制程序中不要忘记汇编语言的特点,注意子程序之间对单片机资源的使用,避免不同子程序交叉共用同一资源引起程序的错误执行。子程序嵌套调用的级数等。本文以“60秒倒计时电路”为例谈一谈51 单片机汇编语言模块化编程的一点技巧。

  一、60秒倒计时电路及编程

1. 功能要求

所谓倒计时,就是首先给定一个初始值,然后对初始值进行减“1”操作,直到该值为“0”为止。60 秒倒计时就是对给定的初始值“60”每隔1 秒钟对其进行减“1”,一直减到该值为“0”为止。

该倒计时电路要求有两个按钮。一个是“复位”按钮,按下按钮设置倒计时初始值,并把指示灯熄灭;另一个是“开始”按钮,按下按钮开始倒计时。并用两位LED 数码管显示当前倒计时值。计时时间到,指示灯点亮。

2. 电路组成

实现上述功能要求的单片机接口电路如图1 所示。


图1 单片机接口电路

图中用按钮SB1 作为“置初值”按钮,按钮SB2 作为“开始”按钮。按下SB1 按钮,将显示值设置为“60”。
按下按钮SB2,每隔一秒显示值减“1”,直到值为“0”
停止计数。按钮和指示灯接在P0 口上,P0.0 为初始按钮,P0.1 为开始按钮,P0.7 为指示灯。十位LED 数码管接P2 口,个位LED 数码管接P1 口。图2 为单片机基本系统电路。


图2 单片机基本系统电路

3. 功能分析

根据60 秒倒计时的功能要求,需要单片机完成以下任务:

⑴ 按键扫描。用来判断有没有键被按下,是哪个键被按下?根据不同的键,给出相应的键值。
⑵ 计时显示。这里时间值使用的是两位数,故需要将被显示的时间值取出个位数和十位数,然后才能进行显示。
⑶ 被显示数转换成7 段码。由于单片机中的数据都是以二进制形式存放或运算的。而这里输出显示使用了两位LED 数码管来显示计时数值的,一个被显示的数要点亮数码管的某几段才能显示出这个数,不同的数需要点亮数码管的不同段。因此需要将被显示的这个数转换成相应的显示段码,才能被正确显示出来。
⑷ 延时。包括1秒钟延时和按键消抖的10毫秒延时。

⒋ 程序编制

程序按实现功能采用模块化结构,有一个主程序和若干个子程序组成。每个子程序分别是完成某个任务的独立模块,有时会用到调用参数。本实例共有5 个子程序,分别是按键扫描子程序、10ms 延时子程序、1s 延时子程序、显示子程序、取段码子程序。

⑴ 按键扫描子程序

按键扫描子程序完成对按键进行扫描,确定有没有键被按下,当有键被按下并抬起后将相关键值返回给主程序的任务。其流程如图3 所示。该子程序没有入口参数,但有一个出口参数,即按键的键值,存放在寄存器R3 中。寄存器R3 中的值为“60H”表示SB1 键被按下;寄存器R3 中的值为“00H”表示SB2 键被按下。


图3 按键扫描子程序流程图

按照图3 的流程图和51 单片机的指令系统编制的子程序如下:
;----------- 按键扫描描--------------
; 出口参数键值存放在寄存器R3 中,用于识别哪个键。
;R3=60H, 说明SB1 被按下;R3=00H, 说明SB2 被按下
key_scan: jnb kb_init, k1check ; SB1 按下转移
jnb kb_begin, k2check ; SB2 按下转移
sjmp ksr ;
k1check: acall del10 ; 调用毫秒延时,去抖
jb kb_init, ksr ; 干扰,返回
jnb kb_init,$ ; 等待按键释放
mov r3, #60h; 是SB1,键值“60H”送寄存器R3
sjmp ksr ; 是,不进行任何操作返回
k2check: acall del10 ; 调用毫秒延时,去抖
jb kb_begin, ksr ; 干扰,返回
jnb kb_begin,$ ; 等待按键释放
mov r3, #00h; 是SB2,键值“00H”送寄存器R3
ksr: ret ; 返回
;---------------------------------
⑵ 显示子程序
显示子程序完成从被显示值中取出十位数将其转换成显示断码,并送单片机的P2 口;从被显示值中取出个位数将其转换成显示断码,并送单片机的P1 口任务。其流程如图4 所示。该子程序有一个入口参数,即被显示的值,存放在寄存器R2 中。


图4 显示子程序流程图

按照图4 的流程图和51 单片机的指令系统编制的子程序如下:

;------------ 显示子程序------------
; 入口参数存放在寄存器R2 中
display:mov a, r2 ; 取被显示值
mov b, #10; 取被显示值的十位数
div ab;
acall seg7; 调用转换子程序,取显示断码
mov p2, a ; 十位数段码送P2 口
mov a, b; 取个位数
acall seg7 ; 调用转换子程序,取显示断码
mov p1, a ; 个位数段码送P1 口
ret ; 返回
;---------------------------------

⑶ 取段码子程序

取段码子程序完成将被显示的数转换成7 段共阳LED 数码管对应数的段码的任务。其流程如图5 所示。


图5 取段码子程序流程图

该子程序有一个入口参数和一个出口参数。入口参数就是被显示的数,出口参数就是该数的段码(相应位=0表示亮),都存放在累加器A 中。[page]

按照图5 的流程图和51 单片机的指令系统编制的子程序如下:
;-------------- 取段码--------------
; 对累计器A 中的值由查表得到显示断码
; 入口和出口参数存放在累计器A 中
seg7: inc a ; 取被显示数,累加器A 加1
movc a, @a+pc ; 查表
ret ; 返回
db 0c0h,0f9h,0a4h,0b0h;0123
db 99h,92h,82h,0f8h;4567
db 80h,90h,88h,83h;89AB
db 0c6h,0a1h,86h,8eh;cdEF
;---------------------------------

⑷ 延时子程序

延时子程序完成一定的延时时间任务。这里有两个延时时间不同的子程序(也可以调用100 次10mS 做1S 延迟),其流程如图6 所示。延时子程序没有入口和出口参数。


图6 延时子程序流程图

按照图6 的流程图和51 单片机的指令系统编制的子程序如下:

;----------- 延时10ms 程序----------
; 用到寄存器组1 中的R6 和R7 寄存器
del10: setb psw.3 ; 切换至第1 组寄存器
mov r7, #0bh ;
dl1: mov r6, #0ffh ;
dl2: djnz r6, dl2 ;
djnz r7, dl1;
clr psw.3 ; 切换至第0 组寄存器
ret ;
;---------------------------------
;------------- 延时1s 程序-----------
; 用到寄存器组1 中的R1、R2 和R3 寄存器
del1s: setb psw.3 ; 选用寄存器区1
mov r1 , #46; 立即数46 送寄存器R1
del0: mov r2 , #100; 立即数100 送寄存器R2
del1: mov r3 , #100 ; 立即数100 送寄存器R3
djnz r3 , $ ; 寄存器R3 中的内容减1,不为零转移到当
前指令
djnz r2 , del1; 寄存器R2 中的内容减1,不为零转移到
del1
djnz r1 , del0; 寄存器R1 中的内容减1,不为零转移到
del0
clr psw.3 ; 选用寄存器区0
ret ; 子程序返回
;---------------------------------

⑸ 主程序编制

主程序需要实现的功能是:完成单片机端口定义;初始化任务;调用键扫描子程序,根据按键状态实现置初值或进行倒计时,并调用显示子程序等。其流程如图7 所示。


图7 主程序编制流程图

按照图7 的流程图和51 单片机的指令系统、以上编制的各子程序,主程序如下:
;**********************************************************
; 文件名:counter.asm 功能:60 秒倒计时
; 说明:p2 和p1 口分别接一个LED 数码管, 显示两位
十进制数。
; p0.0 和p0.1 口接置初值按钮和开始倒计时按钮,p0.7
接提示LED。
; 晶振频率11.0592MHz.
;**********************************************************
;------------ 端口定义--------------
kb_init bit p0.0 ; 置初值按钮定义
kb_begin bit p0.1 ; 开始按钮定义
warn bit p0.7 ; 提示
;---------------------------------
org 0000h
ajmp begin
;============ 主程序===============
org 00b0h
begin:
mov sp, #50h ; 初始化
mov p0, #0ffh
mov p1, #0ffh
mov p2, #0ffh
mov r2, #60
mov r3, #0ffh
main:
lcall key_scan ; 按扫描键
mov a, r3 ; 取返回值
cjne a, #60h, lp1 ; 非SB1 按键转移
mov r2, #60 ; 初值送寄存器R2
setb p0.7 ; 清指示灯
acall display ; 调显示子程序
ajmp main ; 转移
lp1: mov a, r3 ; 取返回值
cjne a, #00h, main ; 非SB2 按键转移
setb p0.7
mov r2, #60
lp2: acall display
acall del1s ; 调用1 秒延时子程序
       dec r2
cjne r2, #00h,lp2
acall display
clr p0.7
mov r3, #0ffh
ajmp main
;=================================

  二、Keil C 中编译

1. 新建项目

打开“Keil C”软件,新建一个项目。项目名也不妨为“counter”。

点击桌面上的图标 ,进入Keil C51 μVision2集成开发环境。在主界面上点下拉菜单“Project”,选“New Project?”命令。在弹出的对话框中将项目命名为“counter”。点“保存”按钮,选“Atmel”下的“AT89S52”后返回。

2. 添加源程序

打开已建立的文件“counter.asm”;并将该文件添加到“Source Group 1”中。
在μVision2 主界面上点击打开文件按钮 ,在弹出的对话框内找到刚才新建并保存的文件“counter.asm”。点“打开”按钮打开。
在中间左边的“项目空间(Project Workspace)”内,点击“+”展开。再用右键点击“Source Group 1”文件夹,在弹出的菜单命令中选“Add Files to group‘Source Group 1’”。

3. 参数设置

在“Options for Target‘ Target 1’”中的“Output”标签页上进行设置。
点下拉菜单“Project”, 选“Options for Target‘Target 1’”。在弹出对话框上的“Target”标签页内,把单片机的运行频率调整为11.0592MHz。在“Output”标签页上,点“Create HEX File”前的复选框,使其内出现“√”,这样编译后就能生成目标文件了。点“确定”按钮返回。

4. 程序编译

点编译和建立目标文件,得到“counter.hex”文件。
在μVision2 主界面上点重新编译按钮,对源程序文件进行编译,结果如图8 所示。


图8

  三、Preteus仿真

ISIS 仿真图如图9 所示。设置CPU:89C51 的特性,加载counter.HEX 代码加载,运行仿真。将光标移至按钮SB1,使光标变成一只“手”时,点击鼠标左键,使按钮按下。按钮释放后,数码管显示值加“60”,如图9 所示。启动倒计时。将光标移至按钮SB2,使光标变成一只“手”时,点击鼠标左键,使按钮按下。按钮释放后倒计时开始。


图9ISIS 仿真图

四、基本系统上运行


用单片机基本系统板来验证程序,首先准备好实验用器材基本系统板、下载器、电源和万能板及所需元器件。然后按下面步骤进行操作。

⒈在应用实验板上按图1 焊接好电阻、电容、数码管和接插件、按钮等。

⒉拔去最小系统板上的跳线J101、J102、J103,插上AT89S52 芯片。将下载线的接口板插入电脑的并口上,连接电缆把最小系统与接口板连好,再在最小系统上接上电源。如图10 所示。


图10

⒊打开下载软件,并设置好有关参数;加载待写文件“counter.hex”;点“编程”按钮下载程序。必要时须先对芯片进行“擦写”( 若该芯片中曾烧录过程序)。

⒋完成上面的操作后,关闭电源,拔下连接电缆,插上跳线J101,接上实验电路。

⒌上电验证程序,按下按键SB1 置初值,按下按键SB2 开始倒计时。若不符合要求则进行修改(可以先在μVision2 进行调试或Proteus 中仿真)。

⒍重复上述步骤直到实现要求的功能。

  五、结束语

用汇编语言编制应用程序时虽然要考虑单片机的硬件资源的分配,且实现相同功能时的语句可能比C51 编程更多,汇编的模块按结构化编程,同样也能编制出结构清晰、功能明确、可读性强、的应用程序。

关键字:模块化编程  C51 引用地址:浅析8051模块化编程技巧

上一篇:单片机片内大容量EEPROM的一种巧妙应用
下一篇:太阳能半导体空调控制装置的设计方法

推荐阅读最新更新时间:2024-03-16 13:44

基于8051实现的可启停/显示或隐藏时间的电子时钟(Version1.2)
程序实现的功能: 1. 实验箱上电后, 不显示当前时间. 2. 向8051发送 Show.E 后, 显示当前时间. 3. 向8051发送 Hide.E 后, 隐藏当前时间. 4. 向8051发送 Start.E 后, 时钟开始计时. 5. 向8051发送 Stop.E 后, 时钟停止计时(若当前处于 Show 状态, 则显示停止计时前的时间). #include STC89C5xRC.H #include string.h unsigned char code DIG_CODE = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f
[单片机]
C51如何实现带死区控制的PID算法
真正要用PID算法的时候,发现书上的代码在我们51上来实现还不是那么容易的事情。简单的说来,就是不能直接调用。仔细分析你可以发现,教材上的、网上现行的PID实现的C语言代码几乎都是用浮点型的数据来做的,可以想象,如果我们的计算使用浮点数据,那我们的51单片机来运行的话会有多痛苦。 所以,本人自己琢磨着弄了一个整型变量来实现了PID算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了。关于系数和采样电压全部是放大10倍处理的。所以精度不是很高,但是也不是那么低,大部分的场合都够用了。实在觉得精度不够,可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了。 本人做的是带死区控制
[单片机]
8051、ARM和DSP指令周期的测试与分析
在实时控制系统中,选择微控制器的指标时最重要的是计算速度的问题。指令周期是反映计算速度的一个重要指标,为此本文对三种最具代表性的微控制器(AT89S51单片机、ARM7TDMI核的LPC2114型单片机和TMS320F2812)的指令周期进行了分析和测试。为了能观察到指令周期,将三种控制器的GPIO口设置为数字输出口,并采用循环不断地置位和清零,通过观察GPIO口的波形变化得到整个循环的周期。为了将整个循环的周期与具体的每一条指令的指令周期对应起来,通过C语言源程序得到汇编语言指令来计算每一条汇编语言的指令周期。 1 AT89S51工作机制及指令周期的测试   AT89S51单片机的时钟采用内部方式,时钟发生器对振荡脉冲进
[测试测量]
<font color='red'>8051</font>、ARM和DSP指令周期的测试与分析
C8051F021型单片机实现数据采集系统
介绍的功角测量数据采集卡是采用Cygnal公司C8051F021型单片机实现的PCI总线接口卡。该卡通过2片双口RAM分别实现与GPS接收板和上位机(PC)的数据交换,从而实现高速、可靠的数据采集、处理与传送。本数据采集卡采用片内12位高速ADC并配以片外采样保持电路,通过直接交流采样方法精确快速地实现对电压和电流的采样,保证了电力系统实时测量的要求。   1 引言   实现自动化的过程中,首要环节就是数据采集。为此我们研究开发了电力系统功角广域测控系统,其中,用C8051F021型单片机实现的数据采集卡不仅可以准确、高效、实时地进行AD数据采集并通过双口RAM和PCI接口与上位机交换数据,还可以通过与GPS接收通信接收秒
[工业控制]
C<font color='red'>8051</font>F021型单片机实现数据采集系统
C51单片机P4口使用
C51单片机(STC11L32/48XE)的P4可以像其他IO可以作为正常的IO来使用。 如图:
[单片机]
C51】源码 1 -- LED 脉冲宽度调制(PWM)调光
  最近迷上了单片机,借着大学的一点儿基础,开始自学 C51 单片机编程,跟着教程看完了发光二极管 LED 相关的编程,编写以下 LED PWM 调光程序作为总结。   先说一下 PWM 调光,PWM 就是 脉冲宽度调制 ,就是在一个固定周期内,改变高低电平的比例,使 LED 呈现不同的明暗程度。   博主编了一个比较简单的:在 CYCLE 个脉冲的周期内,低电平脉冲 PWM_LOW 的个数从 0 递增到 CYCLE,高电平脉冲的个数当然就会递减,这样 LED 就会呈现出 渐亮 的效果, 渐暗 与此同理。 附上源码:(初出茅庐,难免有写的不好的地方,仅作备份之用,欢迎指点,喷子退散 ) #include reg52.h
[单片机]
8051单片机C语言数据采集程序
/8051单片机TLC1549数据采集程序源代码 //单片机:At89S52 //连接类型:232 |485 接口 //校验方式:checksum //开发环境:keil C #i nclude stdio.h #i nclude REGX51.H #i nclude iic.h #define uchar unsigned char #define uint unsigned int uint Timer_Pro_Flag=0;//0为显示处理,1为时序采集处理 sbit TEST_CAP_VOL_CRLT=P1^0;//用于控制外部继电器 sbit PWM_Pin=P3^7;//PWM输出 sbit I
[单片机]
8051单片机的历史_8051单片机的应用领域
  目前,有关8051单片机的说法很多:8051单片机是Intel发明的,可与8位系列处理器一起使用。现在,8051单片机已广泛应用于各个行业以及家庭的各种家用电器上。      一、8051单片机的历史   如果我们回顾历史,8051单片机是由微处理器巨头Intel于1980年首次发明的,并且逐渐被全世界所接受,并且随着未来的每一天,8051单片机的重要性正在不断提高。当它由英特尔发明时,它是通过NMOS技术开发的,但作为NMOS技术却不是很有效。   为了提高效率和生产率,英特尔通过实施CMOS技术对它进行了改型,并出现了一个新版本,名称中带有字母“C”,比如:“80C51”。新版8051单片机具有两条总线,一条总线用于程序
[单片机]
<font color='red'>8051</font>单片机的历史_<font color='red'>8051</font>单片机的应用领域
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved