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

單片機開源項目之基于DS18B20的帶記憶功能溫度報警系統(tǒng)源碼

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

 此程序是基于51hei單片機開發(fā)板上面做的,如需要移植到自己的電路上,修改相應(yīng)的端口即可,開發(fā)板完整的電路圖下載:  點這里 (注意:只需要看相關(guān)部分即可如 溫感 數(shù)碼管 蜂鳴器的使用的端口的連線,其他部分可以忽略)

 /**
  ***********************************************************************************************************
  * @file      :  main.c
  * @author    :  徐冉
  * @date      :  2014年4月27日08:40:23 ~ 2014年5月1日23:03:58
  * @version   :  V1.2.3
  * @brief     :  基于DS18B20的帶記憶功能溫度報警系統(tǒng)  單片機STC89C52RC MCU 晶振 : 11.0592MHZ
  * @note      :  溫度報警值可由開發(fā)板鍵盤和紅外遙控器按鍵進行調(diào)整,調(diào)整后下次上電將保存上一次的調(diào)整值
  * ------------  溫度報警系統(tǒng)有三種狀態(tài):當(dāng)溫度達到設(shè)定的高溫預(yù)警值范圍時LED點陣將顯示"火",同時蜂鳴器
  * ------------  以8000HZ的頻率發(fā)聲報警,且LED小燈全亮;當(dāng)溫度達到設(shè)定的低溫預(yù)警值時LED點陣屏將顯示“水”,
  * ------------  蜂鳴器將以4000HZ的頻率報警,且LED小燈全亮;當(dāng)溫度處于正常溫度值時,LED點陣屏顯示“心形”,
  * ------------  蜂鳴器處于關(guān)閉狀態(tài),且LED小燈全部熄滅。
  ***********************************************************************************************************
  */
#include <reg52.h>

//74HC138
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
//蜂鳴器
sbit BUZZ = P1^6;
//數(shù)碼管編碼表
unsigned char code LedTable[] = {
                0xC0,  //"0"
                0xF9,  //"1"
                0xA4,  //"2"
                0xB0,  //"3"
                0x99,  //"4"
                0x92,  //"5"
                0x82,  //"6"
                0xF8,  //"7"
                0x80,  //"8"
                0x90,  //"9"
                0x9C,  // '小0'
                0xC6,  //'C'
                0xBF   //"-"
            };
//數(shù)碼管顯示緩沖區(qū)+LED獨立小燈
unsigned char idata LedBuff[] = {0xC6, 0x9C, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
//點陣取模
unsigned char pdata LedCode[3][8] = {
                            {0xFF,0x99,0x00,0x00,0x00,0x81,0xC3,0xE7}, //heart
                            {0xF7,0xD5,0xD5,0xE6,0xF7,0xEB,0xDD,0xBE}, //fire
                            {0xF7,0x77,0xA0,0xC3,0xE5,0xD6,0xB7,0x71}  //water
                           };
 
/**************************local values definition***********************************/
//溫度狀態(tài)
unsigned char idata tempSta = 0;//0表示正常溫度,1表示高溫,2表示低溫
bit flag2s = 0;
unsigned char setTempIndex = 0;//0-正常運行狀態(tài) 1-8報警溫度設(shè)定索引
unsigned char thr0, tlr0;//T0定時器重載值
unsigned int counter = 0;//計數(shù)器
unsigned char idata thr1, tlr1;//00H-70H內(nèi)存不夠,使用70H-FFH內(nèi)存
signed int temp;//存儲溫度值
bit buzzflag = 0;//蜂鳴器啟動標(biāo)志
//定義報警溫度的上限值和下限值范圍(以下溫度值是*10之后的溫度值)溫度值分正負且都是int型
signed int shangxianHigh = 300, shangxianLow = 280;//溫度上限值高溫度值和低溫度值
signed int xiaxianHigh = 200, xiaxianLow = 180;    //溫度下限值的高溫度值和低溫度值
signed char num[8] = {0, 0, 0, 0, 0, 0, 0, 0};//保存報警溫度值十位數(shù)和個位數(shù)
extern bit flagIrd;         //紅外解碼完成標(biāo)志
extern unsigned char IrdCode[4];//裝載紅外解碼值
/**************************local function definition***********************************/
void ConfigTimer0(unsigned int xms);
void TempToLedBuf(signed int temp);
void TempertureWarning(signed int temp);
void ConfigBuzzFr(unsigned int fr);
void ReadE2PROMToNumArrary();
/**************************extern function definition***********************************/
extern void KeyDrive();
extern void KeyScan();
extern void LCD1602RefreshCoursor();
extern void InitLCD1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);
extern bit StartConvertTemp();
extern bit ReadDS18B20Temperture(signed int * temperture);
extern void WriteEEPROMByte(unsigned char addr, unsigned char dat);
extern unsigned char ReadEEPROMByte(unsigned char addr);
extern void LEDRefreshPause();
extern void ContinueRefreshLED();
extern void ConfigInfrared();
extern void IrdKeyDrive();
/*主函數(shù)main()*/
void main(void)
{
    ADDR3 = 1;
    ENLED = 0;//選擇LED
    InitLCD1602();
    ConfigTimer0(1);//T0定時1ms
    ConfigInfrared();
    //ConfigBuzzFr(1000);//默認設(shè)定蜂鳴器頻率為1000
   
    StartConvertTemp();//啟動一次溫度轉(zhuǎn)換
   
    LcdShowStr(0, 0, "high T: XX-XX 'C");
    LcdShowStr(0, 1, "low  T: XX-XX 'C");//LCD初始化顯示
   
    ReadE2PROMToNumArrary();
    EA = 1; //打開總中斷
   
    while (1)
    {
        KeyDrive(); //檢測按鍵動作
        if (flagIrd)
        {
            flagIrd = 0;
            IrdKeyDrive();//紅外按鍵檢測
        }
        if (flag2s)
        {
            flag2s = 0;
           
            if (ReadDS18B20Temperture(&temp))
            {
                TempToLedBuf(temp); //將溫度值轉(zhuǎn)換成數(shù)碼管數(shù)字并檢測溫度是否超限,超限啟動聲光報警!
                StartConvertTemp();//再次啟動溫度轉(zhuǎn)換
            }
        }
    }
}
/*將eeprom的存儲的報警溫度值的各個位數(shù)字讀取到num[8]數(shù)組中*/
void ReadE2PROMToNumArrary()
{
    unsigned char str[4];
   
    //數(shù)碼管初始化顯示0.00
    LedBuff[2] = LedTable[0];
    LedBuff[3] = LedTable[0];
    LedBuff[4] = LedTable[0];
    LedBuff[3] &= 0x7F;//add point
   
    /*讀取eeprom中的數(shù)據(jù)*/
    num[0] = ReadEEPROMByte(0x00);
    num[1] = ReadEEPROMByte(0x01);
    num[2] = ReadEEPROMByte(0x02);
    num[3] = ReadEEPROMByte(0x03);
    num[4] = ReadEEPROMByte(0x04);
    num[5] = ReadEEPROMByte(0x05);
    num[6] = ReadEEPROMByte(0x06);
    num[7] = ReadEEPROMByte(0x07);
    LedBuff[6] = 0x7F;//讀取成功指示
   
    /*初始化更新設(shè)定的報警溫度值*/
    shangxianLow  = (num[0] * 100 + num[1] * 10);
    shangxianHigh = (num[2] * 100 + num[3] * 10);
    xiaxianLow    = (num[4] * 100 + num[5] * 10);
    xiaxianHigh   = (num[6] * 100 + num[7] * 10);
   
    /*將報警溫度值顯示到LCD1602上*/
    str[0] = num[0] + '0';
    str[1] = num[1] + '0';
    str[2] = '\0';
    LcdShowStr(8, 0, str);
    str[0] = num[2] + '0';
    str[1] = num[3] + '0';
    str[2] = '\0';
    LcdShowStr(11, 0, str);
    str[0] = num[4] + '0';
    str[1] = num[5] + '0';
    str[2] = '\0';
    LcdShowStr(8, 1, str);
    str[0] = num[6] + '0';
    str[1] = num[7] + '0';
    str[3] = '\0';
    LcdShowStr(11, 1, str);  
}
/*將溫度值轉(zhuǎn)換為有效數(shù)字存儲到LedBuff中*/
void TempToLedBuf(signed int temp)
{
    unsigned char buf[6];//緩沖區(qū)
    signed char i = 0;   //i必須是有符號型數(shù)據(jù)
    if (temp < 0) //負溫度值
    {
        buf[5] = LedTable[12];//添加負號
        //保留一位小數(shù)
        temp = (~temp + 1) * 0.0625 * 10;//負值,讀取到的16位二進制數(shù)值取反+1再*分辨率0.0625
        for (i = 0; i < 4; i++) //溫度值最高3位數(shù)值+小數(shù)位
        {
            buf[i] = temp % 10;
            temp /= 10;
        }
        //去掉無效位數(shù)字
        for (i = 3; i > 1; i--)
        {
            if (buf[i] == 0)
            {
                buf[i] = 0xFF;//去掉高位0不顯示
            }
            else
            {
                break;//遇到第一個有效數(shù)字就退出
            }
        }
        //轉(zhuǎn)換為實際的有效數(shù)字
        for (; i >= 0; i--)
        {
            buf[i] = LedTable[buf[i]];
        }
        //將實際數(shù)字拷貝到數(shù)碼管緩沖區(qū)中
        for (i = 0; i < 4; i++)
        {
            LedBuff[i+2] = buf[i];
        }
    }
    else
    {  
        //溫度值大于等于0,保留一位小數(shù)位
        temp = (temp * 0.0625 * 10);//直接用讀取到的16位二進制數(shù)值*分辨率即是實際的溫度值
        TempertureWarning(temp);    //溫度報警檢測必須函數(shù)必須放在前面
       
        for (i = 0; i < 4; i++)
        {
            buf[i] = temp % 10;
            temp /= 10;
        }
        //去掉高位的0
        for (i = 3; i > 1; i--)
        {
            if (buf[i] == 0)
            {
                buf[i] = 0xFF;
            }
            else
            {
                break;//遇到第一個有效數(shù)字就退出
            }
        }
        //轉(zhuǎn)換為實際的有效數(shù)字
        for (; i >= 0; i--)
        {
            buf[i] = LedTable[buf[i]];
        }
        //拷貝到緩沖區(qū)
        for (i = 0; i < 4; i++)
        {
            LedBuff[i+2] = buf[i]; //最低兩位顯示溫度標(biāo)示符
        }
    }
    //在相應(yīng)的位置點上小數(shù)點
    LedBuff[3] &= 0x7F;//0 111 1111
}
/*刷新LCD設(shè)置位置上的數(shù)字顯示*/
void RefreshLCDDisplay()
{
    unsigned char str[3];//字符串緩沖區(qū)
    switch (setTempIndex)
    {
        case 1: str[0] = num[0] + '0'; str[1] = '\0'; LcdShowStr(8, 0, str);  break;
        case 2: str[0] = num[1] + '0'; str[1] = '\0'; LcdShowStr(9, 0, str);  break;//shangxianLow的十位和個位數(shù)字顯示刷新
        case 3: str[0] = num[2] + '0'; str[1] = '\0'; LcdShowStr(11, 0, str); break;
        case 4: str[0] = num[3] + '0'; str[1] = '\0'; LcdShowStr(12, 0, str); break;
        case 5: str[0] = num[4] + '0'; str[1] = '\0'; LcdShowStr(8, 1, str);  break;
        case 6: str[0] = num[5] + '0'; str[1] = '\0'; LcdShowStr(9, 1, str);  break;
        case 7: str[0] = num[6] + '0'; str[1] = '\0'; LcdShowStr(11, 1, str); break;
        case 8: str[0] = num[7] + '0'; str[1] = '\0'; LcdShowStr(12, 1, str); break;
        default: break;
    }
    LCD1602RefreshCoursor();
}
/*響應(yīng)按鍵值來設(shè)置溫度報警值*/
void SetTempByKeyNum(unsigned char keyNum)
{
    switch (setTempIndex)
    {
        case 1: num[0] = keyNum; break;
        case 2: num[1] = keyNum; break;
        case 3: num[2] = keyNum; break;
        case 4: num[3] = keyNum; break;
        case 5: num[4] = keyNum; break;
        case 6: num[5] = keyNum; break;
        case 7: num[6] = keyNum; break;
        case 8: num[7] = keyNum; break;
        default: break;
    }
    RefreshLCDDisplay();
    setTempIndex++;//光標(biāo)右移
    if (setTempIndex > 8)
    setTempIndex = 1;//設(shè)置光標(biāo)回返
    LCD1602RefreshCoursor();  
}
/*光標(biāo)閃爍位置數(shù)字遞增*/
void IncCoursorNum()
{
    switch (setTempIndex)
    {
        case 1:  {if (num[0] < 9) num[0]++; else num[0] = 0; break;} //十位數(shù)字++后重新設(shè)置溫度值
        case 2:  {if (num[1] < 9) num[1]++; else num[1] = 0; break;}//shangxianLow是小數(shù)*10之后的值
        case 3:  {if (num[2] < 9) num[2]++; else num[2] = 0; break;}
        case 4:  {if (num[3] < 9) num[3]++; else num[3] = 0; break;}
        case 5:  {if (num[4] < 9) num[4]++; else num[4] = 0; break;}
        case 6:  {if (num[5] < 9) num[5]++; else num[5] = 0; break;}
        case 7:  {if (num[6] < 9) num[6]++; else num[6] = 0; break;}
        case 8:  {if (num[7] < 9) num[7]++; else num[7] = 0; break;}
        default: break;
    }
   RefreshLCDDisplay();//刷新設(shè)置位置上的數(shù)字顯示
   LCD1602RefreshCoursor();//再次刷新光標(biāo)顯示
}
/*光標(biāo)閃爍位置數(shù)字遞減*/
void DecCoursorNum()
{
    switch (setTempIndex)  //根據(jù)光標(biāo)閃爍的索引來遞減相應(yīng)位置的數(shù)字
    {
        case 1:  {if (num[0] > 0) --num[0]; else num[0] = 9; break;} //十位數(shù)字++后重新設(shè)置溫度值
        case 2:  {if (num[1] > 0) --num[1]; else num[1] = 9; break;}//shangxianLow是小數(shù)*10之后的值
        case 3:  {if (num[2] > 0) --num[2]; else num[2] = 9; break;}
        case 4:  {if (num[3] > 0) --num[3]; else num[3] = 9; break;}
        case 5:  {if (num[4] > 0) --num[4]; else num[4] = 9; break;}
        case 6:  {if (num[5] > 0) --num[5]; else num[5] = 9; break;}
        case 7:  {if (num[6] > 0) --num[6]; else num[6] = 9; break;}
        case 8:  {if (num[7] > 0) --num[7]; else num[7] = 9; break;}
        default: break;
    }
    RefreshLCDDisplay();
    LCD1602RefreshCoursor();//刷新光標(biāo)閃爍
}
/*設(shè)置報警溫度值*/
void SetWarningTemperture()
{
    /*設(shè)置溫度報警值*/
    shangxianLow  = (num[0] * 100 + num[1] * 10);
    shangxianHigh = (num[2] * 100 + num[3] * 10);
    xiaxianLow    = (num[4] * 100 + num[5] * 10);
    xiaxianHigh   = (num[6] * 100 + num[7] * 10);
   
    /*將數(shù)據(jù)保存到eeprom中*/
    WriteEEPROMByte(0x00, num[0]);
    WriteEEPROMByte(0x01, num[1]);
    WriteEEPROMByte(0x02, num[2]);
    WriteEEPROMByte(0x03, num[3]);
    WriteEEPROMByte(0x04, num[4]);
    WriteEEPROMByte(0x05, num[5]);
    WriteEEPROMByte(0x06, num[6]);
    WriteEEPROMByte(0x07, num[7]);
    LedBuff[6] = 0xFE;//寫入成功指示
}
/*溫度報警檢測*/
void TempertureWarning(signed int temp)
{
    if ((temp > xiaxianLow) && (temp < xiaxianHigh)) //溫度在18.0-20.0度進行低溫報警
    {
        buzzflag = 1;//啟動報警器
        ConfigBuzzFr(4000); //蜂鳴器發(fā)聲頻率2000HZ
        LedBuff[6] = 0x00;//低溫亮8個LED小燈
        tempSta = 2;//water
    }
    else if ((temp > shangxianLow) && (temp < shangxianHigh)) //溫度在28.0-30.0度進行高溫報警
    {
        buzzflag = 1;
        ConfigBuzzFr(8000);//蜂鳴器發(fā)聲頻率5000HZ
        LedBuff[6] = 0x00;//高溫亮八個LED小燈
        tempSta = 1;//fire
    }
    else
    {
        buzzflag = 0;//關(guān)閉報警器
        LedBuff[6] = 0xFF;//關(guān)閉報警燈
        tempSta = 0;//heart
    }
}
/*配置T0定時器,由于刷新時間的要求,定時xms時間*/
void ConfigTimer0(unsigned int xms)
{
    unsigned long tmp;
    tmp = 11059200/12;//周期頻率
    tmp = (tmp * xms) / 1000;//定時xms需要的計數(shù)值
    tmp = 65536 - tmp;//定時xms的定時器裝入初值
    thr0 = (unsigned char)(tmp >> 8);
    tlr0 = (unsigned char)tmp;
    TMOD &= 0xF0;//清零T0控制位
    TMOD |= 0x01;//T0方式1,16位定時器可以設(shè)定
    TH0 = thr0;
    TL0 = tlr0;
    TR0 = 1;//開啟T0定時器
    ET0 = 1;//開定時器T0中斷
}
/*數(shù)碼管刷新*/
void RefreshLEDChar()
{
    static unsigned char index = 0;
    P0 = 0xFF;//消隱
    ADDR3 = 1;
    if ((ENLED == 0) && (ADDR3 == 1))
    {
        P1 &= 0xF8;//清零P1口低三位
        P1 |= index;//index控制三八譯碼器選擇地址
        P0 = LedBuff[index++];
        if (index > 6) //刷新LEDS0-LEDS6,6個數(shù)碼管+LED小燈
        {
            index = 0;
        }
    }
}
/*刷新點陣屏*/
void RefreshLed()
{
    static unsigned char index = 0;
    P0 = 0xFF;   
    ADDR3 = 0;
    if ((ENLED == 0) && (ADDR3 == 0))
    {
        P1 &= 0xF8;//清零P1口低三位
        P1 |= index;
        P0 = LedCode[tempSta][index++];//tempSta == 0表示溫度正常
        if (index > 7)
        index = 0;
        //index &= 0x07;//到8歸0
    }
}
/*配置蜂鳴器發(fā)聲頻率fr*/
void ConfigBuzzFr(unsigned int fr)
{
    unsigned long tmp = 0;
    tmp = 11059200/12; //周期頻率
    tmp = tmp / fr;    //設(shè)定fr頻率需要的計數(shù)值
    tmp = 65536 - tmp;//設(shè)定fr頻率需要裝入的計數(shù)初值
    thr1 = (unsigned char)(tmp >> 8);
    tlr1 = (unsigned char)tmp;       //計數(shù)值高低字節(jié)
    TMOD &= 0x0F; //清零T1控制位
    TMOD |= 0x10; //配置T1工作方式1,16位定時器模式
    TH1 = thr1;
    TL1 = tlr1;
    TR1 = 1;//開啟T1
    ET1 = 1;//開啟定時器T1中斷
}
/*定時器T0中斷服務(wù)*/
void Timer0_ISP() interrupt 1
{  
    static bit biv = 0;
    TH0 = thr0;
    TL0 = tlr0;//重新裝入初值
    counter++;
    KeyScan();        //掃描按鍵
    RefreshLEDChar(); //1ms數(shù)碼管顯示刷新    
    if (!biv)         //2ms
    {
        RefreshLed();//點陣刷新 
    }
    biv = ~biv;           //分頻
   
    if (counter >= 2000)
    {
        counter = 0;//2s
        flag2s = 1;
    }
}
/*定時器T1中斷服務(wù)配置蜂鳴器的發(fā)聲頻率*/
void Timer1_ISP() interrupt 3
{
    TH1 = thr1;
    TL1 = tlr1;
    if (buzzflag)
    {
        BUZZ = ~BUZZ;//以frHZ驅(qū)動蜂鳴器發(fā)聲
    }
}

 /**
  ***********************************************************************************************
  * @file      :  lcd1602.c
  * @author    :  xr
  * @date      :  2014年4月27日08:40:23
  * @version   :  V1.2.3
  * @brief     :  LCD1602驅(qū)動
  ***********************************************************************************************
  */
#include <reg52.h>
//LCD1602
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_EN = P1^5;
//74HC138
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
bit tmpADDR0 = 0;
bit tmpADDR1 = 0;//地址選擇緩沖區(qū)
/**************************local function definition***********************************/
void ContinueRefreshLED();
void LEDRefreshPause();
/*LCD1602忙碌等待*/
void LCD1602Wait()
{
    unsigned char sta;
    P0 = 0xFF;//讀狀態(tài)前先拉高P0口
   
    /*讀狀態(tài)*/
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    LCD1602_EN = 0;
   
    do
    {
        LCD1602_EN = 1;
        sta = P0;
        LCD1602_EN = 0;//關(guān)閉液晶輸出使能,避免液晶輸出數(shù)據(jù)影響總線上的其他器件
    } while (sta & 0x80); //狀態(tài)字的最高位如果為1則表示液晶忙碌,禁止操作
}
/*暫停LED掃描*/
void LEDRefreshPause()
{
    ENLED = 1;//關(guān)閉LED使能
    tmpADDR0 = ADDR0;//因為LED和LCD同時使用了P1^0和P1^1引腳,所以要暫時保存ADDR0和ADDR1的數(shù)據(jù)即LED掃描地址值
    tmpADDR1 = ADDR1;
    P0 = 0xFF;  //數(shù)碼管+LED小燈去抖動
}
/*繼續(xù)掃描LED*/
void ContinueRefreshLED()
{
    ADDR0 = tmpADDR0;
    ADDR1 = tmpADDR1;//恢復(fù)原來LED掃描的地址選擇值
    ENLED = 0;//選擇LED
    P0 = 0xFF; //數(shù)碼管和LED去抖
}
/*LCD1602寫命令*/
void LCD1602WriteCmd(unsigned char cmd)
{  
    LEDRefreshPause();//暫停LED掃描
    //讀寫之前都要進行液晶的忙碌等待
    LCD1602Wait();
   
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_EN = 0;
    P0 = cmd;//送入命令
    LCD1602_EN = 1;//高脈沖
    LCD1602_EN = 0;//恢復(fù)原電平狀態(tài),關(guān)閉液晶輸出
   
    ContinueRefreshLED();//繼續(xù)掃描LED(數(shù)碼管+獨立LED小燈)
}
/*LCD1602寫數(shù)據(jù)*/
void LCD1602WriteData(unsigned char dat)
{
    LEDRefreshPause();//暫停LED掃描
    LCD1602Wait();
   
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_EN = 0;
    P0 = dat;
    LCD1602_EN = 1;//高脈沖
    LCD1602_EN = 0;
   
    ContinueRefreshLED();//繼續(xù)掃描LED
}
/*液晶初始化*/
void InitLCD1602()
{
    LCD1602WriteCmd(0x38);
    LCD1602WriteCmd(0x0C);
    LCD1602WriteCmd(0x06);
    LCD1602WriteCmd(0x01);
}
/*設(shè)置光標(biāo)位置*/
void LCD1602SetCoursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
   
    if (y == 0) //第一行
    {
        addr = 0x00 + x;//x為地址偏移
    }
    else
    {
        addr = 0x40 + x;
    }
    LEDRefreshPause();
    LCD1602WriteCmd(addr + 0x80);//寫光標(biāo)地址
    ContinueRefreshLED();
}
/*打開光標(biāo)閃爍*/
void OpenCoursor()
{
    LCD1602WriteCmd(0x0F);//顯示光標(biāo),且光標(biāo)閃爍
}
/*關(guān)閉光標(biāo)*/
void CloseCoursor()
{      
    LCD1602WriteCmd(0x0C);//關(guān)閉光標(biāo)
}
/*寫str字符串到液晶的坐標(biāo)(x, y)上*/
void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str)
{
    unsigned char addr;
   
    if (y == 0)
    {
        addr = 0x00 + x;
    }
    else
    {
        addr = 0x40 + x;
    }
    LEDRefreshPause();
    LCD1602WriteCmd(addr + 0x80);
    ContinueRefreshLED();
    while (*str != '\0')
    {
        LEDRefreshPause();
        LCD1602WriteData(*str++);
        ContinueRefreshLED();
    }
}

/**
  ***********************************************************************************************
  * @file      :  ds18b20.c
  * @author    :  xr
  * @date      :  2014年4月27日08:40:23
  * @version   :  V1.2.3
  * @brief     :  DS18B20驅(qū)動
  ***********************************************************************************************
  */
#include <reg52.h>
#include <intrins.h>
//DS18B20_IO
sbit DS18B20_IO = P3^2;//1ware總線引腳
/*DS18B20操作時間,延時x*10us*/
void DelayX10us(unsigned char x10us)
{
    do
    {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_(); //大約延時10us
    } while (x10us--);
}
/*復(fù)位DS18B20,讀取DS18B20存在脈沖*/
bit ReadDS18B20Ack()
{
    bit ack = 0;
   
    EA = 0;//先關(guān)閉所有中斷,以避免中斷時間影響DS18B20操作
    DS18B20_IO = 0;//拉低
    DelayX10us(70); //延時700us
    DS18B20_IO = 1;
    DelayX10us(6); //延時60us一定可以讀取到DS18B20的應(yīng)答
    ack = DS18B20_IO;//讀取存在脈沖
    while (!DS18B20_IO);//等待DS18B20復(fù)位結(jié)束
    EA = 1;//打開中斷
   
    return (ack);
}
/*寫一個字節(jié)數(shù)據(jù)到DS18B20總線上*/
void WriteDS18B20Byte(unsigned char byte)
{
    unsigned char mask = 0x01;//最低位開始寫
    EA = 0;//關(guān)閉中斷
    for (mask = 0x01; mask != 0; mask <<= 1)
    {
        DS18B20_IO = 0;//拉低
        _nop_();
        _nop_();//延時2us
        if ((byte & mask) != 0)
        {
            DS18B20_IO = 1;//發(fā)送1
        }
        else
        {
            DS18B20_IO = 0;//發(fā)送0
        } //拉低延時到把數(shù)據(jù)送入總線上的時間不得超過15us,15us后DS18B20進行對總線進行采樣
        DelayX10us(6);//延時60us,等待DS18B20采樣完成
        DS18B20_IO = 1;//釋放總線
    }  
    EA = 1;//打開中斷
}
/*從DS18B20讀一個字節(jié)的數(shù)據(jù)*/
unsigned char ReadDS18B20Byte()
{
    unsigned char mask = 0x01;//接收數(shù)據(jù)探測掩碼
    unsigned char byte = 0;
   
    EA = 0;//關(guān)閉中斷
    for (mask = 0x01; mask != 0; mask <<= 1) //低位在先,逐位接收
    {
        DS18B20_IO = 0;
        _nop_();
        _nop_();//先拉低總線2us
        DS18B20_IO = 1;
        _nop_();
        _nop_();//再拉高總線2us,然后主機進行對DS18B20_IO總線采樣
        if (DS18B20_IO != 0)
        {
            byte |= mask;//相應(yīng)位置1
        }
        else
        {
            byte &= (~mask);//相應(yīng)位清零
        }//主機在將DS18B20拉低再拉高,然后主機進行采樣,時間不超過15us
        DelayX10us(6); //延時60us,這時總線將被上拉電阻拉高
    }
    EA = 1;//開中斷
   
    return (byte); //返回接收到的數(shù)據(jù)
}   
/*啟動溫度轉(zhuǎn)換Convert Temperature*/
bit StartConvertTemp()
{
    bit ack;
   
    ack = ReadDS18B20Ack();//復(fù)位總線,并讀取DS18B20存在脈沖
   
    if (ack == 0) //讀取到復(fù)位脈沖
    {
        WriteDS18B20Byte(0xCC);//跳過ROM尋址
        WriteDS18B20Byte(0x44);//啟動溫度轉(zhuǎn)換
    }
   
    return (~ack);//ack==0表示溫度啟動轉(zhuǎn)換成功
}
/*讀取溫度值,將溫度值保存到*temperture中,并返回應(yīng)答ack*/
bit ReadDS18B20Temperture(signed int * temperture)
{
    unsigned char lsb, msb;
    bit ack = 0;
   
    ack = ReadDS18B20Ack();//復(fù)位總線,并讀取DS18B20存在脈沖
   
    if (ack == 0)
    {
        WriteDS18B20Byte(0xCC);//跳過ROM
        WriteDS18B20Byte(0xBE);//讀暫存數(shù)據(jù)寄存器
        lsb = ReadDS18B20Byte();//讀溫度值低字節(jié)數(shù)據(jù)
        msb = ReadDS18B20Byte();//讀溫度值高字節(jié)數(shù)據(jù)
        /*將溫度值的高低字節(jié)合并成int型數(shù)據(jù)并存入*temperture中*/
        *temperture = ((unsigned int)(msb) << 8) + lsb;
    }
   
    return (~ack);//ack==0則表示溫度值讀取成功
}

/**
  ***********************************************************************************************
  * @file      :  main.c
  * @author    :  xr
  * @date      :  2014年4月27日20:26:26
  * @version   :  V1.2.3
  * @brief     :  按鍵驅(qū)動程序
  ***********************************************************************************************
  */
#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;
//按鍵當(dāng)前狀態(tài)
unsigned char keySta[4][4] = {1, 1, 1, 1, 1, 1, 1, 1,
                              1, 1, 1, 1, 1, 1, 1, 1};
//按鍵到PC標(biāo)準(zhǔn)鍵盤編碼
unsigned char keyCodeMap[4][4] = {
                    '1', '2', '3', 0x26, //數(shù)字鍵123,向上鍵
                    '4', '5', '6', 0x25, //數(shù)字鍵456,向左鍵
                    '7', '8', '9', 0x28, //數(shù)字鍵789,向下鍵
                    '0', 0x1B, 0x0D, 0x27 //數(shù)字鍵0,向右鍵
                };
/*紅外遙控器鍵碼對應(yīng)標(biāo)準(zhǔn)PC鍵盤編碼,21個鍵碼*/
unsigned char code IrdKeyCode[21][2] = {
                                {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, //前者為紅外遙控器鍵碼,后者為對應(yīng)的標(biāo)準(zhǔn)PC鍵盤編碼,0x00表示無對應(yīng)值
                                {0x44, 0x00}, {0x40, 0x25}, {0x43, 0x27}, //后退->向左鍵,前進->向右鍵
                                {0x07, 0x1B}, {0x15, 0x28}, {0x09, 0x26}, //EQ->ESC,-->向下鍵,+->向上鍵
                                {0x16, '0'},  {0x19, 0x00}, {0x0D, 0x0D}, //0->0, U/SD->回車鍵
                                {0x0C, '1'},  {0x18, '2'},  {0x5E, '3'}, //1->1, 2->2, 3->3
                                {0x08, '4'},  {0x1C, '5'},  {0x5A, '6'}, //4->4, 5->5, 6->6
                                {0x42, '7'},  {0x52, '8'},  {0x4A, '9'}  //7->7, 8->8, 9->9
                            };
/***************************local function definition************************************/
void KeyAction(unsigned char keycode);
/***************************extern function and values definition************************************/
extern unsigned char setTempIndex;
extern bit flagIrd;         //紅外解碼完成標(biāo)志
extern unsigned char IrdCode[4];//裝載紅外解碼值
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);
extern void LCD1602SetCoursor(unsigned char x, unsigned char y);
extern void OpenCoursor();
extern void CloseCoursor();
extern void ContinueRefreshLED();
extern void LEDRefreshPause();
extern void IncCoursorNum();
extern void DecCoursorNum();
extern void SetWarningTemperture();
extern void SetTempByKeyNum(unsigned char keyNum);
               
/*按鍵驅(qū)動函數(shù),檢測按鍵動作*/
void KeyDrive()
{
    static unsigned char keybackup[4][4] = {1, 1, 1, 1, 1, 1, 1, 1,
                                            1, 1, 1, 1, 1, 1, 1, 1};//按鍵備份值
    unsigned char i, j;
                                           
    for (i = 0; i < 4; i++) //行
    {
        for (j = 0; j < 4; j++) //列
        { 
            if (keySta[i][j] != keybackup[i][j]) //按鍵兩次的值不相同,按鍵有動作
            {
                //由上一次的按鍵備份值確定這一次的按鍵狀態(tài)值
                if (keybackup[i][j] != 0)
                {
                    //按鍵按下
                    KeyAction(keyCodeMap[i][j]);//傳遞相應(yīng)的按鍵碼值,驅(qū)動按鍵動作
                }
                keybackup[i][j] = keySta[i][j];//備份按鍵的值
            }
        }
    }
}
/*紅外遙控器按鍵驅(qū)動*/
void IrdKeyDrive()
{
    unsigned char i = 0;
    for (i = 0; i < 21; i++)  //遍歷紅外鍵碼表
    {
        if (IrdCode[2] == IrdKeyCode[i][0]) //IrdKeyCode[i][0]為紅外鍵碼,IrdKeyCode[i][1]為對應(yīng)的PC鍵盤編碼
        {
            //在表中找到對應(yīng)的鍵碼
            KeyAction(IrdKeyCode[i][1]); //執(zhí)行相應(yīng)的動作
            break;
        }
    }
}
/*刷新LCD1602光標(biāo)顯示*/
void LCD1602RefreshCoursor()
{
    switch (setTempIndex)
    {
        case 1: LCD1602SetCoursor(8, 0);  break;//shangxianLow的十位數(shù)字
        case 2: LCD1602SetCoursor(9, 0);  break; //shangxianLow的個位數(shù)字
        case 3: LCD1602SetCoursor(11, 0); break; //shangxianHigh的十位數(shù)字
        case 4: LCD1602SetCoursor(12, 0); break;
        case 5: LCD1602SetCoursor(8, 1);  break;
        case 6: LCD1602SetCoursor(9, 1);  break;
        case 7: LCD1602SetCoursor(11, 1); break;
        case 8: LCD1602SetCoursor(12, 1); break;
        default: break;
    }
   OpenCoursor();//打開光標(biāo)
}
/*光標(biāo)閃爍左移*/
void LCDCoursorLeft()
{
    if (setTempIndex > 1)
    {
        setTempIndex--;
    }
    else
    {
       setTempIndex = 8;
    }
    LCD1602RefreshCoursor();//刷新光標(biāo)顯示
}
/*光標(biāo)右移*/
void LCDCoursorRight()
{
    if (setTempIndex < 8)
    {
        setTempIndex++;
    }
    else
    {
        setTempIndex = 1;
    }
    LCD1602RefreshCoursor();//刷新光標(biāo)顯示
}
/*按鍵動作函數(shù),根據(jù)keycode的值執(zhí)行相應(yīng)的動作*/
void KeyAction(unsigned char keycode)
{
    if (keycode >= '0' && keycode <= '9')
    {
        if (setTempIndex != 0) //處于設(shè)置狀態(tài)
        {
            SetTempByKeyNum(keycode - '0'); //0-9
        }
    }
    else if (keycode == 0x25) //<-
    {
        if (setTempIndex != 0) //處于設(shè)置狀態(tài)時響應(yīng)
        {
            LCDCoursorLeft();
        }
    }
    else if (keycode == 0x27) //->
    {
        if (setTempIndex != 0)
        {
            LCDCoursorRight();
        }
    }
    else if (keycode == 0x26) //UP
    {
        if (setTempIndex != 0) //處于設(shè)置狀態(tài)時響應(yīng)
        {
            IncCoursorNum();
        }
    }
    else if (keycode == 0x28)//Down
    {
        if (setTempIndex != 0)
        {
            DecCoursorNum();
        }
    }
    else if (keycode == 0x1B) //ESC
    {
        setTempIndex = 0;  
        CloseCoursor();
    }
    else if (keycode == 0x0D) //Enter
    {
        if (setTempIndex == 0)
        {
            setTempIndex = 1;
            LCD1602RefreshCoursor();
        }
        else
        {
            setTempIndex = 0;
            SetWarningTemperture();//設(shè)定報警溫度值,并將設(shè)定的報警值保存到eeprom中
            CloseCoursor();
        }   
    }
}
/*按鍵掃描函數(shù),定時器消抖*/
void KeyScan()
{
    static unsigned char keyout = 0;//按鍵行索引
    static unsigned char keybuff[4][4] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                          0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
                                          //16個按鍵的掃描緩沖區(qū)
    unsigned char i = 0;
   
    //掃描一行按鍵,將掃描值存入keybuff中
    keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1;
    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++)
    {
        //每行有四個按鍵
        if ((keybuff[keyout][i] & 0x1F) == 0x00) //五次檢測都是0
        {
            keySta[keyout][i] = 0;//按鍵按下
        }
        else if ((keybuff[keyout][i] & 0x1F) == 0x1F)//五次都是1           
        {
            keySta[keyout][i] = 1;//按鍵彈起
        }
    }
    //檢測下一行按鍵
    keyout++;
    keyout &= 0x03;//0x11按位與實現(xiàn)到4歸零
    //根據(jù)keyout的值來選擇檢測哪一行
    switch (keyout)
    {
        case 0: KEY_OUT_1 = 0; KEY_OUT_4 = 1; break;
        case 1: KEY_OUT_2 = 0; KEY_OUT_1 = 1; break;
        case 2: KEY_OUT_3 = 0; KEY_OUT_2 = 1; break;
        case 3: KEY_OUT_4 = 0; KEY_OUT_3 = 1; break;
        default: break;
    }
}

 /**
  ***********************************************************************************************
  * @file      :  I2C.c
  * @author    :  xr
  * @date      :  2014年4月28日19:18:15
  * @version   :  V1.2.3
  * @brief     :  I2C通信底層驅(qū)動
  ***********************************************************************************************
  */
#include <reg52.h>
#include <intrins.h>
//I2C
sbit SDA = P3^6;
sbit SCL = P3^7;
/*I2C通信延時函數(shù)宏定義*/
#define nops()  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } //延時大約5us
 
/*I2C起始信號*/
void I2CStart()
{
    SDA = 1;
    SCL = 1; //先拉高SDA和SCL
    nops();
    SDA = 0;//拉低SDA,在SCL為高電平期間SDA1-0的跳變被當(dāng)做I2C的起始信號
    nops();
    SCL = 0;//拉低SCL,準(zhǔn)備好發(fā)送數(shù)據(jù)
}
/*I2C停止信號*/
void I2CStop()
{
    SDA = 0;
    SCL = 0; //首先確保SDA和SCL為低電平,即忙碌
    nops();
    SCL = 1; //拉高SCL
    nops();
    SDA = 1;//在SCL為高電平期間SDA0-1的變化被當(dāng)做是停止信號
    nops();
}
/*向I2C通信總線發(fā)送一個字節(jié)數(shù)據(jù),并返回從機應(yīng)答信號ack*/
bit I2CWriteByte(unsigned char byte)
{
    bit ack = 0;
    unsigned char mask = 0x80;//從高位開始發(fā)送
   
    //I2CStart中已將SCL拉低,可以直接發(fā)送數(shù)據(jù)了
    for (mask = 0x80; mask != 0; mask >>= 1)
    {
        if ((byte & mask) != 0) //送入數(shù)據(jù)
        {
            SDA = 1;//發(fā)送1
        }
        else
        {
            SDA = 0;//發(fā)送0
        }
        nops();//等待數(shù)據(jù)發(fā)送完成
        SCL = 1;//拉高SCL使數(shù)據(jù)線SDA穩(wěn)定不變
        nops();
        SCL = 0;//等待下一位的發(fā)送
    }
    /*主機釋放SDA數(shù)據(jù)線,從機開始發(fā)送應(yīng)答ack*/
    SDA = 1;
    nops();
    SCL = 1;   //拉高SCL以接收從機應(yīng)答
    ack = SDA;//接收從機應(yīng)答ack
    nops();
    SCL = 0;//拉低SCL等待下一次的數(shù)據(jù)發(fā)送
   
    return (~ack); //ack==0表示寫成功
}
///*從I2C總線上接收一個字節(jié)數(shù)據(jù),主機返回ack 0,返回值:讀取到的數(shù)據(jù)byte*/
//unsigned char I2CReadByteAck()
//{
//    unsigned char byte = 0;
//    unsigned char mask = 0x80;//高位在先,逐位接收
//   
//    //主機釋放SDA數(shù)據(jù)線
//    SDA = 1;
//    //I2CStart中已將SCL拉低,等待從機發(fā)送數(shù)據(jù)
//    for (mask = 0x80; mask != 0; mask >>= 1)
//    {
//        nops();//延時>4.7us等待從機將數(shù)據(jù)發(fā)送到I2C總線上
//        SCL = 1;//拉高SCL使SDA線上的數(shù)據(jù)穩(wěn)定
//        if (SDA != 0)
//        {
//            byte |= mask;//相應(yīng)位置1
//        }
//        else
//        {
//            byte &= (~mask);//相應(yīng)位清零
//        }
//        nops();//等待數(shù)據(jù)讀取成功
//        SCL = 0;//拉低SCL等待從機發(fā)送下一位數(shù)據(jù)
//    }
//    SDA = 0;//主機發(fā)送應(yīng)答位0,繼續(xù)接收數(shù)據(jù)
//    nops();
//    SCL = 1;//拉高SCL從機等待主機的應(yīng)答
//    nops();
//    SCL = 0;//最后拉低SCL以進行下一次數(shù)據(jù)的發(fā)送和接收
//   
//    return (byte);
//}
/*從I2C總線上接收一個字節(jié)的數(shù)據(jù),主機返回非應(yīng)答1,返回值:接收到的數(shù)據(jù)byte*/
unsigned char I2CReadByteNAck()
{
    unsigned char byte = 0;
    unsigned char mask =  0x80;//高位在前,逐位接收
   
    //主機先釋放SDA等待從機發(fā)送數(shù)據(jù)
    SDA = 1;
    //I2CStart起始信號已將SCL拉低,從機開始發(fā)送數(shù)據(jù)
    for (mask = 0x80; mask != 0; mask >>= 1)
    {
        nops();//等待從機將數(shù)據(jù)發(fā)送到I2C總線上
        SCL = 1;//使SDA上的數(shù)據(jù)穩(wěn)定
        if (SDA != 0)
        {
            byte |= mask;
        }
        else
        {
            byte &= (~mask);
        }
        nops();//等待主機采樣數(shù)據(jù)成功
        SCL = 0;//等待從機發(fā)送下一位數(shù)據(jù)
    }
    SDA = 1;//主機發(fā)送非應(yīng)答1,停止接收數(shù)據(jù)
    nops();
    SCL = 1;//拉高SCL從機以等待主機的非應(yīng)答信號
    nops();
    SCL = 0;//拉低SCL等待下一次的I2C通信
   
    return (byte);
}

/**
  ***********************************************************************************************
  * @file      :  eeprom.c
  * @author    :  xr
  * @date      :  2014年4月28日19:18:15
  * @version   :  V1.2.3
  * @brief     :  I2C通信協(xié)議讀寫eeprom存儲器件
  ***********************************************************************************************
  */
#include <reg52.h>
//器件地址宏定義
#define EEPROM_ADDR 0x50 //1010 A2A1A0 七位器件地址
/***************************extern function definition************************************/
/*I2C底層驅(qū)動*/
extern void I2CStart();
extern void I2CStop();
extern bit I2CWriteByte(unsigned char byte);
//extern unsigned char I2CReadByteAck();
extern unsigned char I2CReadByteNAck();
   
/*向EEPROM的addr地址寫一個字節(jié)的數(shù)據(jù)*/
void WriteEEPROMByte(unsigned char addr, unsigned char dat)
{
    do
    {
        I2CStart();
        if (I2CWriteByte(EEPROM_ADDR << 1)) //寫eeprom器件地址ADDR并在讀寫方向上選擇寫,從機回復(fù)應(yīng)答ack
        {
            break;//尋址成功強制退出
        }
        I2CStop();
    } while (1);
    I2CWriteByte(addr);//寫入數(shù)據(jù)地址addr,并返回應(yīng)答ack
    I2CWriteByte(dat); //寫入數(shù)據(jù)dat
    I2CStop();
}
/*從EEPROM的地址addr中讀取一個字節(jié)數(shù)據(jù),讀取成功返回1,否則返回0,指針變量接收數(shù)據(jù)*/
unsigned char ReadEEPROMByte(unsigned char addr)
{
    unsigned char dat = 0;
   
    /*I2C進行EEPROM尋址*/
    do
    {
        I2CStart();
        if (I2CWriteByte(EEPROM_ADDR << 1)) //寫入器件地址ADDR并選擇寫
        {
            break;
        }
        I2CStop();
    } while (1);
    I2CWriteByte(addr); //寫入要讀取的數(shù)據(jù)的地址addr
    I2CStart();
    I2CWriteByte((EEPROM_ADDR << 1) | 0x01); //寫器件地址ADDR并在讀寫方向上選擇讀
    dat = I2CReadByteNAck();//讀取數(shù)據(jù),主機返回非應(yīng)答
    I2CStop();
   
    return (dat);
}

/**
  ******************************************************************************
  * @file      :   Infrared.c
  * @author    :   xr
  * @date      :   2014年5月1日20:57:45
  * @version   :   V1.2.3
  * @brief     :   紅外通信-基于NEC協(xié)議的底層驅(qū)動
  ******************************************************************************
  */
#include <reg52.h>
//紅外通信引腳
sbit IRD = P3^3;//外部中斷1引腳
bit flagIrd = 0;         //紅外解碼完成標(biāo)志
unsigned char IrdCode[4];//裝載紅外解碼值
/*紅外通信T1定時器配置*/
void ConfigInfrared()
{
    TMOD &= 0x0F;//清零T1控制位
    TMOD |= 0x10;//十六位計數(shù)器模式
    TH1 = 0;
    TL1 = 0;//清零T1計數(shù)器
    TR1 = 0;//先關(guān)閉T1計數(shù)
    ET1 = 0;//不用T1中斷
    //配置外部中斷
    IE1 = 0;//外部中斷1標(biāo)志位清零
    IT1 = 1;//設(shè)置外部中斷1的觸發(fā)方式是下降沿觸發(fā)(0:低電平觸發(fā),1:下降沿觸發(fā))
    EX1 = 1;//開啟外部中斷1
}
/*獲得IRD引腳高電平時間即空閑時間計數(shù)值*/
unsigned int GetHighTimers()
{
    IRD = 1;//檢測該引腳之前要先釋放IRD引腳
    TH1 = 0;
    TL1 = 0;//每次都要清零T1計數(shù)值
    TR1 = 1;//打開T1計數(shù)
    while (IRD)
    {
        //超時判斷,超過17ms認為是誤碼,強制退出 TL1加滿256就向TH1進1
        if (TH1 > 0x40)  //(0x40*256)*12/11059200(s)= 17.8ms
        {
            break;
        }
    }
    TR1 = 0;//關(guān)閉T1計數(shù)
    return (TH1 * 256 + TL1);//返回T1計數(shù)值
}
/*獲得IRD引腳低電平時間即載波時間計數(shù)值*/
unsigned int GetLowTimers()
{
    IRD = 1;//檢測IRD引腳之前要先將IRD引腳拉高釋放
    TH1 = 0;
    TL1 = 0;//清零T1計數(shù)值
    TR1 = 1;//開啟T1計數(shù)
    while (!IRD)
    {
        if (TH1 > 0x40)  //超過17ms表示是誤碼,強制退出
        {
            break;
        }
    }
    TR1 = 0;//關(guān)閉T1計數(shù)
    return (TH1 * 256 + TL1);//返回T1計數(shù)值
}
/*外部中斷1中斷服務(wù),接收紅外解碼值*/
void EX1_ISP() interrupt 2
{
    static unsigned int time = 0;
    unsigned char i = 0, j = 0;
    unsigned char Irbyte = 0;
    /*首先判斷引導(dǎo)碼,引導(dǎo)碼(9ms的載波+4.5ms的空閑)*/
    time = GetLowTimers();//獲取載波
    if ((time < 7833) || (time > 8755))  //8.5ms-9.5ms  time = T1計數(shù)值*(12/11059200)(s)
    {
        IE1 = 0;//清零外部中斷標(biāo)志
        return;//退出中斷服務(wù)
    }
    time = GetHighTimers();//獲取空閑
    if ((time < 3686) || (time > 4608))  //4ms-5ms
    {
        IE1 = 0;
        return;
    }
    //引導(dǎo)碼正確,開始接收用戶碼和鍵碼
    /*比特值0:560us載波+560us空閑 比特值1:560us載波+1.68us空閑*/
    for (i = 0; i < 4; i++)  //用戶碼+用戶反碼+鍵碼+鍵碼反碼
    {
        for (j = 0; j < 8; j++)  //解碼值是八位數(shù)據(jù)
        {
            time = GetLowTimers();//載波 時間范圍:360us-760us
            if ((time < 332) || (time > 700))
            {
                IE1 = 0;
                return;
            }
            //560us載波正確
            time = GetHighTimers();//空閑
            if ((time > 332) && (time < 700))  //'0'
            {
                //接收比特0
                Irbyte >>= 1;//低位在先,逐位接收
            }
            else if ((time > 1290) && (time < 1658))    //1.68ms空閑,范圍:1.4ms-1.8ms
            {
                //接收比特1
                Irbyte >>= 1;  //先將這一位移出來
                Irbyte |= 0x80;//再將此位置1
            }
            else
            {
                //誤碼
                IE1 = 0;
                return;
            }
        }
        //接收一個字節(jié)
        IrdCode[i] = Irbyte;
    }
    flagIrd = 1;//接收完成標(biāo)志置1
    IE1 = 0;//清零外部中斷標(biāo)志

 
關(guān)閉窗口

相關(guān)文章