⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtc.c

📁 AVRkaifashili.rar
💻 C
字号:
//***************************FileName:RTC.C************************//
//***************************ICCAVR V6.30编译**********************//

#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);                          //时间显示
   }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -