專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

單片機(jī)開源項(xiàng)目之按鍵可調(diào)時(shí)電子鐘(矩陣按鍵+紅外遙控按鍵進(jìn)行調(diào)時(shí))

作者:寒竹子   來源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年05月02日   【字體:

 此程序是基于51hei單片機(jī)開發(fā)板上面寫的,如需要移植到自己的電路上,修改相應(yīng)的端口即可,開發(fā)板完整的電路圖下載:  點(diǎn)這里 (注意:只需要看相關(guān)部分即可如矩陣鍵盤 數(shù)碼管 紅外等,其他部分可以忽略)

/**
  ************************************************************************
 * @file    :   main.c
 * @author  :   xr
 * @date    :   2014年4月21日 22:23:12 - 2014年4月26日21:22:29
 * @version :   V1.2.3
 * @brief   :   按鍵可調(diào)時(shí)電子鐘(矩陣按鍵+紅外遙控按鍵進(jìn)行調(diào)時(shí))   單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
 ************************************************************************
 */

#include <reg52.h>
#include "main.h"
/*定義結(jié)構(gòu)體來封裝從DS1302中讀取的時(shí)間和日期和設(shè)置到DS1302中的時(shí)間和日期*/
struct Time {
 unsigned char year;  //DS1302中只存放的是年的低兩位字節(jié)
  unsigned char month;
 unsigned char day;
    unsigned char hour;
 unsigned char min;
 unsigned char sec;
 unsigned char week;
};
/*定義結(jié)構(gòu)體時(shí)間變量來保存時(shí)間和日期*/
struct Time timeBuf; //此處必須用結(jié)構(gòu)體變量,不能用結(jié)構(gòu)體指針否則寫入失敗!
unsigned char setTimeIndex = 0; //設(shè)置時(shí)間狀態(tài)及設(shè)置光標(biāo)位置及設(shè)置時(shí)間位置的索引值(0時(shí)正常運(yùn)行,1-12為設(shè)置時(shí)間狀態(tài),1-12是設(shè)置的位置)
bit flag200ms = 0;
unsigned char thr0, tlr0;
//紅外通信解碼的鍵碼和標(biāo)準(zhǔn)PC機(jī)編碼映射表
unsigned char code IrdCodeMap[] = {0x45, 0x46, 0x47, //開關(guān),Mode, 靜音
                                   0x44, 0x40, 0x43, //播放/暫停 快退, 快進(jìn)
                                   0x07, 0x15, 0x09, //EQ, 減, 加
                                   0x16, 0x19, 0x0D, //0, 返回, U/SD
                                   0x0C, 0x18, 0x5E, //1, 2, 3
                                   0x08, 0x1C, 0x5A, //4, 5, 6
                                   0x42, 0x52, 0x4A};//7, 8, 9
//外部變量聲明
extern bit flagIrd; //紅外數(shù)據(jù)碼值接收完畢標(biāo)志位
extern unsigned char irdCode[4]; //保存NEC協(xié)議解碼的四個(gè)字節(jié)的數(shù)據(jù)碼(用戶碼+用戶反碼,鍵碼+鍵碼反碼)
extern void InitLCD1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);
extern void LcdSetCoursor(unsigned char x, unsigned char y);
extern void LcdOpenCoursor();
extern void InitDS1302();
extern void GetTimeFromDS1302(struct Time * time);
extern void SetTimeToDS1302(struct Time * time);
extern void KeyDriver();
extern void KeyScan();
extern void LcdCoursorRight();
extern void LcdCoursorLeft();
void ConfgiTimer0(unsigned int xms);
void RefreshLcdShowTime();
extern void ConfigIrdByTimer1();
void IrdDrive();
void IrdKeyAction();
extern void SetTimeBcdByte(unsigned char keyNum);
/*主程序main()*/
void main()
{
    unsigned char psec = 0xFF;//用于檢測(cè)sec秒是否變化,若變化則刷新時(shí)間顯示
    ConfgiTimer0(1); //定時(shí)1ms
    ConfigIrdByTimer1();//配置紅外通信
 InitLCD1602();
    InitDS1302();
   
    /*液晶初始化顯示*/
    LcdShowStr(1, 0, "*");
 LcdShowStr(2, 0, "20  -  -  ");
    LcdShowStr(12, 0, "*");
    LcdShowStr(14, 0, "--");
 LcdShowStr(0, 1, "time: --:--:--");
 
 while (1)
    {
       
        KeyDriver();//檢測(cè)按鍵動(dòng)作
       
        if (flagIrd)
        {
            flagIrd = 0;
            IrdKeyAction();//檢測(cè)紅外按鍵動(dòng)作
        }
       
        if (flag200ms == 1 && (setTimeIndex == 0))  //每200ms且setTimeIndex==0處于非設(shè)定時(shí)間狀態(tài)時(shí)刷新一次時(shí)間顯示
        {
            flag200ms = 0;
            GetTimeFromDS1302(&timeBuf); //從DS1302中獲取時(shí)間到timeBuf結(jié)構(gòu)體指針變量的成員中
            if (timeBuf.sec != psec) //當(dāng)前秒值和上一次的秒值不相等
            {
                RefreshLcdShowTime();//刷新時(shí)間顯示
                psec = timeBuf.sec;//備份當(dāng)前的秒值(秒寄存器值)
            }
        }
    }   
   
}
/*定時(shí)器T0配置*/
void ConfgiTimer0(unsigned int xms)
{
    unsigned long tmp;
    tmp = 11059200/12;//周期頻率
    tmp = (tmp * xms) / 1000;//定時(shí)xms需要的計(jì)數(shù)值
    tmp = 65536-tmp;//定時(shí)裝入的初值
    thr0 = (unsigned char)(tmp >> 8);
    tlr0 = (unsigned char)tmp;
    TMOD &= 0xF0;//清零T0控制位
    TMOD |= 0x01;//T0方式1,16位可設(shè)定時(shí)模式
    TH0 = thr0;
    TL0 = tlr0;
    TR0 = 1;
    ET0 = 1;
    EA  = 1;
}
/*將一個(gè)BCD碼字節(jié)數(shù)據(jù)分解顯示到LCD1602的(x, y)坐標(biāo)上*/
void LcdShowBCDByte(unsigned char x, unsigned char y, unsigned char bcdbyte)
{
    unsigned char str[4];
   
    str[0] = (bcdbyte >> 4) + '0';//取BCD碼的高四位字節(jié)
    str[1] = (bcdbyte & 0x0F) + '0';//取BCD碼的第四位字節(jié)
    str[2] = '\0';
   
    LcdShowStr(x, y, str);
}
/*刷新時(shí)間顯示到LCD1602液晶上*/
void RefreshLcdShowTime()
{
    LcdShowBCDByte(4, 0, timeBuf.year); //顯示年
    LcdShowBCDByte(7, 0, timeBuf.month);
    LcdShowBCDByte(10, 0, timeBuf.day);
    LcdShowBCDByte(6, 1, timeBuf.hour);
    LcdShowBCDByte(9, 1, timeBuf.min);
    LcdShowBCDByte(12, 1, timeBuf.sec);
    LcdShowBCDByte(14, 0, timeBuf.week); //顯示星期
}
/************以下函數(shù)功能是BCD碼字節(jié)的高位和低位數(shù)字+1和-1*******************/
/*遞增BCD碼的高位數(shù)字*/
unsigned char IncrementBCDByteHigh(unsigned char bcdbyte)
{
    if ((bcdbyte & 0xF0) < 0x90) //取bcdbyte的高四位字節(jié)是否小于9
    {
        bcdbyte += 0x10;//高四位字節(jié)+1
    }
    else
    {
        //高四位字節(jié)數(shù)值到9歸零
        bcdbyte &= 0x0F;//0000 1111
    }
   
    return (bcdbyte); //返回修改后的BCD碼值
}
/*遞增BCD碼的低位字節(jié)數(shù)字*/
unsigned char IncrementBCDByteLow(unsigned char bcdbyte)
{
    if ((bcdbyte & 0x0F) < 0x09) //取bcdbyte的低四位字節(jié)數(shù)字
    {
        bcdbyte += 0x01; //低位字節(jié)+1
    }
    else
    {
        //到9歸零
        bcdbyte &= 0xF0;//低四位清零
    }
   
    return (bcdbyte);
}
/*遞減BCD碼數(shù)據(jù)字節(jié)的高字節(jié)數(shù)字*/
unsigned char DescBCDByteHigh(unsigned char bcdbyte)
{
    if ((bcdbyte & 0xF0) > 0) //取BCD碼字節(jié)的高四位字節(jié)
    {
        bcdbyte -= 0x10; //高四位字節(jié)數(shù)字-1
    }
    else
    {
        //到0歸9
        bcdbyte |= 0x90; //或bcdbyte &= 0x9F
    }
   
    return (bcdbyte);
}
/*遞減BCD碼數(shù)據(jù)字節(jié)的低字節(jié)數(shù)字*/
unsigned char DescBCDByteLow(unsigned char bcdbyte)
{
    if ((bcdbyte & 0x0F) > 0)
    {
        bcdbyte -= 0x01;//低位數(shù)字-1
    }
    else
    {
        //到0歸9
        bcdbyte |= 0x09;
    }
   
    return (bcdbyte);
}

/*根據(jù)setTimeIndex的值來設(shè)置光標(biāo)閃爍的位置*/
void LcdRefreshSetCoursor()
{
    switch (setTimeIndex)
    {
        case 1:  LcdSetCoursor(4, 0);  break;//設(shè)置年的十位數(shù)字
        case 2:  LcdSetCoursor(5, 0);  break;
        case 3:  LcdSetCoursor(7, 0);  break;
        case 4:  LcdSetCoursor(8, 0);  break;
        case 5:  LcdSetCoursor(10, 0); break;
        case 6:  LcdSetCoursor(11, 0); break;
        case 7:  LcdSetCoursor(6,  1); break;
        case 8:  LcdSetCoursor(7, 1);  break;
        case 9:  LcdSetCoursor(9, 1);  break;
        case 10: LcdSetCoursor(10, 1); break;
        case 11: LcdSetCoursor(12, 1); break;
        case 12: LcdSetCoursor(13, 1); break;
        default: break;
    }
    LcdOpenCoursor();
}
/*遞增光標(biāo)閃爍位置的時(shí)間值*/
void IncTimeBysetTimeIndex()
{
    switch (setTimeIndex)
    {
        case 1:  timeBuf.year  = IncrementBCDByteHigh(timeBuf.year);  break;//year10++年的十位數(shù)字++
        case 2:  timeBuf.year  = IncrementBCDByteLow(timeBuf.year);   break;//年的個(gè)位數(shù)字++
        case 3:  timeBuf.month = IncrementBCDByteHigh(timeBuf.month); break;//月十位++
        case 4:  timeBuf.month = IncrementBCDByteLow(timeBuf.month);  break;//月個(gè)位++
        case 5:  timeBuf.day   = IncrementBCDByteHigh(timeBuf.day);   break;
        case 6:  timeBuf.day   = IncrementBCDByteLow(timeBuf.day);    break;
        case 7:  timeBuf.hour  = IncrementBCDByteHigh(timeBuf.hour);  break;
        case 8:  timeBuf.hour  = IncrementBCDByteLow(timeBuf.hour);   break;
        case 9:  timeBuf.min   = IncrementBCDByteHigh(timeBuf.min);   break;
        case 10: timeBuf.min   = IncrementBCDByteLow(timeBuf.min);    break;
        case 11: timeBuf.sec   = IncrementBCDByteHigh(timeBuf.sec);   break;
        case 12: timeBuf.sec   = IncrementBCDByteLow(timeBuf.sec);    break;
        default: break;
    }
    RefreshLcdShowTime();//刷新時(shí)間顯示
    LcdRefreshSetCoursor();//刷新光標(biāo)閃爍顯示
}
/*遞減光標(biāo)位置的時(shí)間值*/
void DecTimeBySetTimeIndex()
{
    switch (setTimeIndex)
    {
        case 1:  timeBuf.year  = DescBCDByteHigh(timeBuf.year);  break;//年十位數(shù)字遞減
        case 2:  timeBuf.year  = DescBCDByteLow(timeBuf.year);   break;//年個(gè)位數(shù)字遞減
        case 3:  timeBuf.month = DescBCDByteHigh(timeBuf.month); break;
        case 4:  timeBuf.month = DescBCDByteLow(timeBuf.month);  break;
        case 5:  timeBuf.day   = DescBCDByteHigh(timeBuf.day);   break;
        case 6:  timeBuf.day   = DescBCDByteLow(timeBuf.day);    break;
        case 7:  timeBuf.hour  = DescBCDByteHigh(timeBuf.hour);  break;
        case 8:  timeBuf.hour  = DescBCDByteLow(timeBuf.hour);   break;
        case 9:  timeBuf.min   = DescBCDByteHigh(timeBuf.min);   break;
        case 10: timeBuf.min   = DescBCDByteLow(timeBuf.min);    break;
        case 11: timeBuf.sec   = DescBCDByteHigh(timeBuf.sec);   break;
        case 12: timeBuf.sec   = DescBCDByteLow(timeBuf.sec);    break;
        default: break;
    }
    /*先刷新時(shí)間顯示,再刷新光標(biāo)閃爍顯示*/
    RefreshLcdShowTime();
    LcdRefreshSetCoursor();
}
/*紅外按鍵動(dòng)作函數(shù)*/
void IrdKeyAction()
{
    if (irdCode[2] == 0x44) // >>||
    {
        if (setTimeIndex == 0) //正常運(yùn)行狀態(tài)
        {
            setTimeIndex = 1;
            LcdRefreshSetCoursor();//刷新光標(biāo)設(shè)置顯示    
        }
        else
        {
            SetTimeToDS1302(&timeBuf); //將時(shí)間寫入到DS1302中
            setTimeIndex = 0;
            RefreshLcdShowTime();
        }
    }
    else if (irdCode[2] == 0x40) //|<<
    {
        if (setTimeIndex != 0)
        {
            LcdCoursorLeft();
        }
    }
    else if (irdCode[2] == 0x43) // >>|
    {
        if (setTimeIndex != 0)
        {
            LcdCoursorRight();
        }
    }
    else if (irdCode[2] == 0x15) //-
    {
        DecTimeBySetTimeIndex();
    }
    else if (irdCode[2] == 0x09) //+
    {
        IncTimeBysetTimeIndex();
    }
    else if (irdCode[2] == 0x19) //EQ
    {
        setTimeIndex = 0;
        RefreshLcdShowTime();
    }
    else if (irdCode[2] == 0x16) //數(shù)字鍵0
    {
        SetTimeBcdByte(0);
    }
    else if (irdCode[2] == 0x0C) //數(shù)字鍵1
    {
        SetTimeBcdByte(1);
    }
    else if (irdCode[2] == 0x18) //數(shù)字鍵2
    {
        SetTimeBcdByte(2);
    }
    else if (irdCode[2] == 0x5E)
    {
        SetTimeBcdByte(3);
    }
    else if (irdCode[2] == 0x08)
    {
        SetTimeBcdByte(4);
    }
    else if (irdCode[2] == 0x1C)
    {
        SetTimeBcdByte(5);
    }
    else if (irdCode[2] == 0x5A)
    {
        SetTimeBcdByte(6);
    }
    else if (irdCode[2] == 0x42)
    {
        SetTimeBcdByte(7);
    }
    else if (irdCode[2] == 0x52)
    {
        SetTimeBcdByte(8);
    }
    else if (irdCode[2] == 0x4A)
    {
        SetTimeBcdByte(9);
    }
    else
    {
    }
}
/*T0中斷服務(wù)*/
void Timer0_ISP() interrupt 1
{
    static unsigned char counter = 0;
   
    TH0 = thr0;
    TL0 = tlr0; //1ms
    counter++;
    KeyScan();//按鍵掃描
   
    if (counter >= 200)
    {
        counter = 0;
        flag200ms = 1;//200ms
    }    
}

 #ifndef _MAIN_H_
#define _MAIN_H_
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
#endif //_MAIN_H_

 /**
  ************************************************************************
 * @file    :   Lcd1602.c
 * @author  :   xr
 * @date    :   2014年4月21日 22:23:12
 * @version :   V1.2.3
 * @brief   :   LCD1602底層驅(qū)動(dòng)   單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
 ************************************************************************
 */
#include <reg52.h>
//LCD1602
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_EN = P1^5;
#define LCD1602_DB P0
/*LCD1602忙碌等待*/
void LCD1602Wait()
{
 unsigned char sta;//讀取LCD1602狀態(tài)字
 
    /*讀取液晶狀態(tài)字之前必須將P0口全部拉高*/
 LCD1602_DB = 0xFF;
 
 LCD1602_RS = 0;
 LCD1602_RW = 1;
 LCD1602_EN = 0;
 
 do
 {
  LCD1602_EN = 1;
  sta = LCD1602_DB;//讀狀態(tài)字
  LCD1602_EN = 0;
 } while (sta & 0x80); //檢測(cè)最高位是否為1,1忙碌,0空閑
}
/*LCD1602寫命令*/
void LCD1602WriteCmd(unsigned char cmd)
{
 //讀寫前要進(jìn)行液晶的忙碌等待
 LCD1602Wait();
 
 LCD1602_RS = 0;
 LCD1602_RW = 0;
 LCD1602_EN = 0;
 LCD1602_DB = cmd;
 LCD1602_EN = 1;//高脈沖
 LCD1602_EN = 0;//關(guān)閉液晶輸出
}
/*LCD1602寫數(shù)據(jù)*/
void LCD1602WriteData(unsigned char dat)
{
 LCD1602Wait();
 
 LCD1602_RS = 1;
 LCD1602_RW = 0;
 LCD1602_EN = 0;
 LCD1602_DB = dat;//送入數(shù)據(jù)
 LCD1602_EN = 1;//高脈沖
 LCD1602_EN = 0;//關(guān)閉液晶輸出
}
/*液晶初始化*/
void InitLCD1602()
{
 LCD1602WriteCmd(0x38); //寫指令38H
 LCD1602WriteCmd(0x0C); //開顯示不顯示光標(biāo)
 LCD1602WriteCmd(0x06); //寫入字符時(shí)字符指針++且光標(biāo)++
 LCD1602WriteCmd(0x01); //顯示清屏
}
/*在LCD1602的坐標(biāo)(x, y)位置顯示str*/
void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str)
{
 unsigned char addr;
 
 if (y == 0)
 {
  addr = 0x00 + x; //第一行的x位置顯示
 }
 else
 {
  addr = 0x40 + x; //第二行x的位置顯示
 }
 LCD1602WriteCmd(addr + 0x80);
 while (*str != '\0')
 {
  LCD1602WriteData(*str++);
 }
}
/*設(shè)置光標(biāo)的位置為(x, y)*/
void LcdSetCoursor(unsigned char x, unsigned char y)
{
 unsigned char addr;
 
 if (y == 0)
 {
  addr = 0x00 + x;
 }
 else
 {
  addr = 0x40 + x;
 }
    LCD1602WriteCmd(addr | 0x80); //寫入光標(biāo)閃爍地址
}
/*打開光標(biāo)顯示*/
void LcdOpenCoursor()
{
 LCD1602WriteCmd(0x0F); //顯示光標(biāo)病使光標(biāo)閃爍
}
/*關(guān)閉光標(biāo)顯示*/
void LcdCloseCoursor()
{
 LCD1602WriteCmd(0x0C); //開顯示但不顯示光標(biāo)
}

 /**
  ************************************************************************
 * @file    :   Ds1302.c
 * @author  :   xr
 * @date    :   2014年4月21日 22:23:12
 * @version :   V1.2.3
 * @brief   :   DS1302底層驅(qū)動(dòng)   單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
 ************************************************************************
 */
#include <reg52.h>
//DS1302
sbit DS1302_SIO = P3^4;//數(shù)據(jù)IO
sbit DS1302_SCK = P3^5;//時(shí)鐘線
sbit DS1302_CE  = P1^7;//片選使能
/*使用外部數(shù)據(jù)類型時(shí)必須在這個(gè)文件中再一次聲明*/
struct Time {
 unsigned char year;//年在DS1302中只存放的是低兩位,這里用unsigned char型
 unsigned char month;
 unsigned char day;
 unsigned char hour;
 unsigned char min;
 unsigned char sec;
 unsigned char week;
};
/*向SIO發(fā)送一個(gè)字節(jié)數(shù)據(jù)*/
void DS1302WriteByte(unsigned char byte)
{
 unsigned char mask = 0x01;//低位在前,逐位發(fā)送
 /*初始化DS1302時(shí),將SIO和SCK引腳拉低,空閑*/
 for (mask = 0x01; mask != 0; mask <<= 1)
 {
  if ((byte & mask) != 0)  //上升沿DS1302進(jìn)行數(shù)據(jù)的采樣鎖存
  {
   DS1302_SIO = 1;
  }
  else
  {
   DS1302_SIO = 0;
  }
  DS1302_SCK = 1;
  DS1302_SCK = 0;//下降沿主機(jī)進(jìn)行數(shù)據(jù)輸出
 }
 //主機(jī)發(fā)送數(shù)據(jù)完成后要進(jìn)行釋放SIO數(shù)據(jù)線
 DS1302_SIO = 1;
}
/*讀取SIO數(shù)據(jù)線上的數(shù)據(jù)*/
unsigned char DS1302ReadByte()
{
 unsigned char mask = 0x01;//低位在先,逐位接收
 unsigned char byte = 0;
 
 for (mask = 0x01; mask != 0; mask <<= 1)
 {
  if (DS1302_SIO != 0) //上升沿主機(jī)進(jìn)行數(shù)據(jù)采樣鎖存
  {
   byte |= mask; //相應(yīng)位置1
  }
  else
  {
   byte &= (~mask);//相應(yīng)位清零
  }
  DS1302_SCK = 1;
  DS1302_SCK = 0;//DS1302在下降沿進(jìn)行數(shù)據(jù)的輸出
 }
 
 return (byte);
}
/*向DS1302的reg地址寄存器中寫入單個(gè)字節(jié)數(shù)據(jù)*/
void DS1302WriteSingleByte(unsigned char reg, unsigned char dat)
{
 /*首先打開DS1302片選端,然后寫寄存器地址reg,然后再寫入數(shù)據(jù)dat*/
 DS1302_CE = 1;
 DS1302WriteByte((reg << 1) | 0x80);//寫入寄存器地址,reg<<1留出讀寫方向位,reg的高位是1,次高位為0
 DS1302WriteByte(dat);              //寫入數(shù)據(jù)
 DS1302_CE = 0;
 DS1302_SIO = 0;//因?yàn)榘遄由蠜]有SIO口沒有加上拉電阻,開漏輸出不定態(tài),將SIO=0,單片機(jī)IO口會(huì)輸出穩(wěn)定的0態(tài)
}
/*從DS1302的reg地址寄存器中讀取一個(gè)字節(jié)的數(shù)據(jù)*/
unsigned char DS1302ReadSingleByte(unsigned char reg)
{
 unsigned char byte = 0;
 
 DS1302_CE = 1;
 DS1302WriteByte((reg << 1) | 0x81); //寫入寄存器地址reg并在讀寫方向上選擇讀
 byte = DS1302ReadByte();
 DS1302_CE = 0;
 DS1302_SIO = 0; //SIO輸出穩(wěn)定的0狀態(tài)
 
 return (byte);
}
/*Burst模式寫八個(gè)字節(jié)到DS1302八個(gè)寄存器中*/
void DS1302BurstWrite(unsigned char * date)
{
 unsigned char i = 0;
 
 DS1302_CE = 1;
 DS1302WriteByte(0xBE); //寫入突發(fā)模式指令(Burst模式)
 for (i = 0; i < 8; i++)
 {
  DS1302WriteByte(date[i]);
 }
 DS1302_CE = 0;
 DS1302_SIO = 0;
}
/*Burst模式從DS1302寄存器中連續(xù)讀取八個(gè)字節(jié)的數(shù)據(jù)*/
void DS1302BurstRead(unsigned char * date)
{
 unsigned char i = 0;
 
 DS1302_CE = 1; //片選使能
 DS1302WriteByte(0xBF); //突發(fā)讀指令
 for (i = 0; i < 8; i++)
 {
  date[i] = DS1302ReadByte();
 }
 DS1302_CE = 0;
 DS1302_SIO = 0;
}
/*從DS1302中獲取當(dāng)前時(shí)間*/
void GetTimeFromDS1302(struct Time * time)
{
 unsigned char buff[8];//保存八個(gè)寄存器中的數(shù)據(jù)
 
 DS1302BurstRead(buff); //將DS1302寄存器中的數(shù)據(jù)讀入buff數(shù)組中
 
 time->year  = buff[6];//將年寄存器中的bcd碼取出來存入結(jié)構(gòu)體time->year中
 time->month = buff[4];
 time->week  = buff[5];
 time->day   = buff[3];
 time->hour  = buff[2];
 time->min   = buff[1];
 time->sec   = buff[0];
}
/*設(shè)置時(shí)間,將當(dāng)前修改后的時(shí)間值設(shè)置到DS1302中*/
void SetTimeToDS1302(struct Time * time)
{
 unsigned char buff[8]; //保存當(dāng)前修改后的time結(jié)構(gòu)體成員的值
 
 buff[0] = time->sec; //將秒寄存器中的值存入buff[0
 buff[1] = time->min;
 buff[2] = time->hour;
 buff[3] = time->day;
 buff[4] = time->month;
    buff[5] = time->week;
    buff[6] = time->year;
    buff[7] = 0x00;    //WP寫保護(hù)寄存器
   
    DS1302BurstWrite(buff); //將buff中的值以Burst模式寫入DS1302中
}
/*初始化DS1302*/
void InitDS1302()
{
 struct Time code InitTime[] = {0x14, 0x04, 0x22, 0x23, 0x59, 0x59, 0x02}; //2014年4月22日23:59:59
    unsigned char psec; //檢測(cè)DS1302的停止位CH
    /*初始化DS1302的通信引腳*/
    DS1302_SCK = 0;
    DS1302_CE  = 0;
   
    psec = DS1302ReadSingleByte(0x00); //0x00<<1 | 0x81=0x81, 讀取秒寄存器
    if ((psec & 0x80) != 0) //最高位CH=1,時(shí)鐘停止
    {
        DS1302WriteSingleByte(7, 0x00); //去除寫保護(hù)
        SetTimeToDS1302(InitTime); //將初始時(shí)間設(shè)置到DS1302中
    }   
}

 /**
  **************************************************************************
  * @file    :   Infrared.c
  * @author  :   xr
  * @date    :   2014年4月23日22:01:12
  * @version :   V1.2.3
  * @brief   :   紅外通信解碼-NEC協(xié)議解碼
  **************************************************************************
  */
 
#include <reg52.h>
//紅外通信引腳
sbit IRD = P3^3;//紅外通信引腳,外部中斷1引腳
bit flagIrd = 0; //紅外數(shù)據(jù)碼值接收完畢標(biāo)志位
unsigned char irdCode[4]; //保存NEC協(xié)議解碼的四個(gè)字節(jié)的數(shù)據(jù)碼(用戶碼+用戶反碼,鍵碼+鍵碼反碼)
/*紅外通信-定時(shí)器T1計(jì)數(shù)進(jìn)行紅外接收數(shù)據(jù)判定的時(shí)間獲取*/
void ConfigIrdByTimer1()
{
    TMOD &= 0x0F;//清零T1控制位
    TMOD |= 0x10;//使用T1方式1,16位可設(shè)定模式
    TH1 = 0;
    TL1 = 0;//開始時(shí)沒有紅外信號(hào),清零T1計(jì)數(shù)
    TR1 = 0;//開始時(shí)關(guān)閉T1計(jì)數(shù)
    ET1 = 0;//關(guān)閉T1中斷,只用T1計(jì)數(shù)功能
    /*外部中斷1配置*/
    IE1 = 0;//外部中斷1標(biāo)志位清零
    IT1 = 1;//設(shè)置外部中斷1為下降沿觸發(fā)
    EX1 = 1;//開啟外部中斷
    EA  = 1;//開總中斷
}
/*獲取IRD引腳即紅外引腳高電平T1計(jì)數(shù)值*/
unsigned int GetHighTimers()
{
    IRD = 1;//在檢測(cè)紅外引腳之前,要先將IRD引腳拉高釋放
    TH1 = 0;
    TL1 = 0;//先清零上一次的T1計(jì)數(shù)值
    TR1 = 1;//開啟T1計(jì)數(shù)
    while (IRD)
    {  //高電平T1進(jìn)行計(jì)數(shù)
        if (TH1 > 0x40) //0x40 * 256 * (12/11059200) * 1000 = 17.7ms
        {
            break; //當(dāng)時(shí)間>17.7ms時(shí)我們認(rèn)為是誤碼,強(qiáng)制退出
        }
    }
    TR1 = 0; //關(guān)閉T1計(jì)數(shù)
   
    return (TH1 * 256 + TL1); //返回IRD引腳高電平時(shí)T1的計(jì)數(shù)值
}
/*獲得低電平載波時(shí)間*/
unsigned int GetLowTimers()
{
    IRD = 1;//在檢測(cè)紅外引腳之前,要先將IRD引腳釋放
    TH1 = 0;
    TL1 = 0; //清零T1計(jì)數(shù)值
    TR1 = 1; //開啟T1計(jì)數(shù)
   
    while (!IRD)
    {
        //超時(shí)判斷
        if (TH1 > 0x40) //超出17.7ms就退出
        {
            break;
        }
    }
    TR1 = 0;//關(guān)閉T1計(jì)數(shù)
   
    return (TH1 * 256 + TL1);//返回T1計(jì)數(shù)值
}
/*外部中斷1服務(wù),判定紅外并接收紅外NEC解碼*/
void EXINT1_ISP() interrupt 2 //EXINT1中斷標(biāo)號(hào)為2
{
    unsigned char byte = 0;//接收解碼數(shù)據(jù)
    unsigned int time = 0;//接收引導(dǎo)碼和空閑與載波的時(shí)間
    unsigned char i, j;
   
    time = GetLowTimers();//載波 引導(dǎo)碼(9ms的載波+4.5ms的空閑):范圍(8.5ms-9.5ms)
    if ((time < 7833) ||(time > 8755))  //計(jì)數(shù)周期=12/11059200 計(jì)數(shù)時(shí)間=(TH1*256+TL1)*12/11059200
    {
        //誤碼,清零中斷標(biāo)志并退出中斷
        IE1 = 0;
        return;
    }
   
    time = GetHighTimers();//空閑 4.5ms的空閑:范圍:4ms-5ms
    if ((time < 3686) || (time > 4608)) //判斷時(shí)必須加上()
    {
        //不符合
        IE1 = 0;//外部中斷標(biāo)志位
        return; //退出中斷函數(shù)
    }       
    //引導(dǎo)碼正確,開始循環(huán)接收用戶碼和鍵碼
    for (i = 0; i < 4; i++) //接收4個(gè)字節(jié)數(shù)據(jù)
    {
        for (j = 0; j < 8; j++) //接收8位
        {
            time = GetLowTimers();//載波:560us載波+560us/1.68ms空閑:340us 760us
            if ((time < 313) || (time > 700))
            {
                //誤碼
                IE1 = 0;//清零外部中斷標(biāo)志
                return;
            }
            time = GetHighTimers();//空閑
            if ((time > 313) && (time < 700)) //560us的空閑,比特值'0'time大于340us并且time<780us
            {
                byte >>= 1;//低位在先,逐位接收,將數(shù)據(jù)位右移到低位
            }
            else if ((time > 1271) && (time < 1658))  //1.68ms空閑:范圍:1.38ms-1.8ms,比特值是'1'
            {
                byte >>= 1;//先右移一位,將這一位移到byte的最高位
                byte |= 0x80;//再將這一位置1
            }
            else
            {
                //接收的是誤碼
                IE1 = 0;//清零外部中斷1標(biāo)志位
                return;//退出中斷函數(shù)
            }
        }   
            irdCode[i] = byte;//接收碼值
    }
    flagIrd = 1;//接收完成標(biāo)志置1
    IE1 = 0;//清零外部中斷標(biāo)志
}

 /**
  ************************************************************************
 * @file    :   Keyboard.c
 * @author  :   xr
 * @date    :   2014年4月21日 22:23:12
 * @version :   V1.2.3
 * @brief   :   按鍵底層驅(qū)動(dòng)   單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
 ************************************************************************
 */
#include <reg52.h>
//KEY
sbit KEY_IN_1  = P2^4;
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;
static unsigned char volatile keySta[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1},
                                    {1, 1, 1, 1}, {1, 1, 1, 1}}; //16個(gè)按鍵當(dāng)前狀態(tài)
unsigned char pdata keyCodeMap[4][4] = {  //按鍵編碼根據(jù)ASCII碼進(jìn)行編碼
                                    {'1', '2', '3', 0x26}, //數(shù)字鍵1,2,3和向上鍵
                                    {'4', '5', '6', 0x25}, //數(shù)字鍵4,5,6和向左鍵
                                    {'7', '8', '9', 0x28}, //數(shù)字鍵7,8,9和向下鍵
                                    {'0', 0x1B, 0x0D, 0x27} //數(shù)字鍵0和ESC鍵,回車鍵,向右鍵
                                };
                                   
/*需要使用main.c文件中的struct Time類型的結(jié)構(gòu)體變量timeBuf,需要在重新進(jìn)行聲明*/
struct Time {
    unsigned char year;
    unsigned char month;
    unsigned char day;
    unsigned char hour;
    unsigned char min;
    unsigned char sec;
    unsigned char week;
};                    
extern struct Time timeBuf;
extern unsigned char setTimeIndex;//外部變量聲明
void LcdCoursorRight();
void LcdCoursorLeft();
void SetTimeBcdByte(unsigned char keyNum);
void KeyAction(unsigned char keycode);
extern void LcdRefreshSetCoursor();
extern void LcdCloseCoursor();
extern void IncTimeBysetTimeIndex();
extern void DecTimeBySetTimeIndex();
extern GetTimeFromDS1302(struct Time * time);
extern void SetTimeToDS1302(struct Time * time);
extern void RefreshLcdShowTime();
/*按鍵驅(qū)動(dòng),進(jìn)行按鍵狀態(tài)的判斷,傳遞相應(yīng)按鍵的鍵碼到按鍵動(dòng)作函數(shù)中*/
void KeyDriver()
{
    static unsigned char pdata keyBackup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1},
                                                  {1, 1, 1, 1}, {1, 1, 1, 1}}; //按鍵的備份即上一次按鍵的狀態(tài)值
    unsigned char i, j;
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            if (keySta[i][j] != keyBackup[i][j])
            {
                //按鍵有動(dòng)作
                if (keyBackup[i][j] != 0) //根據(jù)上一次的備份值來確定本次的按鍵值,即按鍵的動(dòng)作
                {
                    //按鍵按下,執(zhí)行動(dòng)作
                    KeyAction(keyCodeMap[i][j]); //傳遞相應(yīng)的鍵碼
                }
                //備份本次按鍵的值
                keyBackup[i][j] = keySta[i][j];
            }
        }
    }
}
/*按鍵的動(dòng)態(tài)掃描,進(jìn)行按鍵去抖*/
void KeyScan()
{
    static unsigned char keyout = 0;//按鍵行索引,每次都要用到上一次變化的keyout值所以定義為靜態(tài)變量
    static unsigned char keybuff[4][4] = {{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF},
                                          {0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}}; //按鍵掃描緩沖區(qū)
    unsigned char i = 0;
   
    /*掃描按鍵的值,并將按鍵的狀態(tài)值存入keybuff緩沖區(qū)中*/
    keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1; //將第keyout行的第一個(gè)按鍵的掃描值存入keybuff[keyout][0]緩沖區(qū)中
    keybuff[keyout][1] = (keybuff[keyout][1] << 1) | KEY_IN_2;
    keybuff[keyout][2] = (keybuff[keyout][2] << 1) | KEY_IN_3;
    keybuff[keyout][3] = (keybuff[keyout][3] << 1) | KEY_IN_4;
   
    /*更新掃描消抖后按鍵的狀態(tài)*/
    for (i = 0; i < 4; i++) //每行有四個(gè)按鍵需要進(jìn)行判斷
    {
        if ((keybuff[keyout][i] & 0x1F) == 0x00) //5次按鍵掃描值都是0,表示按鍵是穩(wěn)定按下
        {
            keySta[keyout][i] = 0;
        }
        else if ((keybuff[keyout][i] & 0x1F) == 0x1F) //5次按鍵的掃描值都是1,表示按鍵是穩(wěn)定彈起
        {
            keySta[keyout][i] = 1;
        }
    }
    //行++
    keyout++;
    keyout &= 0x03;//實(shí)現(xiàn)到4歸零
   
    /*根據(jù)keyout的值來確定選擇哪一行按鍵進(jìn)行掃描*/
    switch (keyout)
    {
        case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;//掃描第1行
        case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;//掃描第2行
        case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;//掃描第3行
        case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;//掃描第4行
        default: break;
    }
}
/*按鍵動(dòng)作,根據(jù)按鍵的鍵碼來執(zhí)行相應(yīng)的操作*/
void KeyAction(unsigned char keycode)
{
    if (keycode >= '0' && keycode <= '9')
    {
        if (setTimeIndex != 0) //處于設(shè)置狀態(tài)才相應(yīng)
        SetTimeBcdByte(keycode - '0'); //數(shù)字鍵設(shè)置時(shí)間
    }
    else if (keycode == 0x26)  //向上鍵進(jìn)行光標(biāo)閃爍位置上的數(shù)值的++
    {
        IncTimeBysetTimeIndex();//遞增BCD碼的高位或低位數(shù)字
    }
    else if (keycode == 0x27) //向右鍵進(jìn)行進(jìn)行光標(biāo)位置的右移
    {
       if (setTimeIndex != 0) //處于設(shè)置狀態(tài)才相應(yīng)
       LcdCoursorRight();//遞減BCD碼的高位或低位數(shù)字
    }
    else if (keycode == 0x25) //向左鍵進(jìn)行光標(biāo)閃爍位置的左移
    {
        if (setTimeIndex != 0)
        LcdCoursorLeft();
    }
    else if (keycode == 0x28) //向下鍵光標(biāo)閃爍位置上的數(shù)值的遞減
    {
        DecTimeBySetTimeIndex();
    }
    else if (keycode == 0x1B) //ESC鍵,取消當(dāng)前的設(shè)置
    {
        setTimeIndex = 0;//時(shí)鐘正常運(yùn)行索引=0
        LcdCloseCoursor();//關(guān)閉光標(biāo)閃爍
    }
    else if (keycode == 0x0D) //回車鍵,進(jìn)行設(shè)置時(shí)間和恢復(fù)時(shí)鐘運(yùn)行的狀態(tài)的切換
    {
        if (setTimeIndex == 0) //正常運(yùn)行狀態(tài),開始切換到設(shè)置狀態(tài)
        {
            setTimeIndex = 1;
            LcdRefreshSetCoursor();//刷新光標(biāo)閃爍位置并讓光標(biāo)閃爍
        }
        else
        {
            //寫入設(shè)置的時(shí)間值,并切換到正常運(yùn)行狀態(tài)
            SetTimeToDS1302(&timeBuf);
            GetTimeFromDS1302(&timeBuf);
            setTimeIndex = 0;
            LcdCloseCoursor();//關(guān)閉光標(biāo)閃爍
        }
    }
}
/*setTimeIndex++,實(shí)現(xiàn)設(shè)置光標(biāo)閃爍的右移*/
void LcdCoursorRight()
{
    if (setTimeIndex < 12)
        setTimeIndex++;//光標(biāo)設(shè)置索引++
    else
        setTimeIndex = 1;       
    LcdRefreshSetCoursor();
}
/*setTimeIndex--,實(shí)現(xiàn)設(shè)置光標(biāo)閃爍的左移*/
void LcdCoursorLeft()
{
    if (setTimeIndex > 1)
        setTimeIndex--;//光標(biāo)設(shè)置索引--
    else
        setTimeIndex = 12;
    LcdRefreshSetCoursor();
}
/*設(shè)置BCD碼的高位數(shù)字*/
unsigned char SetBCDHighByte(unsigned char bcd, unsigned char keyNum)
{
    bcd &= 0x0F;//清零高位
    bcd |= (keyNum << 4); //keyNum移至高位
   
    return (bcd);
}
/*設(shè)置BCD碼的低位數(shù)字*/
unsigned char SetBCDLowByte(unsigned char bcd, unsigned char keyNum)
{
    bcd &= 0xF0;//低位清零
    bcd |= keyNum; //將keyNum數(shù)字放到低位
   
    return (bcd); //返回改變后的bcd字節(jié)數(shù)據(jù)
}
/*通過按鍵值設(shè)置時(shí)間值(設(shè)置時(shí)間值的高位和低位數(shù)字)*/
void SetTimeBcdByte(unsigned char keyNum) //傳遞按鍵的數(shù)值
{
    switch (setTimeIndex)
    {
        case 1: timeBuf.year  = SetBCDHighByte(timeBuf.year, keyNum); break;//設(shè)置年的高位BCD字節(jié)
        case 2: timeBuf.year  = SetBCDLowByte(timeBuf.year, keyNum); break; //設(shè)置年的低位BCD字節(jié)
        case 3: timeBuf.month = SetBCDHighByte(timeBuf.month, keyNum); break;
        case 4: timeBuf.month = SetBCDLowByte(timeBuf.month, keyNum); break;
        case 5: timeBuf.day   = SetBCDHighByte(timeBuf.day, keyNum); break;
        case 6: timeBuf.day   = SetBCDLowByte(timeBuf.day, keyNum); break;
        case 7: timeBuf.hour  = SetBCDHighByte(timeBuf.hour, keyNum); break;
        case 8: timeBuf.hour  = SetBCDLowByte(timeBuf.hour, keyNum); break;
        case 9: timeBuf.min   = SetBCDHighByte(timeBuf.min, keyNum); break;
        case 10: timeBuf.min  = SetBCDLowByte(timeBuf.min, keyNum); break;
        case 11: timeBuf.sec  = SetBCDHighByte(timeBuf.sec, keyNum); break;
        case 12: timeBuf.sec  = SetBCDLowByte(timeBuf.sec, keyNum); break;
    }
    RefreshLcdShowTime();   //刷新時(shí)間值顯示
    LcdCoursorRight();      //光標(biāo)閃爍右移
    LcdRefreshSetCoursor(); //刷新光標(biāo)閃爍
}

 
關(guān)閉窗口

相關(guān)文章