欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

標題: 48單片機鬧鐘設計 內部時鐘源無法高精度校準,每20分鐘較標準時鐘快1秒 [打印本頁]

作者: 128單片機    時間: 2019-3-12 13:09
標題: 48單片機鬧鐘設計 內部時鐘源無法高精度校準,每20分鐘較標準時鐘快1秒
/*
*內部時鐘源無法高精度校準,每20分鐘較標準時鐘快1秒,可通過代碼修正
*/
#include <iom48v.h>
#define BUTTON_REPEAT_TIME 19 //按鍵重復速度,N個數值(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設置鬧鐘和確認,5取消鬧鐘功能,2,3改變時和分
*PC0-3為數碼管位選
*PD為數碼管段選
*/
  MCUCR&=0xEF;//清零PUD,使能上拉
  DDRB=0XC2;//0-3輸入
  PORTB|=0X3C;//2-5輸出高電平
  DDRC|=0X0F;//0-3為輸出
  PORTC|=0X0E;//0-3輸出高,數碼管關閉
  DDRD=0XFF;//全部為輸出
  PORTD=0XFF;//關閉數碼管
}
void timerInit(void)
{
    /*
    *定時器0用于定時刷新數碼管,62Hz左右;定時檢測按鍵
    *定時器1用于輸出音頻
    */
  TCCR0A=0X02;//CTC模式,匹配即清零計數
  TIMSK0=0X02;//使能A匹配中斷
  OCR0A=249;//時鐘產生250Hz的中斷
  TCCR0B=0X02;//選擇時鐘為64分頻,計數器開始計數
}
#pragma interrupt_handler TIM0_COMPA:15
void TIM0_COMPA(void)
{
    //處理按鍵事件
  if(~(PINB|0XC3))
  {
        buttonRepeatTime++;
        if(buttonRepeatTime>BUTTON_REPEAT_TIME)
  {
            buttonRepeatTime=0;
            if(~(PINB|0XDF))
   {//判斷取消鬧鈴按鍵是否按下,優先級最高
                //顯示回當前時間
                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;//關閉鬧鐘
                s.dot[3]=0;//熄滅鬧鐘指示點
                setAlarm=0;//狀態切換
                if(alarming)//關閉鬧鐘
    {
                    alarming=0;
                    canaelTheBell();
                }
            }
   else if(~(PINB|0XEF)) //判斷設置確定按鍵
   {
                if(setAlarm)
    {
                    //保存設置
                    alarmClock.isAlarmEnable=1;
                    s.dot[3]=1;
                    //顯示回當前時間
                    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
    {
                    //顯示上次保存的鬧鐘時間
                    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;//熄滅秒顯示點
                }
                setAlarm=!setAlarm;
            }
   else
   {
                //設置當前顯示的時間數值
                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
    {
                    //重置秒計數和定時器計數
                    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;
  //時間定時
  if(timerInterruptTimes>=249)  //第250個中斷
  {
        timerInterruptTimes=0;
        //第二點閃爍,指示秒
        if(!setAlarm) s.dot[1]=!s.dot[1];
        if(second>=59)
  {
            //重新計算時間
            second=0;
            if(baseClock.minutes>=59)
   {
                baseClock.minutes=0;
                baseClock.hours=baseClock.hours<23?baseClock.hours+1:0;
            }
   else baseClock.minutes++;
            //刷新數碼管時間值
            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++;
  //刷新數碼管
    currentTube=currentTube<3?currentTube+1:0;
    PORTD=0XFF;//熄滅數碼管
    PORTC=0XFF;//關閉位控
    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;//修改占空比數值,有緩存器,會在BOTTOM修改
  OCR1AL=10;
  TIMSK1=0X01;//開啟溢出中斷
  TCNT1H=0;//歸零計數器
  TCNT1L=0;
  ICR1H=0X07;//0X01//設置輸出頻率,稍大于11025
  ICR1L=0X08;//0X69
  TCCR1B=0X19;
  TCCR1A=0X82;//快速PWM模式,在BOTTOM置位,匹配清零,時鐘無分頻
}
void canaelTheBell(void)
{
    //關閉音頻輸出步驟
  TCCR1B=0;//先關閉時鐘
  TCCR1A=0X80;//修改模式為匹配時清零
  TCCR1C=0;//強制輸出為低,關閉音頻
}








歡迎光臨 (http://m.raoushi.com/bbs/) Powered by Discuz! X3.1