|
/*
*內(nèi)部時(shí)鐘源無(wú)法高精度校準(zhǔn),每20分鐘較標(biāo)準(zhǔn)時(shí)鐘快1秒,可通過(guò)代碼修正
*/
#include <iom48v.h>
#define BUTTON_REPEAT_TIME 19 //按鍵重復(fù)速度,N個(gè)數(shù)值(N+1)*4ms
void clockInit(void);
void IOInit(void);
void timerInit(void);
void TIM0_COMPA(void);
void TIMER1_OVF(void);
void ringTheBell(void);
void canaelTheBell(void);
const unsigned char tubeData[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};//0-9
typedef struct{
unsigned char hours;
unsigned char minutes;
unsigned char isAlarmEnable;
}Clock;
struct{
unsigned char data[4];
unsigned char dot[4];
}s;
Clock baseClock={12,30,0},alarmClock={0};
unsigned char buttonRepeatTime=0;
unsigned char second=0;
unsigned timerInterruptTimes=0;
unsigned char setAlarm=0;
unsigned char alarming=0;
unsigned char currentTube=0;
unsigned short ringToneCursor=10;
unsigned char cursorDirection=1;
void main(void)
{
s.data[0]=baseClock.hours/10;
s.data[1]=baseClock.hours%10;
s.data[2]=baseClock.minutes/10;
s.data[3]=baseClock.minutes%10;
clockInit();
IOInit();
timerInit();
SREG|=0X80;
while(1);
}
void IOInit(void){
/*
*PB1為蜂鳴器,2-5為按鍵輸入,4設(shè)置鬧鐘和確認(rèn),5取消鬧鐘功能,2,3改變時(shí)和分
*PC0-3為數(shù)碼管位選
*PD為數(shù)碼管段選
*/
MCUCR&=0xEF;//清零PUD,使能上拉
DDRB=0XC2;//0-3輸入
PORTB|=0X3C;//2-5輸出高電平
DDRC|=0X0F;//0-3為輸出
PORTC|=0X0E;//0-3輸出高,數(shù)碼管關(guān)閉
DDRD=0XFF;//全部為輸出
PORTD=0XFF;//關(guān)閉數(shù)碼管
}
void timerInit(void)
{
/*
*定時(shí)器0用于定時(shí)刷新數(shù)碼管,62Hz左右;定時(shí)檢測(cè)按鍵
*定時(shí)器1用于輸出音頻
*/
TCCR0A=0X02;//CTC模式,匹配即清零計(jì)數(shù)
TIMSK0=0X02;//使能A匹配中斷
OCR0A=249;//時(shí)鐘產(chǎn)生250Hz的中斷
TCCR0B=0X02;//選擇時(shí)鐘為64分頻,計(jì)數(shù)器開(kāi)始計(jì)數(shù)
}
#pragma interrupt_handler TIM0_COMPA:15
void TIM0_COMPA(void)
{
//處理按鍵事件
if(~(PINB|0XC3))
{
buttonRepeatTime++;
if(buttonRepeatTime>BUTTON_REPEAT_TIME)
{
buttonRepeatTime=0;
if(~(PINB|0XDF))
{//判斷取消鬧鈴按鍵是否按下,優(yōu)先級(jí)最高
//顯示回當(dāng)前時(shí)間
s.data[0]=baseClock.hours/10;
s.data[1]=baseClock.hours%10;
s.data[2]=baseClock.minutes/10;
s.data[3]=baseClock.minutes%10;
alarmClock.isAlarmEnable=0;//關(guān)閉鬧鐘
s.dot[3]=0;//熄滅鬧鐘指示點(diǎn)
setAlarm=0;//狀態(tài)切換
if(alarming)//關(guān)閉鬧鐘
{
alarming=0;
canaelTheBell();
}
}
else if(~(PINB|0XEF)) //判斷設(shè)置確定按鍵
{
if(setAlarm)
{
//保存設(shè)置
alarmClock.isAlarmEnable=1;
s.dot[3]=1;
//顯示回當(dāng)前時(shí)間
s.data[0]=baseClock.hours/10;
s.data[1]=baseClock.hours%10;
s.data[2]=baseClock.minutes/10;
s.data[3]=baseClock.minutes%10;
}
else
{
//顯示上次保存的鬧鐘時(shí)間
s.data[0]=alarmClock.hours/10;
s.data[1]=alarmClock.hours%10;
s.data[2]=alarmClock.minutes/10;
s.data[3]=alarmClock.minutes%10;
s.dot[1]=0;//熄滅秒顯示點(diǎn)
}
setAlarm=!setAlarm;
}
else
{
//設(shè)置當(dāng)前顯示的時(shí)間數(shù)值
if(setAlarm)
{
if(~(PINB|0XFB)) alarmClock.hours=alarmClock.hours<23?alarmClock.hours+1:0;
if(~(PINB|0XF7)) alarmClock.minutes=alarmClock.minutes<59?alarmClock.minutes+1:0;
s.data[0]=alarmClock.hours/10;
s.data[1]=alarmClock.hours%10;
s.data[2]=alarmClock.minutes/10;
s.data[3]=alarmClock.minutes%10;
}
else
{
//重置秒計(jì)數(shù)和定時(shí)器計(jì)數(shù)
timerInterruptTimes=0;
second=0;
s.dot[1]=0;
if(~(PINB|0XFB)) baseClock.hours=baseClock.hours<23?baseClock.hours+1:0;
if(~(PINB|0XF7)) baseClock.minutes=baseClock.minutes<59?baseClock.minutes+1:0;
s.data[0]=baseClock.hours/10;
s.data[1]=baseClock.hours%10;
s.data[2]=baseClock.minutes/10;
s.data[3]=baseClock.minutes%10;
}
}
}
}
else buttonRepeatTime=0;
//時(shí)間定時(shí)
if(timerInterruptTimes>=249) //第250個(gè)中斷
{
timerInterruptTimes=0;
//第二點(diǎn)閃爍,指示秒
if(!setAlarm) s.dot[1]=!s.dot[1];
if(second>=59)
{
//重新計(jì)算時(shí)間
second=0;
if(baseClock.minutes>=59)
{
baseClock.minutes=0;
baseClock.hours=baseClock.hours<23?baseClock.hours+1:0;
}
else baseClock.minutes++;
//刷新數(shù)碼管時(shí)間值
if(!setAlarm)
{
s.data[0]=baseClock.hours/10;
s.data[1]=baseClock.hours%10;
s.data[2]=baseClock.minutes/10;
s.data[3]=baseClock.minutes%10;
}
} else second++;
//判斷鬧鐘是否匹配
if(alarmClock.isAlarmEnable&&baseClock.hours==alarmClock.hours&&baseClock.minutes==alarmClock.minutes)
{
if(!alarming)
{
alarming=1;
ringTheBell();
}
}
else if(alarming)
{
alarming=0;
canaelTheBell();
}
}
timerInterruptTimes++;
//刷新數(shù)碼管
currentTube=currentTube<3?currentTube+1:0;
PORTD=0XFF;//熄滅數(shù)碼管
PORTC=0XFF;//關(guān)閉位控
PORTC&=~(1<<currentTube);//1左移currentTube位
PORTD=tubeData[s.data[currentTube]];
if(s.dot[currentTube]) PORTD&=0X7F;
}
#pragma interrupt_handler TIMER1_OVF:14
void TIMER1_OVF(void)
{
OCR1AH=ringToneCursor/256;
OCR1AL=ringToneCursor%256;
if(cursorDirection)
{
if(ringToneCursor<1790)
{
ringToneCursor++;
}
else cursorDirection=0;
}else
{
if(ringToneCursor>500)
{
ringToneCursor--;
}
else cursorDirection=1;
}
}
void ringTheBell(void)
{
OCR1AH=0;//修改占空比數(shù)值,有緩存器,會(huì)在BOTTOM修改
OCR1AL=10;
TIMSK1=0X01;//開(kāi)啟溢出中斷
TCNT1H=0;//歸零計(jì)數(shù)器
TCNT1L=0;
ICR1H=0X07;//0X01//設(shè)置輸出頻率,稍大于11025
ICR1L=0X08;//0X69
TCCR1B=0X19;
TCCR1A=0X82;//快速PWM模式,在BOTTOM置位,匹配清零,時(shí)鐘無(wú)分頻
}
void canaelTheBell(void)
{
//關(guān)閉音頻輸出步驟
TCCR1B=0;//先關(guān)閉時(shí)鐘
TCCR1A=0X80;//修改模式為匹配時(shí)清零
TCCR1C=0;//強(qiáng)制輸出為低,關(guān)閉音頻
}
|
評(píng)分
-
查看全部評(píng)分
|