C51单片机实现数字秒表计时(分段计时,LCD1602显示,总计时),误差精度在1s之内
一、设计题目:数字秒表设计
二、课程设计内容及要求
基本要求:
1.按键2个,一个用于计时开始/停止,一个用于数字清零
2.数码管显示,数码管初始显示00-00-00(分-秒-毫秒)
3.基本功能,按计时开始/停止键,数码管从当前计时数字累加,精度为10ms,计时10分钟误差补超过2秒,再按计时开始/停止键,数码管停止计时,按数字清零键,数码管恢复初始显示,重 新计时
扩展功能:
1.显示更换为1602液晶屏显示
2.实现分段计时和总计时两个模式
此次设计实现了基本功能和拓展功能。
三、明确用户需求,根据设计需求绘制原理图(K4键可删掉):
原理图
四、代码解析
第一步:根据原理图定义引脚信息,及相关控制位、标志位、以及需要用到的延时函数
//定义引脚
sbit LCD_RS = P1^0;
sbit LCD_RW = P1^1;
sbit LCD_E = P2^5;sbit K1 = P3^6; //定时开始、暂停键
sbit K2 = P3^7; //定时清零键
sbit K3 = P3^4; //显示分段计时键
uint keyCount = 0; //按键次数标志
uint flag1 = 0; //计时时的时间是否显示
uint time[] = {0x00,0x00,0x00,0x00,0x00,0x00}; //用来存放计时所产生的时间
uint temp[] = {0x00,0x00,0x00,0x00,0x00,0x00}; //用于计算、并time数组时间的时、分、秒
uchar msg[] = {" round"}; //提示界面
uchar wname[] = {"welcome"}; //友好界面uchar all_time[4][6]; //存放分段计时所产生的时间uint flag = -1; //作为向all_time数组保存时间的数组下标
//延时函数delay_nops()
void delay_nops(){_nop_();_nop_();_nop_();_nop_();
}
//延时函数Delay(uint num)
void Delay(uint num)
{while( --num );
}
//延时函数delay1(int ms)
void delay1(int ms)
{unsigned char n;while(ms--){for(n = 0; n<250; n++){_nop_();_nop_();_nop_();_nop_();}}
}
第二步:LCD1602显示部分
//在对LCD1602进行写操作(包括写命令和写数据)的时候(读操作不需要),需要检查“忙”标志位,不“忙”即可写入
int LCD_BUSY(){bit isBusy;LCD_RS = 0; //设置RS为命令寄存器LCD_RW = 1; //设置RW为读操作,读busy位LCD_E = 1; //设置E(使能端)为1,进行读操作delay_nops(); //延时isBusy = (bit)(P0&0X80); //根据原理图引脚信息及LCD1602文档,busy位对应P1^7口,从P1^7读出端口的状态LCD_E = 0; //恢复使能标志return isBusy; //返回busy位状态信息
}
//LCD1602 写命令操作
void LCD_WCMD(uchar cmd){while(LCD_BUSY()); //对LCD1602进行写操作前,要检查“忙”标志位,不“忙”即可继续写操作LCD_RS = 0; //设置RS为命令寄存器LCD_RW = 0; //设置RW为写操作LCD_E = 0; //设置使能E为低电平,后续给予高电平,即形成一个正脉冲,完成写操作_nop_(); //延时一个空操作时间,保证引脚初始状态正确赋值_nop_(); //延时一个空操作时间,保证引脚初始状态正确赋值P0 = cmd; //向P0口写入命令,16进制delay_nops(); //延时若干个空操作LCD_E = 1; //给予E高电平,形成正脉冲,完成写操作delay_nops(); //延时若干个空操作,保证命令正确写入 LCD_E = 0; //恢复使能E为低电平Delay(10); //延时
}
//LCD1602 写数据操作,与LCD1602写命令操作类似,但又有不同之处,不同之处在下面代码中标出
void LCD_WDATA(uchar dat){while(LCD_BUSY()); LCD_RS = 1; //将RS设置为数据寄存器LCD_RW = 0;LCD_E = 0;P0 = dat; //向P0口写入数据delay_nops();LCD_E = 1;delay_nops();LCD_E = 0;Delay(5);
}
//设置LCD1602 的显示位置,以标准 0x80+RAM 地址方式写入命令,具体LCD1602RAM地址映射图如下
void LCD_POS(uchar pos){LCD_WCMD(pos | 0x80); //根据下面RAM地址映射图,举例,例如:LCD_WCMD(0x00 | 0x80);即显示在LCD1602的第一行,从第一个单元开始显示、LCD_WCMD(0x40 | 0x80);即显示在LCD1602的第二行,从第一个单元开始显示
}
LCD1602 RAM地址映射图:
//配置完LCD1602引脚和端口信息,以及LCD1602相关函数后,根据LCD1602使用手册进行LCD1602的初始化
void LCD_INIT(){LCD_RW = 0; //设置LCD1602中RS为命令寄存器delay1(15); //延时LCD_WCMD(0x01); //写入命令,清屏,清除LCD的显示内容LCD_WCMD(0x38); //16*2显示,5*7点阵,8位数据delay1(5); //延时,保证正确写入,下方延时函数功能皆是如此LCD_WCMD(0x38); //重复写入,保证正确写入delay1(5);LCD_WCMD(0x38); delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x0c); //开显示,不显示光标 delay1(5);LCD_WCMD(0x01); //清除LCD的显示内容delay1(5);
}
//LCD1602 显示部分
void display(){uchar i;for(i = 0;i<6;i++){temp[i] = time[i] + 0x30; //这里是把time数组(定时器T0计时产生的时间),进行赋值给temp数组,便于后期进行时、分、秒拆分显示}LCD_POS(0x45); //设置LCD1602上显示为第二行第6个单元开始,具体请看上面提到的RAM地址映射图LCD_WDATA(temp[5]); //显示定时器T0产生的 分(十位)LCD_WDATA(temp[4]); //显示定时器T0产生的 分(个位)LCD_WDATA(0x3a); //显示“:”LCD_WDATA(temp[3]); //显示定时器T0产生的 秒(十位)LCD_WDATA(temp[2]); //显示定时器T0产生的 秒(个位)LCD_WDATA(0x3a); //显示“:”LCD_WDATA(temp[1]); //显示定时器T0产生的 0.1sLCD_WDATA(temp[0]); //显示定时器T0产生的 0.01s}
第三步:主函数部分
int main(){uchar i;TMOD = 0X01; //选择T0工作方式1TH0 = 0XDC; //10ms触发一次中断TL0 = 0X00; //10ms触发一次中断EA = 1; //开启中断总开关ET0 = 1; //开启定时中断T0LCD_INIT(); //LCD1602初始化LCD_POS(0X00); //设置LCD1602 显示位置为第一行第一个单元for(i = 0;i<7;i++){LCD_WDATA(wname[i]); //友好界面}delay1(100);while(1){if(K1 == 0){ //判断按键K1是否按下,按下则进行计时,或者暂停(根据keyCount判断)keyCount++; delay1(100);switch(keyCount){case 1:TR0 = 1; //打开定时器T0,开始LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X31); //显示这是第几轮计时break;case 2:TR0 = 0; //关闭定时器T0,暂停flag++;saveTime(); //在暂停的时候进行时间保存,即达到分段计时的效果break;case 3:TR0 = 1; //打开定时器T0,开始LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X32);break;case 4:TR0 = 0; //关闭定时器T0,暂停flag++; saveTime();break;case 5:TR0 = 1; //打开定时器T0,开始LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X33);break;case 6:TR0 = 0; //关闭定时器T0,暂停flag++;saveTime();break;case 7:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X34);break;case 8:TR0 = 0;flag++;saveTime();break;default:TR0 = 0;flag = -1; break;}delay1(10);}if(K2==0){ //定时时间清零键TR0=0;keyCount = 0;flag=3;delay1(10);flag=3;delay1(10);flag=3;delay1(10);for(i=0;i<6;i++){ //对在中断处理函数中保存在time中的时间进行清零time[i] = 0;}}if(K3==0){ //显示分段计时,所存储的时间段TR0 = 0;flag1 = 1;display1(flag); //显示分段时间段flag1 = 0; //显示完自动隐式退出delay1(10); } if(flag1==0){ // 当flag1==0,即自动退出“显示分段计时”后,显示计时页面display(); //显示计时页面} }
}
定时中断处理函数:
//定时器T0的中断处理函数,time数组用来保存定时器T0计时所产生的时间void timer0() interrupt 1{TH0 = 0XDC; //重新装入初值TL0 = 0X00;time[0]++; //保存0.01sif(time[0]==10){ time[1]++; //保存0.1stime[0] = 0;}if(time[1]==10){ time[2]++; //保存1stime[1] = 0;}if(time[2]==10){ time[3]++; //保存10stime[2] = 0;}if(time[3]==6){ time[4]++; //保存1mintime[3] = 0;}if(time[4]==10){ time[5]++; //保存10mintime[4] = 0;}if(time[5]==6){time[5] = 0;}
}
LCD1602 显示时间函数(循环显示):
//LCD1602 显示函数 时分秒函数
void display1(uint m){uchar i;uint t = 0x31;for(i = 0;i<=m;i++){LCD_WCMD(0X01);LCD_POS(0X00);LCD_WDATA(0X3C);LCD_WDATA(t++);LCD_WDATA(0X3E);LCD_POS(0x45);LCD_WDATA(all_time[i][5] + 0x30);LCD_WDATA(all_time[i][4] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][3] + 0x30);LCD_WDATA(all_time[i][2] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][1] + 0x30);LCD_WDATA(all_time[i][0] + 0x30);delay1(500);}}
在main函数中调用的保存分段时间函数:
//保存时间段
void saveTime(){uchar j = 0;if(flag != -1){for(j = 0;j<6;j++){all_time[flag][j] = time[j]; //保存每次暂停所产生的时间段,即分段计时功能}}
}
在main函数中调用的显示分段时间的函数:
//显示分段计时存储的时间信息,类似前面的display()函数
void display1(uint m){uchar i;uint t = 0x31;for(i = 0;i<=m;i++){LCD_WCMD(0X01); LCD_POS(0X00);LCD_WDATA(0X3C);LCD_WDATA(t++);LCD_WDATA(0X3E);LCD_POS(0x45);LCD_WDATA(all_time[i][5] + 0x30); //这里加上0x30是根据单片机系统自带字符库编码方式LCD_WDATA(all_time[i][4] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][3] + 0x30);LCD_WDATA(all_time[i][2] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][1] + 0x30);LCD_WDATA(all_time[i][0] + 0x30);delay1(500);}}
第四步:实物连接
完整代码:
#include<reg51.h>
#include<intrins.h>#define uchar unsigned char
#define uint unsigned intsbit LCD_RS = P1^0;
sbit LCD_RW = P1^1;
sbit LCD_E = P2^5;sbit K1 = P3^6;
sbit K2 = P3^7;
sbit K3 = P3^4;
uint keyCount = 0;
uint flag1 = 0;
uint time[] = {0x00,0x00,0x00,0x00,0x00,0x00};
uint temp[] = {0x00,0x00,0x00,0x00,0x00,0x00};
uchar msg[] = {" "};
uchar wname[] = {"welcome"};uchar all_time[4][6];uint flag = -1;
void delay_nops(){_nop_();_nop_();_nop_();_nop_();
}
void Delay(uint num)
{while( --num );
}
void delay1(int ms)
{unsigned char n;while(ms--){for(n = 0; n<250; n++){_nop_();_nop_();_nop_();_nop_();}}
}
int LCD_BUSY(){bit isBusy;LCD_RS = 0;LCD_RW = 1;LCD_E = 1;delay_nops();isBusy = (bit)(P0&0X80);LCD_E = 0;return isBusy;
}
void LCD_WCMD(uchar cmd){while(LCD_BUSY());LCD_RS = 0;LCD_RW = 0;LCD_E = 0;_nop_();_nop_();P0 = cmd;delay_nops();LCD_E = 1;delay_nops();LCD_E = 0;Delay(10);
}
void LCD_WDATA(uchar dat){while(LCD_BUSY());LCD_RS = 1;LCD_RW = 0;LCD_E = 0;P0 = dat;delay_nops();LCD_E = 1;delay_nops();LCD_E = 0;Delay(5);
}void LCD_INIT(){LCD_RW = 0;delay1(15); LCD_WCMD(0x01);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x0c);delay1(5);LCD_WCMD(0x01);delay1(5);
}
void LCD_POS(uchar pos){LCD_WCMD(pos | 0x80);
}
void display(){uchar i;for(i = 0;i<6;i++){temp[i] = time[i] + 0x30;}LCD_POS(0x45);LCD_WDATA(temp[5]);LCD_WDATA(temp[4]);LCD_WDATA(0x3a);LCD_WDATA(temp[3]);LCD_WDATA(temp[2]);LCD_WDATA(0x3a);LCD_WDATA(temp[1]);LCD_WDATA(temp[0]);}
void saveTime(){uchar j = 0;if(flag != -1){for(j = 0;j<6;j++){all_time[flag][j] = time[j];}}
}
void display1(uint m){uchar i;uint t = 0x31;for(i = 0;i<=m;i++){LCD_WCMD(0X01);LCD_POS(0X00);LCD_WDATA(0X3C);LCD_WDATA(t++);LCD_WDATA(0X3E);LCD_POS(0x45);LCD_WDATA(all_time[i][5] + 0x30);LCD_WDATA(all_time[i][4] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][3] + 0x30);LCD_WDATA(all_time[i][2] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][1] + 0x30);LCD_WDATA(all_time[i][0] + 0x30);delay1(500);}}
int main(){uchar i;TMOD = 0X01;TH0 = 0XDC;TL0 = 0X00;EA = 1;ET0 = 1;LCD_INIT();LCD_POS(0X00);P3 = 0XC0 | P3;LCD_POS(0X00);for(i = 0;i<7;i++){LCD_WDATA(wname[i]);}delay1(100);while(1){if(K1 == 0){keyCount++;delay1(100);switch(keyCount){case 1:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X31);break;case 2:TR0 = 0;flag++;saveTime();break;case 3:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X32);break;case 4:TR0 = 0;flag++; saveTime();break;case 5:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X33);break;case 6:TR0 = 0;flag++;saveTime();break;case 7:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X34);break;case 8:TR0 = 0;flag++;saveTime();break;default:TR0 = 0;flag = -1;break;}delay1(10);}if(K2==0){TR0=0;keyCount = 0;flag=3;delay1(10);flag=3;delay1(10);flag=3;delay1(10);for(i=0;i<6;i++){time[i] = 0;}}if(K3==0){TR0 = 0;flag1 = 1;display1(flag);flag1 = 0;delay1(10); } if(flag1==0){display();} }
}
void timer0() interrupt 1{TH0 = 0XDC;TL0 = 0X00;time[0]++; //0.01sif(time[0]==10){ time[1]++; //0.1stime[0] = 0;}if(time[1]==10){ time[2]++; //1stime[1] = 0;}if(time[2]==10){ time[3]++; //10stime[2] = 0;}if(time[3]==6){ time[4]++; //1mintime[3] = 0;}if(time[4]==10){ time[5]++; //10mintime[4] = 0;}if(time[5]==6){time[5] = 0;}
}
C51单片机实现数字秒表计时(分段计时,LCD1602显示,总计时),误差精度在1s之内相关推荐
- 基于单片机的数字秒表
设计简介: 本设计是基于单片机的数字秒表的设计,主要实现以下功能: 可实现LCD12864显示时间以及倒计时.顺计时等信息: 可实现通过按键调节调节时间的大小以及实现计时功能: 可实现通过通过语音播报 ...
- 单片机经典外围电路(一)--LCD1602显示
单片机经典外围电路(一)----LCD1602显示(1) 学无止境,生活就像一首歌,时代是歌的旋律,个人就是时代的音符,前路漫漫,因为坚持看到希望. 一.序言 随着现代数字电路的发展,显示技术也在逐渐 ...
- 51单片机+L298驱动步进电机+L297测速+LCD1602显示+按键调试+Proteus仿真
51单片机+L298驱动步进电机+L297测速+LCD1602显示+按键调试+Proteus仿真 *Proteus仿真 L298N是双H桥式驱动器. L297是步进电机控制集成芯片(包括环形分配器), ...
- 基于51单片机的自动浇花浇水系统LCD1602显示仿真
硬件设计 基本框架 该电路的工作原理是由STC89C52单片机和ADC0832组成系统的核心部分,湿度传感器将采集到的数据直接传送到ADC0832的IN端作为输入的模拟信号.选用湿度传感器和AD转换, ...
- 单片机设计时钟程序c语言,基于.C51单片机的数字时钟课程设计(C语言,带闹钟).pdf...
- - .. -- 单片机技术课程设计 数字电子钟 学院 : word 可编辑 . - - .. -- 班级 : 姓名 : 学号 : 教师 : 摘 要 电子钟在生活中应用非常广泛 ,而一种简单方便的数 ...
- 计算机原理实验中断计数器加一,数字秒表系统的设计.doc
精品 基于单片机的数字秒表系统设计 1.引言 在科技高度发展的今天,集成电路和计算机应用得到了高速发展.尤其是计算机应用的发展,它在人们日常生活中已经崭露头角.大多数电子产品多是由计算机电路组成,如: ...
- 单片机 LCD1602显示实验
电路图如下: 1.请描述液晶显示器的显示原理,及其与数码管相比的技术特点. 显示原理: 液晶显示器是利用偏光板这个特性来完成的,利用上下两片栏栅之间相互垂直的偏光板之间充满了液晶, 再利用电场控制液晶 ...
- c语言单片机计时程序,C51单片机秒表计时(C语言)
<C51单片机秒表计时(C语言)>由会员分享,可在线阅读,更多相关<C51单片机秒表计时(C语言)(4页珍藏版)>请在人人文库网上搜索. 1.南开大学滨海学院C51嵌入式软件设 ...
- 51单片机c语言秒表,C51单片机秒表计时(C语言).doc
C51单片机秒表计时(C语言).doc 南开大学滨海学院C51嵌入式软件设计(C语言) 题目计时秒表 l 功能描述本设计实现在99秒内的秒表计时,一个按键实现开始.暂停.复位.l 原理概述P1接四位七 ...
最新文章
- 牛X,一系列Chrome 灵魂插件!爱了爱了!
- Tungsten Fabric SDN — 软件架构
- JavaScript学习笔记之 数组方法一 堆栈 和队列
- Scala算术运算符的一览图
- leetcode 95. Unique Binary Search Trees II | 96. Unique Binary Search Trees
- npm 安装依赖遇到的问题
- POJ 3608 旋转卡壳
- Google地球查看香港地形
- Selenium Grid
- 客户服务与工单管理系统—工单管理
- matlab pn码捕获,直扩系统PN码捕获和跟踪的FPGA实现
- 干货:react新手入门之react小书
- Windows照片查看器无法显示此图片
- 数学分析高等代数考研试题不断更新
- Htmlcssjs 图片轮播,加箭头
- 如何打印复印试卷,试卷打印复印去哪里方便
- 6个月融资超50亿元,云计算创业团队正做得风生水起?
- 1亿数据 redis 内存_Redis10亿数据量只需要100MB内存,为什么这么牛?
- 如何和测试团队做复盘?
- 目标跟踪--CamShift