一、设计题目:数字秒表设计

二、课程设计内容及要求

基本要求:

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之内相关推荐

  1. 基于单片机的数字秒表

    设计简介: 本设计是基于单片机的数字秒表的设计,主要实现以下功能: 可实现LCD12864显示时间以及倒计时.顺计时等信息: 可实现通过按键调节调节时间的大小以及实现计时功能: 可实现通过通过语音播报 ...

  2. 单片机经典外围电路(一)--LCD1602显示

    单片机经典外围电路(一)----LCD1602显示(1) 学无止境,生活就像一首歌,时代是歌的旋律,个人就是时代的音符,前路漫漫,因为坚持看到希望. 一.序言 随着现代数字电路的发展,显示技术也在逐渐 ...

  3. 51单片机+L298驱动步进电机+L297测速+LCD1602显示+按键调试+Proteus仿真

    51单片机+L298驱动步进电机+L297测速+LCD1602显示+按键调试+Proteus仿真 *Proteus仿真 L298N是双H桥式驱动器. L297是步进电机控制集成芯片(包括环形分配器), ...

  4. 基于51单片机的自动浇花浇水系统LCD1602显示仿真

    硬件设计 基本框架 该电路的工作原理是由STC89C52单片机和ADC0832组成系统的核心部分,湿度传感器将采集到的数据直接传送到ADC0832的IN端作为输入的模拟信号.选用湿度传感器和AD转换, ...

  5. 单片机设计时钟程序c语言,基于.C51单片机的数字时钟课程设计(C语言,带闹钟).pdf...

    - - .. -- 单片机技术课程设计 数字电子钟 学院 : word 可编辑 . - - .. -- 班级 : 姓名 : 学号 : 教师 : 摘 要 电子钟在生活中应用非常广泛 ,而一种简单方便的数 ...

  6. 计算机原理实验中断计数器加一,数字秒表系统的设计.doc

    精品 基于单片机的数字秒表系统设计 1.引言 在科技高度发展的今天,集成电路和计算机应用得到了高速发展.尤其是计算机应用的发展,它在人们日常生活中已经崭露头角.大多数电子产品多是由计算机电路组成,如: ...

  7. 单片机 LCD1602显示实验

    电路图如下: 1.请描述液晶显示器的显示原理,及其与数码管相比的技术特点. 显示原理: 液晶显示器是利用偏光板这个特性来完成的,利用上下两片栏栅之间相互垂直的偏光板之间充满了液晶, 再利用电场控制液晶 ...

  8. c语言单片机计时程序,C51单片机秒表计时(C语言)

    <C51单片机秒表计时(C语言)>由会员分享,可在线阅读,更多相关<C51单片机秒表计时(C语言)(4页珍藏版)>请在人人文库网上搜索. 1.南开大学滨海学院C51嵌入式软件设 ...

  9. 51单片机c语言秒表,C51单片机秒表计时(C语言).doc

    C51单片机秒表计时(C语言).doc 南开大学滨海学院C51嵌入式软件设计(C语言) 题目计时秒表 l 功能描述本设计实现在99秒内的秒表计时,一个按键实现开始.暂停.复位.l 原理概述P1接四位七 ...

最新文章

  1. 牛X,一系列Chrome 灵魂插件!爱了爱了!
  2. Tungsten Fabric SDN — 软件架构
  3. JavaScript学习笔记之 数组方法一 堆栈 和队列
  4. Scala算术运算符的一览图
  5. leetcode 95. Unique Binary Search Trees II | 96. Unique Binary Search Trees
  6. npm 安装依赖遇到的问题
  7. POJ 3608 旋转卡壳
  8. Google地球查看香港地形
  9. Selenium Grid
  10. 客户服务与工单管理系统—工单管理
  11. matlab pn码捕获,直扩系统PN码捕获和跟踪的FPGA实现
  12. 干货:react新手入门之react小书
  13. Windows照片查看器无法显示此图片
  14. 数学分析高等代数考研试题不断更新
  15. Htmlcssjs 图片轮播,加箭头
  16. 如何打印复印试卷,试卷打印复印去哪里方便
  17. 6个月融资超50亿元,云计算创业团队正做得风生水起?
  18. 1亿数据 redis 内存_Redis10亿数据量只需要100MB内存,为什么这么牛?
  19. 如何和测试团队做复盘?
  20. 目标跟踪--CamShift

热门文章

  1. 【电脑故障】PIN无效,显示无用户配置文件
  2. error 系统错误 错误码10007_使用 Go 定义错误码
  3. 腾讯云2022web前端开发校招一面后续
  4. CentOs7 安装Docker 并配置代理访问外网
  5. 四大领先优势加持,华为云会议服务更省心可靠!
  6. 精美教学教育道德讲座PPT模板
  7. HCIA-数通学习总结1
  8. breakdancer安装过程中报错信息解决方法——SV结构变异
  9. 诺基亚微软软件测试,【诺基亚6710N评测】软件测试1-中关村在线
  10. 技术猿、攻城狮日常必知