SD2303的具体应用

来源:互联网 发布:图片音乐合成软件 编辑:程序博客网 时间:2024/06/12 01:19

 

#include <io8535v.h>                   //寄存器定义文件
#include <macros.h>                    //使用到宏
#define uchar unsigned char            //数据类型定义
#define uint unsigned char             //数据类型定义
#define SD2303 0x64                    //SD2303器件IIC识别码


uchar Table[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x38,0x76};
     //显示数据表 0    1    2     3   4    5    6    7    8    9    L    H 
uchar Data[4]={0,0,0,0};               //DS1722
uchar Enter_Flag;                      //确定
uchar F_Flag;                          //数据应答标志

void DelayMs(uint i)                   //延时函数1
{uchar j;
 for(;i!=0;i--)
  {for(j=2000;j!=0;j--) {;}}
}

void Display(uchar *p)                //显示函数
{uchar i,sel=0x00;
 for(i=0;i<16;i++)
  {PORTC=sel;
   PORTA=Table[p[i]];
   DelayMs(10);
   sel=sel<<1;
  }
}

 
void NOPNOP(uchar i)                   //延时函数2
{for(;i!=0;i--) NOP();}

void SetSCL(uchar i)                   //IIC时钟线SCL设置
{if(i==1) PORTB=PORTB|0x01;
 else     PORTB=PORTB&0xFE;}
 
void SetSDA(uchar i)                   //IIC数据线SDA设置
{if(i==1) PORTB=PORTB|0x02;
 else     PORTB=PORTB&0xFD;}
 
//SCL=PB^0;       SD2303时钟线 
//SDA=PB^1;       SD2303数据线
//INTRB=PB^3;     SD2303中断线A
//INTRA=PB^2;     SD2303中断线B

void Start()                           //IIC总线开始信号
{SetSDA(1);
 SetSCL(1);
 NOPNOP(50);
 SetSDA(0);
 NOPNOP(50);
 SetSCL(0);
}

void Stop()                            //IIC总线停止信号
{SetSDA(0);            
 SetSCL(1);
 NOPNOP(50);
 SetSDA(1);
 NOPNOP(50);
 SetSCL(0);
}

void Ack()                             //单片机应答信号
{SetSDA(0);
 SetSCL(1);  
 NOPNOP(50);
 SetSCL(0);
 SetSDA(1);    
}

void Nack()                            //单片机非应答信号
{SetSDA(1);
 SetSCL(1);
 NOPNOP(50);
 SetSCL(0);
 SetSDA(0);
}

void Check_Ack()                       //器件应答信号检查
{SetSDA(1);
 SetSCL(1);
 F_Flag=0;
 DDRB=DDRB&0xFD;
 if((PINB&0x02)==0)
   {SetSCL(0);
    NOPNOP(50);}
 else
    {F_Flag=1;
     SetSCL(0);
     NOPNOP(50);}
DDRB=DDRB|0x02;
}

void Write_Bit0()                      //向IIC总线写0
{SetSDA(0);
 SetSCL(1);
 NOPNOP(50);
 SetSCL(0);
}

void Write_Bit1()                      //向IIC总线写1
{SetSDA(1);
 SetSCL(1);
 NOPNOP(50);
 SetSCL(0);
 SetSDA(0);
}

void Write_Byte(uchar Data)            //向IIC总线写一字节数据
{uchar i;
 for(i=0;i<8;i++)
   {if((Data&0x80)>0)      
         Write_Bit1();
    else
         Write_Bit0();
    Data<<=1;                       
    }
}


uchar Read_Byte()                      //从IIC总线读一字节数据
{uchar nn=0xff;            
 uchar j;
 for (j=0;j<8;j++)
    {SetSDA(1);
     SetSCL(1);
     DDRB=DDRB&0xFB;
 
       if((PINB&0x02)==0)
     {nn<<=1;
         nn=(nn&0xfe);                
         SetSCL(0);}
     else
        {nn<<=1;
         nn=(nn|0x01);                
         SetSCL(0);}
    }
  DDRB=DDRB|0x02;
 return(nn);             
}

//****************************写N个字节子程序**********************//
//函数参数说明:
//Slave:IIC器件地址,如上文定义的SD2303
//Address:起始地址
//Array:读数据存放的数组
//Number:读取的字节数
void Write_Nbyte(uchar Slave,uchar Address,uchar *Array,uchar Number)
{uchar k;
 writ:do                     //开始->写IIC器件地址->检查应答位
    {Start();
     Write_Byte(Slave);
     Check_Ack();
    }while(F_Flag==1);
   do
    {Write_Byte(Address<<4); //送起始地址->检查应答位
     Check_Ack();
    }while(F_Flag==1);
   for(k=0;k<Number;k++)     //写Number个数据
    {Write_Byte(*Array);
  Array++;
     Check_Ack();}           //检查应答位
   Stop();                
}

//****************************写一个字节子程序**********************//
//函数参数说明:
//Slave:IIC器件地址,如上文定义的SD2303
//Address:IIC器件寄存器地址
//Data:数据
void Write_1byte(uchar Slave,uchar Address,uchar Data)
{writ:do                     //开始->写IIC器件地址->检查应答位
    {Start();
     Write_Byte(Slave);
     Check_Ack();
    }while(F_Flag==1);
   do
    {Write_Byte(Address<<4); //送起始地址->检查应答位
     Check_Ack();
    }while(F_Flag==1);
   Write_Byte(Data);
   Check_Ack();              //检查应答位
   Stop();                   //停止信号
}


//***************************读N个字节子程序***********************//
//函数参数说明:
//Slave:IIC器件地址,如上文定义的SD2303
//Address:起始地址
//Array:读数据存放的数组
//Number:读取的字节数
void Read_Nbyte(uchar Slave,uchar Address,uchar *Array,uchar Number)
{uchar data0,x;
    //第一步:开始信号->写IIC器件地址->检查应答位
 do{Start();Write_Byte(Slave);Check_Ack();}while(F_Flag==1);
    //第二步:写起始地址->检查应答位
    do {Write_Byte(Address<<4);Check_Ack();}while(F_Flag==1);
    //第三步:开始信号->写IIC器件地址+1(表示读)->检查应答位
    do{Start();Write_Byte(Slave+1);Check_Ack();}while(F_Flag==1);
    //第四步:读N字节,每读完一字节发一个Ack应答,最后一字节发Nack
    for(x=0;x<Number;x++)
     {data0=Read_Byte();*Array=data0;Array++;
   if(x<(Number-1)) { Ack(); }}
    Nack();
    //第五步:发停止信号,结束读操作
    Stop();
}

//***************************按键处理程序**************************//
//说明:为简化程序设计,此程序不保证输入的时间数据的合理性。
void Key_Process(void)
{uchar temp1[17]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  //输入数据格式依次为年、月、日、星期、小时和分钟
 uchar temp2[7]={0,0,0,0,0,0,0,};
 uchar temp3[3]={0,0,0xff};
  //输入数据格式依次为小时和分钟
 uchar Key;
 uchar *Flag;
 uchar i;
 Flag=temp1;
 if(PIND!=0xff)
  {DelayMs(20);                        //延时去抖
   if(PIND!=0xff)
   Key=PINB;
   if(Key==0xfe)                       //"时间设置"键按下
    {temp1[0]|=0x80;                   //年高位设置提示
  while(!Enter_Flag)                //直到按下确定键方停止
       {for(i=0;i<50;i++)
       Display(temp1);              //显示和延时
  Key=~PIND;
  switch(Key)
   {case 0x04:                   //"+"键处理
         (*Flag)++;
      if(((*Flag)&0x7f)==10) *Flag=0|0x80;
         break;
    case 0x08:                   //"-"键处理
          if(((*Flag)&0x7f)==0) *Flag=10|0x80;
    (*Flag)--;
    break;
    case 0x10:                   //"下一位"键处理
          Flag++;
    (*(Flag-1))&=0x7f;     //上一位去掉小数点显示
    (*Flag)|=0x80;         //当前位加上小数点显示
    if(Flag==temp1+13)
     {Flag=temp1;
      (*Flag)|=0x80;
      (*(Flag+13))&=0x7f;}
    break;
    case 0x20:                   //"上一位"键处理
          if(Flag==temp1)
        {(*Flag)&=0x7f;
      Flag=temp1+13;
      (*Flag)|=0x80;}
    else Flag--;          
    (*Flag)|=0x80;         //当前位加上小数点显示
    (*(Flag+1))&=0x7f;     //下一位去掉点小数点显示
    break;
    case 0x40:Enter_Flag=1;break;//"确定"键处理
 //   case 0x80:Enter_Flag=1;break;  //测试用
    default:break;}
    
    }
  Enter_Flag=0;                     //按键状态恢复
     temp2[0]=0x00;                    //秒,默认从00开始计时
  temp2[1]=(temp1[11]<<4)|temp1[12];//分
  temp2[2]=(temp1[9]<<4)|temp1[10]; //时
  temp2[3]=temp1[8];                //周
  temp2[4]=(temp1[6]<<4)|temp1[7];  //日
  temp2[5]=(temp1[4]<<4)|temp1[5];  //月
  temp2[6]=(temp1[2]<<4)|temp1[3];  //年
  Write_Nbyte(SD2303,0x00,temp2,7); //初始化设定时间
    }
   if(Key==0xfd)                       //"闹铃设置"键按下
    {temp1[9]|=0x80;
  Flag=temp1+9;                     //定时小时高位设置提示
  while(!Enter_Flag)                //直到按下确定键方停止
       {for(i=0;i<50;i++)
       Display(temp1);
  Key=~PINB;
  switch(Key)
   {case 0x04:                   //"+"按键处理
         (*Flag)++;
      if(((*Flag)&0x7f)==10) *Flag=0|0x80;
         break;
    case 0x08:                   //"-"按键处理
          if(((*Flag)&0x7f)==0) *Flag=10|0x80;
    (*Flag)--;
    break;
    case 0x10:                   //"下一位"按键处理
          Flag++;
    (*(Flag-1))&=0x7f;     //上一位去掉小数点显示
    (*Flag)|=0x80;         //当前位加上小数点显示
    if(Flag==temp1+13)
     {(*Flag)&=0x7f;
      Flag=temp1+9;
      (*Flag)|=0x80;}
    break;
    case 0x20:                   //"上一位"按键处理
          if(Flag==temp1+9)
     {(*Flag)&=0x7f;
      Flag=temp1+13;
      (*Flag)|=0x80;}
    else Flag--;
    (*Flag)|=0x80;         //当前位加上小数点显示
    (*(Flag+1))&=0x7f;     //下一位去掉小数点显示
    break;
    case 0x40:Enter_Flag=1;break;//"确定"键处理
  //  case 0x80:Enter_Flag=1;break;//测试用
    default:break;}
    
    }
  Enter_Flag=0;
     temp3[0]=((temp1[11]<<4)|temp1[12])&0x7f; //分数据处理,去掉小数点
  temp3[1]=((temp1[9]<<4)|temp1[10])&0x7f;  //时数据处理,去掉小数点
  if((temp3[0]<0x60)&&(temp3[1]<0x24))      //判断是否为合法时间
    {Write_1byte(SD2303,0x0e,0b10110000);   //开启闹铃使能
     Write_1byte(SD2303,0x0f,0b00101000);   //开始中断使能
  Write_Nbyte(SD2303,0x08,temp3,3);}     //初始化闹铃设置
  else 
     Write_1byte(SD2303,0x0e,0b00110000);   //取消闹铃功能
    }
  }
}
 
 
//***************************DS1722函数开始************************//

void Convert(uchar p1,uchar *p2)
{uchar temp;
 if(p1&0x80)  
   {p2[13]=10;               //零下温度用10表示                   
    p1=0xff-p1;}             //温度绝对值
 else
   p2[13]=11;                //零上温度用11表示
   p2[14]=p1/10;             //温度十位
   p2[15]=p1-p2[14]*10;      //温度个位
}

//***************************通过SPI接口写数据函数*****************//
//函数参数说明:
//Address:DS1722寄存器地址
//Data:写入的数据
void DSWrite_Byte(uchar Address,uchar Data)
{uchar clear;
 PORTB=PORTB|0x10;           //使能SPI器件
 SPDR=Address;
 while(!(SPSR&0x80)) {;}
 clear=SPSR;
 clear=SPDR;
 SPDR=Data;
 while(!(SPSR&0x80)) {;}
 clear=SPSR;
 clear=SPDR;
 PORTB=PORTB&0xef;
}


//***************************通过SPI接口读数据函数*****************//
//函数参数说明:
//Address:DS1722寄存器地址
//返回值:读取的温度数据
uchar DSRead_Byte(uchar Address)
{uchar clear;
 uchar Data;
 PORTB=PORTB|0x10;
 SPDR=Address;
 while(!(SPSR&0x80)) {;}
 clear=SPSR;
 clear=SPDR;
 SPDR=Address;               //发空数据
 while(!(SPSR&0x80)) {;}
 clear=SPSR;
 Data=SPDR;
 PORTB=PORTB&0xef;
 return(Data);
}
 
void main(void)
{uchar i;
 uchar time[16]={2,0,0,4,1,2,2,7,1,1,7,3,0,0,0,0};
 uchar Set_Time[7]={0x50,0x30,0x20,0x03,0x05,0x01,0x05};
     //初始化时间   2005-01-05 Wed 20-30-50
 uchar SD,DS;
 uchar SD2303_Controller1=0x00;              //禁止中断
 uchar SD2303_Controller2=0x20;              //时间格式:24小时制
 DDRA=0xff;                                  //A口输出
 DDRC=0xff;                                  //C口输出
 DDRD=0x80;                                  //D口最高位输出,其他带上拉输入
 PORTD=0x7F;
 DDRB=0xF3;                                  //B口带第2、3位带上拉输入,其他输出
 PORTB=0xF3;
 Write_1byte(SD2303,0x0e,SD2303_Controller1);//写控制字
 Write_1byte(SD2303,0x0f,SD2303_Controller2);//写控制字
 Write_Nbyte(SD2303,0x00,Set_Time,7);        //初始化时间
 SPCR=0b01011100;
 DSWrite_Byte(0x80,0xf0);                      //DS1722 8位分辨率自由转换模式
 while(1)
 {Key_Process();                          //按键处理  
  Read_Nbyte(SD2303,0x00,Set_Time,7);     //读取时间
     time[2]=Set_Time[6]>>4;                 //年高位;
  time[3]=Set_Time[6]&0x0f;               //年低位;
  time[4]=Set_Time[5]>>4;                 //月高位;
     time[5]=Set_Time[5]&0x0f;               //月低位;
  time[6]=Set_Time[4]>>4;                 //日高位;
  time[7]=Set_Time[4]&0x0f;               //日低位;
  time[8]=Set_Time[3];                    //星期;
  time[9]=Set_Time[2]>>4;                 //时高位;
  time[10]=Set_Time[2]&0x0f;              //时低位;
  time[11]=Set_Time[1]>>4;                //分高位;
     time[12]=Set_Time[1]&0x0f;              //分低位;
  time[13]=Set_Time[0]>>4;                //秒高位;
  time[14]=Set_Time[0]&0x0f;              //秒低位;
  Read_Nbyte(SD2303,0x0f,&SD,1);          //读取中断标志位
  if(SD&0x02)  PORTD=PORTD|0x80;          //响铃1分钟
  else            PORTD=PORTD&0x7F;       //关闭闹铃
     DS=DSRead_Byte(0x02);                   //读取温度值
     Convert(DS,time);
     Display(time);                          //时间显示
   }
}