单片机延时子程序流程图

单片机延时子程序流程图,第1张

延时程序在单片机编程中使用非常广泛,但一些读者在学习中不知道延时程序怎么编程,不知道机器

周期指令周期的区别,不知道延时程序指令的用法, ,本文就此问题从延时程序的基本概念、机器周期和指

令周期的区别和联系、相关指令的用法等用图解法的形式详尽的回答读者

我们知道程序设计是单片机开发最重要的工作,而程序在执行过程中常常需要完成延时的功能。例如

在交通灯的控制程序中,需要控制红灯亮的时间持续30秒,就可以通过延时程序来完成。延时程序是如何

实现的呢?下面让我们先来了解一些相关的概念。

一、机器周期和指令周期

1.机器周期是指单片机完成一个基本 *** 作所花费的时间,一般使用微秒来计量单片机的运行速度,

51 单片机的一个机器周期包括12 个时钟振荡周期,也就是说如果51 单片机采用12MHz 晶振,那么执行

一个机器周期就只需要1μs;如果采用的是6MHz 的晶振,那么执行一个机器周期就需要2 μs。

2 .指令周期是指单片机执行一条指令所需要的时间,一般利用单片机的机器周期来计量指令周期。

在51 单片机里有单周期指令(执行这条指令只需一个机器周期),双周期指令(执行这条指令只需要两个

机器周期),四周期指令(执行这条指令需要四个机器周期)。除了乘、除两条指令是四周期指令,其余均

为单周期或双周期指令。也就是说,如果51 单片机采用的是12MHz 晶振,那么它执行一条指令一般只需

1~2 微秒的时间;如果采用的是6MH 晶振,执行一条指令一般就需2~4 微秒的时间。

现在的单片机有很多种型号,但在每个型号的单片机器件手册中都会详细说明执行各种指令所需的机

器周期,了解以上概念后,那么可以依据单片机器件手册中的指令执行周期和单片机所用晶振频率来完成

需要精确延时时间的延时程序。

二、延时指令

在单片机编程里面并没有真正的延时指令,从上面的概念中我们知道单片机每执行一条指令都需要一

定的时间,所以要达到延时的效果,只须让单片机不断地执行没有具体实际意义的指令,从而达到了延时

的效果。

1.数据传送指令 MOV

数据传送指令功能是将数据从一个地方复制、拷贝到另一个地方。

如:MOV R7,#80H   ;将数据80H 送到寄存器R7,这时寄存器R7 里面存放着80H,就单这条

指令而言并没有任何实际意义,而执行该指令则需要一个机器周期。

2.空 *** 作指令 NOP

空 *** 作指令功能只是让单片机执行没有意义的 *** 作,消耗一个机器周期。

3.循环转移指令 DJNZ

循环转移指令功能是将第一个数进行减1 并判断是否为0,不为0 则转移到指定地点;为0 则往下执行。

如:DJNZ R7,KK ;将寄存器R7 的内容减1 并判断寄存器R7 里的内容减完1 后是否为0,如果

不为0 则转移到地址标号为KK 的地方;如果为0 则执行下一条指令。这条指令需要2 个机器周期。

利用以上三条指令的组合就可以比较精确地编写出所需要的延时程序。

三、1 秒延时子程序、流程图及时间计算 (以单片机晶振为12MHz 为例,1 个机器周期需要1μs)

了解了以上的内容,现在让我们来看看

程序总共所需时间:1+10+2560+330240+660480+5120+20+2=998433 μs≈1S

在这里运行这段程序共需998433 μs,还差1567μs 才达到1S 的,所以想要达到完美的1S 延时,需

要在返回指令RET 前再添加一些指令让它把1567μs 的延时完成。有兴趣的读者可以自己试着添加完成。

最后补充一点,编写程序时一般将延时程序编写成独立的子程序,而所谓子程序也就是一个实现某个功能

的小模块。这样在主程序中就可以方便地反复调用编写好的延时子程序。

小提示:循环转移指令(DJNZ )除了可以给定地址标号让其跳转外,还可以将地址标号改成$,这样

程序就跳回本指令执行。例如:

DJNZ R7,$ ;R7 内容减1 不为0,则再次执行本指令;为0 则往下执行,当R7 的值改为10

时,则执行完该条程序所需的时间为210=20 μs。

51单片机汇编延时程序算法详解

将以12MHZ晶振为例,详细讲解MCS-51单片机中汇编程序延时的精确算法。

指令周期、机器周期与时钟周期

指令周期:CPU执行一条指令所需要的时间称为指令周期,它是以机器周期为单位的,指令不同,所需的机器周期也不同。

时钟周期:也称为振荡周期,一个时钟周期 =晶振的倒数。

MCS-51单片机的一个机器周期=6个状态周期=12个时钟周期。

MCS-51单片机的指令有单字节、双字节和三字节的,它们的指令周期不尽相同,一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占时间为12(1/12000000)=1μs。

程序分析

例1 50ms 延时子程序:

DEL:MOV R7,#200 ①

DEL1:MOV R6,#125 ②

DEL2:DJNZ R6,DEL2 ③

DJNZ R7,DEL1 ④

RET ⑤

精确延时时间为:1+(1200)+(2125200)+(2200)+2

=(2125+3)200+3 ⑥

=50603μs

≈50ms

由⑥整理出公式(只限上述写法)延时时间=(2内循环+3)外循环+3 ⑦

详解:DEL这个子程序共有五条指令,现在分别就 每一条指令 被执行的次数和所耗时间进行分析。

第一句:MOV R7,#200 在整个子程序中只被执行一次,且为单周期指令,所以耗时1μs

第二句:MOV R6,#125 从②看到④只要R7-1不为0,就会返回到这句,共执行了R7次,共耗时200μs

第三句:DJNZ R6,DEL2 只要R6-1不为0,就反复执行此句(内循环R6次),又受外循环R7控制,所以共执行R6R7次,因是双周期指令,所以耗时2R6R7μs。

例2 1秒延时子程序:

DEL:MOV R7,#10 ①

DEL1:MOV R6,#200 ②

DEL2:MOV R5,#248 ③

DJNZ R5,$ ④

DJNZ R6,DEL2 ⑤

DJNZ R7,DEL1 ⑥

RET ⑦

对每条指令进行计算得出精确延时时间为:

1+(110)+(120010)+(224820010)+(220010)+(210)+2

=[(2248+3)200+3]10+3 ⑧

=998033μs≈1s

由⑧整理得:延时时间=[(2第一层循环+3)第二层循环+3]第三层循环+3 ⑨

此式适用三层循环以内的程序,也验证了例1中式⑦(第三层循环相当于1)的成立。

注意,要实现较长时间的延时,一般采用多重循环,有时会在程式序里加入NOP指令,这时公式⑨不再适用,下面举例分析。

例3仍以1秒延时为例

DEL:MOV R7,#10 1指令周期1

DEL1:MOV R6,#0FFH 1指令周期10

DEL2:MOV R5,#80H 1指令周期25510=2550

KONG:NOP 1指令周期12825510=326400

DJNZ R5,$ 2指令周期212825510=652800

DJNZ R6,DEL2 2指令周期225510=5110

DJNZ R7,DEL1 2指令周期210=20

RET 2

延时时间=1+10+2550+326400+652800+5110+20+2 =986893μs约为1s

整理得:延时时间=[(3第一层循环+3)第二层循环+3]第三层循环+3 ⑩

结论:针对初学者的困惑,对汇编程序的延时算法进行了分步讲解,并就几种不同写法分别总结出相应的计算公式,只要仔细阅读例1中的详解,并用例2、例3来加深理解,一定会掌握各种类型程序的算法并加以运用。

单片机延时子程序

1)延时为:20ms 晶振12M

1+(1+2248+2)4+1+1+1=20000US=20MS

用汇编优点就是精确

缺点就是算有点复杂

DELAY20MS:

MOV R7,#4

D1:

MOV R6,#248

DJNZ R6,$

DJNZ R7,D1

NOP

NOP

RET

2)一些通过计算51汇编指令得出的软延时子程序

;

;延时10uS

;

time10us:               mov     r5,#05h                 ;11us

djnz    r5,$

ret

;

;延时50uS

;

time50us:               mov     r5,#19h                 ;51us

djnz    r5,$

ret

;

;延时100uS

;

time100us:              mov     r5,#31h                 ;996us

djnz    r5,$

ret

;

;延时200uS

;

time200us:              mov     r5,#64h                 ;201us

djnz    r5,$

ret

;

;延时250uS

;

time250us:              mov     r5,#7ch                 ;2496us

djnz    r5,$

ret

;

;延时350uS

;

time350us:              mov     r5,#0afh                 ;351us

time350us_1:            djnz    r5,time350us_1

ret

;

;延时500uS

;

time500us:              mov     r5,#0fah                 ;501us

time500us_1:            djnz    r5,time500us_1

ret

;

;延时1mS

;

time1ms:                mov     r5,#0fah                ;1001us

time1ms_1:              nop

nop

djnz    r5,time1ms_1

ret

;

;延时25mS

;

time2_5ms:              mov     r5,#05h          ;2496ms

time2_5ms_1:            mov     r6,#0f8h         ;497us

djnz    r6,$

djnz    r5,time2_5ms_1

ret

;

;延时10mS

;

time10ms:               mov    r5,#14h         ;10262ms

time10ms_1:             mov    r6,#0ffh        ;511us

djnz   r6,$

djnz   r5,time10ms_1

ret

;

;延时50mS

;

time50ms:               mov    r5,#63h         ;49996ms

time50ms_1:             mov    r6,#0fbh        ;503us

djnz   r6,$

djnz   r5,time50ms_1

ret

;

;延时100mS

;

time100ms:              mov     r5,#0c3h        ;100036ms

time100ms_1:            mov     r6,#0ffh        ;511us

djnz    r6,$

djnz    r5,time100ms_1

ret

;

;延时200mS

;

time200ms:              mov     r5,#02h         ;250351ms

time200ms_1:            mov     r6,#0f4h        ;125173ms

time200ms_2:            mov     r7,#0ffh        ;511us

djnz    r7,$

djnz    r6,time200ms_2

djnz    r5,time200ms_1

ret

;

;延时500mS

;

time500ms:              mov    r5,#04h         ;500701ms

time500ms_1:            mov    r6,#0f4h        ;125173ms

time500ms_2:            mov    r7,#0ffh        ;511us

djnz   r7,$

djnz   r6,time500ms_2

djnz   r5,time500ms_1

ret

;

;延时1S

;

time1s:                 mov    r5,#08h         ;1001401ms

time1s_1:               mov    r6,#0f4h        ;125173ms

time1s_2:               mov    r7,#0ffh        ;511us

djnz   r7,$

djnz   r6,time1s_2

djnz   r5,time1s_1

ret

12M晶振 机器周期为1US  NOP为单周期指令 DJNZ为双周期指令.

3)

;;晶振12MHZ,延时1秒

DELAY:MOV   72H,#100

LOOP3:MOV   71H,#100

LOOP1:MOV   70H,#47

LOOP0:DJNZ   70H,LOOP0

NOP

DJNZ   71H,LOOP1

MOV   70H,#46

LOOP2:DJNZ   70H,LOOP2

NOP

DJNZ   72H,LOOP3

MOV   70H,#48

LOOP4:DJNZ   70H,LOOP4

4);延时1分钟子程序,F=6MHz

;程序已测过,延时时间60,000,0000uS

delay60s:mov r3,#228

mov r2,#253

mov r1,#219

loop1:   djnz r1,$

djnz r2,loop1

djnz r3,loop1

nop

ret

5)计算机反复执行一段程序以达到延时的目的称为软件延时,单片机程序中经常需要短时间的延时,但是相当一部分人对延时程序很模糊,对延时程序的算法不够了解,在这里我以12MHz晶振和两个经典延时子程序为例,详细分析单片机汇编延时程序。

何为时钟周期、机器周期、和指令周期?

时钟周期:也就是振荡周期,以12MHz的时钟脉冲为例,那时钟周期就为(1/12000000)s=(1/12)us;

机器周期:1个机器周期=6个状态周期=12个时钟周期=1us;

指令周期:CPU执行一条指令所需要的时间称为指令周期,指令周期是以机器周期为单位的,不同的指令所需的机器周期不一定相同,可参考51单片机指令速查表。

由上可得:CPU执行一条单周期指令,需要1us;执行一条双周期指令需要2us。

下面是具体的延时子程序分析:

01s延时子程序(12MHz晶振):

MOV R7,#200   ;单周期指令(1us)

D1:     MOV R6,#250   ;单周期指令(1us)

DJNZ R6,$      ;双周期指令(2us)//该指令自身执行R6次

DJNZ R7,D1     ;双周期指令(2us)//D1执行R7次

RET            ;双周期指令(2us)

T=1+(1+2R6+2)R7+2

=100603us

≈01s

05s延时子程序(12MHz晶振):

MOV R7,#5     ;单周期指令(1us)

D1:     MOV R6,#200   ;单周期指令(1us)

D2:     MOV R5,#250   ;单周期指令(1us

DJNZ R5,$      ;双周期指令(2us)//该指令自身执行R5次

DJNZ R6,D2     ;双周期指令(2us)//D2执行R6次

DJNZ R7,D1     ;双周期指令(2us)//D1执行R7次

RET            ;双周期指令(2us)

T=1+[1+(1+2R5+2)R6+2]R7+2

=503018us

≈05s

6) 51单片机经典流水灯程序,在51单片机的P2口接上8个发光二极管,产生流水灯的移动效果。

ORG        0                   ;程序从0地址开始

START:      MOV      A,#0FEH     ;让ACC的内容为11111110

LOOP:         MOV      P2,A            ;让P2口输出ACC的内容

RR          A                  ;让ACC的内容左移

CALL     DELAY       ;调用延时子程序

LJMP     LOOP          ;跳到LOOP处执行

;01秒延时子程序(12MHz晶振)===================

DELAY:      MOV      R7,#200      ;R7寄存器加载200次数

D1:               MOV      R6,#250      ;R6寄存器加载250次数

DJNZ     R6,$             ;本行执行R6次

DJNZ     R7,D1          ;D1循环执行R7次

RET                            ;返回主程序

END                           ;结束程序

首先,你需要单片机吧,其次需要下载器,下载线,单片机仿真芯片等,如果你还要自己做电路,那么还要一套电子工具,什么电烙铁,剪线钳,镊子,吸锡器什么的

我拿51系列单片机来举例

(1)首先你要做的是,规划好你要做什么,对设计的各个方面做一个粗略的规划如,编程要实现什么,需不需要自己做电路

(2)把电路图画好,对照电路图做电路,如果自己做电路的话,你需要去电子城购买电子元器件,然后对照电路图把硬件电路做好检查电路有没有问题,如是否短路,虚焊什么的

(3)步骤2是针对较简单的单片机最小系统,如果你做的电路有点复杂,最好做一块PCB板,这时你就需要用电路编辑工具如DXP,等PCB文件发给生产PCB板的厂家加工,这个过程也不长,如果你经验积累得很多的话但要设计一块好的PCB板,还有电路图设计,这都是有很深的学问的冰冻三尺,非一日之寒

(4)通过步骤2,3你的硬件已有了,现在可以编程,编程也是分几个阶段的,但主要阶段是:设计算法-->绘制流程图-->编写代码-->编译-->下载-->运行或调试-->程序的优化

其中,算法设计的优劣很重要,它是决定你的设计的质量如何的一方面绘制流程图这个环节被很多人忽略,对于一些小程序,不需要绘制流程图,但对于一个很大的程序,你没有一个体系的思想,是很难写下去的但不否认,有这样的高手,但我觉得要从一开始养成良好的习惯,简单的画画流程图是有好处的日积月累,它会提高你编程的效率接下来,编写代码,可以用KEIL软件,其它还有什么ASM什么的我知道的最多的都是用的KEIL代码编写好后,编译生成HEX,BIN文件,这两种类型的文件都是可以下载到单片机的ROM中的

(5)下载到单片机后,就开始运行了,或用仿真芯片进行在线调试,有问题就改,直到没有问题为止成功后,还需要反思一下,自己的设计还有没有需要改进的地方如程序需不需要优化,电路需不需要优化,换种算法行不行

(注:你问题中说要”做成一个芯片”,这一点我不知道我没做过向ATMEL,SST,周立功等的工程师打听打听说不定会有更大的收获)

/

[文件名] C51音乐程序(八月桂花)

[功能] 通过单片机演奏音乐

注意:通过了74HC14控制ULN2003 驱动芯片驱动蜂鸣器

//

#include <REG52H>

#include <INTRINSH>

//本例采用89C52, 晶振为110592MHZ

//关于如何编制音乐代码, 其实十分简单,各位可以看以下代码

//频率常数即音乐术语中的音调,而节拍常数即音乐术语中的多少拍;

//所以拿出谱子, 试探编吧!

sbit Beep = P1^5 ;

unsigned char n=0; //n为节拍常数变量

unsigned char code music_tab[] ={

0x18, 0x30, 0x1C , 0x10, //格式为: 频率常数, 节拍常数, 频率常数, 节拍常数,

0x20, 0x40, 0x1C , 0x10,

0x18, 0x10, 0x20 , 0x10,

0x1C, 0x10, 0x18 , 0x40,

0x1C, 0x20, 0x20 , 0x20,

0x1C, 0x20, 0x18 , 0x20,

0x20, 0x80, 0xFF , 0x20,

0x30, 0x1C, 0x10 , 0x18,

0x20, 0x15, 0x20 , 0x1C,

0x20, 0x20, 0x20 , 0x26,

0x40, 0x20, 0x20 , 0x2B,

0x20, 0x26, 0x20 , 0x20,

0x20, 0x30, 0x80 , 0xFF,

0x20, 0x20, 0x1C , 0x10,

0x18, 0x10, 0x20 , 0x20,

0x26, 0x20, 0x2B , 0x20,

0x30, 0x20, 0x2B , 0x40,

0x20, 0x20, 0x1C , 0x10,

0x18, 0x10, 0x20 , 0x20,

0x26, 0x20, 0x2B , 0x20,

0x30, 0x20, 0x2B , 0x40,

0x20, 0x30, 0x1C , 0x10,

0x18, 0x20, 0x15 , 0x20,

0x1C, 0x20, 0x20 , 0x20,

0x26, 0x40, 0x20 , 0x20,

0x2B, 0x20, 0x26 , 0x20,

0x20, 0x20, 0x30 , 0x80,

0x20, 0x30, 0x1C , 0x10,

0x20, 0x10, 0x1C , 0x10,

0x20, 0x20, 0x26 , 0x20,

0x2B, 0x20, 0x30 , 0x20,

0x2B, 0x40, 0x20 , 0x15,

0x1F, 0x05, 0x20 , 0x10,

0x1C, 0x10, 0x20 , 0x20,

0x26, 0x20, 0x2B , 0x20,

0x30, 0x20, 0x2B , 0x40,

0x20, 0x30, 0x1C , 0x10,

0x18, 0x20, 0x15 , 0x20,

0x1C, 0x20, 0x20 , 0x20,

0x26, 0x40, 0x20 , 0x20,

0x2B, 0x20, 0x26 , 0x20,

0x20, 0x20, 0x30 , 0x30,

0x20, 0x30, 0x1C , 0x10,

0x18, 0x40, 0x1C , 0x20,

0x20, 0x20, 0x26 , 0x40,

0x13, 0x60, 0x18 , 0x20,

0x15, 0x40, 0x13 , 0x40,

0x18, 0x80, 0x00

};

void int0() interrupt 1 //采用中断0 控制节拍

{ TH0=0xd8;

TL0=0xef;

n--;

}

void delay (unsigned char m) //控制频率延时

{

unsigned i=3m;

while(--i);

}

void delayms(unsigned char a) //豪秒延时子程序

{

while(--a); //采用while(--a) 不要采用while(a--); 各位可编译一下看看汇编结果就知道了!

}

void main()

{ unsigned char p,m; //m为频率常数变量

unsigned char i=0;

TMOD&=0x0f;

TMOD|=0x01;

TH0=0xd8;TL0=0xef;

IE=0x82;

play:

while(1)

{

a: p=music_tab[i];

if(p==0x00) { i=0, delayms(1000); goto play;} //如果碰到结束符,延时1秒,回到开始再来一遍

else if(p==0xff) { i=i+1;delayms(100),TR0=0; goto a;} //若碰到休止符,延时100ms,继续取下一音符

else {m=music_tab[i++], n=music_tab[i++];} //取频率常数 和 节拍常数

TR0=1; //开定时器1

while(n!=0) Beep=~Beep,delay(m); //等待节拍完成, 通过P1口输出音频(可多声道哦!)

TR0=0; //关定时器1

}

}

没有定时器的不过有数字钟的

你可以参考下

其中可有有用的

摘要

本题给出基于单片机的数字中的设计,设计由单片机作为核心控制器,通过频率计数实现计时功能,将实时时间经由单片机输出到显示设备——数码管上显示出来,并通过键盘来实现启动、停止、复位和调整时间的功能。

关键词: 单片机、数字钟、AT89S52、LED

1 引言

在单片机技术日趋成熟的今天,其灵活的硬件电路的设计和软件的设计,让单片机得到了广泛的应用,几乎是从小的电子产品,到大的工业控制,单片机都起到了举足轻重的作用。单片机小的系统结构几乎是所有具有可编程硬件的一个缩影,可谓是“麻雀虽小,五脏俱全”。

现在是一个知识爆炸的新时代。新产品、新技术层出不穷,电子技术的发展更是日新月异。可以毫不夸张的说,电子技术的应用无处不在,电子技术正在不断地改变我们的生活,改变着我们的世界。在这快速发展的年代,时间对人们来说是越来越宝贵,在快节奏的生活时,人们一旦遇到重要的事情而忘记了时间,这将会带来很大的损失,因此我们需要一个计时系统来提醒这些忙碌的人。 然而,随着科技的发展和社会的进步,人们对时钟的要求也越来越高,传统的时钟已不能满足人们的需求。多功能数字钟不管在性能上还是在样式上都发生了质的变化,如电子闹钟、数字闹钟等等。 单片机在多功能数字钟中的应用已是非常普遍的,基于单片机的数字钟给人们带来了极大的方便。

现今,高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟,石英表,石英钟都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要经常调校,数字式电子钟用集成电路计时,译码代替机械式传动,用LED显示器代替指针显示进而显示时间,减小了计时误差,这种表具有时,分,秒显示时间的功能,还可以进行时和分的校对,片选的灵活性好。本文利用单片机实现数字时钟计时功能的主要内容,其中AT89S52是核心元件同时采用数码管动态显示“时”,“分”,“秒”的现代计时装置。与传统机械表相比,它具有走时精确,显示直观等特点。它的计时周期为24小时,显满刻度为“23时59分59秒”,另外具有校时功能,断电后有记忆功能,恢复供电时可实现计时同步等特点。

2 方案论证

21 方案一

数字钟采用FPGA作为主控制器。由于FPGA具有强大的资源,使用方便灵活,易于进行功能扩展,特别是结合了EDA,可以达到很高的效率。此方案逻辑虽然简单一点,但是一块FPGA的价格很高,对于做电子钟来说有一点浪费,而且FPGA比较难掌握,本设计中不作过多研究,也不采用此方案。

22 方案二

数字钟由几种逻辑功能不同的CMOS数字集成电路构成,共使用了10片数字集成电路,其原理图如图21所示。它是由秒信号发生器(时基电路)、小时分钟计数器及译码和驱动显示电路3部分组成,其基本工作过程是:时基电路产生精确周期的脉冲信号,经过分频器作用给后面的计数器输送1HZ的秒信号,最后由计数器及驱动显示单元按位驱动数码管时间显示,但是这样设计的电路比较复杂,使用也不灵活,而且价格比较高,故不采用此方案。

图21 方案二原理示意图

23 方案三

AT89S52是一种低功耗、高性能CMOS 8位微控制器。使用Atmel公司高密度非易失性存储器技术制造,与工业80C51产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。在单芯片上,拥有灵巧的8位CPU和在系统可编程Flash,使得AT89S52为众多嵌入式控制应用系统提供高灵活、有效的解决方案。它具有串行口,片内晶振及时钟电路。另外,AT89S52可降至0Hz 静态逻辑 *** 作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。

基于AT89S52单片机来实现系统的控制,外围电路比较简单,成本比较低,此系统控制灵活能很好地满足本课题的基本要求和扩展要求,因此选用该方案。其硬件框图如图22所示,原理图见附录图61。

图22 数字钟硬件框图

24 电路组成及工作原理

本文数字时钟设计原理主要利用AT89S52单片机,由单片机的P0口控制数码管的位显示,P2口控制数码管的段显示,P1口与按键相接用于时间的校正。在设计中引入220V交流电经过整流、滤波后产生+5V电压,用于给单片机及显示电路提供工作电压。

整个系统工作时,秒信号产生器是整个系统的时基信号,它直接决定计时系统的精度,将标准秒信号送入“秒计数器”,“秒计数器”采用60进制计数器,每累计60秒发出一个“分脉冲”信号,该信号将作为“分计数器”的时钟脉冲。“分计数器”也采用60进制计数器,每累计60分钟,发出一个“时脉冲”信号,该信号将被送到“时计数器”。“时计数器”采用24进制计时器,可实现对一天24小时的累计。显示电路将“时”、“分”、“秒”计数器的输出,通过六个七段LED显示器显示出来。校时电路是直接加一个脉冲信号到时计数器或者分计数器或者秒计数器来对“时”、“分”、“秒”显示数字进行校对调整。在本设计中,24小时时钟显示、秒表的设计和显示都是依靠单片机中的定时器完成。使用定时器T0产生1s的中断,在中断程序中完成每一秒数字的变化,并在主程序中动态显示该字符。其功能框图如图23所示。

图23 秒表外中断的功能示意图

数字钟的电路设计主要功能是提供单片机和外部的LED显示、273地址锁存和片选以及外部存储器2764的接口电路,此外还需要设计相关的LED驱动电路。

(1)电路原理和器件选择

本实例相关的关键部分的器件名称及其在数字钟电路中的主要功能:

89S52:单片机,控制LED的数据显示。

LED1--LED6:用于显示单片机的数据,其中三个采用7段显示用于显示时、分、秒的十位,另三个采用8段显示用于显示时、分、秒的个位。

74LS273:锁存器,LED显示扩展电路中的段码和位码使用了两片74LS273,上升沿锁存。

74LS02:与非门,与单片机的读写信号一起使用,选中外部的74LS273,决定LED的字段和字位的显示内容。

7407:驱动门电路,提供数码管显示的驱动电流。

74LS04:非门,对单片机的片选信号取反,并和读写信号一起使用,决定74LS273的片选。

L1--L4:发光二极管,通过单片机的P14--P17控制,用以显示秒表和时钟的时间变化。

BUZZER:扬声器,在程序规定的情况下,发出声音,提示计时完毕。

74LS373:地址锁存器,将P0口的地址和数据分开,分别输入到2764的数据和地址端口。

2764:EPROM,为单片机提供外部的程序存储区。

开关K0、K1、K2分别调整秒、分、时。

按键RESET:在复位电路中,起到程序复位的作用。

按键PULSE:提供单脉冲,从而实现单片机对外部脉冲的计数功能,利用单脉冲实现相应位加1。

(2)地址分配和连接

P27:和写信号一起组成字位口的片选信号,字位口的对应地址位8000H

P26:和写信号一起组成字段口的片选信号,字段口的对应地址位4000H

D0--D7:单片机的数据总线,LED显示的内容通过D0--D7数据线从单片机传送到LED

P20--P25:单片机的P2口,和2764的高端地址线相连,决定2764中的存储单元的地址。

P14--P17:单片机的P1口,和反光二极管L1--L4相连,通过单片机的P14--P17控制,用以显示秒表和时钟的时间变化。

(3)功能简介

LED显示模块与单片机的连接中,对LED显示模块的读写和字位、字段通道的选择是通过单片机的P26、P27口完成。其中,P26、P27口的片选信号需要和读写信号做一定的逻辑 *** 作,以保证字位和字段选择的正确性。

外部存储器2764是通过74LS373和单片机相连,并且通过P2口的相关信号线进行地址的分配。地址范围为0000H--1FFFH。

3 各电路设计和论证

31电源电路设计

在各种电子设备中,直流稳压电源是必不可少的组成部分,它不仅为系统提供多路电压源,还直接影响到系统的技术指标和抗干扰性能。要想得到我们所要的+5V输出电压,就需将交流220V的电压经过二极管全波整流、电容滤波、7805稳压输出稳定的5V直流电压为整个电路提供电源。

图31 电源电路图

4个IN4004组成桥式整流电路,电容(104uf)用于滤波,LM7805将经过整流滤波的电压稳定在5V输出。

32 晶体振荡器

51系列单片机内部有一个时钟电路(其核心时一个反相放大器),但并没有形成时钟的振荡信号,因此必须外接谐振器才能形成振荡。如何用这个内部放大器,可以根据不同的场合做出不同的选择。这样就对应了单片机时钟产生的不同方式:若采用这个放大器,产生振荡即为内部方式;若采用外部振荡输入,即为外部方式。

方案一、内部方式

如果在51单片机的XTAL1和XTAL2引脚之间外接晶体谐振器,便会产生自激振荡,即可在内部产生与外加晶体同频率的振荡时钟。

最常见的内部方式振荡图如图32所示。

图32 晶体振荡电路

不同单片机最高工作频率不一样,如AT89C51的最高工作频率为24MHZ,AT89S51的最高工作频率可达33MHZ。由于制造工艺的改进,现在单片机的工作频率范围正向两端延伸,可达40MHZ以上。振荡频率越高表示单片机运行的速度越快,但同时对存储器的速度和印刷电路板的要求也就越高。频率太高有时反而会导致程序不好编写(如延时程序)。一般来说,不建议使用很高频率的晶体振荡器。51系列的单片机应用系统一般都选用频率为6~12MHZ的晶振。

这个电路对C1、C2的值没有严格的要求,但电容的大小多少会影响振荡器的稳定性、振荡器频率的高低、起振的快速性等。一般外接晶体时,C1、C2的值通常选为20~100PF。

晶体振荡器是数字钟的核心。振荡器的稳定度和频率的精确度决定了数字钟计时的准确程度,通常采用石英晶体构成振荡器电路。一般说来,振荡器的频率越高,计时的精度也就越高。在此设计中,信号源提供1HZ秒脉冲,它是采用晶体分频得到的。AT89S52单片机有一个用于构成内部振荡器的反相放大器,XTAL1和XTAL2分别是放大器的输入、输出端。石英晶体和陶瓷谐振器都可以用来一起构成自激振荡器。从外部时钟源驱动器件,XTAL2可以不接,而从XTAL1接入,由于外部时钟信号经过二分频触发后作为外部时钟电路输入的,所以对外部时钟信号的占空比没有其它要求,最长低电平持续时间和最少高电平持续时间等还是要符合要求的。反相放大器的输入端为XTAL1,输出端为XTAL2,两端连接石英晶体及两个电容形成稳定的自激振荡器。电容通常取30PF左右。振荡频率范围是12~12MHz。

晶体振荡器的振荡信号从XTAL2端输出到片内的时钟发生器上。时钟发生器为二分频器。向CPU提供两相时钟信号P1和P2。每个时钟周期有两个节拍(相)P1和P2,CPU就以两相时钟P1和P2为基本节拍指挥AT89S52单片机各部件协调工作。在本次设计中取石英晶体的振荡频率为110592MHz。

另外在设计电路板时,晶振、电容等均应尽量靠近单片机芯片,以减小分布电容,进一步保证振荡器的稳定性。

方案二、外部方式

在较大规模的应用系统中可能会用到多个单片机,为保证各单片机之间时钟信号的同步,应当引入唯一的公用外部脉冲信号作为各单片机的共同的振荡脉冲,也就是要采用外部方式,外部振荡信号直接引入XTAL1和XTAL2引脚。

由于HMOS、CHMOS单片机内部时钟进入的引脚不同,因此外部振荡信号的接入方式也不一样。所以不选用此方案。

33 校时电路

当数字钟走时出现误差时,需要校正时间。校时控制电路实现对“秒”、“分”、“时”的校准。其电路图如图33所示:

图33 校时电路

34 译码显示电路

译码电路的功能是将“秒”、“分”、“时” 计数器中每个计数器的输出状态(8421码),翻译成七段(或八段)数码管能显示十进制数所要求的电信号,然后再经数码管把相应的数字显示出来。译码器采用74LS248译码/驱动器。显示器采用七段共阴极数码管。显示部分是整个电子时钟最为重要的部分,共需要6位LED显示器。采用动态显示方式,所谓动态显示方式是时间数字在LED上一个一个逐个显示,它是通过位选端控制在哪个LED上显示数字,由于这些LED数字显示之间的时间非常的短,使的人眼看来它们是一起显示时间数字的,并且动态显示方式所用的接口少,节省了CPU的管脚。由于端口的问题以及动态显示方式的优越性,在此设计的连接方式上采用共阴级接法。显示器LED有段选和位选两个端口,首先说段选端,它由LED八个端口构成,通过对这八个端口输入的不同的二进制数据使得它的时间显示也不同,从而可以得到我们所要的时间显示和温度。但对于二十个管脚的AT89S52来说,LED八个段选管脚太多,于是我选用2764芯片来扩展主芯片的管脚,74LS164是数据移位寄存器,还选用了74LS373作为数据缓存器。

选用器件时应注意译码器和显示器的匹配,包括两个方面:一是功率匹配,即驱动功率要足够大。因为数码管工作电流较大,应选用驱动电流较大的译码器或OC输出译码器。二是逻辑电平匹配。例如,共阴极型的LED数码管采用高电平有效的译码器。推荐使用的显示译码器有74LS48、74LS49、CC4511。

35 显示电路结构及原理

(1)单片机中通常用七段LED构成 “8” 字型结构,另外,还有一个小数点发光二极管以显示小数位!这种显示器有共阴和共阳两种!发光二极管的阳极连在一起的(公共端)称为共阳极显示器,阴极连在一起的称为共阴极显示器。

一位显示器由8个发光二极管组成,其中,7个发光二极管构成字型“8”的各个笔划,另一个发光二极管为小数点为。当在某段发光二极管上施加一定的正向电压时,该段笔画即亮;不加电压则暗。为了保护各段LED不被损坏,需外加限流电阻。

在本设计中时、分、秒的十位采用七段显示,个位采用八段显示,使得更易于区分时、分、秒。

(2)LED显示器接口及显示方式

LED显示器有静态显示方式和动态显示方式两种。静态显示就是当显示器显示某个字符时,相应的段恒定的导通或截止,直到显示另一个字符为止。LED显示器工作于静态显示方式时,各位的共阴极接地;若为共阳极则接+5V电源。每位的段选线分别与一个8位锁存器的输出口相连,显示器中的各位相互独立,而且各位的显示字符一经确定,相应锁存的输出将维持不变。

正因为如此,静态显示器的亮度较高。这种显示方式编程容易,管理也较简单,但占用I/O口线资源较多。因此,在显示位数较多的情况下,一般都采用动态显示方式。

由于所有6位段皆由一个I/O口控制,因此,在每一瞬间,6位LED会显示相同的字符。要想每位显示不同的字符,就必须采用扫描方法流点亮各位LED,即在每一瞬间只使某一位显示字符。在此瞬间,段选控制I/O口输出相应字符段选码(字型码),而位选则控制I/O口在该显示位送入选通电平(因为LED为共阴,故应送低电平),以保证该位显示相应字符。如此轮流,使每位分时显示该位应显示字符。

在多位LED显示时,为了简化电路,降低成本,将所有位的段选线并联在一起,由一个8位I/O口控制。而共阴(共阳)极公共端分别由相应的I/O口线控制,实现各位的分时选通。

段选码,位选码每送入一次后延时2MS,因人的视觉暂留效应,给人看上去每个数码管总在亮。

图34 六位LED动态显示电路

36 键盘部分

它是整个系统中最简单的部分,根据功能要求,本系统共需三个按键:分别对时、分、秒进行控制。并采用独立式按键。

按键按照结构原理可分为两类,一类是触点式开关按键,如机械式开关、导电橡胶式开关等;另一类是无触点式开关按键,如电气式按键,磁感应按键等。前者造价低后者寿命长。目前,微机系统中最常见的是触点式开关按键。

按键按照接口原理可分为编码键盘与非编码键盘两类,这两类键盘的主要区别是识别键符及给出相应键码的方法。编码键盘主要是用硬件来实现对键的识别,非编码键盘主要是由软件来实现键盘的定义与识别。

全编码键盘能够由硬件逻辑自动提供与键对应的编码,此外,一般还具有去抖动和多键、窜键保护电路。这种键盘使用方便,但需要较多的硬件,价格较贵,一般的单片机应用系统较少采用。非编码键盘只简单地提供行和列的矩阵,其它工作均由软件完成。由于其经济实用,较多地应用于单片机系统中。在本套设计中由于只需要几个功能键,此时,可采用独立式按键结构。

独立式按键是直接用I/O口线构成的单个按键电路,其特点是每个按键单独占用一根I/O口线,每个按键的工作不会影响其它I/O口线的状态。独立式按键的典型应用如图35 所示。

独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一根I/O口线,因此,在按键较多时,I/O口线浪费较大,不宜采用。

图35 独立式按键结构图

37 复位电路

复位时使CPU和系统中的其他功能部件都处于一个确定的初始状态,复位后计算机就从这个状态开始工作。在复位期间,CPU并没有开始执行程序,是在做准备工作。

无论时在计算机刚上电时、断电后、还是系统出现故障时都需要复位。

51单片机的复位条件靠外部电路实现。当时钟电路工作时,只要在单片机的RESET引脚上持续出现2个TP以上的高电平就可以使单片机复位。但时间过短往往使复位部可靠。为了确保复位,RESET引脚上的高电平一般要维持大约10ms以上。

常见的复位电路有上电复位和按键复位电路。在此我们选用按键复位电路。

(1)上电复位电路

上电复位电路是利用电容充电来实现的。在接通电源的瞬间,RESET端的电位与VCC相同,都是+5V。随着RC电路的充电,RESET的电位逐渐下降,只要保证RESET为高电平的时间大于10ms就能正常复位了。如图36(1)所示。

图36(1)上电复位电路

(2)按键复位电路

在单片机已经通电的情况下,只需要按下图36(2)的K键也可以复位,此时VCC经过电阻Rs、Rk分压,在RESET端产生一个复位高电平。

在图36(2)的电路中,干扰容易窜入复位端,虽然在大多数情况下不会造成单片机的错误复位,但可能会引起内部某些寄存器的错误复位。这时可在RESET端接上一个去耦电容。

另外有些单片机应用系统中的外围芯片也需要复位,如果这些复位端的复位电平要求和单片机的复位要求一致,则可以直接与之相连。常将RC电路接施密特电路后再接入单片机的复位端。这样系统可以有多个复位端,以便保证外部芯片和单片机可靠地同步复位。

图36(2) 按键复位电路

4 软件设计

41 程序流程

程序整体设计:定时模块,显示模块,时间调整模块,状态调整模块。

(1)总体介绍:此部分主要介绍定时模块,和显示模块。定时部分采用经典的定时器定时。它实现了数字钟的主要部分和秒表的主要部分,以及进行定时设置。显示模块是实现数字钟的又一重要部分,其模块的独立程度直接影响到数字钟的可视化程度。在此部分的设计中,设置专用显示数据缓冲区,与分、时及其他数据缓冲区数据区别,在其中存放的是显示段码,而其他缓冲区存放的是时间数据。在显示时,首先将时间十进制数据转化为显示段码,然后送往数码管显示。显示段码采用动态扫描的方式。在要求改变显示数据的类别时,只须改变指向数据缓冲区的指针所指向的十进制数据缓冲区即可。

(2)时间调整:时间调整有多种方式。一、可以直接进入相关状态进行有关 *** 作,二、将调整分两步,先进入状态,然后执行 *** 作,这两步分别由两个键控制。方式一,比较直接,设计思想也比较简单,但是,这种方式存在 *** 作时间和控制键数目的矛盾。如果用比较少的键,那么可能会在进入状态后处于数据调整等待状态,这样会影响到显示的扫描速度(显示部分可以采用8279芯片来控制,可以解决此问题)。 当然在这种方式下,还可以使用多个状态键,每个状态键,完成一个对应数据的调整。如果采用二的方式,就不会出现这种情况。因为状态的调整,与状态的 *** 作可以分别由两个键控制,其状态的调整数可以多达256个(理论上), *** 作的完成是这样的,一键控制状态的调整,一键控制数据的调整。以上两种方式的实现都可以采用查询和中断的方式。两种方式必须注意的问题是两者进行相关 *** 作的过程不能太长否则会影响显示的扫描。利用查询的方式,方法传统,对此就不作过多的讨论,以下是采用中断的方式实现的数字钟的一些讨论和有关问题作的一些处理。基于以上的讨论可以设计如下:将调整分为状态调整和数据调整两部分,每次进入中断只执行一次 *** 作,然后返回,这样,就不必让中断处于调整等待状态,这样,可以使中断的耗时很小。将定时器中断的优先级设置为最高级,那么中断的方式和查询的方式一样不会影响到时钟的记数。

(3)中断方式应注意的问题:

采用中断的方式,最好将定时器中断的优先级设置为最高级,关于程序数据的稳定性应注意两个问题:一、在低优先级中断响应时,应在入栈保护数据时禁止高优先级的中断响应。二、在入栈保护有关数据后,对中断程序执行有影响的状态位,寄存器,必须恢复为复位状态的值。例如,在用到了十进制调整时,在中断进入时,需将PSW中的AC,CY位清零,否则,十进制调整出错。

(4)定时准确性的讨论:

程序中定时器,一直处于运行状态,也就是说定时器是理想运作的,其中断程序每隔01秒执行一次,在理想状态下,定时器定时是没有系统误差的,但由于定时器中断溢出后,定时器从0开始计数,直到被重新置数,才开始正确定时,这样中断溢出到中断响应到定时器被重新置数,其间消耗的时间就造成了定时器定时的误差。如果在前述定时器不关的情况下,在中断程序的一开始就给定时器置数,此时误差最小,误差大约为:每01秒,误差7—12个机器周期。当然这是在定时器定时刚好为01秒时的情况,由以上分析,如果数字钟设计为查询的方式或是在中断的方式下将定时器中断设置为最高级,我们在定时值设置时,可以适当的扣除9个机器周期的时间值。但如果在中断的情况下,没有将定时器中断设置为最高级,那就要视中断程序的大小,在定时值设置时,扣除相应的时间值。

(5)软件消抖:

消抖可以采用硬件(施密特触发器)的方式如图44所示,也可以采用软件的方式。在此只讨论软件方式。软件消抖有定时器定时,和利用延时子程序的方式。一,定时器定时消抖可以不影响显示模块扫描速度,其实现方法是:设置标志位,在定时器中断中将其置位,然后在程序中查询。将其中断优先级设置为低于时钟定时中断,那么它就可以完全不影响时钟定时。二,在采用延时子程序时,如果显示模块的扫描速度本来就不是很快,此时可能会影响到显示的效果,一般情况下,每秒的扫描次数不应小于50次,否则,数码的显示会出现闪烁的情况。因此,延时子程序的延时时间应该小于20毫秒,如果采用定时器定时的方式,延时时间不影响时钟。

如果,设计时采用的是中断的方式来完成有关 *** 作,同样可以采用软件的方式来消抖,其处理思想是:中断不能连续执行,两次之间有一定的时间间隔。

411 系统主程序流程图

图41 主程序流程图

412 各子程序流程图

图42 时钟调整子程序流程图希望可以帮到你!

#include <reg52h>

#define uint unsigned int

#define uchar unsigned char

sbit PRESS1=P1^0;

sbit PRESS2=P1^1;

sbit PRESS3=P1^2;

uint a[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0到9

uint b[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

int miao=45,fen=58,shi=15;

uint jishu;

uint miaog,miaos,feng,fens,shig,shis;

int ji;

void init()//初始化函数设置中断寄存器的值。

{

jishu=0;

TMOD=0x01;

TR0=1;

ET0=1;

EA=1;

TH0=0x3c;

TL0=0xb0;

}

void delay(x)//延时函数。

{

uint i,j;

for(i=x;i>0;i--)

for(j=120;j>0;j--);

}

void xian()//把时分秒送到数码管显示。

{

uint i;

miaog=miao%10;

miaos=miao/10;

feng=fen%10;

fens=fen/10;

shig=shi%10;

shis=shi/10;

for(i=0;i<8;i++)

{

switch(i)

{

case 0:P3=b[7];P2=a[miaog];break;

case 1:P3=b[6];P2=a[miaos];break;

case 2:P3=b[5];P2=0x40;break;

case 3:P3=b[4];P2=a[feng];break;

case 4:P3=b[3];P2=a[fens];break;

case 5:P3=b[2];P2=0x40;break;

case 6:P3=b[1];P2=a[shig];break;

case 7:P3=b[0];P2=a[shis];break;

}

delay(1);

};

}

void jiance()//检测键是否按下按不同键实现不同的处理。

{

if(PRESS1==0)

{

delay(2);

if(PRESS1==0)

{

while(!PRESS1);

ji++;

if(ji>=4)

ji=0;

}

}

if(ji==1)

{

if(PRESS2==0)

{

delay(1);

while(!PRESS2);

miao++;

if(miao>=60)

{

miao=0;

fen++;

}

}

if(PRESS3==0)

{

delay(1);

while(!PRESS3);

miao--;

if(miao<0)

{

miao=59;

}

}

}

if(ji==2)

{

if(PRESS2==0)

{

delay(1);

while(!PRESS2);

fen++;

if(fen>=60)

{

fen=0;

shi++;

}

}

if(PRESS3==0)

{

delay(1);

while(!PRESS3);

fen--;

if(fen<0)

{

fen=59;

}

}

}

if(ji==3)

{

if(PRESS2==0)

{

delay(1);

while(!PRESS2);

shi++;

if(shi>=24)

{

shi=0;

}

}

if(PRESS3==0)

{

delay(1);

while(!PRESS3);

shi--;

if(shi<0)

{

shi=23;

}

}

}

if(ji==0)

EA=1;

else

EA=0;

}

void main()

{

init();

while(1)

{

xian();

jiance();

}

}

void duan() interrupt 1 //计时中断0工作方式1函数。

{

TH0=0x3c;

TL0=0xb0;

jishu++;

if(jishu==20)

{

jishu=0;

miao++;

if(miao==60)

{

miao=0;

fen++;

if(fen==60)

{

fen=0;

shi++;

if(shi==24)

shi=0;

}

}

}

}

8个数码管的话一般都是由一个三八译码器控制,而且有三个i/o口作为选择数码管的钥匙,三个i/o口按一定顺序组合成的二进制000~111即是数字为0~7的8个数码管分别对应的三极管(开关),三个i/o口对应哪个数字就打开哪个数字的开关从而对应的数码管就会亮,其他一定会灭,所以为i/o口的一次赋值,就只开一个数码管。所以要求8个数码管分别显示1~8其实就是很快地轮次开闭8个数码管的开关,不断循环往复,切换开关的速度让肉眼无法识别有闪动感,而且每切换一次开关之前记得先消除鬼影

如何快速切换开关?

1定时器中断或定时器中断函数

2普通的延时函数(延时要自己测试)

3不延时(开关切换之前要消除鬼影)

以上就是关于单片机延时子程序流程图全部的内容,包括:单片机延时子程序流程图、单片机编程的整个流程、51单片机控制喇叭的程序(c语言)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9312954.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存