功能描述
- 使用6段數(shù)碼管顯示時(shí)間 分鐘-秒-100毫秒 (十分鐘以內(nèi)毡惜,0.1秒一位)
- 記錄8組數(shù)據(jù) 使用LED燈代表那組數(shù)據(jù)
- 使用三個(gè)按鍵 K1開始/暫停 K2重置 K3計(jì)次/記錄(說明:運(yùn)行狀態(tài)下,不能重置柑晒,k3增加一條記錄點(diǎn)亮一個(gè)LED,暫停狀態(tài)下,可重置,k3從第一條記錄查看并點(diǎn)亮相應(yīng)LED燈)
實(shí)現(xiàn)分析
- 定時(shí)器 產(chǎn)生固定周期中斷(16 13 8位定時(shí)器)
- 數(shù)碼管動態(tài)刷新(軟延時(shí)、定時(shí)器)
- 按鍵消抖(軟延時(shí)礼仗、定時(shí)器)
- 記錄 使用數(shù)組或字符串?使用LED表示那組數(shù)據(jù)
- 按鍵功能定義和狀態(tài)(開始狀態(tài)計(jì)次苞七、重置失效藐守,暫停狀態(tài)重置、記錄激活)
最終實(shí)現(xiàn)
- 16位定時(shí)器蹂风,定時(shí)2ms(由于單片機(jī)晶振為11.0592MHz所以有0.01%誤差 中斷相應(yīng)也會導(dǎo)致誤差)
- 6位數(shù)碼管 分-秒-0.1s卢厂,最大10分鐘
- 按鍵消抖使用定時(shí)器 10ms
- 8組記錄 對應(yīng)8個(gè)LED燈
相關(guān)說明
P1對應(yīng)8個(gè)LED燈
六位共陰數(shù)碼管 由P0連接兩個(gè)鎖存器 控制位選和段選
效果如下圖
#include <reg51.h>
unsigned char code leddata[]= { 0x3F, 0x06, 0x5B, 0x4F, //0 1 2 3
0x66, 0x6D, 0x7D, 0x07, //4 5 6 7
0x7F, 0x6F, 0x77, 0x7C, //8 9 A b
0x39, 0x5E, 0x79, 0x71, //c d E F
0x76, 0x38, 0x37, 0x3E, //H L n u
0x73, 0x5C, 0x40, 0x00, //P o - 清屏
};
#define digitData P0 //數(shù)碼管數(shù)據(jù)
#define startBtn 0 //按鍵值
#define resetBtn 1
#define counterBtn 2
sbit DX = P2^6;//段選
sbit WX = P2^7;//位選
sbit kaiShi = P3^4;//開始、暫停按鍵
sbit chongZhi = P3^5;//重置按鍵
sbit jiCi = P3^6;//計(jì)次惠啄、記錄查看按鍵
unsigned int recode[8] = {0};//記錄數(shù)據(jù)
unsigned char recodeNum = 0;//記錄數(shù)據(jù)值位置
unsigned char showRe = 0; //查看哪項(xiàng)記錄值
unsigned int times = 0; //當(dāng)前計(jì)時(shí)時(shí)間
unsigned int saveTimes = 0;//暫停查看記錄時(shí)保存時(shí)間數(shù)據(jù)
unsigned char counter = 0;//定時(shí)器次數(shù)慎恒,構(gòu)成100ms
unsigned char shuanXi = 0,sXW = 1;//刷新數(shù)碼管
unsigned char runState = 0;//0表示停止任内,1表示運(yùn)行
unsigned char keyTemp[3]= {0}; //按鍵按下狀態(tài)持續(xù)時(shí)間
//六位數(shù)碼管顯示 dat:顯示內(nèi)容下標(biāo) wei:哪一個(gè)數(shù)碼管
void display(unsigned char dat,unsigned char wei)//wei 1-6
{
digitData = 0xff; //關(guān)掉顯示 消除重影
WX = 1;
WX = 0;
//如果不先關(guān)閉顯示,不論先段選還位選(位選前關(guān)閉都不行)融柬,而且必須先送段選死嗦,再送位選,
//先位選則當(dāng)前位置會顯示上次殘留段選數(shù)據(jù) 導(dǎo)致重影
digitData = leddata[dat];//段選
DX = 1;
DX = 0;
digitData = ~(1<<(wei-1));//位選
WX = 1;
WX = 0;
}
//判斷當(dāng)前按鍵
unsigned char scanKey()
{
P3 = 0x70;//k1 k2 k3給高
if(kaiShi==0)//開始鍵按下
{
if(keyTemp[0] == 0) keyTemp[0]=1 ;//按鍵按下 開始記延時(shí)
}
else
{
keyTemp[0] = 0; //有抖動重新延時(shí)
}
if(chongZhi==0)
{
if(keyTemp[1] == 0) keyTemp[1]=1 ;
}
else
{
keyTemp[1] = 0;
}
if(jiCi==0)
{
if(keyTemp[2] == 0) keyTemp[2]=1 ;
}
else
{
keyTemp[2] = 0;
}
if(keyTemp[0]>5) return startBtn; //5次 5*2ms 超過10ms 消抖
if(keyTemp[1]>5) return resetBtn;
if(keyTemp[2]>5) return counterBtn;
return 0xFF; //沒有按鍵
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
//AUXR &= 0x7F; //定時(shí)器時(shí)鐘12T模式
TMOD &= 0xF0; //設(shè)置定時(shí)器模式
TMOD |= 0x01; //設(shè)置定時(shí)器模式
TL0 = 0xCF; //設(shè)置定時(shí)初值
TH0 = 0xF8; //設(shè)置定時(shí)初值
TF0 = 0; //清除TF0標(biāo)志
TR0 = 1; //定時(shí)器0開始計(jì)時(shí)
ET0 = 1; //運(yùn)行定時(shí)器0中斷
EA = 1; //開全局中斷
}
void main()
{
unsigned char keyValue = 0xFF,keyT = 0xFF;//按鍵值
unsigned char weiXian[6] = {0,22,0,0,22,0};
Timer0Init();
while(1)
{
if(shuanXi)//刷新sXW位置的數(shù)碼管中
{
if(times>=6000) //十分鐘
{
times = 0;
}
weiXian[0] = times/600;//分鐘
weiXian[2] = times/10%60/10;
weiXian[3] = times/10%60%10;
weiXian[5] = times%10;
display(weiXian[sXW-1],sXW);
shuanXi = 0;
}
keyT = scanKey();//當(dāng)前按鍵值
if(keyT!=keyValue)//當(dāng)前按鍵值與上次按鍵值不同粒氧,則表示按鍵狀態(tài)改變越除。需要做按鍵處理
{
keyValue = keyT;
//P1 = keyValue;
switch(keyValue)//按鍵處理
{
case startBtn://開始暫停按下
//if(runState) TR0 = 0; else TR0 = 1;
//runState ? (TR0 = 0) : (TR0 = 1);
runState = !runState;//改變狀態(tài)
if(runState)//恢復(fù)時(shí)間
{
times = saveTimes;
}
else//保存時(shí)間
{
saveTimes = times;
}
break;
case resetBtn: //重置
if(!runState)
{
times = 0;
saveTimes = 0;
recodeNum = 0;
P1 = 0xFF;
}
break;
case counterBtn: //記錄或查看記錄
if(runState)//運(yùn)行時(shí),記錄
{
if(recodeNum<8)
{
recode[recodeNum++] = times;
P1 = (0xFF<<recodeNum);//點(diǎn)亮recodeNum個(gè)燈
}
}
else//暫停查看記錄
{
P1 = (0xFF ^(1 << showRe));//點(diǎn)亮showRe位置的燈
times = recode[showRe++];
if(showRe >= recodeNum)
{
showRe = 0;//循環(huán)查看記錄
}
}
break;
}
}
}
}
void T0_2ms() interrupt 1
{
//定時(shí)器重新賦初值 放在終端服務(wù)程序最開始有利于降低定時(shí)中斷誤差
TL0 = 0xCF; //設(shè)置定時(shí)初值
TH0 = 0xF8; //設(shè)置定時(shí)初值
if(++counter>=50 && runState)//運(yùn)行狀態(tài)下100ms 加0.1秒
{
times++;
counter = 0;
}
shuanXi = 1;//數(shù)碼管周期刷新
if(++sXW>6) //六位循環(huán)刷新
{
sXW = 1;
}
if(keyTemp[0]) keyTemp[0]++;//按鍵持續(xù)
if(keyTemp[1]) keyTemp[1]++;//按鍵持續(xù)
if(keyTemp[2]) keyTemp[2]++;//按鍵持續(xù)
}