单片机 秒表和抢答器.docx
- 文档编号:10925396
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:18
- 大小:127.77KB
单片机 秒表和抢答器.docx
《单片机 秒表和抢答器.docx》由会员分享,可在线阅读,更多相关《单片机 秒表和抢答器.docx(18页珍藏版)》请在冰豆网上搜索。
单片机秒表和抢答器
秒表(电子表)
一、内容
设计一个秒表,使之有清零功能。
本程序进行了拓展,设计为时钟,有清零功能,有设置时间功能。
图11电路原理图
二、方案
1、设计思想
主函数设置定时器T0、T1为方式1定时,打开总中断,允许定时器T0、T1、外部中断0中断,T0用读秒,T1用来刷新数码管,外部中断0用来控制四个按键。
四个按键接到外部中断,进行时钟的调整:
K1:
进入/退出时钟设置。
K2:
选择设置秒/分/时。
K3:
调整按键,秒:
清零(当前秒数大于30分进一,小于30仅清零秒);时/分:
进一,分超过60时清零,时超过24时清零。
(与传统电子表设置时间方式一样)。
K4:
时钟清零。
对于显示单个数码管:
先OE=1关闭锁存器输出,LE1=1开启段码锁存器输入,接收来自P0口输出的段码数据,LE1=0关闭段码锁存器输入,LE2=1开启位选码锁存器输入,接收来自P0口输出的位选码数据,LE2=0关闭位选码锁存器输入,OE=0开启锁存器输出。
即可实现指定单个数码管的显示,利用位选中断次数计数变量int_mark实现对8个数码管的显示。
定时器T0中断实现读秒及时分秒进位运算。
浮点型变量second记录秒数,int_time记录定时器T0中断次数,一次为50ms,10次即0.5秒清零int_time并使second+0.5(为了实现闪烁的功能)。
时钟设置:
定义全局变量setMark作为时钟设置标志,(0:
未进入时钟设置;1:
设置秒;2:
设置分;3设置时),利用外部中断判断及设置该变量及时分秒变量实现时钟设置功能。
详细程序设计请看源程序注释。
2、电路原理图
如图1-1。
三、源程序
#include"reg51.h"
#defineucharunsignedchar
#defineuintunsignedint
#defineTH(a)(65536-a)/256//定义装入定时器高8位的时间常数
#defineTL(a)(65536-a)%256//定义装入定时器低8位的时间常数
#defineoutP0
sbitOE=P1^3;
sbitLE1=P1^4;
sbitLE2=P1^5;
sbitK1=P2^0;
sbitK2=P2^1;
sbitK3=P2^2;
sbitK4=P2^3;
ucharnumCode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};//共阴极数码段码
ucharmark[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//共阴极位选码
//ucharnumCode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0Xf8,0x80,0x90,0xff,0xbf};//共阳极数码段码
//ucharmark[]={0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//共阳极位选码
uinthour;//记录小时
uintminute;//记录分钟
floatsecond;//记录秒数
ucharint_time;//定义时间中断次数计数变量
ucharint_mark;//定义位选中断次数计数变量
ucharisP2=1;//是否显示第二个数码管
ucharsetMark=0;//定义设置标志(0:
未进入时钟设置;1:
设置秒;2:
设置分;3设置时)
voidmain(){
TMOD=0x11;//设置定时器T0、T1为方式1定时
IE=0x8b;//总中断开,允许定时器T0、T1、外部中断0中断
IT0=1;//选择外部中断0为跳沿触发方式
TH0=TH(50000);//给定时器T0高8位赋值
TL0=TL(50000);//给定时器T0低8位赋值
TH1=TH(500);//给定时器T1高8位赋值
TL1=TL(500);//给定时器T1低8位赋值
int_mark=0;//位选中断次数清零
int_time=0;//时间中断次数清零
hour=20;//小时初始化
minute=25;//分钟初始化
second=20;//秒数初始化
TR0=1;//启动定时器T0
TR1=1;//启动定时器T1
while
(1){
}
}
//定时器T0中断,读秒
voidtime()interrupt1{
int_time++;
if(int_time==10){//定时器计数读秒
second=second+0.5;//秒数加0.5
int_time=0;//时间中断次数清零
}
if(second==60){//秒数溢出,分进一,秒清零
minute++;
second=0;
}
if(minute==60){//分溢出,时进一,分清零
hour++;
minute=0;
}
if(hour==24){//时溢出,时分秒全部清零
hour=0;
minute=0;
second=0;
}
TH0=TH(50000);//给定时器T0高8位赋值
TL0=TL(50000);//给定时器T0低8位赋值
}
//定时器T1中断,刷新数码管
voidrefresh()interrupt3{
P2=mark[0];
if(int_mark==9){//位选计数溢出清零
int_mark=1;
}
//显示时
if(int_mark==1||int_mark==2){//1、2数码管显示时
OE=1;
LE1=1;
if(setMark==3){//判断是否为设置时
if((int)second-second==0){//判断秒数是否含有0.5
out=numCode[int_mark==1?
hour/10:
hour%10];
}else{//秒数有0.5不显示数码管(起到闪烁效果)
out=numCode[10];
}
}else{//显示时的高低位
out=numCode[int_mark==1?
hour/10:
hour%10];
}
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
}
//显示横杠(横杠段码放在numCode数组下标11中)
if(int_mark==3){
OE=1;
LE1=1;
out=numCode[11];
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
}
//显示分
if(int_mark==4||int_mark==5){//4、5数码管显示分
OE=1;
LE1=1;
if(setMark==2){//判断是否为设置分
if((int)second-second==0){//判断秒数是否含有0.5
out=numCode[int_mark==4?
minute/10:
minute%10];
}else{//秒数有0.5不显示数码管(起到闪烁效果)
out=numCode[10];
}
}else{//显示分的高低位
out=numCode[int_mark==4?
minute/10:
minute%10];
}
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
}
//显示横杠
if(int_mark==6){
OE=1;
LE1=1;
out=numCode[11];
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
}
//显示秒
if(int_mark==7||int_mark==8){//7、8数码管显示秒
OE=1;
LE1=1;
if(setMark==1){//判断是否为设置秒
if((int)second-second==0){//判断秒数是否含有0.5
if(int_mark==7){//显示秒高位
floats=second;
//1.先将十位上的数字挪到个位(乘以0.1即可)
s=second*0.1;
//2.让该数与10取余(需要先把f强制转换为int型)
out=numCode[(int)s%10];
}else{//显示秒低位
floats=second;
s=second;
out=numCode[(int)s%10];
}
}else{//秒数有0.5不显示数码管(起到闪烁效果)
out=numCode[10];
}
}else{
if(int_mark==7){//显示秒高位
floats=second;
//1.先将十位上的数字挪到个位(乘以0.1即可)
s=second*0.1;
//2.让该数与10取余(需要先把f强制转换为int型)
out=numCode[(int)s%10];
}else{//显示秒低位
floats=second;
s=second;
out=numCode[(int)s%10];
}
}
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
}
int_mark++;
TH1=TH(500);//给定时器T1高8位赋值
TL1=TL(500);//给定时器T1低8位赋值
}
//外部中断0,按键控制
voidkeyControl()interrupt0{
if(INT0==0)
{
//K1键按下,开始或结束设置时间
if(K1==0){
setMark=setMark==0?
1:
0;
}
//K2键按下,调整设置单元
if(K2==0){
if(setMark!
=0){//判断当前是否为时钟设置状态
setMark++;//设置位进一,进入下一个设置方式
if(setMark==4){//设置位溢出,调整为1设置秒
setMark=1;
}
}
}
//K3键按下,秒清零,分时加一
if(K3==0){
if(setMark==1){//调整秒:
判断当前秒是否大于30,大于30设置second为60在定时器T0中完成进位运算,小于30则直接清零秒
second=second>30?
60:
0;
}
if(setMark==2){//调整分
if(minute==59){//当前分为59,直接清零
minute=0;
}else{//当前分不为59,进一
minute++;
}
}
if(setMark==3){//调整时
if(hour==23){//当前时为23,直接清零
hour=0;
}else{//当前时不为23,进一
hour++;
}
}
}
//K4键按下,清零
if(K4==0){
hour=0;minute=0;second=0;
}
}
}
抢答器
一、内容
设计一个拥有16个按键的抢答器,裁判拥有开始/停止抢答及复位的功能。
当首个抢答成功后其他按键将无效。
图21电路原理图
二、方案
1、设计思想
主函数设置定时器T0为方式1定时,打开总中断,允许定时器T0、外部中断0中断。
定时器T0用来刷新数码管,外部中断0用来控制按键。
定义全局变量记录共阴极数码段码数组、位选中段次数计数(用于记录当次定时器中断显示哪个数码管)、抢答按键标志(记录矩阵式键盘按下了哪个键)、抢答状态标志。
矩阵式键盘:
P2口低四位连接矩阵键盘的四行,高四位连接矩阵键盘的四列,先使P2=0xef(第一列置0),扫描四行,判断行值是否也为0,为0说明第一列中的某一行的按键按下,设置按键标志;若都不为0,P2左移一位,即P2=0xdf(第二列置0),继续扫描四行判断键盘是否有按下;P2左移,行扫描……,四列扫描完毕,P2置为0xef重新从第一列进行键盘扫描。
对于显示单个数码管:
先OE=1关闭锁存器输出,LE1=1开启段码锁存器输入,接收来自P0口输出的段码数据,LE1=0关闭段码锁存器输入,LE2=1开启位选码锁存器输入,接收来自P0口输出的位选码数据,LE2=0关闭位选码锁存器输入,OE=0开启锁存器输出。
即可实现指定单个数码管的显示,利用位选中断次数计数变量int_mark实现对8个数码管的显示。
抢答按键设计:
isStart用来记录抢答状态,为0表示未进入抢答状态,为1进入抢答状态,矩阵式键盘生效,外部中断中K1控制isStart值。
key_mark用来记录键盘按键标志,0~15对应键盘16个按键,为16表示未按键标志,因此矩阵键盘扫描之前加入条件if(isStart==1&&key_mark==16)通过才可进行矩阵式键盘扫描,条件:
抢答标志为1且矩阵键盘未按下,一旦矩阵键盘有键按下,key_mark便不再为16,即实现无法继续抢答。
外部中断K2键按下即置key_mark为16实现抢答复位。
2、电路原理图
如图2-1。
三、源程序
#include"reg51.h"
#defineucharunsignedchar
#defineuintunsignedint
#defineTH(a)(65536-a)/256//定义装入定时器高8位的时间常数
#defineTL(a)(65536-a)%256//定义装入定时器低8位的时间常数
#defineoutP0
#defineNP2
sbitOE=P1^3;
sbitLE1=P1^4;
sbitLE2=P1^5;
sbitK1=P3^4;
sbitK2=P3^5;
sbitK3=P3^6;
sbitK4=P3^7;
sbitL1=P2^0;
sbitL2=P2^1;
sbitL3=P2^2;
sbitL4=P2^3;
ucharnumCode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};//共阴极数码段码
ucharmark[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//共阴极位选码
ucharint_mark;//定义位选中断次数计数变量
ucharkey_mark=16;//定义抢答按键标志
ucharisStart=0;//定义抢答状态
ucharerror_mark;//定义犯规按键标志
voidmain(){
uchartemp;
uchari;
TMOD=0x01;//设置定时器T0为方式1定时
IE=0x83;//总中断开,允许定时器T0、外部中断0中断
IT0=1;//选择外部中断0为跳沿触发方式
TH0=TH(500);//给定时器T0高8位赋值
TL0=TL(500);//给定时器T0低8位赋值
int_mark=0;//位选中断次数清零
TR0=1;//启动定时器T0
while
(1){
if(isStart==1&&key_mark==16){
P2=0xef;
for(i=0;i<=3;i++){//列扫描,i代表列值(0:
第一列、1:
第二列、2:
第三列、3:
第四列)
//行扫描
if(L1==0)key_mark=i+0;//第一行
if(L2==0)key_mark=i+4;//第二行
if(L3==0)key_mark=i+8;//第三行
if(L4==0)key_mark=i+12;//第四行
//P2值左移
temp=P2;
temp=temp|0x0f;
temp=temp<<1;
temp=temp|0x0f;
P2=temp;
}
}
}
}
//定时器T0中断,刷新数码管
voidrefresh()interrupt1{
if(int_mark==9){//位选计数溢出清零
int_mark=1;
}
if(isStart==1){//当前为抢答状态
switch(int_mark){
case1:
OE=1;
LE1=1;
out=numCode[key_mark];
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
break;
case2:
break;
case3:
break;
case4:
break;
case5:
break;
case6:
break;
case7:
break;
case8:
break;
}
TH0=TH(500);//给定时器T1高8位赋值
TL0=TL(500);//给定时器T1低8位赋值
}else{//非抢答状态,循环显示12345678(抢答预备状态)
OE=1;
LE1=1;
out=numCode[int_mark];
LE1=0;
LE2=1;
out=mark[int_mark];
LE2=0;
OE=0;
TH0=TH(65536);//给定时器T1高8位赋值
TL0=TL(65536);//给定时器T1低8位赋值
}
int_mark++;
}
//外部中断0,按键控制
voidkeyControl()interrupt0{
if(INT0==0)
{
//K1键按下,控制抢答状态并复位抢答器
if(K1==0){
isStart=isStart==0?
1:
0;
key_mark=16;
}
//K2键按下,抢答器复位
if(K2==0){
key_mark=16;
}
//K3键按下,
if(K3==0){
}
//K4键按下,
if(K4==0){
}
}
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 秒表和抢答器 秒表 抢答