目录

总体设计

晶体震荡电路

复位电路

按键控制电路

LCD1602显示电路

蜂鸣器电路

Proteus仿真图调试结果

源代码:

Proteus仿真提取链接


总体设计

本设计是采用AT89C51单片机为中心,利用其定时器/计数器定时和记数的原理,结合显示电路、电源电路、LCD1602液晶以及键盘电路来设计计时器。将软、硬件有机的结合起来,使得系统能够实现四位LCD显示,最大显示时间为09:59:99,有开始/暂停、复位、记录和查看功能,并设有每秒提醒功能。

此次的设计是采用定时器进行计时并且在LCD1602上显示时间,先要基本了解硬件内在结构,确定用P0并行端口进行LCD1602控制输入,使用P2.0、P2.1、P2.2控制LCD的RE、RW、EN端口。P1.0控制蜂鸣器、P1.1控制开始/暂停、P1.2、P1.3控制查看上一条、下一条、P1.4控制记录、P1.5控制复位、P1.6控制每秒提醒。

晶体震荡电路

利用12分频的晶振的一个机器周期为一微妙,通过循环延时产生0.1秒的延时,通过XTAL1和XTAL2外接晶体振荡器构成内部振荡方式。由于单片机内部有一个高增益反相放大器,当外接晶振后,就构成了自激振荡器并产生振荡时钟脉冲。51单片机内部的振荡电路是一个高增益反相放大器,引线XTAL1和XTAL2引脚分别为振荡器的反相放大器输入端,振荡器的反相放大输出端,再接上晶振形成一个完整电路,产生震荡。

复位电路

采用上电加按键复位电路,也就是手动复位,上电后,由于电容充电,使RET持续一段高电平时间,当单片机运行时,按下复位键也能使RET持续一段时间的高电平,从而实现上电加开关复位的操作上电加复位电路。

按键控制电路

需要实现秒表的开始/暂停、记录、查看上一条、查看下一条、复位、每秒提醒的开关。用6个按键实现。P1.1控制开始/暂停、P1.2、P1.3控制查看上一条、下一条、P1.4控制记录、P1.5控制复位、P1.6控制每秒提醒。

LCD1602显示电路

所谓的1602是指显示的时候,有两行内容每行有16个字符。

基本操作时许

  1. 读状态:输入:RS=L,RW=H,E=H
                --输出:D0-D7=状态字
  2. 写指令:输入:RS=L,RW=L,D0-D7=指令码
                --输出:无
  3. 读数据:输入:RS=H,RW=H,E=H
                --输入:D0-D7=数据
  4. 写数据:输入:RS=H,RW=L,D0-D7=数据,E=高脉冲
                --输入:无

蜂鸣器电路

蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。由于题目内容有计时时间每秒都得有提醒功能,因此我们还得用蜂鸣器。如图所示:

Proteus仿真图调试结果

 

源代码:

#include<reg52.h>
#include<intrins.h>
//1602定义
sbit RS = P2^0;   //定义端口
sbit RW = P2^1;
sbit EN = P2^2;#define RS_CLR RS=0 //状态量定义,方便读取代码
#define RS_SET RS=1#define RW_CLR RW=0
#define RW_SET RW=1 #define EN_CLR EN=0
#define EN_SET EN=1#define DataPort P0 //1602数据接口
//按键定义
sbit key1=P1^3;            //查看上一天记录
sbit key2=P1^2;            //查看下一条记录
sbit key3=P1^1;            //开始/暂停
sbit key4=P1^4;            //记录
sbit key5=P1^5;            //复位
sbit key6=P1^6;
//蜂鸣器定义
sbit Beep=P1^0;            //1时不响,0时响
//全局变量定义
unsigned int    RecordTableH[11];       //保存分和秒
unsigned char RecordTableL[11];     //保存毫秒
unsigned int    CountTimeH;                 //记录分、秒时间
unsigned char   CountTimeL;                 //记录毫秒时间
unsigned char DataRecordFlag = 0;  //数据记录标志位,表示记录的数据量(记录了多少个数据)
unsigned char DataFlag = 0;                //保存数据标志,用于记录保存数据的个数
unsigned int buzzer=0;
code unsigned char NumTable[]="0123456789";
bit Counting = 0;              //计时标志0暂停/停止,1计时状态
//函数声明
void LCD1602_WriteCom(unsigned char com);           //1602部分
void LCD1602_WriteData(unsigned char Data);
void LCD1602_Clear(void);
void LCD1602_PutString(unsigned char x,unsigned char y,unsigned char *s);
void LCD1602_PutChar(unsigned char x,unsigned char y,unsigned char Data);
void LCD1602_Init(void);
void LCD1602_Delay(unsigned int t);void delay_ms(unsigned int t);
void IniTC0(void) ;                     //初始化定时计数器0
void KeyWork(void);                     //按键扫描以及按键功能动作
void DisplayCountTime(void);    //显示计时的时间void main()
{IniTC0();LCD1602_Init();Beep = 1;LCD1602_PutString(4,0,"Well Come");            LCD1602_PutString(2,1,"  Stopwatch   ");delay_ms(1000);LCD1602_Clear();while(1){DisplayCountTime();KeyWork();}
}
/*------------------------------------------------写入命令函数
------------------------------------------------*/
void LCD1602_WriteCom(unsigned char com)
{LCD1602_Delay(5);RS_CLR; RW_CLR; EN_SET; DataPort= com; _nop_(); EN_CLR;
}
/*------------------------------------------------写入数据函数
------------------------------------------------*/
void LCD1602_WriteData(unsigned char Data)
{ LCD1602_Delay(5);RS_SET; RW_CLR; EN_SET; DataPort= Data; _nop_();EN_CLR;
}
/*------------------------------------------------清屏函数
------------------------------------------------*/
void LCD1602_Clear(void)
{ LCD1602_WriteCom(0x01); LCD1602_Delay(5);
}
/*------------------------------------------------写入字符串函数
------------------------------------------------*/
void LCD1602_PutString(unsigned char x,unsigned char y,unsigned char *s)
{     if (y == 0) {     LCD1602_WriteCom(0x80 + x);     //表示第一行}else {      LCD1602_WriteCom(0xC0 + x);      //表示第二行}        while (*s) {     LCD1602_WriteData( *s);     s ++;     }
}
/*------------------------------------------------写入字符函数
------------------------------------------------*/
void LCD1602_PutChar(unsigned char x,unsigned char y,unsigned char Data)
{     if (y == 0) {     LCD1602_WriteCom(0x80 + x);     }else {     LCD1602_WriteCom(0xC0 + x);     }        LCD1602_WriteData( Data);
}
/*------------------------------------------------初始化函数
------------------------------------------------*/
void LCD1602_Init(void)
{LCD1602_WriteCom(0x38);    /*显示模式设置*/ LCD1602_Delay(5); LCD1602_WriteCom(0x38); LCD1602_Delay(5); LCD1602_WriteCom(0x38); LCD1602_Delay(5); LCD1602_WriteCom(0x38);  LCD1602_WriteCom(0x08);    /*显示关闭*/ LCD1602_WriteCom(0x01);    /*显示清屏*/ LCD1602_WriteCom(0x06);    /*显示光标移动设置*/ LCD1602_Delay(5); LCD1602_WriteCom(0x0C);    /*显示开及光标设置*/LCD1602_Clear();
}
/*------------------------------------------------1602延时函数
------------------------------------------------*/
void LCD1602_Delay(unsigned int t)
{unsigned char c;while(t--){for(c = 50; c > 0; c--);}
}
void delay_ms(unsigned int t)
{unsigned char c;while(t--){for(c = 50; c > 0; c--);}
}
void IniTC0(void)
{TMOD=0x01;        //设置定时计数器的工作模式TR0 = 0;         //关闭定时计数器TF0 = 0;          //清空定时计数器标志位TH0=0xFC;              //定时1ms,当计时时间不准在这修改TL0=0x18;ET0 = 1;           //开启定时计数器0中断EA=1;              //开总中断
}
void KeyWork(void)                  //判断按键按下就动作,提高实时性
{if(key1 == 0)                                    //显示上一条记录,只有在不计时时有效{if(!Counting && DataRecordFlag != 0)//只有不在计时,并且有数据时才能察看(DataRecordFlag表示记录的数据条数){DataFlag++;if(DataFlag >= DataRecordFlag){DataFlag = DataRecordFlag;}if(DataFlag >= 10){      LCD1602_PutString(0,1,"10:             ");//显示条数并且把后面的显示清空}else {LCD1602_PutChar(0, 1, NumTable[DataFlag]);LCD1602_PutString(1,1,":              ");}LCD1602_PutChar(4, 1, NumTable[(RecordTableH[DataFlag]/6000)%6]);      //显示记录的时间LCD1602_PutChar(5, 1, NumTable[(RecordTableH[DataFlag]/600)%10]);LCD1602_PutChar(6, 1, ':');LCD1602_PutChar(7, 1, NumTable[(RecordTableH[DataFlag]/100)%6]);LCD1602_PutChar(8, 1, NumTable[(RecordTableH[DataFlag]/10)%10]);LCD1602_PutChar(9, 1, ':');LCD1602_PutChar(10, 1, NumTable[((RecordTableL[DataFlag]%10)%10)%10]);LCD1602_PutChar(11, 1, NumTable[RecordTableL[DataFlag]/10]);}delay_ms(5);                     //避开抖动防止多次触发,期间继续显示计数时间while(!key1) DisplayCountTime();                 //等待按键释放,避开抖动防止多次触发,期间继续显示计数时间}if(key2 == 0)                                  //显示下一条记录,只有在不计时时有效{if(!Counting && DataRecordFlag != 0)//只有不在计时,并且有数据时才能察看(DataRecordFlag表示记录的数据条数){DataFlag--;if(DataFlag == 0){DataFlag = 1;}LCD1602_PutChar(0, 1, NumTable[DataFlag]);//显示条数并且把后面的显示清空LCD1602_PutString(1,1,":              ");LCD1602_PutChar(4, 1, NumTable[(RecordTableH[DataFlag]/6000)%6]);     //显示记录的时间LCD1602_PutChar(5, 1, NumTable[(RecordTableH[DataFlag]/600)%10]);LCD1602_PutChar(6, 1, ':');LCD1602_PutChar(7, 1, NumTable[(RecordTableH[DataFlag]/100)%6]);LCD1602_PutChar(8, 1, NumTable[(RecordTableH[DataFlag]/10)%10]);LCD1602_PutChar(9, 1, ':');LCD1602_PutChar(10, 1, NumTable[((RecordTableL[DataFlag]%10)%10)%10]);LCD1602_PutChar(11, 1, NumTable[RecordTableL[DataFlag]/10]);}delay_ms(5);                     //避开抖动防止多次触发,期间继续显示计数时间while(!key2) DisplayCountTime();                 //等待按键释放,避开抖动防止多次触发,期间继续显示计数时间}if(key3 == 0)                      //开始/停止计时{Counting = !Counting;        //切换计时状态并进行相应地动作if(Counting){TR0 = 1;          //开启定时器计数,开始计时}else {TR0 = 0;          //关闭定时几计数,停止计时}delay_ms(5);                     //避开抖动防止多次触发,期间继续显示计数时间while(!key3) DisplayCountTime();                 //等待按键释放,避开抖动防止多次触发,期间继续显示计数时间}if(key4 == 0)                                  //记录时间{if(Counting)         //在计时时才有用{DataRecordFlag++;DataFlag = DataRecordFlag;if(DataRecordFlag > 10)      //判断是否为第十条,第十条数据时进行记录,超过第十条时无动作需要复位{DataRecordFlag = 10;DataFlag = 10;}else {if(DataRecordFlag == 10){RecordTableH[DataFlag] = CountTimeH;RecordTableL[DataFlag] = CountTimeL;LCD1602_PutString(0,1,"10:             ");}else {LCD1602_PutChar(0, 1, NumTable[DataRecordFlag]);LCD1602_PutString(1,1,":              ");RecordTableH[DataFlag] = CountTimeH;RecordTableL[DataFlag] = CountTimeL;}}LCD1602_PutChar(4, 1, NumTable[(RecordTableH[DataRecordFlag]/6000)%6]);     //显示记录的时间LCD1602_PutChar(5, 1, NumTable[(RecordTableH[DataRecordFlag]/600)%10]);LCD1602_PutChar(6, 1, ':');LCD1602_PutChar(7, 1, NumTable[(RecordTableH[DataRecordFlag]/100)%6]);LCD1602_PutChar(8, 1, NumTable[(RecordTableH[DataRecordFlag]/10)%10]);LCD1602_PutChar(9, 1, ':');LCD1602_PutChar(10, 1, NumTable[((RecordTableL[DataRecordFlag]%10)%10)%10]);LCD1602_PutChar(11, 1, NumTable[RecordTableL[DataRecordFlag]/10]);}delay_ms(5);                       //避开抖动防止多次触发,期间继续显示计数时间while(!key4) DisplayCountTime();                 //等待按键释放,避开抖动防止多次触发,期间继续显示计数时间}if(key5 == 0){if(!Counting)        //只有不在计时,并且有数据时才能复位(DataRecordFlag表示记录的数据条数){CountTimeH=0;CountTimeL=0;DataFlag=0;DataRecordFlag=0;LCD1602_PutChar(4, 1, NumTable[(RecordTableH[DataRecordFlag]/6000)%6]);     //显示记录的时间LCD1602_PutChar(5, 1, NumTable[(RecordTableH[DataRecordFlag]/600)%10]);LCD1602_PutChar(6, 1, ':');LCD1602_PutChar(7, 1, NumTable[(RecordTableH[DataRecordFlag]/100)%6]);LCD1602_PutChar(8, 1, NumTable[(RecordTableH[DataRecordFlag]/10)%10]);LCD1602_PutChar(9, 1, ':');LCD1602_PutChar(10, 1, NumTable[((RecordTableL[DataRecordFlag]%10)%10)%10]);LCD1602_PutChar(11, 1, NumTable[RecordTableL[DataRecordFlag]/10]);LCD1602_Clear();                //清屏delay_ms(5);                        while(!key5)      //避开抖动防止多次触发,期间继续显示计数时间DisplayCountTime();                    //等待按键释放,避开抖动防止多次触发,期间继续显示计数时间}}}
void DisplayCountTime(void)
{LCD1602_PutChar(4, 0, NumTable[(CountTimeH/6000)%6]);  //显示计时的时间LCD1602_PutChar(5, 0, NumTable[(CountTimeH/600)%10]);LCD1602_PutChar(6, 0, ':');LCD1602_PutChar(7, 0, NumTable[(CountTimeH/100)%6]); //10sLCD1602_PutChar(8, 0, NumTable[(CountTimeH/10)%10]);   //sLCD1602_PutChar(9, 0, ':');LCD1602_PutChar(10, 0, NumTable[((CountTimeH%10)%10)%10]);  //CountTimeH   100ms 0.1s计时  最大3599LCD1602_PutChar(11, 0, NumTable[CountTimeL/10]);         //CountTimeL   1ms计时   最大100ms  /10 10ms  0.01s
}
void timer0() interrupt 1
{TH0=0xFC;                 //定时1msTL0=0x18;if(!(CountTimeL == 99 && CountTimeH == 6000))//判断是否到达计时最大值,到达09:59:99时无动作并且退出计时状态(毫秒的进制为100){CountTimeL++;if(CountTimeL > 99)      //毫秒的计数时间到达100时进1到秒 10000us=10ms=0.01s{CountTimeL = 0;CountTimeH++;        //0.01sbuzzer++;if(buzzer==10)      //蜂鸣器每秒响一次{if(key6==0){Beep=0;delay_ms(100);Beep=1;}buzzer=0;}if(CountTimeH > 6000)     //设定计时最大值{CountTimeH = 6000;Counting = 0;}}}else {Counting = 0;      //计时标志位,为1时才开始计时Beep = 0;               //蜂鸣器响一下delay_ms(5);Beep = 0;}
}

Proteus仿真提取链接

链接:https://pan.baidu.com/s/14fx9nKl5zEEOhQ0Kd2dftAhttps://pan.baidu.com/s/14fx9nKl5zEEOhQ0Kd2dftA
提取码:5fdf

基于51单片机的秒表系统设计(源代码+Proteus仿真图)相关推荐

  1. 基于51单片机电子秒表倒计时器proteus仿真 汇编程序 数码管显示LCD1602显示

    刚刚咱们讲了电子秒表用的是C语言,接下来咱们再讲一讲用汇编. 硬件设计 电路图1: 数码管显示:时间清零:启动计时:暂定计时:继续计时: 电路图2 程序设计 TLOW EQU 78H THIGH EQ ...

  2. 【011】基于51单片机的低频信号发生proteus仿真与实物设计

    ​一.资料内容 (1).基于51单片机的低频信号发生proteus仿真设计一份: (2).基于51单片机的低频信号发生proteus仿真设计keli源代码一份: (3).基于51单片机的低频信号发生A ...

  3. 【004】基于51单片机的音乐播放器proteus仿真设计

    一.压缩包资料内容(私信获取) (1).基于51单片机的音乐播放器proteus仿真设计一份: (2).基于51单片机的音乐播放器proteus仿真设计keli源代码一份: (3).基于51单片机的音 ...

  4. 【006】基于51单片机的简易电子计算器Proteus仿真设计

    一.压缩包资料内容(私信获取) (1).基于51单片机的简易电子计算器proteus仿真设计一份: (2).基于51单片机的简易电子计算器proteus仿真设计keli源代码一份: (3).基于51单 ...

  5. 基于51单片机的LCD1602电子钟闹钟proteus仿真设计

    本设计是基于51单片机的LCD1602电子钟闹钟proteus仿真设计 源码+仿真+原理图+器件清单 仿真软件版本:proteus 7.8 程序编译器:keil 4/keil 5 编程语言:C语言 编 ...

  6. 基于51单片机的简易数字计算器Proteus仿真(源码+仿真+全套资料)

     资料编号:115 全套资料齐全,功能说明: 该计算器系统51 系列的单片机进行的数字计算器系统设计,可以完成计算器的键盘输入, 进行加. 减.乘.除的简单四则运算,并在 LCD屏幕上相应的显示结果. ...

  7. 基于51单片机的八路电压表采集Proteus仿真(源码+仿真+原理图+全套资料)

    资料编号:110 程序语言:C语言 仿真软件:Proteus8.9版本 功能讲解如下: 利用单片机及其外围器件(A/D转换器等)实现一款简易电压表,实现以下功能: 1   电压表能够进行8路模拟电压测 ...

  8. 基于51单片机火灾监测自动灭火装置Proteus仿真

    资料编号:167   下面是相关功能视频演示: 167-基于51单片机火灾监测自动灭火装置Proteus仿真(源码+仿真+全套资料) 功能讲解: 采用51单片机作为控制CPU,采用ADC0832采集火 ...

  9. 基于51单片机的音乐盒播放器proteus仿真

    资料编号:092  下面是相关功能视频演示: 92-基于51单片机的音乐盒播放器proteus仿真(源码+仿真+全套资料) 功能介绍:使用51单片机,采用蜂鸣器进行音乐播放,提供了音乐代码生成器软件, ...

  10. 基于51单片机智能导盲拐杖Proteus仿真

    功能介绍: 采用51单片机作为主控CPU,采用HC-SR04超声波模块测量障碍物距离,LCD1602显示屏显示当前的障碍物距离,并且可以设置报警的阈值,通过传感器测量障碍物的距离的远近来进行相关报警, ...

最新文章

  1. 新手求助:大神们帮帮我,关于在ViewPage中添加GridView的问题
  2. python电脑配置要求-1.安装python3.5及电脑环境变量的配置
  3. 编程入门python语言是多大孩子学的-Python 适合初学编程的人学吗?
  4. php怎么查询mysql_php如何查询数据库
  5. phpcms文件结构
  6. Android启动initlogo.rle制作
  7. git使用.ignore忽略工程中的文件变动
  8. Minecraft Forge:如何下载,安装和使用Forge
  9. python 微服务架构实战_《分布式服务架构:原理、设计与实战》第一章分布式微服务架构设计原理...
  10. Java ArrayList到数组
  11. 17082 两个有序数序列中找第k小(优先做)
  12. STM8S103之外部中断
  13. 手机二维码应用潜力无限
  14. iOS之获取手机DeviceToken,以及苹果测试推送工具Easy APNs Provider
  15. 房地产业务学习(04)-房企信息化:谁忽悠了谁?
  16. C#开发自动照片(图片)裁剪(缩放)工具
  17. 一个简单的自定义alert方法
  18. 使用OpenCV+Tensorflow跟踪排球的轨迹
  19. Practical Full Resolution Learned Lossless Image Compression
  20. H264/H265码流类型

热门文章

  1. 用python获取指定路径下的所有目录路径和文件路径
  2. Pytorch实现mnist手写数字识别
  3. 同桌的你1080pHD国语中字_马立杰_新浪博客
  4. 历届上海国际电影节获奖名单
  5. Java各数据库的JDBC驱动包下载地址
  6. 【CTF题解NO.00008】mini-LCTF 2021 official write up by arttnba3
  7. HackTheBox | Horizontall
  8. 地理遥感专业属于计算机行业吗,遥感科学与技术专业怎么样?
  9. codereview(codereview什么意思)
  10. RHEL 7.0下载