51单片机用红外遥控变频空调的程序,带时钟走时DS1302,温度DS18B20带CRC,湿度HTU31D的I2C带CRC,电路图和二千行源代码全公开

2022.9

STC51单片机STC12C5A60S2,KEIL C,改了十多年的程序,二千行了。带时钟校正,走时DS1302,温度DS18B20带CRC,湿度HTU31D的I2C带CRC。

走时有程序上校正功能,可用频率计校到1PPM以下,一年都不用调时间。以前都是调振荡电容调到1ppm以下,累。后来发现可以程序中调,方便多了。

这次目的是用红外遥控奥克斯变频空调,顺便把所有程序发布一下吧。

电路图:

//====================================================/

主文件:

//STC12C5A60S2   FLASH 60K,  SRAM 1280字节=内部RAM低128字节+高128字节+内部扩展RAM1024字节

//温度和湿度值:均按值的10倍,有符号整数

bit    bit_T0_interrupt_prohibited=0;     // 是否禁用T0中断中的耗时代码

#define MACRO_WXL_INTERRUPT_PROHIBITED    bit_T0_interrupt_prohibited=1;

#define MACRO_WXL_INTERRUPT_ALLOWED       bit_T0_interrupt_prohibited=0;

#include <STC\STC12C5A60S2.H>

#include <INTRINS.h>

#include "DELAY_STC12_WXL.H"

//温度  DS18B20

sbit DQ_DS18_OUTDOOR=P3^4;

sbit DQ_DS18_INDOOR=P1^4;

#include "DS18B20_wxl.h"

int data i_DS18_INDOOR=240;          //温度值(10倍)        设成24度,以免空调制冷、制热控制失误

int data i_DS18_OUTDOOR=0;

bit bit_DS18_OUTDOOR_exist=0;

bit bit_DS18_INDOOR_exist=0;

unsigned char data  dispbuf_DS18_INDOOR[3]={17,17,17};    //保存各个显示值  

unsigned char data  dispbuf_DS18_OUTDOOR[3]={17,17,17};

/*

数组保存显示值。 [0]存十位及百位(A,b,C等表示)或负号 (可选带点) 。     [1]存个位(可选带点)。   [2]存小数位

第[0]位: 100 显示 A, 110 B, 120 C ,130 D ,140 E, 150 F,然后就没有了,所以最高是159.9

第[0]位: -10 显示 A, -20 B, -30 C, -40 D ,-50 E, -60 F,然后就没有了,所以最低是-69.9

比如:

25.6℃数组为{2,5,6}    即 2 5 6

-5.6℃数组为{17,5,6}   即 - 5 6

-15.6℃数组为{10,5,6}  即 A 5 6

-25.6℃数组为{10,5,6}  即 B 5 6

105.6℃数组为{10,5,6}  即 A 5 6

115.6℃数组为{11,5,6}  即 B 5 6

*/

//温度  HTU31D  I2C

//HTU31D模块,芯片焊板上,温度响应慢,用于空调控制一般般,于是仍采用DS18B20来控制温度

//HTU31D和DS18B20,静态温度HTU31D高0.5度不准,动态HTU31D反应慢

int idata   i_HTU31D_INDOOR=0;          //温度值(10倍)

int idata   i_HTU31D_OUTDOOR=0;

unsigned char idata  dispbuf_HTU31D_INDOOR[3]={17,17,17};    //保存各个显示值

unsigned char idata  dispbuf_HTU31D_OUTDOOR[3]={17,17,17};

//湿度 HF3223频率、 HTU31D I2C

int idata i_HF32_INDOOR=0;       //湿度值10倍       //湿度HF3223采用频率计数,这里淘汰不用了,给HTU31D用

int idata i_HF32_OUTDOOR=0;

unsigned char  idata   dispbuf_HF32_INDOOR[3]={14,5,17};    //保存各个显示值       //这里没用到,赋成E5-

unsigned char  idata   dispbuf_HF32_OUTDOOR[3]={17,17,17};     

sbit SDA=P3^2;

sbit SCL=P3^3;

#include "I2C_HTU31D.H"

//按键相关

sbit P1_0=P1^0;   

sbit P1_1=P1^1;   

sbit P1_2=P1^2;   

unsigned char  idata  uc_keycount=0;      //用于判断 20ms内均为高电平,则是键松开

//时钟相关

volatile unsigned int   data  tcnt=0;             //计数到1秒的次数(用于时钟)

unsigned char data second=0;              //时钟

unsigned char data minute=0;

unsigned char data hour=0;

unsigned long idata   ul_time_compensate=0;      //晶振不准,在软件中进行时间补偿,经n秒后,加一秒或减一秒。  最好是晶振调成偏快,然后程序中就不用加秒,比较方便

//传感器检测相关

unsigned char  idata do_what=0;                 //传感器检测步序

volatile unsigned int  data   i_dowhat_interval=1800;    //中断中,do_what的时间计数

//工作模式

unsigned char  idata  uc_display_mode=0;         //工作模式   0正常 1制冷 2制热

unsigned char  idata  uc_display_mode_pre=0;

unsigned char  code  displaybuf_display_mode[3]={0, 12, 42};     //显示0、C、H

//设置模式

unsigned char  idata  g_uc_setting_mode=0;

volatile  unsigned int data    g_ui_settingmode_timeout_cnt=0;  //设置时,进行计时

unsigned char idata  g_uc_settingmode_timeout_second=0;

//显示LED相关

volatile unsigned char   data  mstcnt=0;        //计数到改变显示LED位的次数

//dispcode[]是 共“阳”极数码管的 笔划数据!!

unsigned char  data   dispcode[]={                          //强行放在data中,以加快速度

0x48, 0xFC, 0x29, 0x38, 0x9C, 0x1A, 0x0A, 0x7C, 0x08, 0x18,    //[0]。。。9

0x0C, 0x8A, 0x4B, 0xA8, 0x0B, 0x0F,                            //[10](A),11(b),12(C),13(d),14(E),15(F)

0xFF, 0xBF, 0xBF, 0xBF,                                        //[16](空),17(负号), 18, 19

0x40, 0xF4, 0x21, 0x30, 0x94, 0x12, 0x02, 0x74, 0x00, 0x10,    //[20](带小数点的0.)。。。29

0x04, 0x82, 0x43, 0xA0, 0x03, 0x07,                            //[30](A.)  。。。 35(F.)

0xF7, 0xB7, 0xB7, 0xB7,                                        //[36](空带点.),37(负号带点.), 38, 39

0xAA, 0x4C, 0x8C                                               //[40](小o), 41(大N), 42(H)

};

/*

8个数码管     时间     温度

        [7]左 8 8 8 8  8 8 8 8 右[0]

*/

unsigned char data dispbuf[8]={17,17,17,17,17,17,17,17};    //dispbuf保存显示数据,[7]最左数码管 --> [0]最右数码管

unsigned char data dispbitcode[8]={1,2,4,8,16,32,64,128};   //即选择数码管,依次是[0]最右数码管-->[7]最左数码管,即P2.0接置1(0000 0001)、P2.1置1...

unsigned char data dispbitcnt=0;       //选择显示哪个数码管, 0表示最右那个数码管(温度小数位),7表示最左那个数码管

//串口

unsigned char idata    sbuf[3],  sbufnum;   //串口数据

//DS1302

//DS1302 走时不准!  所以从单片机走时间,DS1302只是保存一下时间

sbit DS1302_CLK=P1^5; 

sbit DS1302_IO=P1^6; 

sbit DS1302_RST=P1^7;

#include "DS1302_wxl.h"

bit bitDS1302exist=0;      //DS1302是否存在

unsigned char idata  ds1302_BCDdata[9]={0x59,0x32,0x23, 1, 1,  1,    0x13,  0,      0};     //BCD格式的数据 

                                    //  0     1    2    3  4   5       6     7      8

                                    //  秒    分   时   日 月 星期几  年   写保护   充电

                                    //DS1302数据按BCD格式,0x59即是表示59。

                                    //秒最高位0表示不停止时钟。  小时最高位0表示按24小时制。  0不写保护。  0不充电。

//空调红外遥控      //发送时,低比特位优先!!   先发送低bit!!

sbit  P_IR = P1^3;

volatile  unsigned char data  g_uc_ir_time=0;    //中断T0中执行多少次红外IR发射

volatile  bit data    g_b_ir_onoff=0;

unsigned char idata  uc_ir_state=0;           // 空调状态:  0表示关机   1表示开机+制冷    2表示只ECO    3表示ECO+静音   (风都是1档)

unsigned char code   g_uc_irdata[5][13]=            //红外数据

{

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x45, 0x15,     //关机0

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x0, 0x20, 0x0, 0x45, 0x35,    //开机+制冷1

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x0, 0x28, 0x0, 0x53, 0x4B,    //ECO2

0xC3 ,0xAD ,0xE0 ,0x0 ,0x60 ,0x80 ,0x20 ,0x0 ,0x0 ,0x28 ,0x0 ,0x53 ,0xCB,     //ECO+静音3

0xC3, 0xC5, 0xE0, 0x00, 0x60, 0x80, 0x20, 0x00, 0x00, 0x28, 0x00, 0x40, 0xD0//32度ECO+静音3

};  

unsigned char code   g_uc_irdata_with_disp[5][13]=         //红外数据   加空调屏显键

{

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x55, 0x25,     //关机0

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x0, 0x20, 0x0, 0x55, 0x45,   //开机+制冷1

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x0, 0x28, 0x0, 0x55, 0x4D,   //ECO2

0xC3, 0xAD, 0xE0, 0x0, 0x60, 0x80, 0x20, 0x0, 0x0, 0x28, 0x0, 0x55, 0xCD,     //ECO+静音3

0xC3, 0xC5, 0xE0, 0x00, 0x60, 0x80, 0x20, 0x00, 0x00, 0x28, 0x00, 0x55, 0xE5//32度ECO+静音3

};  

unsigned char idata  uc_ir_heat_state=0;   // 空调加热状态:  0表示关机   1表示开机+制热    。。。    待完善

unsigned char code   g_uc_ir_heat_data[5][13];

bit idata  b_ir_key_delay=0;        //按键检测延时

unsigned char idata  g_uc_ir_second=0;  //按键延时检测,按秒

unsigned char idata  g_uc_ir_minute=0;      //空调温度延时时长,按分钟   ,比如1分钟后检测温度

unsigned char idata  g_uc_ir_minute_pre=0;  //空调温度延时检测

unsigned int idata  ui_airtemp_set=260;      //空调制冷温度设定值 (10倍)

unsigned int idata  ui_airtemp_heat_set=200;      //空调制热温度设定值 (10倍)

unsigned char idata  dispbuf_ui_airtemp_set[3];

bit idata   b_ECO_ON=0;                 //ECO开7小时检测,开7小时ECO后需要关掉ECO再开,不然会自动消掉

unsigned char idata  ECO_hour_pre=0;

///

//数值转换到显示值

void  INT10_TO_dispbuf_nodot(unsigned char  *c,  int  i)        //c[0]存十位及百位(A,b,C等表示),c[1]存个位,c[2]存小数。  负数:c[0]为负号或A,b,C等表示-10、-20、-30等

{

    if( i>1599  || i<-699) return;  //大于159.9度  小于-69.9度

   

    if( i < 0 )     //如果是负数

    {

        i=-i;

        c[0]=i/100; //最高位

        i=i%100;

        c[1]=i/10;  //个位

        c[2]=i%10;  //小数

        if (c[0] == 0) c[0]=17;    //显示负号

        else c[0]+=9;           //用A,b,C等表示-10、-20、-30等           

    }

    else    //正数

    {

        c[0]=i/100;

        i=i%100;

        c[1]=i/10;

        c[2]=i%10;

    }

}

void  INT10_TO_dispbuf(unsigned char  *c,   int  i)  

{

    if( i>1599  || i<-699) return;  //大于159.9度  小于-69.9度

       

    INT10_TO_dispbuf_nodot( c,  i);

   

    //显示带点

    if( c[2] <3)    ;                     //显示带点的数字

    else if( c[2] < 5 )     c[0]+=20;      //显示带点的数字   [0]是十位

    else if( c[2] < 8) c[1]+=20;        //显示带点的数字

    else  {     c[0]+=20;  c[1]+=20;    }     //显示带点的数字

}

void sendSBUF(unsigned char  *a, unsigned char   num)       //串口发送N字节数据

{

    unsigned char idata  i;

    if(num==0) return;

    TI=0;

    for(i=0;i<num;i++)

    {

        SBUF = a[i]; //输出字符

        while(!TI);     //空语句判断字符是否发完,TI=1表示发完

        TI = 0;         //要人工清TI

    }

}

void readDS1302_and_setclock()

{

    BurstRead1302(ds1302_BCDdata) ;

    second=( (ds1302_BCDdata[0]&0x7f) >>4)*10 + (ds1302_BCDdata[0] & 0x0f);       //去掉最高位"时钟停止"位,再运算

    minute=(ds1302_BCDdata[1]>>4)*10 + (ds1302_BCDdata[1] & 0x0f);

    hour=  ( (ds1302_BCDdata[2]&0x7f) >>4)*10 + (ds1302_BCDdata[2] & 0x0f);       //去掉最高位"24小时"位,再运算

}

//每个小时的30分时,写入时间到DS1302中,以使DS1302时间正确   ///

void DO_WRITETODS1302_EVERY_HALF_HOUR()

{

    if(bitDS1302exist)

    {

        DS1302_WriteOne(DS1302_SEC_AD, (second/10)*16+second%10 );

        DS1302_WriteOne(DS1302_MIN_AD, (minute/10)*16+minute%10 );

        DS1302_WriteOne(DS1302_HOUR_AD, (hour/10)*16+hour%10 );        

    }

}

//传感器检测  /

void DO_WHAT_FUNC()

{

        unsigned char idata  uc_DS18_temp1, uc_DS18_temp2,   uc_DS18_temp[10];

        EA=0;

        if(i_dowhat_interval<3600) { EA=1;  return;}   //如果间隔时间未到,则不执行

        i_dowhat_interval=0;        //间隔时间重新计时,即每隔1秒做一次检测

        EA=1;

        switch(do_what)

        {

            case 0:

                // 内DS18B20测温

                RESET_DS18_INDOOR(  );

                SEND_TO_DS18_INDOOR( 0xCC );   //传送数据   0xcc表示SKIP ROM COMMAND指令

                SEND_TO_DS18_INDOOR( 0x44 );   //传送数据   0X44  CONVERT T指令

               

                RESET_DS18_OUTDOOR(  );

                SEND_TO_DS18_OUTDOOR( 0xCC );   //传送数据   0xcc表示SKIP ROM COMMAND指令

                SEND_TO_DS18_OUTDOOR( 0x44 );   //传送数据   0X44  CONVERT T指令

               

                HTU31D_conversion(  0x40  );   //addr地址接GND是0x40,接VCC是0x41 。   我室内用第一次买的接GND,室外以后用接VCC的

   

                do_what++;

                break;

   

   

            case 1:

                if ( HTU31D_readTRH( &i_HTU31D_INDOOR,  &i_HF32_INDOOR  ,  0x40 )  )     //addr地址接GND是0x40,接VCC是0x41

                {

                        if(  i_HTU31D_INDOOR >=1100  )  //响应值太大,说明HTU数据异常

                        {

                            i_HTU31D_INDOOR=0;          //设成0

                            dispbuf_HTU31D_INDOOR[0]=15;    //显示F1      [0]是十位

                            dispbuf_HTU31D_INDOOR[1]=1;

                            dispbuf_HTU31D_INDOOR[2]=17;   

                        }

                        else

                        {

                            INT10_TO_dispbuf(dispbuf_HTU31D_INDOOR, i_HTU31D_INDOOR);       //存到显示缓存

                        }

                       

                        if(  i_HF32_INDOOR >=1100  )       //响应值太大,说明HTU数据异常

                        {

                                i_HF32_INDOOR=0;          //湿度设成0

                                dispbuf_HF32_INDOOR[0]=15;  //显示F6     [0]是十位

                                dispbuf_HF32_INDOOR[1]=6;

                                dispbuf_HF32_INDOOR[2]=17;                                 

                        }

                        else

                            INT10_TO_dispbuf_nodot(dispbuf_HF32_INDOOR, i_HF32_INDOOR);     //存到显示缓存   无点

                }

                else        //HTU回应错误

                {

                        i_HTU31D_INDOOR=0;         //设成0

                        dispbuf_HTU31D_INDOOR[0]=15;    //显示F0         [0]是十位

                        dispbuf_HTU31D_INDOOR[1]=0;

                        dispbuf_HTU31D_INDOOR[2]=17;                           

                       

                        i_HF32_INDOOR=0;         //湿度设成0

                        dispbuf_HF32_INDOOR[0]=15;  //显示F5         [0]是十位

                        dispbuf_HF32_INDOOR[1]=5;

                        dispbuf_HF32_INDOOR[2]=17;     

                }

                       

                do_what++;

                break;

   

   

   

            case 2:

                // 内DS18B20读温

                if( RESET_DS18_INDOOR(  ) )     //存在DS18B20

                {

                    bit_DS18_INDOOR_exist=1;

                    SEND_TO_DS18_INDOOR( 0xCC );   //传送数据   0xcc表示SKIP ROM COMMAND指令

                    SEND_TO_DS18_INDOOR( 0xBE );   //传送数据   0XBE  READ SCRATCHPAD指令

                   

                    //接收9字节数据

                    for(uc_DS18_temp1=0; uc_DS18_temp1<9 ; uc_DS18_temp1++)

                                    uc_DS18_temp[ uc_DS18_temp1 ]=RECEIVE_FROM_DS18_INDOOR(  );   //读取9字节=8字节数据+1字节CRC

                   

                    if( DS18_CRC(uc_DS18_temp,9 ))   //为0则是CRC成功

                    {

                        //失败

                        i_DS18_INDOOR=240;           //设成24度,以免空调控制失误

                        dispbuf_DS18_INDOOR[0]=14;  //显示E1        [0]是十位

                        dispbuf_DS18_INDOOR[1]=1;

                        dispbuf_DS18_INDOOR[2]=17;     

                    }

                    else

                    {

                        uc_DS18_temp1=uc_DS18_temp[0];    // 第1字节是LSB字节

                        uc_DS18_temp2=uc_DS18_temp[1];    // 第2字节是MSB字节

                        i_DS18_INDOOR =  DS18_TEMP_TO_SIGNED_INT10( uc_DS18_temp1, uc_DS18_temp2 ); //转成int

                        INT10_TO_dispbuf(dispbuf_DS18_INDOOR, i_DS18_INDOOR);       //存到显示缓存

                    }

                }

                else        //不存在DS18B20

                {

                    bit_DS18_INDOOR_exist=0;

                   

                    i_DS18_INDOOR=240;           //设成24度,以免空调控制失误

                    dispbuf_DS18_INDOOR[0]=14;  //显示E0        [0]是十位

                    dispbuf_DS18_INDOOR[1]=0;

                    dispbuf_DS18_INDOOR[2]=17;     

                }

               

                do_what++;

                break;

   

            case 3:

                // 外DS18B20读温

                if( RESET_DS18_OUTDOOR(  ) )        //存在DS18B20

                {

                    bit_DS18_OUTDOOR_exist=1;

                    SEND_TO_DS18_OUTDOOR( 0xCC );   //传送数据   0xcc表示SKIP ROM COMMAND指令

                    SEND_TO_DS18_OUTDOOR( 0xBE );   //传送数据   0XBE  READ SCRATCHPAD指令

                   

                    //接收9字节数据

                    for(uc_DS18_temp1=0; uc_DS18_temp1<9 ; uc_DS18_temp1++)

                                    uc_DS18_temp[ uc_DS18_temp1 ]=RECEIVE_FROM_DS18_OUTDOOR(  );   //读取9字节=8字节数据+1字节CRC

                   

                    if( DS18_CRC(uc_DS18_temp,9 ))   //为0则是CRC成功

                    {

                        //失败

                        i_DS18_OUTDOOR=0;           //设成0

                        dispbuf_DS18_OUTDOOR[0]=14; //显示E1        [0]是十位

                        dispbuf_DS18_OUTDOOR[1]=1;

                        dispbuf_DS18_OUTDOOR[2]=17;    

                    }

                    else

                    {

                        uc_DS18_temp1=uc_DS18_temp[0];    // 第1字节是LSB字节

                        uc_DS18_temp2=uc_DS18_temp[1];    // 第2字节是MSB字节

                        i_DS18_OUTDOOR =  DS18_TEMP_TO_SIGNED_INT10( uc_DS18_temp1, uc_DS18_temp2 );    //转成int

                        INT10_TO_dispbuf(dispbuf_DS18_OUTDOOR, i_DS18_OUTDOOR);     //存到显示缓存

                    }

                }

                else        //不存在DS18B20

                {

                    bit_DS18_OUTDOOR_exist=0;

                   

                    i_DS18_OUTDOOR=0;           //设成0

                    dispbuf_DS18_OUTDOOR[0]=14; //显示E0        [0]是十位

                    dispbuf_DS18_OUTDOOR[1]=0;

                    dispbuf_DS18_OUTDOOR[2]=17;    

                }

               

                do_what++;

               

                break;

            case 4:

                if ( HTU31D_readTRH( &i_HTU31D_OUTDOOR,  &i_HF32_OUTDOOR  ,  0x41 )  )     //addr地址接GND是0x40,接VCC是0x41

                {

                        if(  i_HTU31D_OUTDOOR >=1100  )  //响应值太大,说明HTU数据异常

                        {

                            i_HTU31D_OUTDOOR=0;          //设成0

                            dispbuf_HTU31D_OUTDOOR[0]=15;   //显示F1      [0]是十位

                            dispbuf_HTU31D_OUTDOOR[1]=1;

                            dispbuf_HTU31D_OUTDOOR[2]=17;  

                        }

                        else

                        {

                            INT10_TO_dispbuf(dispbuf_HTU31D_OUTDOOR, i_HTU31D_OUTDOOR);     //存到显示缓存

                        }

                       

                        if(  i_HF32_OUTDOOR >=1100  )       //响应值太大,说明HTU数据异常

                        {

                                i_HF32_OUTDOOR=0;          //湿度设成0

                                dispbuf_HF32_OUTDOOR[0]=15; //显示F6     [0]是十位

                                dispbuf_HF32_OUTDOOR[1]=6;

                                dispbuf_HF32_OUTDOOR[2]=17;                                

                        }

                        else

                            INT10_TO_dispbuf_nodot(dispbuf_HF32_OUTDOOR, i_HF32_OUTDOOR);       //存到显示缓存   无点

                }

                else        //HTU回应错误

                {

                        i_HTU31D_OUTDOOR=0;         //设成0

                        dispbuf_HTU31D_OUTDOOR[0]=15;   //显示F0         [0]是十位

                        dispbuf_HTU31D_OUTDOOR[1]=0;

                        dispbuf_HTU31D_OUTDOOR[2]=17;                          

                       

                        i_HF32_OUTDOOR=0;         //湿度设成0

                        dispbuf_HF32_OUTDOOR[0]=15; //显示F5         [0]是十位

                        dispbuf_HF32_OUTDOOR[1]=5;

                        dispbuf_HF32_OUTDOOR[2]=17;    

                }

                       

                do_what++;

                do_what=0;     //回零

                break; 

   

            default:

                do_what=0;

        }      

   

}

//发送时间和温度 到串口SD记录器  进行记录

void SENDTXTEMP()

{

   

        unsigned char idata a[26];

        char idata  i;

       

        for (i=0;i<26;i++)  a[i]=' ';

       

       

        if(bitDS1302exist)

        {

                BurstRead1302(ds1302_BCDdata) ;

                wxl_BCDToStr(ds1302_BCDdata,  a);  //17字节

        }

        else

        {

               

                a[4]=minute%10+48;

                a[3]=minute/10+48;

                a[2]=':';

                a[1]=hour%10+48;

                a[0]=hour/10+48;       

               

        }

       

        a[17]='\t';

        a[18]=0;

        a[19]=0;

        a[20]=0;

       

        INT10_TO_dispbuf_nodot(a+18, i_DS18_INDOOR );

       

        a[18]+=48;

        a[19]+=48;

        a[21]=a[20]+48;

        a[20]='.';

       

        a[22]='\t';

        a[23]=uc_ir_state+'0';

       

        a[24]=0x0D;

        a[25]=0x0A;

       

        sendSBUF(a, 26);

}

//刷新显示           ///

void REFRESH_DISPLAY()

{          

    switch(g_uc_setting_mode)

    {

        case 0:              //不在设置模式

            dispbuf[4]=minute%10;

            dispbuf[5]=minute/10;

            dispbuf[6]=hour%10;

            dispbuf[7]=hour/10;

           

            switch(uc_display_mode)       // 显示模式,  0=2个温度2个湿度      1=空调控制   2=空调控制

            {

                case 0:     //正常显示

                    if(second%10==0||second%10==5)       //   在0,5。。。     

                    {

                        dispbuf[0]=dispbuf_DS18_INDOOR[1];        //显示内DS18B20的温度        dispbuf[0]是低位    INDOOR[0]是十位

                        dispbuf[1]=dispbuf_DS18_INDOOR[0];       

                        dispbuf[2]=dispbuf_DS18_OUTDOOR[1];        //显示外DS18B20的温度

                        dispbuf[3]=dispbuf_DS18_OUTDOOR[0];        

                    }

                    else if(second%10==3||second%10==8)  //   在3,8。。。

                    {

                        dispbuf[0]=dispbuf_HTU31D_INDOOR[1];        //显示内HTU31D的温度

                        dispbuf[1]=dispbuf_HTU31D_INDOOR[0];     

                        dispbuf[2]=dispbuf_HTU31D_OUTDOOR[1];       //显示外HTU31D的温度

                        dispbuf[3]=dispbuf_HTU31D_OUTDOOR[0];     

                    }

                    else if(second%10==4||second%10==9)  //   在4,9。。。

                    {

                        dispbuf[0]=dispbuf_HF32_INDOOR[1];        //显示内HF3223的湿度

                        dispbuf[1]=dispbuf_HF32_INDOOR[0];     

                        dispbuf[2]=dispbuf_HF32_OUTDOOR[1];       //显示外HF3223的湿度

                        dispbuf[3]=dispbuf_HF32_OUTDOOR[0];     

                    }                  

                    break;

                   

                case 1:      //空调制冷显示

                    dispbuf[1]=  12;               //[0]最右数码管   显示C表示制冷

                    dispbuf[0]=uc_ir_state;        //[0]最右数码管

                    goto CASE2_DISPLAY;

                   

                case 2:      //空调加热显示                

                    dispbuf[1]=  42;                    //[0]最右数码管   显示H表示制热

                    dispbuf[0]=uc_ir_heat_state;        //[0]最右数码管

                   

                CASE2_DISPLAY:   //在0秒显示内温,3秒外温,5秒内湿,8秒外湿

                       

                    if(second%10==0)          

                    {

                        dispbuf[2]=dispbuf_DS18_INDOOR[1];       //  dispbuf[0]是低位    INDOOR[0]是十位

                        dispbuf[3]=dispbuf_DS18_INDOOR[0];         

                    }

                    else if(second%10==3) 

                    {

                        dispbuf[2]=dispbuf_DS18_OUTDOOR[1];      

                        dispbuf[3]=dispbuf_DS18_OUTDOOR[0];    

                    }

                    else if(second%10==6) 

                    {

                        dispbuf[2]=dispbuf_HF32_INDOOR[1];   

                        dispbuf[3]=dispbuf_HF32_INDOOR[0];    

                    }

                    else if(second%10==8) 

                    {

                        dispbuf[2]=dispbuf_HF32_OUTDOOR[1];   

                        dispbuf[3]=dispbuf_HF32_OUTDOOR[0];     

                    }                  

                    break;

                   

                default:

                    dispbuf[0]=16;

                    dispbuf[1]=16;

                    dispbuf[2]=16;

                    dispbuf[3]=16;

            }  //SWITCH

            break;

       

       

        //设置中

        case 1:       

            dispbuf[3]=16;

            dispbuf[2]=5  ;  //显示5=S  调节小时

            dispbuf[0]=hour%10;

            dispbuf[1]=hour/10;

            break;

       

        case 2:

            dispbuf[3]=16;

            dispbuf[2]=15  ;  //显示F  调节分钟

            dispbuf[0]=minute%10;

            dispbuf[1]=minute/10;                          

            break;

           

        case 3:

            dispbuf[3]=16;

            dispbuf[2]=40  ;  //显示o  调节工作模式

            dispbuf[0]= displaybuf_display_mode[uc_display_mode];

            dispbuf[1]=16;                             

            break; 

           

        case 4:

            dispbuf[3]=16;

            dispbuf[2]=12  ;  //显示C  调节制冷温度

            INT10_TO_dispbuf( dispbuf_ui_airtemp_set, ui_airtemp_set);

            dispbuf[0]= dispbuf_ui_airtemp_set[1];

            dispbuf[1]= dispbuf_ui_airtemp_set[0];                     

            break; 

           

        case 5:

            dispbuf[3]=16;

            dispbuf[2]=42  ;  //显示H  调节制热温度

            INT10_TO_dispbuf( dispbuf_ui_airtemp_set,   ui_airtemp_heat_set);

            dispbuf[0]= dispbuf_ui_airtemp_set[1];

            dispbuf[1]= dispbuf_ui_airtemp_set[0];                         

            break; 

                       

       

        default:

            dispbuf[3]=16;

            dispbuf[2]=16;

            dispbuf[0]=16;

            dispbuf[1]=16;                             

            break;         

       

        }//SWITCH

}

//时间走时  /

void TIME_PROCESS()

{  

        //以下本来放在中断T0中,现在移出来,避免中断超时问题

        ET0=0;      //在对tcnt进行操作前,一定要将定时器的中断禁掉

                    //因为tcnt是整型,在运算时要好几条指令,如果被定时器中断,中断中又修改了值!!  则运算结果就不准了,造成时间严重不准!!!

        if(tcnt>=3600)       //3600次,表示过了一秒钟,晶体11.0592

        {

            tcnt-=3600;     // 这句,受中断影响,中断中又修改了值!!   如果只是用tcnt=0;这句,则没有问题。  有可能别的程序在处理时(比如串口),tcnt会多计,故不能清零,不然时间不准

            ET0=1;      //马上开定时器0的中断,这样不会影响到中断服务程序

           

            ul_time_compensate++;                //时间补偿修正

            if (ul_time_compensate >= 151515UL )        //晶振偏快,经计算,XXXX秒后要减少一秒

            { ul_time_compensate=0;  }           //不增秒

            else

            {

                second++;

               

                if(second>=60)

                {

                    second=0;

                    minute++;

                    if(minute>=60)

                    {

                        minute=0;

                        hour++;

                        if(hour>=24)    hour=0;

                    }

                   

                    SENDTXTEMP();     //每分钟发送温度给TX串口记录仪

   

                    if( minute==30 ) DO_WRITETODS1302_EVERY_HALF_HOUR();  //30分时 记录时间

                }

            }

           

            //每秒 刷新显示

            REFRESH_DISPLAY();

               

        }

        ET0=1;

}

//发射红外遥控全部信号         /

//注意:不能用软延时,因为中断ISR会严重影响延时精度,造成红外发射数据错误。  要用定时器中断来统计发射时长!  这里用T0统计发射时长,用T1生成38KHZ。

void SendIRdata(unsigned char *ir_data)

{

    unsigned char idata  i,j;

    unsigned char idata  irdata;

   

    //引导码高电平 9ms

    g_uc_ir_time=32;      //实际278us*32=8.9ms

    g_b_ir_onoff=1;

    while(g_uc_ir_time);

   

    //引导码低电平 4.5ms

    g_uc_ir_time=16;      //实际278us*16=4.45ms

    g_b_ir_onoff=0;

    while(g_uc_ir_time);   

   

    //发送13字节数据

    for(i=0; i<13; i++)  

    {

        irdata=ir_data[i];

       

        for(j=0;j<8;j++)

        {

            g_uc_ir_time=2;   //0.56ms 每bit高电平,实际278us*2=0.556ms

            g_b_ir_onoff=1;

            while(g_uc_ir_time);               

       

            if(irdata & 1)    //判断最低位为1还是0。   低位先发送!!

            {

                g_uc_ir_time=6;         //1为 1.69ms长的低电平,实际278us*6=1.668ms

                g_b_ir_onoff=0;

                while(g_uc_ir_time);

            }

            else

            {

                g_uc_ir_time=2;         //0为 0.565ms长的低电平,实际278us*2=0.556ms

                g_b_ir_onoff=0;

                while(g_uc_ir_time);

            }   

             irdata=irdata>>1;

        }

    }

   

    //发送总的结束位1bit 0.56ms

    g_uc_ir_time=2;             //实际278us*2=0.556ms

    g_b_ir_onoff=1;

    while(g_uc_ir_time);

   

    //此时还在执行发射1中,不能马上退出,故后续再发射一下0

    g_uc_ir_time=2;             //实际278us*2=0.556ms

    g_b_ir_onoff=0;

    while(g_uc_ir_time);

   

    ET1=0;

    P_IR=0;   //关掉红外

}

void  P1_0_key_waitfor_release()        //等待按键松开

{

    Delay50ms(); //延时,用于消除毛刺信号,一般10~50ms

    //判断键松开,判断 连续 20ms内 均为高电平,则是键松开

    uc_keycount=0;

    while(uc_keycount<20)

    {

        if(P1_0==0) uc_keycount=0;

        Delay1ms();

        uc_keycount++;

        TIME_PROCESS();   //处理时间事务,以免按键一直按着就无法处理

    }

}

void  P1_1_key_waitfor_release()        //等待按键松开

{

    //等待按键松开

    Delay50ms(); //延时,用于消除毛刺信号,一般10~50ms

    //判断键松开,判断20ms内均为高电平,则是键松开

    uc_keycount=0;

    while(uc_keycount<20)

    {

        if(P1_1==0) uc_keycount=0;

        Delay1ms();

        uc_keycount++;

        TIME_PROCESS();   //处理时间事务,以免按键一直按着就无法处理

    }  

}

void  P1_2_key_waitfor_release()        //等待按键松开

{

    Delay50ms(); //延时,用于消除毛刺信号,一般10~50ms

    //判断键松开,判断20ms内均为高电平,则是键松开

    uc_keycount=0;

    while(uc_keycount<20)

    {

        if(P1_2==0) uc_keycount=0;

        Delay1ms();

        uc_keycount++;

        TIME_PROCESS();   //处理时间事务,以免按键一直按着就无法处理

    }

}

//切换制冷中的各种模式

void my_aircontrol_cold_turnto(unsigned char i,  unsigned char j)

{

    SendIRdata( &g_uc_irdata[i][0] ); 

    uc_ir_state=i;

   

    //设置下次检测空调温度时间

    g_uc_ir_minute=j;             //延时j分钟

    g_uc_ir_minute_pre=minute;

   

    if(i<=1)   b_ECO_ON=0;

}

//检测按键进入设置状态   

void DO_KEY_PRESS_SETTING()

{

    unsigned char idata  i;

   

    if( P1_1==1)  return;

   

    //进入设置模式

    for(i=0;  i<8;  i++)   dispbuf[i]=16;  //全显示空

    g_uc_setting_mode=1;

    REFRESH_DISPLAY();

    P1_1_key_waitfor_release();     //等待按键松开

    g_uc_settingmode_timeout_second=0;   //设置时,只进行时间走时,暂停了其它工作:不进行传感器检测、不进行串口通讯、不进行空调控制,所以需要判断一个超时,以免一直困在设置模式中

    g_ui_settingmode_timeout_cnt=0;   

   

    while(1)  //设置中

    {

            ET0=0;

            if(g_ui_settingmode_timeout_cnt>=3600)         //超过1秒

            {

                g_ui_settingmode_timeout_cnt=0;         //(有点误差没关系)

                ET0=1;

                g_uc_settingmode_timeout_second++;

                if(g_uc_settingmode_timeout_second>60)   break;    //超时,退出循环  (有点误差没关系)

            }

            ET0=1; 

               

            TIME_PROCESS();      //处理时间事务,      每秒刷新显示

       

            if( P1_2==0 )

            {  

                switch(g_uc_setting_mode)

                {

                    case 1:       //小时加1

                        hour++;

                        if(hour>=24) hour=0;

                        break;

                   

                    case 2:      //分钟加1

                        minute++;

                        if(minute>=60) minute=0;     //小时不变

                       

                        TL0=0;          //定时器重新置数

                        tcnt=0;                 //程序计数清0

                        second=0;

                        break;

                       

                    case 3:      //模式变化

                        uc_display_mode++;

                        if(uc_display_mode > 2) uc_display_mode=0;    

                        break;

                       

                    case 4:      //制冷温度设定

                        ui_airtemp_set+=5;

                        if(ui_airtemp_set > 270) ui_airtemp_set=260;

                        break;

                       

                    case 5:      //制热温度设定

                        ui_airtemp_heat_set+=5;

                        if(ui_airtemp_heat_set > 210) ui_airtemp_heat_set=200;

                        break;                                             

                }

                REFRESH_DISPLAY();

                P1_2_key_waitfor_release();     //等待按键松开

               

                g_uc_settingmode_timeout_second=0;

            }

           

            else   if  ( P1_1==0 )        //设置下一项

            {

                g_uc_setting_mode++;

                REFRESH_DISPLAY();

               

                P1_1_key_waitfor_release();     //等待按键松开

                               

                g_uc_settingmode_timeout_second=0;

               

                if(g_uc_setting_mode > 5 ) break;

            }  

    }  //WHILE

    //退出设置了,恢复显示,如果工作模式切换,则关空调

    if(uc_display_mode != uc_display_mode_pre)

    {

        //关空调

        if(uc_display_mode_pre==1)

        {

            my_aircontrol_cold_turnto(0, 0); //关空调

        }

        else if(uc_display_mode_pre==2)

        {

            //待完善

        }

        uc_display_mode_pre=uc_display_mode;

    }

   

    g_uc_setting_mode=0;

    REFRESH_DISPLAY();

   

}

//检测按键进行红外开关空调on off       

void DO_KEY_PRESS_AIRCONTROL()

{

    if( !uc_display_mode )  return;     //没在控制模式

       

   

    //进行时间延时

    if(b_ir_key_delay==1)

    {

        if(second > g_uc_ir_second  &&  second-g_uc_ir_second > 5)  b_ir_key_delay=0;          //没跨分钟

        if(second < g_uc_ir_second  &&  second+60-g_uc_ir_second > 5)  b_ir_key_delay=0;    //跨分钟了

    }

   

    if( b_ir_key_delay)    return;

       

    if(P1_0==1)  return;

    //按键有按下了

    if(uc_display_mode==1)      //制冷

    {

        if( uc_ir_state)    my_aircontrol_cold_turnto(0, 0);      //如果已开机,则关机

        else      my_aircontrol_cold_turnto(1, 1);               //没开机,则开机            //1分钟后检测温度, 以免太快发送下一个

    }

    else if(uc_display_mode==2)   //制热

    {

        //待未来加入程序

        if( uc_ir_heat_state)         //如果已开机,则关机

            ;

        else   //没开机,则开机

            ;

    }

               

    P1_0_key_waitfor_release();     //等待按键松开

   

    //按键后需要延时后才接受下一次按键,以免一直快速按键

    b_ir_key_delay=1;      

    g_uc_ir_second=second;

}  

//红外控制空调制冷   /

void DO_IR_COLD_AIRCONTROL()

{

    if( uc_display_mode!=1 )  return;     //没在制冷模式

       

    if( !bit_DS18_INDOOR_exist &&  uc_ir_state  )      my_aircontrol_cold_turnto(0, 0);       // 如果传感器突然掉线

   

   

    if(b_ECO_ON)

    {

        if( hour > ECO_hour_pre  &&  hour - ECO_hour_pre > 7)       my_aircontrol_cold_turnto(1, 1);        //没跨天

        if( hour < ECO_hour_pre  &&  hour+24 - ECO_hour_pre > 7 )   my_aircontrol_cold_turnto(1, 1);        //跨天了

    }

   

    //按键进行切换屏显

    if(P1_2==0)

    {

        SendIRdata( &g_uc_irdata_with_disp[ uc_ir_state ][0] );

        P1_2_key_waitfor_release();

    }

   

   

    //进行时间延时

    if( g_uc_ir_minute )   //需要延时

    {

        if( minute > g_uc_ir_minute_pre  &&  minute - g_uc_ir_minute_pre > g_uc_ir_minute)  g_uc_ir_minute=0;          //没跨小时

        if( minute < g_uc_ir_minute_pre  &&  minute+60 - g_uc_ir_minute_pre > g_uc_ir_minute )  g_uc_ir_minute=0;      //跨小时了

    }

   

    if( g_uc_ir_minute )    return;

    switch( uc_ir_state )

    {

    case 0:   //关机0中

        break;

       

    case 1:   //全力制冷1中

        if( i_DS18_INDOOR <= ui_airtemp_set )   { my_aircontrol_cold_turnto(2, 10);   ECO_hour_pre=hour;  b_ECO_ON=1; }//温度小于,转成ECO   //n分钟后检测温度, 因为温度会先回升,再下降,不能马上检测

        break;

       

    case 2:   //ECO2中

        if( i_DS18_INDOOR <= ui_airtemp_set )   my_aircontrol_cold_turnto(3, 10);    //温度小于,转成静音+ECO    //10分钟后检测温度, 以免太快发送下一个      如果ECO自动消掉,则温度会下降

        else if( i_DS18_INDOOR >= ui_airtemp_set+10 )    my_aircontrol_cold_turnto(1, 1);    //大于,回退至全力制冷   //1分钟后检测温度, 以免太快发送下一个

        break;

    case 3:   //ECO+静音3

        if( i_DS18_INDOOR <= ui_airtemp_set-3   )    my_aircontrol_cold_turnto(4, 10);  //ECO+静音很省电,也可能会温度太低

        else if( i_DS18_INDOOR > ui_airtemp_set+5 )  my_aircontrol_cold_turnto(2, 10);   //大于,回退至ECO            //10分钟后检测温度, 以免太快发送下一个

        break;

    case 4:   //太冷了,32度ECO+静音4

        if( i_DS18_INDOOR > ui_airtemp_set+5 )  my_aircontrol_cold_turnto(2, 10);   //大于,回退至ECO            //10分钟后检测温度, 以免太快发送下一个

        break; 

    }

}

       

   

//红外控制空调制热     ///

void DO_IR_HEAT_AIRCONTROL()

{

    if( uc_display_mode!=2 )   return;     //没在控制模式

       

    if( !bit_DS18_INDOOR_exist &&  uc_ir_heat_state )      ;                            // 如果传感器突然掉线

    //程序待补充

   

}  

   

//检测串口进行通讯       

//串口接受2个字节为一组,第一字节是命令,第二字节是数据

//没有用串口中断,4800bps的2个字节之间只有2ms,如果程序做别的事,就会收不全数据,故电脑发送时,一个字节、一个字节慢慢发

void DO_PROCESS_SERIAL_COM()

{

   

        if(RI==1)       //串口收到数据,进行处理

        {

            sbuf[sbufnum]=SBUF;

            RI=0;   //要人工清RI

            sbufnum++;     

           

            if(sbufnum>=2) 

            {

                sbufnum=0;

                //sendSBUF( "COM=", 4 );    //回显命令

                sendSBUF( sbuf, 2 );

                //sendSBUF( "!", 1 );

               

                if(sbuf[0]>=0x80)         //第一字节是命令,如果是0X80以上,发送温度、湿度;   0x80以下留给DS1302

                {

                    sendSBUF( dispbuf_DS18_OUTDOOR, 3 );

                    sendSBUF( dispbuf_DS18_INDOOR, 3 );

                }

                else if(bitDS1302exist)

                {

                    switch (sbuf[0])       //第一字节是0~8,则写入DS1302。   如果是9等,则读出DS1302

                    {

                        case 0:  //second RAW data

                                if( (sbuf[1]&0x0f)>9 || ((sbuf[1]&0xf0)>>4)>5 ) {sendSBUF("secoER!",7);break;}

                                DS1302_WriteOne(DS1302_SEC_AD,sbuf[1]);

                                readDS1302_and_setclock();

                                sendSBUF("secoOK!",7);

                                break;

                        case 1:  //minute RAW data

                                if( (sbuf[1]&0x0f)>9 || ((sbuf[1]&0xf0)>>4)>5 ) {sendSBUF("minuER!",7);break;}

                                DS1302_WriteOne(DS1302_MIN_AD,sbuf[1]);

                                readDS1302_and_setclock();

                                sendSBUF("minuOK!",7);

                                break;

                        case 2:  //hour RAW data

                                if(   (sbuf[1]&0x0f)>9 ||   ((sbuf[1]&0xf0)>>4)>2  ||     ( ((sbuf[1]&0xf0)>>4)*10+(sbuf[1]&0x0f) )>23  ) {sendSBUF("hourER!",7);break;}

                                DS1302_WriteOne(DS1302_HOUR_AD,sbuf[1]);

                                readDS1302_and_setclock();

                                sendSBUF("hourOK!",7);

                                break;

                        case 3:  //date RAW data

                                if( ( ((sbuf[1]&0xf0)>>4)*10+(sbuf[1]&0x0f) )>31  ) {sendSBUF("dateER!",7);break;}

                                DS1302_WriteOne(DS1302_DATE_AD,sbuf[1]);

                                //readDS1302_and_setclock();

                                sendSBUF("dateOK!",7);

                                break;

                        case 4:  //month RAW data

                                if( ( ((sbuf[1]&0xf0)>>4)*10+(sbuf[1]&0x0f) )>12  ) {sendSBUF("montER!",7);break;}

                                DS1302_WriteOne(DS1302_MONTH_AD,sbuf[1]);

                                //readDS1302_and_setclock();

                                sendSBUF("montOK!",7);

                                break;

                        case 5:  //week RAW data

                                if( ( ((sbuf[1]&0xf0)>>4)*10+(sbuf[1]&0x0f) )>7  ) {sendSBUF("weekER!",7);break;}

                                DS1302_WriteOne(DS1302_WEEK_AD,sbuf[1]);

                                //readDS1302_and_setclock();

                                sendSBUF("weekOK!",7);

                                break; 

                        case 6:  //year RAW data

                                if( ( ((sbuf[1]&0xf0)>>4)*10+(sbuf[1]&0x0f) )>99  ) {sendSBUF("yearER!",7);break;}

                                DS1302_WriteOne(DS1302_YEAR_AD,sbuf[1]);

                                //readDS1302_and_setclock();

                                sendSBUF("yearOK!",7);

                                break;                                                                                     

                        case 7: //设置CONTROL字节  写保护

                                sbuf[1]=sbuf[1] & 0x80; //只有最高位bit7有效,其它都是0

                                DS1302_WriteOne(DS1302_CONTROL, sbuf[1]);

                                sendSBUF("ContOK!",7);

                                break;

                        case 8: //设置TRICKLE CHARGER字节  充电

                                DS1302_WriteOne(DS1302_CHARGER_AD, sbuf[1]);

                                sendSBUF("charOK!",7);

                                break;                         

                        default:    //读出全部DS1302字节,并串口发送出去

                                BurstRead1302(ds1302_BCDdata) ;

                                ds1302_BCDdata[8]=DS1302_ReadOne(DS1302_CHARGER_AD);

                                sendSBUF( ds1302_BCDdata, 9 );

                                break;

                    }

                }

                else

                {

                    sendSBUF("DS1302 NOT exist!",17);

                }

            }//END 二个字节处理

        } //END RI==1

       

}

///

void main(void)

{

/* 测试晶振的频率,用来校准晶振的误差

AUXR = (AUXR | 0x04);  //独立波特率发生器工作在1T 模式  0000 0100   --BRTCLKOUT(CLKOUT2)      

BRT = (256-5);         //预置数,BRT独立波特率发生器的8位重装载值    //输出频率= 晶振11.0592MHz/5/2=1.10592MHz   --BRTCLKOUT(CLKOUT2)

WAKE_CLKO = (WAKE_CLKO | 0x04);  //允许 独立波特率发生器脚BRTCLKO(CLKOUT2)(P1.0) 输出时钟频率,   输出频率=定时器溢出率/2

AUXR = (AUXR | 0x10);            //启动独立波特率发生器开始计数工作   --BRTCLKOUT(CLKOUT2)

while(1) ; 

   

*/

   

   

   

   

    //红外状态

    uc_ir_state=0;

    uc_ir_heat_state=0;

    P_IR=0;

   

   

    uc_display_mode=0;                    //按走时模式

    uc_display_mode_pre=uc_display_mode;

   

    //开机是弱上拉

    P0M1=0;    //P0推挽

    P0M0=0xFF;

   

    P2M1=0;   //P2推挽

    P2M0=0xFF;

    P0=0;       //P0接各个笔划,共阳极,接地时点亮

    P2=0xFF;    //P2,置1时选择数码管

   

   

    P1M1=0;  

    P1M0=0x08;  // 0000 1000  //空调口设成推挽(红外)

    P1=0xF7;    //1111 0111  关闭空调口(红外)

   

    P3=0xFF;  //弱上拉

    DS1302_RST = 0; 

    DS1302_CLK = 0;

    Delay20ms();         //延时,让DS1302等外设上电复位

   

    DS1302_SetProtect(0);                     //上电后要取消写保护,才能对DS1302的RAM进行写入

   

    DS1302_WriteOne( 0xC0 , 0xAB);            //测试DS1302的RAM,判断DS1302是存在

    if (DS1302_ReadOne( 0xC0 ) == 0xAB)    

    {

        bitDS1302exist=1;

        DS1302_WriteOne(DS1302_CHARGER_AD,  0);   //取消对电池充电

    }

    else    bitDS1302exist=0;

    if(bitDS1302exist)  readDS1302_and_setclock();      //读取和设置时间

       

    //先显示一下,以免黑屏

    dispbuf[4]=minute%10;

    dispbuf[5]=minute/10;

    dispbuf[6]=hour%10;

    dispbuf[7]=hour/10;

    //设置定时器T0

    //TMOD=0x52;    // 0101 0010 =  T1的GATE=0选通,C/T选择为外部计数方式=1,工作方式=1 (16位计数器);  T0的GATE选通,C/T选择为C定时方式=0,工作方式=2

    TMOD = 0x22; //(定时器0和1:  GATE选通,定时方式,   工作方式2,自动重装,8位)

   

    TH0=0;     //预置数=0

    TL0=0;     //从0开始计数 即:(256-0)=256次 ,11.0592/12/256=3600 次/S

    TR0=1;        //开始计数

    ET0=1;        //允许T0的中断

   

   

    //设置定时器T1  --用于红外遥控

    TH1=244;        //预置数         //即计数12次中断一次,11.0592MHZ,即:11.0592/12/12=76.8K 次/S

    TL1=244;        //开始计数值

    TR1=1;          //开始计数  

    ET1=0;       

    PT1=1;      //中断优先级IP中的PT1=1,提高中断优先级比T0高!       这样T1中断可以中断掉T0中断

   

   

    //设置 "独立波特率发生器",用于串口 --V2版新增

    AUXR=AUXR | 1;  //不可位AUXR中的BIT0的S1BRS=1,即选用独立波特率发生器,定时器1得到释放!

    SCON=0x50;      //01 0 1 0000 模式1,无多处理机,允许接收,发送8位,接收8位,清TI=0,RI=0

    BRT=250;        //从0开始计数 即:(256-250)=6次 ,11.0592/12/6/32=4800bps,需要 波特率倍增位SMOD=0。   波特率低一些,以免处理不过来

    AUXR=AUXR | 0x10;   //不可位AUXR中的BIT4的BRTR=1,即允许独立波特率发生器运行

    ES=0;               //不允许串口总断   

    EA=1;         //允许总中断

   

   

    //串口接收到一个数据后,这时RI要为0,才会放入SBUF中并且自动置RI=1,否则丢弃这个数据。如果RI为1,则后续数据都丢掉了。

    //串口发送时,就会马上发,发完自动置TI=1。如果TI=1,不影响数据发送。  

    RI=0;       //清理一下串口

    sbufnum=0;  //串口接收到的数量

    I2C_Init();   //HTU31D

/* 测试 红外发射信号是否正常

uc_ir_state=1;

while(1)

{

    if(P1_0==0)

    {

        SendIRdata( &g_uc_irdata[uc_ir_state][0] );

        uc_ir_state++;     

        if(uc_ir_state>=4) uc_ir_state=0;

       

        P1_0_key_waitfor_release();     //等待按键松开

    }

}

*/

    while(1)  

    {

        DO_PROCESS_SERIAL_COM();    //检测串口进行通讯

        DO_KEY_PRESS_SETTING();     //检测按键进入设置状态

   

        DO_KEY_PRESS_AIRCONTROL();   //检测按键进行红外开关空调

        DO_IR_COLD_AIRCONTROL();   //红外控制空调制冷

       

        DO_IR_HEAT_AIRCONTROL();   //红外控制空调制热

        TIME_PROCESS();        //走时

       

        DO_WHAT_FUNC();      //传感器检测

    }

}

///

//中断TSR    中断处理时间不能超过一次计数时间277.777US

/*

中断每秒3600次,每次277.7777us。时间计算在主程序中进行。

//---注意:这个会影响软延时delay函数,执行一次如果是10us,则对于277us来说误差就是4%(实际执行时间未知)

*/

void t0(void) interrupt 1

{

    tcnt++;

   

    i_dowhat_interval++;   //如果按键一直按住,则会多计数,或溢出,没关系,就是dowhat间隔时间再延长而已

   

    mstcnt++;

   

   

    if(bit_T0_interrupt_prohibited)    return;    //时序要求强的操作,则后序代码不执行

       

       

    if( mstcnt>=4 )      //计数器每计数n次,改变一次显示位(定时器是3600HZ,数码管闪烁频率=3600/9次/8个管=50HZ,数码管闪烁频率=3600/4次/16个管=56HZ)

    {

        mstcnt=0;

        if(dispbitcnt<8)

        {

            P0= dispcode[dispbuf[dispbitcnt]];    //P0输出笔划。  dispbuf中是显示数据,[0]是最右那个数码管。  dispcode中是笔划。

       

            P2= dispbitcode[dispbitcnt];         //P2选择哪个数码管,dispbitcode是数码管选择码,[0]是最右那个数码管

        }

        else

            P2=0;   //不显示,16管只显示8管,用于减少一半显示亮度,以免太亮

           

        dispbitcnt++;        //选LED的下一显示位

        if(dispbitcnt>=16)  dispbitcnt=0;            //这里数值大,则亮度小,但闪烁。闪烁频率在25HZ,明显会闪。闪烁频率在50HZ,不闪。

    }

   

   

    //红外发射IR控制

    if(g_uc_ir_time)

    {

        if(g_b_ir_onoff)   ET1=1;   //本次发射IR  278us

        else    ET1=0;              //本次不发射IR  278us

        g_uc_ir_time--;

    }

    else    ET1=0;   //把红外IR关了

       

   

    //在设置模式中,需要进行计时

    if(g_uc_setting_mode)    g_ui_settingmode_timeout_cnt++;

   

}

///

//T1  --用于红外发射38KHZ

//只进行端口翻转,处理时间要短。   76.8K 次/S,  13.021us一次中断。38KHZ是26.316us周期。 1%的误差,对载波来说,没有问题。

//---这个会严重影响软延时delay函数,执行一次可能要1us,对于13us来说误差就是10%,软延时就被影响10%!!造成红外发射严重不准或其它问题

void t1(void) interrupt 3

{

    P_IR=~P_IR;        //端口翻转就有了38KHZ信号

}  

//====================================================/

DELAY_STC12_WXL.H文件:

//  STC12C5A60S2 单片机 1T  11.0592MHZ

void Delay2us()     //@11.0592MHz

{

    unsigned char i;

    _nop_();

    _nop_();

    i = 2;

    while (--i);

}

//

void Delay8us()     //@11.0592MHz

{

    unsigned char i;

    i = 19;

    while (--i);

}

//

void Delay10us()        //@11.0592MHz

{

    unsigned char i;

    _nop_();

    _nop_();

    _nop_();

    i = 24;

    while (--i);

}

//

void Delay80us()        //@11.0592MHz

{

    unsigned char i, j;

    _nop_();

    _nop_();

    _nop_();

    i = 1;

    j = 216;

    do

    {

        while (--j);

    } while (--i);

}

//

void Delay600us()       //@11.0592MHz

{

    unsigned char i, j;

    _nop_();

    _nop_();

    i = 7;

    j = 112;

    do

    {

        while (--j);

    } while (--i);

}

//

void Delay1ms()     //@11.0592MHz

{

    unsigned char i, j;

    _nop_();

    i = 11;

    j = 190;

    do

    {

        while (--j);

    } while (--i);

}

///

void Delay20ms()        //@11.0592MHz

{

    unsigned char i, j, k;

    i = 1;

    j = 216;

    k = 35;

    do

    {

        do

        {

            while (--k);

        } while (--j);

    } while (--i);

}

void Delay50ms()        //@11.0592MHz

{

    unsigned char i, j, k;

    i = 3;

    j = 26;

    k = 223;

    do

    {

        do

        {

            while (--k);

        } while (--j);

    } while (--i);

}

///以下是红外遥控用的           

void Delay9ms()     //@11.0592MHz

{

    unsigned char i, j;

    _nop_();

    _nop_();

    _nop_();

    i = 97;

    j = 206;

    do

    {

        while (--j);

    } while (--i);

}

void Delay4500us()      //@11.0592MHz

{

    unsigned char i, j;

    i = 49;

    j = 101;

    do

    {

        while (--j);

    } while (--i);

}

void Delay560us()       //@11.0592MHz

{

    unsigned char i, j;

    _nop_();

    _nop_();

    _nop_();

    i = 7;

    j = 1;

    do

    {

        while (--j);

    } while (--i);

}

void Delay1690us()      //@11.0592MHz

{

    unsigned char i, j;

    i = 19;

    j = 42;

    do

    {

        while (--j);

    } while (--i);

}

//====================================================/

DS18B20_WXL.H文件:

/*  先设置端口

sbit DQ_DS18_OUTDOOR=P3^4;

sbit DQ_DS18_INDOOR=P1^4;

*/

//

unsigned char  DS18_CRC( unsigned char   *addr, unsigned char  len)

//计算8位CRC,输入是一串字节流数据。  数据不需要扩展CRC位的0。

//注意:这里的addr[]中是原始数据,不需要扩展的一字节0,len长度为原始数据长度!!  重要!!

{

    unsigned char  idata  crc = 0, inbyte, i, mix;

    while (len--)

    {

        // inbyte 存储当前参与计算的新字节

        inbyte = *addr++;

        for (i = 8; i; i--)

        {

            mix = (crc ^ inbyte) & 0x01; // CRC寄存器最低位 与 数据的最低位 进行XOR(高位都是忽略的),看结果是1还是0,如果是1,则需要用POLY对CRC寄存器进行XOR

            crc >>= 1;      //高位移入的是0

            if (mix)

            {

                crc ^= 0x8C;   //颠倒后的POLY

            }

            inbyte >>= 1;  

        }

    }

    return crc;

}

//

int  DS18_TEMP_TO_SIGNED_INT10(unsigned char  uc_DS18_temp1, unsigned char  uc_DS18_temp2) //LSB字节 , MSB字节。

//返回值:  温度的10倍,有符号整数

//ds18b20的2个字节:  负数是全部bit取反,再加1,比如:

//55度:0000 0011 0111 0000

//取反:1111 1100 1000 1111

//加1:1111 1100 1001 0000 得-55度

//ds18b20的低4bit是小数,需要单独处理,不能合在一起转成十进制。   高5bit是符号位。  中间7bit是非小数

{

    unsigned char  idata  uc_fraction=0;

    int  idata  i_temp=0;

    bit bitminus=0;

    unsigned char  code  DS18_decimaltable[16]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};  //小数换算表,二进制温度数据0001是0.0625度,即小数显示1;0010是0.125度,即小数还是显示1;...

   

    if((uc_DS18_temp2 & 0xf8)!=0x00)     //如果是负数

    {        //是负数,2个字节合在一起整个减一,再取反,就是正数值(小数还要乘以精度)

            //或者,2个字节合在一起整个取反再加1

        bitminus=1;    //表示是负数

        uc_DS18_temp2=~uc_DS18_temp2;    

        uc_DS18_temp1=~uc_DS18_temp1;      //取反

        uc_DS18_temp1++;                 //加1

        if (uc_DS18_temp1==0) uc_DS18_temp2++;  //如果有进位,则要加1

    }

   

    uc_fraction=DS18_decimaltable[ uc_DS18_temp1 & 0x0f ];   //查表得到小数部分

   

    uc_DS18_temp2=uc_DS18_temp2<<4;        

    uc_DS18_temp2=uc_DS18_temp2 & 0x70;     //保证MSB其它位均为0

    uc_DS18_temp1=uc_DS18_temp1>>4;    //移掉LSB中的小数

    uc_DS18_temp1=uc_DS18_temp1 & 0x0f;     //保证LSB其它位均为0

    uc_DS18_temp2=uc_DS18_temp2 | uc_DS18_temp1;    //MSB与LSB的非小数部分合并,这样就是温度的绝对值的整数值

   

    i_temp=uc_DS18_temp2*10;

    i_temp+=uc_fraction;

   

    if(bitminus)    return -i_temp;

    else    return i_temp;

}

/*

//

unsigned int DS18_TEMP_TO_INT(unsigned char  uc_DS18_temp1, unsigned char  uc_DS18_temp2)   //LSB字节 , MSB字节。

//返回值 低15位=温度绝对值的10倍。如果是负数,则最高位是1。同AM2321的表达方式

//ds18b20的2个字节:  负数是全部bit取反,再加1,比如:

//55度:0000 0011 0111 0000

//取反:1111 1100 1000 1111

//加1:1111 1100 1001 0000 得-55度

//ds18b20的低4bit是小数,需要单独处理,不能合在一起转成十进制。   高5bit是符号位。

{

    unsigned char  idata  uc_fraction=0;

    unsigned int  idata  ui_temp=0;

    bit bitminus=0;

    unsigned char  idata  DS18_decimaltable[16]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};  //小数换算表,二进制温度数据0001是0.0625度,即小数显示1;0010是0.125度,即小数还是显示1;...

   

    if((uc_DS18_temp2 & 0xf8)!=0x00)     //如果是负数

    {        //是负数,2个字节合在一起整个减一,再取反,就是正数值(小数还要乘以精度)

            //或者,2个字节合在一起整个取反再加1

        bitminus=1;    //表示是负数

        uc_DS18_temp2=~uc_DS18_temp2;    

        uc_DS18_temp1=~uc_DS18_temp1;      //取反

        uc_DS18_temp1++;                 //加1

        if (uc_DS18_temp1==0) uc_DS18_temp2++;  //如果有进位,则要加1

    }

   

    uc_fraction=DS18_decimaltable[ uc_DS18_temp1 & 0x0f ];   //查表得到小数部分

   

    uc_DS18_temp2=uc_DS18_temp2<<4;        

    uc_DS18_temp2=uc_DS18_temp2 & 0x70;     //保证MSB其它位均为0

    uc_DS18_temp1=uc_DS18_temp1>>4;    //移掉LSB中的小数

    uc_DS18_temp1=uc_DS18_temp1 & 0x0f;     //保证LSB其它位均为0

    uc_DS18_temp2=uc_DS18_temp2 | uc_DS18_temp1;    //MSB与LSB的非小数部分合并,这样就是温度的绝对值的整数值

   

    ui_temp=uc_DS18_temp2*10;

    ui_temp+=uc_fraction;

   

    if(bitminus) ui_temp=ui_temp | 0x8000;      //如果是负数,则最高位变1

   

    return ui_temp;

}

*/

//

void SEND_TO_DS18_OUTDOOR( unsigned char  command ) //DQ_DS18_OUTDOOR表示哪一个DS1302,调用前DQ_DS18_OUTDOOR为高电平

{

    unsigned char  idata  i;

    for(i=0;i<8;i++)

    {

        if((command & 0x01)==0)   //command为待发送的数据。 现要发送“0”     60至120us之间

        {

            DQ_DS18_OUTDOOR=0;      //DATA=0,DATA从高到低,表示开始传送数据(传送开始到传送完的整个时间在60-120US之内)

            Delay80us();    //延时120us(不能太大,不然就变成复位了)   (先经过15US,然后DS18会开始检测DATA数据)

            DQ_DS18_OUTDOOR=1;      //“0”发送完成,拉高 ,然后需要至少1US的恢复时间(即高电平时间)

            Delay2us();

        }

        else            //现要发送“1”       最小 60  us

        {

            MACRO_WXL_INTERRUPT_PROHIBITED      //自定义宏,强时序操作时中断服务简化

            DQ_DS18_OUTDOOR=0;      //DATA=0,DATA从高到低,表示开始传送数据(传送开始到传送完的整个时间在60-120US之内)

            Delay2us(); //延时(经过15US后DS18会开始检测DATA数据,因此应尽快变1)

            DQ_DS18_OUTDOOR=1;      //DATA=1,送出DATA值

            MACRO_WXL_INTERRUPT_ALLOWED

            Delay80us();    //延时80~∝us

        }

        command=_cror_(command,1);   //循环移位

    }

}   //END,调用后DQ_DS18_OUTDOOR为高电平

//

unsigned char RECEIVE_FROM_DS18_OUTDOOR( )  //DQ_DS18_OUTDOOR表示哪一个DS1302,调用前DQ_DS18_OUTDOOR为高电平

{

    unsigned char  idata  i,temp;

    temp=0;

    for(i=0;i<8;i++)   

    {

        temp=_cror_(temp,1);    //移位,LSb先传送

        MACRO_WXL_INTERRUPT_PROHIBITED       //自定义宏,强时序操作时中断服务简化

        DQ_DS18_OUTDOOR=0;                   //DATA=0,从高到低,表示开始数据接收

        Delay2us();     //开始数据接收后,需先DATA=0至少1US进行INIT

        DQ_DS18_OUTDOOR=1;                   //DATA=1,以进行检测

        Delay8us(); //延时8us    (开始数据接收后,DS18只输出数据15US)

        if(DQ_DS18_OUTDOOR==1)    temp=temp | 0x80;           //读DATA

        MACRO_WXL_INTERRUPT_ALLOWED

        Delay80us();    //延时80~∝us    (整个读取时间至少是60US,再加1US的恢复时间(即高电平时间)

    }

    return temp;

}   //END,调用后DQ_DS18_OUTDOOR为高电平

//

bit RESET_DS18_OUTDOOR(  )  //DQ_DS18_OUTDOOR表示哪一个DS1302,调用前DQ_DS18_OUTDOOR为高电平。   返回0表示出错

{

    DQ_DS18_OUTDOOR=1;

    Delay2us();

    if(DQ_DS18_OUTDOOR==0) return 0;

   

    DQ_DS18_OUTDOOR=0;

    Delay600us();       //延时750us

    DQ_DS18_OUTDOOR=1;

    Delay80us();        //延时80us 

    if(DQ_DS18_OUTDOOR==1) return 0;   //如果DS18B20有下拉,则存在DS18B20

    Delay600us();       //延时670us

    return 1;

}   //END,调用后DQ_DS18_OUTDOOR为高电平

//

//

void SEND_TO_DS18_INDOOR( unsigned char  command )  //DQ_DS18_INDOOR表示哪一个DS1302,调用前DQ_DS18_INDOOR为高电平

{

    unsigned char  idata  i;

    for(i=0;i<8;i++)

    {

        if((command & 0x01)==0)   //command为待发送的数据。 现要发送“0”     60至120us之间

        {

            DQ_DS18_INDOOR=0;       //DATA=0,DATA从高到低,表示开始传送数据(传送开始到传送完的整个时间在60-120US之内)

            Delay80us();    //延时120us(不能太大,不然就变成复位了)   (先经过15US,然后DS18会开始检测DATA数据)

            DQ_DS18_INDOOR=1;       //“0”发送完成,拉高 ,然后需要至少1US的恢复时间(即高电平时间)

            Delay2us();

        }

        else            //现要发送“1”       最小 60  us

        {

            MACRO_WXL_INTERRUPT_PROHIBITED    //自定义宏,强时序操作时中断服务简化

            DQ_DS18_INDOOR=0;       //DATA=0,DATA从高到低,表示开始传送数据(传送开始到传送完的整个时间在60-120US之内)

            Delay2us(); //延时(经过15US后DS18会开始检测DATA数据,因此应尽快变1)

            DQ_DS18_INDOOR=1;       //DATA=1,送出DATA值

            MACRO_WXL_INTERRUPT_ALLOWED

            Delay80us();    //延时80~∝us

        }

        command=_cror_(command,1);   //循环移位

    }

}   //END,调用后DQ_DS18_INDOOR为高电平

//

unsigned char RECEIVE_FROM_DS18_INDOOR( )   //DQ_DS18_INDOOR表示哪一个DS1302,调用前DQ_DS18_INDOOR为高电平

{

    unsigned char  idata  i,temp;

    temp=0;

    for(i=0;i<8;i++)   

    {

        temp=_cror_(temp,1);    //移位,LSb先传送

        MACRO_WXL_INTERRUPT_PROHIBITED     //自定义宏,强时序操作时中断服务简化

        DQ_DS18_INDOOR=0;                   //DATA=0,从高到低,表示开始数据接收

        Delay2us();     //开始数据接收后,需先DATA=0至少1US进行INIT

        DQ_DS18_INDOOR=1;                   //DATA=1,以进行检测

        Delay8us(); //延时8us    (开始数据接收后,DS18只输出数据15US)

        if(DQ_DS18_INDOOR==1)    temp=temp | 0x80;           //读DATA

        MACRO_WXL_INTERRUPT_ALLOWED

        Delay80us();    //延时80~∝us    (整个读取时间至少是60US,再加1US的恢复时间(即高电平时间)

    }

    return temp;

}   //END,调用后DQ_DS18_INDOOR为高电平

//

bit RESET_DS18_INDOOR(  )   //DQ_DS18_INDOOR表示哪一个DS1302,调用前DQ_DS18_INDOOR为高电平。   返回0表示出错

{

    DQ_DS18_INDOOR=1;

    Delay2us();

    if(DQ_DS18_INDOOR==0) return 0;

   

    DQ_DS18_INDOOR=0;

    Delay600us();       //延时750us

    DQ_DS18_INDOOR=1;

    Delay80us();        //延时80us 

    if(DQ_DS18_INDOOR==1) return 0;     //如果DS18B20有下拉,则存在DS18B20

    Delay600us();       //延时670us

    return 1;

}   //END,调用后DQ_DS18_INDOOR为高电平

//====================================================/

I2C_HTU31D.H文件:

//根据别人的程序修改的

void I2C_Delay(unsigned char t)

{

    while(t--)

    {

        Delay10us();

    }

}

/*================================================================

【名 称】unsigned char I2CWRByte(unsigned char WriteData)

【功 能】I2C写一个字节数据,返回ACK或者NACK

【备 注】从高到低,依次发送

================================================================*/

unsigned char I2C_WriteByte(unsigned char   WriteData)

{

    unsigned char idata i;

    //SCL = 0;                //写之前,SCL、SDA已经是0

    for(i = 0;i < 8;i++)       //第1~8位,写给对方,  MSb先发

    {

        I2C_Delay(10);   //稳定SCL低电平

        if(WriteData & 0x80)            SDA = 1;   

        else            SDA = 0;

        I2C_Delay(40);   //稳定SDA

       

        SCL = 1;           //输出SDA稳定后,拉高SCL给出上升沿,从机检测到后进行数据采样

        I2C_Delay(50);   //高电平500us

        SCL = 0;

           

        WriteData <<= 1;

    }

   

    I2C_Delay(10);     //稳定SCL低电平

    SDA = 1;

    I2C_Delay(40);

   

    SCL = 1;                 //第9位,读对方发来的是ACK还是NACK。   注意: I2C里,回应ACK是SDA拉低电平,NACK是释放SDA(高电平)!!对于主机设备、外设都是这样!!

    I2C_Delay(50);

    if( SDA )   i=1;            //SDA为高,收到NACK

    else        i=0;            //SDA为低,收到ACK

    SCL = 0;

   

    //_nop_(); _nop_();    _nop_();    _nop_();

    I2C_Delay(1);                            //稳定SCL低电平

    SDA=0;                                    //返回时,SCL、SDA都是0

    return i;

}

/*================================================================

【名 称】unsigned char I2CRDByte(unsigned char AckValue)

【功 能】I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK

【备 注】从高到低,依次接收

================================================================*/

unsigned char I2C_ReadByte(unsigned char   AckValue)

{

    unsigned char idata i;

    unsigned char idata ReadData = 0;

   

     //读之前,SCL、SDA已经是0

     

    SDA = 1;            //释放SDA

   

    for(i = 0;i < 8;i++)

    {

       

        I2C_Delay(50);  //稳定SCL低电平   

       

        SCL = 1;               //SCL上升沿

        I2C_Delay(50);     //延时SCL高电平500us等待信号稳定    注:在后期测比较好,相当于速率更慢,SDA信号更稳定

        ReadData <<= 1;

        if(SDA == 1)        //采样获取数据      数据是MSB最高字节在先、MSb最高位在先

            ReadData |= 0x01;

        else

            ReadData &= 0xfe;

        SCL = 0;       

    }  

   

    I2C_Delay(10);    //稳定SCL低电平

    SDA = AckValue;   //应答状态

    I2C_Delay(40);

    SCL = 1;  

  I2C_Delay(50);         

  SCL = 0;

    I2C_Delay(1);

    SDA=0;                           //返回时,SCL、SDA都是0

   

    return ReadData;

}

/*================================================================

【名 称】void I2CStart(void)

【功 能】I2C启动信号

【备 注】SCL、SDA同为高,SDA跳变成低之后,SCL跳变成低

================================================================*/

void I2C_Start(void)

{

    SDA = 1;

    I2C_Delay(1);

    SCL = 1;

    I2C_Delay(20);       // SCL高电平200us

    SDA = 0;

    I2C_Delay(10);       // SCL高电平100us

    SCL = 0;

    I2C_Delay(1);        //返回时,SCL、SDA都是0

}

/*================================================================

【名 称】void I2CStop(void)

【功 能】I2C停止信号

【备 注】SCL、SDA同为低,SCL跳变成高之后,SDA跳变成高

================================================================*/

void I2C_Stop(void)

{

        //之前,SCL、SDA已经是0

        I2C_Delay(10);        // SCL低电平500us

        SDA = 0;

        I2C_Delay(40);

       

    SCL = 1;

    I2C_Delay(10);       // SCL高电平100us

    SDA = 1;               //返回时,SCL、SDA都是0

}

/*================================================================

【名 称】void I2C_Init(void)

【功 能】I2C初始化,空闲状态

================================================================*/

void I2C_Init(void)

{

    unsigned char idata  i;

    for(i = 0;i < 99;i++)       //做99次,如果 外设 有发送什么数据什么的,可以让它全部发完

    {

    I2C_Start();

    I2C_Stop();

    }

}

/

unsigned char HTU31D_conversion( unsigned char addr )    //返回  0表示HTU回应错误,  1表示成功

{

   

    I2C_Start();

   

    if(I2C_WriteByte( addr<<1 ) == 0)   //发送地址+wr,  addr接GND是0x40,接VCC是0x41,  wr是LSB位是0。   HTU会反馈ACK0

    {

        if(I2C_WriteByte( 0x5E ) == 0)   //发送精度要求, 按最大精度,  01011110= 0x5E。   HTU会反馈ACK0

        {

            I2C_Stop();

            return 1;   //成功

        }

    }

    I2C_Stop();

    return 0;  //不成功

}

unsigned char  CRC_noadd0(unsigned char    *addr, unsigned char    len)  

//计算8位CRC,输入是一串字节流数据。  按变种计算方式,数据不需要扩展CRC位的0,可以扩展CRC值。

//注意:这里的addr[]中是原始数据,不需要扩展的一字节0,len长度为原始数据长度!!  重要!!

//注意:这里的addr[]中可以扩展一字节CRC值,len长度为原始数据长度+1,这样计算出来CRC值就是0。

{

    unsigned char  idata   crc = 0, inbyte, i;

    while (len--)

    {

        // inbyte 存储当前参与计算的新字节

        inbyte = *addr++;

        for (i = 8; i; i--)

        {

             //CRC寄存器移出的高位与待测数据移出的高位相XOR,是1则要把CRC寄存器XOR

            if(    (crc & 0x80) ^ (inbyte & 0x80)  )

            {

                    crc<<=1;

                    crc^=0x31;                             

            }

            else

                  crc<<=1;

               

                    inbyte<<=1;

        }

    }

    return crc;

}

unsigned char HTU31D_CRC(unsigned char  MSB,  unsigned char LSB,   unsigned char   CRC)      //HTU31D发送数据是MSB最高字节在先、MSb最高位在先,计算CRC也这样

{

    unsigned char  idata  ucdata[3];

    ucdata[0]=MSB;

    ucdata[1]=LSB;

    ucdata[2]=CRC;

    return CRC_noadd0(ucdata, 3);

}

unsigned char HTU31D_readTRH(int   *wendu,  int   *shidu,  unsigned char addr )     //返回0表示HTU回应错误,  1表示成功。   值低15位= 温度或湿度 绝对值的10倍。如果是负数,则最高位是1。

{

   

    unsigned char idata MSB, LSB, CRC;

    unsigned int idata temp;

    float idata ftemp;

   

    I2C_Start();

   

    if(I2C_WriteByte( addr<<1 ) == 0)   //发送地址+wr,  addr接GND是0x40,接VCC是0x41,  wr是LSB位是0。   HTU会反馈ACK0

    {

        if(I2C_WriteByte( 0 ) == 0)   //发送Read T & RH。   HTU会反馈ACK0

        {

            I2C_Stop();

            I2C_Start();

            if(I2C_WriteByte( (addr<<1) + 1 ) == 0)   //发送地址+rd,  addr接GND是0x40,接VCC是0x41,  rd是LSB位是1。   HTU会反馈ACK0

            {

                MSB = I2C_ReadByte(0);    //读取温度MSB,并发送ACK0来确认

                LSB = I2C_ReadByte(0);     //读取温度LSB,并发送ACK0来确认

                CRC = I2C_ReadByte(0);          //读取CRC,并发送ACK0来确认

                if(HTU31D_CRC(MSB,LSB,CRC))          //CRC出错

                {

                    *wendu=1200;

                }      

                else    //CRC正常

                {

                    temp = MSB;

                    temp<<=8;

                    temp += LSB;

                   

                    ftemp= -40. + 165. * ( (float)temp / 65535. ) ;        //温度:T ℃= -40 + 165 * ST / 65535    ,float 约精确到6位数,可以满足               

                    if(ftemp>=0)

                        *wendu=  (int)(  (ftemp+0.05) *10.);               //四舍五入 

                    else

                        *wendu=  (int)(  (ftemp-0.05) *10.);                 

                }

               

                MSB = I2C_ReadByte(0);    //读取湿度MSB,并发送ACK0来确认

                LSB = I2C_ReadByte(0);     //读取湿度LSB,并发送ACK0来确认

                CRC = I2C_ReadByte(1);          //读取CRC,并发送 NACK1 来确认要停止了

                I2C_Stop();

                if(HTU31D_CRC(MSB,LSB,CRC))          //CRC出错

                {

                    *shidu=1200;

                }      

                else    //CRC正常              

                {

                    temp = MSB;

                    temp<<=8;

                    temp += LSB;

                    *shidu=(int)( (100.*( (float)temp / 65535.) + 0.05) *10. ) ;   //四舍五入     //湿度: RH%= 100 * SRH / 65535   ,float 约精确到6位数,可以满足

                }

               

                //在主程序判断数值是否异常。比如温度值太大,说明数据异常

               

                return 1;  //成功

            }

        }

    }

    I2C_Stop();

    return 0;  //不成功

}

//====================================================/

DS1302_wxl.H文件:

/********************************************************************

文件名称: DS1302.H

创建人:kuloqiu

描述:

   完成于2010.9.9 硬件测试通过

********************************************************************/    

//硬件接口定义

/*

sbit DS1302_CLK=P1^5; 

sbit DS1302_IO=P1^6; 

sbit DS1302_RST=P1^7;

*/

//DS1302内部寄存器地址

#define DS1302_SEC_AD    0x80 //秒数据地址   //秒寄存器地址   1000 000X    BIT0是1表示读,是0表示写。  BIT7恒为1。   BIT6是1表示内存RAM区,0表示CLOCK区。

#define DS1302_MIN_AD   0x82 //分数据地址

#define DS1302_HOUR_AD   0x84 //时数据地址

#define DS1302_DATE_AD    0x86 //日数据地址

#define DS1302_MONTH_AD   0x88 //月数据地址

#define DS1302_WEEK_AD    0x8A //星期数据地址   

#define DS1302_YEAR_AD    0x8C //年数据地址

#define DS1302_CONTROL    0x8E //WP写保护控制

#define DS1302_CHARGER_AD 0x90 //充电涓电流                  1001 000X

//传输方式

#define DS1302_NWCLOCK    0xBE   //多字节突发方式写时钟

#define DS1302_NRCLOCK    0xBF   //多字节突发方式读时钟

#define DS1302_NWRAM    0xFE   //多字节突发方式写RAM

#define DS1302_NRRAM    0xFF   //多字节突发方式读RAM

#define DS1302_RAM(X) (0xC0+(X)*2)   //用于计算 RAM 地址的宏。  1100 000X  ~ 1111 111X  ,即 写C0/读C1、写C2/读C3、写C4/读C5、 ~  写FE/读FF ,即地址按C0、C2、C4。。。再赋BIT0

#define BCD(X) ((X/10)<<4|(X%10))     //数值  转成 BCD格式

//地址命令0位

#define DS1302_READ       0X01 //读

#define DS1302_WRITE      0X00 //写

//函数定义

extern void DS1302_innerWriteByte(unsigned char cdata);

extern unsigned char DS1302_innerReadByte();

extern void DS1302_WriteOne(unsigned char address,unsigned char cdata);

extern unsigned char DS1302_ReadOne(unsigned char address);

extern void DS1302_SetProtect(bit flag);

extern void DS1302_SetRtc(unsigned char *tible);

extern void DS1302_ReadRtc(unsigned char *timeread);

extern void Display_TimePROESS(unsigned char dplay[8],unsigned char *tible); 

extern void DS1302_NReadRam(unsigned char *rstr);

extern void DS1302_NWriteRam(unsigned char *wstr);

/********************************************************************

文件名称: DS1302.c

********************************************************************/ 

void DS1302delay(void )

{

_nop_();

_nop_();

_nop_();

_nop_();

   

}

void DS1302_innerWriteByte(unsigned char cdata) //实时时钟写入一字节(内部函数),调用时需要CLK=0,返回时CLK=0, IO=1

//写入DS1302是CLK=0时准备数据,上升沿写入;

//读取DS1302是CLK下降沿后的CLK=0时可以读

{

    unsigned char  idata  i;

    unsigned char  idata  acc;

    acc = cdata;

    for(i=8; i>0; i--)

    {

        DS1302_IO  =acc & 1;            //低位先传送

        DS1302delay();                              //(进入时,CLK先进行延时一下)

        DS1302_CLK = 1;        //上升沿写入

        DS1302delay();

        DS1302_CLK = 0;               

        acc = acc >> 1;

    }

    DS1302_IO  =1;

}  //返回时CLK=0,IO=1,没有延时一下

unsigned char  DS1302_innerReadByte() //实时时钟读取一字节(内部函数),调用时需要CLK=0,数据IO处于可读状态,返回时CLK=0, IO=1

//写入DS1302是CLK=0时准备数据,上升沿写入;

//读取DS1302是CLK下降沿后的CLK=0时可以读

{

    unsigned char  idata  i;

    unsigned char  idata  acc,temp;

    for(i=8; i>0; i--)

    {   

        acc = acc >>1;            //低位先传送

        DS1302_IO=1;

        DS1302delay();                                   //(进入时,CLK先进行延时一下)

        temp=DS1302_IO;          //先读数,再 CLK 上升沿

        acc = (temp<<7) | acc;

        DS1302_CLK = 1;

        DS1302delay();

        DS1302_CLK = 0;         

    }

    return(acc);

}  //返回时CLK=0,IO=1,没有延时一下

/********************************************************************

函数名称: DS1302_WriteOne(unsigned char address,unsigned char cdata)

函数功能: 向指定地址写单个数据

输入参数: address要写入对象的地址, cdata 要写的数据

输出参数:     

********************************************************************/

void DS1302_WriteOne(unsigned char address,unsigned char cdata)

//ucAddr: DS1302地址,   ucData: 要写的数据

{

    DS1302_RST = 0;

    DS1302_CLK = 0;

    DS1302delay();    //RST变上升要有1us以上间隔

    DS1302_RST = 1;

   

    DS1302_innerWriteByte(address & 0xFE);       // 地址 | "写命令"   BIT0是0

    DS1302_innerWriteByte(cdata);       // 写1Byte数据

   

    DS1302delay();      //延时一下CLK低电平

    DS1302_CLK = 0;  

    DS1302_RST = 0;

}

/********************************************************************

函数名称: DS1302_ReadOne(unsigned char address)

函数功能: 向指定地址读出单个数据

输入参数: address要读出对象的地址

输出参数:     

********************************************************************/

unsigned char DS1302_ReadOne(unsigned char address) //读取DS1302某地址的数据

{

    unsigned char  idata  ucData;

    DS1302_RST = 0;

    DS1302_CLK = 0;

    DS1302delay();    //RST变上升要有1us以上间隔

    DS1302_RST = 1;

   

    DS1302_innerWriteByte(address | 0x01);        // 地址 | "读命令"    BIT0是1

    ucData = DS1302_innerReadByte();         // 读1Byte数据

   

    DS1302delay();        //延时一下CLK低电平

    DS1302_CLK = 0;

    DS1302_RST = 0;

    return(ucData);

}

/********************************************************************

函数名称: DS1302_SetProtect(bit flag)

函数功能: wp保护开关

输入参数: flag:1保护,0不保护

输出参数:     

********************************************************************/

void DS1302_SetProtect(bit flag)        //是否写保护 

{

if(flag)

   DS1302_WriteOne(DS1302_CONTROL,0x80);    //DS1302_CONTROL=0x8E,WP写保护

else

   DS1302_WriteOne(DS1302_CONTROL,0x00);

}

/********************************************************************

函数名称: DS1302_SetRtc(unsigned char *settime)

函数功能: 设置实时时钟

输入参数: *settime:设置的具体时间数组首地址

输出参数:     

********************************************************************/

/* 未使用

void DS1302_SetRtc(unsigned char *settime)  

{

unsigned char i;

unsigned char tible[7];

for(i=0;i<7;i++)

{      

   tible[i]=BCD(settime[i]); //BCD转换

}

DS1302_SetProtect(0);   //关写保护

DS1302_WriteOne((DS1302_YEAR_AD|DS1302_WRITE),tible[6]);   //年

DS1302_WriteOne((DS1302_WEEK_AD|DS1302_WRITE),tible[5]);   //周

DS1302_WriteOne((DS1302_MONTH_AD|DS1302_WRITE),tible[4]); //月

DS1302_WriteOne((DS1302_DATE_AD|DS1302_WRITE),tible[3]); //日

DS1302_WriteOne((DS1302_HOUR_AD|DS1302_WRITE),tible[2]); //时

DS1302_WriteOne((DS1302_MIN_AD|DS1302_WRITE),tible[1]); //分

DS1302_WriteOne((DS1302_SEC_AD|DS1302_WRITE),tible[0]); //秒

//DS1302_SetProtect(1);   //开写保护

}

*/

/********************************************************************

函数名称: DS1302_ReadRtc(unsigned char *timeread)

函数功能: 读取时钟

输入参数: *timeread:读到的时间数据存放的地址

输出参数:     

********************************************************************/

/* 未使用

void DS1302_ReadRtc(unsigned char *timeread)

{    

timeread[6]=DS1302_ReadOne(DS1302_YEAR_AD);

timeread[5]=DS1302_ReadOne(DS1302_WEEK_AD);

timeread[4]=DS1302_ReadOne(DS1302_MONTH_AD);

timeread[3]=DS1302_ReadOne(DS1302_DATE_AD);

timeread[2]=DS1302_ReadOne(DS1302_HOUR_AD);

timeread[1]=DS1302_ReadOne(DS1302_MIN_AD);

timeread[0]=DS1302_ReadOne(DS1302_SEC_AD);

}

*/

/********************************************************************

函数名称: Display_TimePROESS(unsigned char dplay[8],unsigned char tible[7])

函数功能: 处理显示的数据 __仅显示时分秒 ,因为时间寄存器内存放的是BCD码

输入参数: dplay[8]:处理后的数据   tible[7]:读到后未处理的数据

输出参数:        

********************************************************************/

/* 未使用

void Display_TimePROESS(unsigned char dplay[8],unsigned char tible[7]) //BCD分成两部分转十六进制

{

dplay[0]=tible[2]/16; //时

dplay[1]=tible[2]%16;

dplay[2]=10;

dplay[3]=tible[1]/16; //分

dplay[4]=tible[1]%16;

dplay[5]=10;

dplay[6]=tible[0]/16; //秒

dplay[7]=tible[0]%16;

}   

*/

/********************************************************************

函数名称: DS1302_NReadRam(unsigned char *rstr)

函数功能: 多字节突发模式读RAM,

    DS1302_NRRAM 一次可进行31个片内RAM单元读

输入参数: *rstr:存放读到的N个数据

输出参数:        

********************************************************************/

void DS1302_NReadRam(unsigned char *rstr)

{

unsigned char  idata  i;

DS1302_RST=0;

DS1302_CLK=0;

DS1302delay();    //RST变上升要有1us以上间隔

DS1302_RST=1;       

DS1302_innerWriteByte(DS1302_NRRAM);   // 写0xFF,多字节突发方式读RAM

for(i=0;i<31;i++)     //连续31 字节

{

   *rstr=DS1302_innerReadByte() ;

   rstr++;

}

DS1302delay();        //延时一下CLK低电平

DS1302_RST=0;

DS1302_CLK=0;

}

/********************************************************************

函数名称: DS1302_NReadRam(unsigned char *rstr)

函数功能: 多字节突发模式写RAM,

    DS1302_NRRAM 一次可进行31个片内RAM单元写

输入参数: *wstr:要被写入的N个数据

输出参数:        

********************************************************************/

void DS1302_NWriteRam(unsigned char *wstr)

{

unsigned char  idata  i;

unsigned char  idata  *tmpstr;  

tmpstr=wstr ;

DS1302_SetProtect(0);   //关写保护

DS1302_RST=0;

DS1302_CLK=0;

DS1302delay();    //RST变上升要有1us以上间隔

DS1302_RST=1;

DS1302_innerWriteByte(DS1302_NWRAM);   //写 0xFE ,多字节突发方式写RAM

for(i=0;i<31;i++)     //连续31 字节

{

   DS1302_innerWriteByte(*tmpstr) ;      

   tmpstr++;

}

DS1302delay();      //延时一下CLK低电平

DS1302_RST=0;

DS1302_CLK=0;

//DS1302_SetProtect(1);   //开写保护

}

//

void BurstWrite1302(unsigned char *pWClock)  //往DS1302写入时钟数据(多字节方式)

{

    unsigned char  idata  i;

   

    DS1302_SetProtect(0);   //关写保护

   

    DS1302_RST = 0;

    DS1302_CLK = 0;

    DS1302delay();    //RST变上升要有1us以上间隔

    DS1302_RST = 1;

   

    DS1302_innerWriteByte(0xbe);         // 0xbe为时钟多字节写时钟命令

    for (i = 8; i>0; i--)         //8Byte = 7Byte 时钟数据 + 1Byte 控制       //时钟块写时,必须至少写8个字节。

    {

        DS1302_innerWriteByte(*pWClock);  // 写1Byte数据   //返回时CLK=0

        pWClock++;

    }

   

    DS1302delay();      //延时一下CLK低电平

    DS1302_CLK = 0;

    DS1302_RST = 0;     //  RST  0=复位  1=运行

}   //返回时  RST=0

//

void BurstRead1302(unsigned char *pRClock) //读取DS1302时钟数据(时钟多字节方式)

{

    unsigned char  idata  i;

   

    DS1302_RST = 0;             //  RST  0=复位  1=运行。复位后都是先写

    DS1302_CLK = 0;     //  CLK

            //写入DS1302是CLK=0时准备数据,上升沿写入;

            //读取DS1302是CLK下降沿后的CLK=0时可以读

    DS1302delay();    //RST变上升要有1us以上间隔

    DS1302_RST = 1;             //  RST  0=复位  1=运行

   

    DS1302_innerWriteByte(0xbf);        // 0xbf:   时钟多字节读命令

    for (i=8; i>0; i--)

    {

       *pRClock = DS1302_innerReadByte();   // 读1Byte数据    //返回时CLK=0

       pRClock++;

    }

   

    DS1302delay();      //延时一下CLK低电平

    DS1302_CLK = 0;

    DS1302_RST = 0;     //  RST  0=复位  1=运行

}       //返回时  RST=0

//

void  wxl_BCDToStr(unsigned char  *ds1302_BCDdata,  char  *ds1302_strtime)     //ds1302_strtime[18]时间字串,用于串口输出。时间18字节。

{

ds1302_strtime [0] = ((ds1302_BCDdata[6]>>4) & 0x0F) + '0';  //年

ds1302_strtime [1] = ((ds1302_BCDdata[6]) & 0x0F) + '0';

ds1302_strtime [2] ='.';

ds1302_strtime [3] = ((ds1302_BCDdata[4]>>4) & 0x0F) + '0';  //月

ds1302_strtime [4] = ((ds1302_BCDdata[4]) & 0x0F) + '0';

ds1302_strtime [5] ='.';

ds1302_strtime [6] = ((ds1302_BCDdata[3]>>4) & 0x0F) + '0';  //日

ds1302_strtime [7] = ((ds1302_BCDdata[3]) & 0x0F) + '0';

ds1302_strtime [8] =' ';

ds1302_strtime [9] = ((ds1302_BCDdata[2]>>4) & 0x0F) + '0';  //时

ds1302_strtime [10] = ((ds1302_BCDdata[2]) & 0x0F) + '0';

ds1302_strtime [11] =':';

ds1302_strtime [12] = ((ds1302_BCDdata[1]>>4) & 0x0F) + '0';  //分

ds1302_strtime [13] = ((ds1302_BCDdata[1]) & 0x0F) + '0';

ds1302_strtime [14] =':';

ds1302_strtime [15] = ((ds1302_BCDdata[0]>>4) & 0x0F) + '0';  //秒

ds1302_strtime [16] = ((ds1302_BCDdata[0]) & 0x0F) + '0';

ds1302_strtime [17] =0;

}

 

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值