[PIC®/AVR®/dsPIC®产品]

基于单片机的电子秒表设计

[复制链接]
32309|15
手机看帖
扫描二维码
随时随地手机跟帖
空速星痕001|  楼主 | 2022-8-9 14:00 | 显示全部楼层 |阅读模式
1.方案设计
1.1.设计要求
设计一个电子秒表,4位数码管显示时间,显示时间范围00.00秒到99.99秒,共计100秒。利用按键修改时间,按键一按下加一秒,按键二按下减一秒,按键三按下置零,按键四启动或暂停计时。
1.2.方案讨论
本系统用STC89C51RC为主控,利用4位共阴数码管显示,避免了用4个独立的数码管造成单片机IO口不够用和资源的浪费。单片机驱动4位共阴数码管用两块74HC573芯片,当使能端为高电平时,输出将随数据输入而变。当使能为低电平时,输出将锁存在已建立的数据电平上。输出控制不影响锁存器的内部工作,原来的数据可以保持,甚至当输出被关闭时,新的数据也可以置入。74HC573可以驱动大电容或低阻抗负载,可以直接与系统总线接口并驱动总线,而不需要外接口。利用4个独立按键就可以满足时间的设置。


2.硬件设计
2.1.主控制器
主 CPU 电路选用 STC89C51RC 系列单片机,STC89C51RC 是采用 8051 核的 ISP(In System Programming)在系统可编程芯片,最高工作时钟频率为 80MHz,片内含4KB的可反复擦写 1000 次的 Flash 只读程序存储器,器件兼容标准 MCS-51 指令系统及 80C51 引脚结构,芯片内集成了通用8位中央处理器和ISP Flash 存储单元,具有在系统可编程(ISP)特性,配合PC端的控制程序即可将用户的程序代码下载进单片机内部,省去了购买通用编程器,而且速度更快。
STC89C52RC 系列单片机是单时钟/ 机器周期(1T)的兼容 8051 内核单片机,是高速/低功耗的新一代 8051 单片机,全新的流水线/ 精简指令集结构,内部集成 MAX810 专用复位电路。
STC89C51 系列单片机的特点:
(1) 增强型 1T 流水线/ 精简指令集结构 8051 CPU
(2) 工作电压:3.4V-5.5V(5V 单片机/2.0V-3.8V(3V 单片机)
(3) 工作频率范围:0 - 35 MHz,相当于普通 8051 的 0~420MHz.实际工作频率可达48MHz.
(4)用户应用程序空间 12K / 10K / 8K / 6K / 4K / 2K 字节
(5) 片上集成 512 字节 RAM
(6) 通用 I/O 口(27/23 个),复位后为: 准双向口/ 弱上拉(普通 8051 传统 I/O 口)可设置成四种模式:准双向口/ 弱上拉,推挽/ 强上拉,仅为输入/ 高阻,开漏每个 I/O 口驱动能力均可达到 20mA,但整个芯片最大不得超过 55mA
(7) ISP(在系统可编程)/IAP(在应用可编程),无需专用编程器可通过串口(P3.0/P3.1)直接下载用户程序,数秒即可完成一片
(8) EEPROM 功能
(9) 看门狗
(10)内部集成 MAX810 专用复位电路(外部晶体 20M 以下时,可省外部复位电路)
(11)时钟源:外部高精度晶体/ 时钟,内部 R/C 振荡器。用户在下载用户程序时,可选择是使用内部 R/C 振荡器还是外部晶体/ 时钟。常温下内部 R/C 振荡器频率为:5.2MHz ~ 6.8MHz。精度要求不高时,可选择使用内部时钟,因为有温漂,请选 4MHz ~ 8MHz
(12)有 2 个 16 位定时器/ 计数器
(13)外部中断 2 路,下降沿中断或低电平触发中断,Power Down 模式可由外部中断低电平触发中断方式唤醒
(14)PWM ( 4 路)/ P C A(可编程计数器阵列),也可用来再实现 4 个定时器或 4 个外部中断(上升沿中断/ 下降沿中断均可支持)
(15) STC89Cc516AD 具有 ADC 功能。 10 位精度 ADC,共 8 路
(16) 通用异步串行口(UART)
(17) SPI 同步通信口, 主模式/ 从模式
(18)工作温度范围: 0 - 75℃ / -40 - +85℃
(19)封装: PDIP-28,SOP-28,PDIP-20,SOP-20,STC89C52RC系列单片机为真正的看门狗,缺省为关闭(冷启动),启PLCC-32,TSSOP-20(超小封状,定货)动后无法关闭,可省去外部看门狗。此系列单片机P4口地址为E8H,并有2个附加外部中断,P4.2/INT3,P4.3/INT2。
2.2.晶振及复位模块
晶振电路部分,使用12MHz 晶振,和两个30PF电容。在复位电路中,采用按键电平复位,电容为 10uF,电阻为10k。当系统处于正常状态时,如果RST引脚上有一个高电平并维持2个机器周期,CPU响应并将系统复位。晶振及复位电路如右图。
4346662f1f7bde564f.png
2.3.按键模块
系统设计有四路独立的输入按键,按键直接接入到单片机的 P3 口,当按键未按下时,单片机检测到引脚为高电平;当按键被按下时,单片机检测到引脚为低电平,执行相应的程序。所以只要通过检测相应端口的状态的变化,就可以检测到是否有按键按下。键盘电路如下图所示。
8165262f1f7c69caa3.png
数码管采用四段的共阴数码管,通过两块74HC573分别控制数码管的段选和位选。
当第一块74HC573的LE端为高电平时,第二块74HC573的LE端为低电平时,P0口控制段选,数码管可以显示内容。显示数字可以给0到9十个数字编码,再把要显示的数字通过这个编码送到P0口即可。当第二块74HC573的LE端为高电平时,第一块74HC573的LE端为低电平时,P0口控制位选,可以控制数码管第几位显示。由于P0口作为I/O口使用时,P0口内部的场效应管截止,输出为漏极开路,必须要接上拉电阻才能有高电平输出。在本系统中,P0口接了10K的排阻作为上拉电阻。显示电路如下图所示。
8050562f1f7ce8500b.png
3.系统仿真图
利用Proteus仿真软件绘制的系统仿真图如下:
9069962f1f7d6186e8.png
8121062f1f7df0b072.png
4.软件设计
在Keil软件中,利用C51编程实现电子秒表的功能。程序包括主函数、延时函数、定时器初始化、数码管显示、键盘扫描和中断服务程序。程序从主函数执行,先初始化定时器,然后一直循环调用数码管显示和键盘扫描函数。
4.1.软件流程图
2953862f1f7e5e5ca0.png
4.2.参考程序


#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit duan=P2^6;                                                //控制数码管段选
sbit wei=P2^7;                                                //控制数码管位选
sbit K1=P3^4;                                                //按键1加1秒
sbit K2=P3^5;                                                //按键1减1秒
sbit K3=P3^6;                                                //按键3清零
sbit K4=P3^7;                                                //按键4暂停/启动
uchar code table[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x7f,0x6f};
                                                                         //0~9的共阴数码管编码(不带小数点)
uchar code table2[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};                       
                                                                        //0~9的共阴数码管编码(带小数点)
uint num,sec1=0,sec2=0;                                //sec1为小数部分,sec2为整数部分
void delay(uint z)                                         //延时函数
{
        uint i,j;
        for(i=z;i>0;i--)
                for(j=110;j>0;j--);
}
void begin()                                        //初始化函数
{       
        TMOD=0x01;                                        //设置定时器0工作方式1
        TH0=(65536-1000)/256;           //中断一次1毫秒
        TL0=(65536-1000)%256;
        EA=1;                                           //开总中断
        ET0=1;                                           //开定时器中断0
        TR0=1;                                           //启动定时器0
}
void display(uchar sec1,uchar sec2)//数码管显示
{               
        wei=1;                                           //打开位选锁存器
        P0=0xf7;                                   //数码管第1位
        wei=0;                                            //关闭位选锁存器       
        duan=1;                                           //打开段选锁存器
        P0=table[sec1%10];                   //送入数据百分位
        duan=0;                                           //关闭段选锁存器
        P0=0xff;                                   //消影
        delay(2);                                   //延时2毫秒,用于数码管动态显示
        wei=1;                                          
        P0=0xfb;                                   //数码管第2位
        wei=0;                 
        duan=1;
        P0=table[sec1/10];                  //送入数据十分位
        duan=0;
        P0=0xff;       
        delay(2);
        wei=1;
        P0=0xfd;                                 //数码管第3位
        wei=0;                  
        duan=1;
        P0=table2[sec2%10];                //送入数据个位
        duan=0;         
        P0=0xff;
        delay(2);
        wei=1;
        P0=0xfe;                                 //数码管第4位
        wei=0;                  
        duan=1;
        P0=table[sec2/10];                 //送入数据十位
        duan=0;
        P0=0xff;
        delay(2);
}
void keyscan()//独立按键函数
{       
        if(K1==0)                                //按键1按一次增加1秒
        {       
                delay(5);                        //去除抖动
                if(K1==0)                        //如果K1确认按下
                {                               
                        sec2++;                        //加1秒钟       
                        if(sec2==100)        //到99秒清零
                                sec2=0;                       
                        while(!K1);                //等待按键松开
                }
        }
        if(K2==0)                                //按键2按一次减少1秒
        {       
                delay(5);                        //去除抖动
                if(K2==0)                        //如果K2确认按下
                {       
                        sec2--;                          //减1秒钟
                        if(sec2==-1)                //减到0继续从99秒开始
                                sec2=99;                       
                        while(!K2);
                }
        }
        if(K3==0)                                //按键3清零
        {       
                delay(5);                        //去除抖动
                if(K3==0)                        //如果K3确认按下
                {       
                        sec1=0;                        //整数全部清零
                        sec2=0;                         //小数全部清零
                }
                while(!K3);               
        }       
        if(K4==0)                                //按键4暂停/开启计时
        {       
                delay(5);                        //去除抖动
                if(K4==0)                    //如果K4确认按下
                {                               
                        TR0=~TR0;           //启动或关闭定时器0
                        while(!K4);
                }
        }
}
void main()
{         
        begin();                           //调用初始化函数
        while(1)                           //程序一直执行数码管显示和按键函数
        {       
                display(sec1,sec2);
                keyscan();
        }
}
void time0() interrupt 1   //定时器0中断服务程序
{       
        TH0=(65536-1000)/256;  //重装初值
        TL0=(65536-1000)%256;
        num++;
        if(num==10)                           //如果计数值等于10,那么1ms到
        {       
                num=0;                           //把num清零重新计数10次,等待下一次中断
                sec1++;                           //小数加1
                if(sec1==100)           //小数到99清零
                {       
                        sec1=0;
                        sec2++;                   //小数加满后向整数进位
                        if(sec2==100)   //整数到99清零
                                sec2=0;
                }       
        }
}


5.系统验证及分析
下图为仿真效果图。
7271162f1f7f83f3e5.png
下图为开始仿真的效果图。当前显示数字表示计时到3.02秒.
8499462f1f7ff11c44.png
下图为即将计时到99.99秒的效果。到达99.99秒后会全部清零。
1617162f1f804aa646.png
通过以上Proteus的仿真效果图可以看出,系统实现了所有基本功能,达到了预期的效果。但是在仿真过程中,由于仿真软件运行有一定延时,所以计时的精度不够准确,比正常的秒表慢。此外,小数点后面两位数码管计数时间很快,人眼难以分辨数码管的变化。


6.结论
本设计是基于单片机控制的数字秒表,系统的成本较低,但实用价值很高而且采用的技术较为稳定而且成熟,另外系统的应用要求不是很高。通过这次秒表的设计,我们学到了许多知识,还学到了许多思考问题的方法,同时也提高了分析问题、解决问题的能力。


使用特权

评论回复
评论
LED2013 2022-8-22 23:01 回复TA
赞的,期待视频 
carpsnow| | 2022-8-11 21:55 | 显示全部楼层
不错,实物有么

使用特权

评论回复
guijial511| | 2022-8-12 08:05 | 显示全部楼层
谢谢分享,做个实物出来就更好了!

使用特权

评论回复
剑_舞| | 2022-8-18 15:00 | 显示全部楼层
谢谢分享,做个实物出来就更好了!

使用特权

评论回复
tpgf| | 2022-9-3 18:58 | 显示全部楼层
精度大概能到多少呢

使用特权

评论回复
qcliu| | 2022-9-3 19:14 | 显示全部楼层
使用的是内部晶振还是外部晶振啊

使用特权

评论回复
drer| | 2022-9-3 19:20 | 显示全部楼层
供阴和共阳的区别是什么呢

使用特权

评论回复
coshi| | 2022-9-3 19:25 | 显示全部楼层
去抖的延时 是经验值吗

使用特权

评论回复
kxsi| | 2022-9-3 19:35 | 显示全部楼层
电路连接并不复杂

使用特权

评论回复
wiba| | 2022-9-3 20:06 | 显示全部楼层
一般对单片机的要求也不高

使用特权

评论回复
scherneman| | 2022-9-12 17:10 | 显示全部楼层
谢谢基础讲解

使用特权

评论回复
lzkpop001| | 2022-9-25 17:38 | 显示全部楼层
就是厉害啊,学习学习

使用特权

评论回复
chenjun89| | 2022-10-5 12:50 | 显示全部楼层
现在这个仿真软件还在更新吗?

使用特权

评论回复
Undshing| | 2022-10-10 21:02 | 显示全部楼层
这个的精度怎么样呢?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

30

主题

33

帖子

0

粉丝