Rtc._c
上传用户:rbltsz
上传日期:2007-09-19
资源大小:2509k
文件大小:12k
源码类别:

单片机开发

开发平台:

C/C++

  1. //***************************FileName:RTC.C************************//
  2. //***************************ICCAVR V6.30编译**********************//
  3. #include <io8535v.h>                   //寄存器定义文件
  4. #include <macros.h>                    //使用到宏
  5. #define uchar unsigned char            //数据类型定义
  6. #define uint unsigned char             //数据类型定义
  7. #define SD2303 0x64                    //SD2303器件IIC识别码
  8. uchar Table[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x38,0x76};
  9.      //显示数据表 0    1    2     3   4    5    6    7    8    9    L    H  
  10. uchar Data[4]={0,0,0,0};               //DS1722
  11. uchar Enter_Flag;                      //确定
  12. uchar F_Flag;                          //数据应答标志
  13. void DelayMs(uint i)                   //延时函数1
  14. {uchar j;
  15.  for(;i!=0;i--)
  16.   {for(j=2000;j!=0;j--) {;}}
  17. }
  18. void Display(uchar *p)
  19. {uchar i,sel=0x00;
  20.  for(i=0;i<16;i++)
  21.   {PORTC=sel;
  22.    PORTA=Table[p[i]];
  23.    DelayMs(10);
  24.    sel=sel<<1;
  25.   }
  26. }
  27.   
  28. void NOPNOP(uchar i)                   //延时函数2
  29. {for(;i!=0;i--) NOP();}
  30. void SetSCL(uchar i)                   //IIC时钟线SCL设置
  31. {if(i==1) PORTB=PORTB|0x01;
  32.  else     PORTB=PORTB&0xFE;}
  33.  
  34. void SetSDA(uchar i)                   //IIC数据线SDA设置
  35. {if(i==1) PORTB=PORTB|0x02;
  36.  else     PORTB=PORTB&0xFD;}
  37.  
  38. //SCL=PB^0;       SD2303时钟线  
  39. //SDA=PB^1;       SD2303数据线 
  40. //INTRB=PB^3;     SD2303中断线A
  41. //INTRA=PB^2;     SD2303中断线B
  42. void Start()                           //IIC总线开始信号
  43. {SetSDA(1);
  44.  SetSCL(1);
  45.  NOPNOP(50);
  46.  SetSDA(0);
  47.  NOPNOP(50);
  48.  SetSCL(0);
  49. }
  50. void Stop()                            //IIC总线停止信号
  51. {SetSDA(0);             
  52.  SetSCL(1);
  53.  NOPNOP(50);
  54.  SetSDA(1);
  55.  NOPNOP(50);
  56.  SetSCL(0);
  57. }
  58. void Ack()                             //单片机应答信号
  59. {SetSDA(0);
  60.  SetSCL(1);   
  61.  NOPNOP(50);
  62.  SetSCL(0);
  63.  SetSDA(1);     
  64. }
  65. void Nack()                            //单片机非应答信号
  66. {SetSDA(1);
  67.  SetSCL(1);
  68.  NOPNOP(50);
  69.  SetSCL(0);
  70.  SetSDA(0);
  71. }
  72. void Check_Ack()                       //器件应答信号检查
  73. {SetSDA(1);
  74.  SetSCL(1);
  75.  F_Flag=0;
  76.  DDRB=DDRB&0xFD; 
  77.  if((PINB&0x02)==0)
  78.    {SetSCL(0);
  79.     NOPNOP(50);}
  80.  else
  81.     {F_Flag=1;
  82.      SetSCL(0);
  83.      NOPNOP(50);}
  84. DDRB=DDRB|0x02;
  85. }
  86. void Write_Bit0()                      //向IIC总线写0
  87. {SetSDA(0);
  88.  SetSCL(1);
  89.  NOPNOP(50);
  90.  SetSCL(0);
  91. }
  92. void Write_Bit1()                      //向IIC总线写1
  93. {SetSDA(1);
  94.  SetSCL(1);
  95.  NOPNOP(50);
  96.  SetSCL(0);
  97.  SetSDA(0);
  98. }
  99. void Write_Byte(uchar Data)            //向IIC总线写一字节数据
  100. {uchar i;
  101.  for(i=0;i<8;i++)
  102.    {if((Data&0x80)>0)       
  103.          Write_Bit1();
  104.     else
  105.          Write_Bit0();
  106.     Data<<=1;                        
  107.     }
  108. }
  109. uchar Read_Byte()                      //从IIC总线读一字节数据
  110. {uchar nn=0xff;             
  111.  uchar j;
  112.  for (j=0;j<8;j++)
  113.     {SetSDA(1);
  114.      SetSCL(1);
  115.      DDRB=DDRB&0xFB;
  116.        if((PINB&0x02)==0)
  117.     {nn<<=1;
  118.          nn=(nn&0xfe);                 
  119.          SetSCL(0);}
  120.      else 
  121.         {nn<<=1;
  122.          nn=(nn|0x01);                 
  123.          SetSCL(0);}
  124.     }
  125.   DDRB=DDRB|0x02;
  126.  return(nn);              
  127. }
  128. //****************************写N个字节子程序**********************//
  129. //函数参数说明:
  130. //Slave:IIC器件地址,如上文定义的SD2303
  131. //Address:起始地址
  132. //Array:读数据存放的数组
  133. //Number:读取的字节数
  134. void Write_Nbyte(uchar Slave,uchar Address,uchar *Array,uchar Number)
  135. {uchar k;
  136.  writ:do                     //开始->写IIC器件地址->检查应答位
  137.     {Start();
  138.      Write_Byte(Slave);
  139.      Check_Ack();
  140.     }while(F_Flag==1);
  141.    do
  142.     {Write_Byte(Address<<4); //送起始地址->检查应答位
  143.      Check_Ack();
  144.     }while(F_Flag==1);
  145.    for(k=0;k<Number;k++)     //写Number个数据
  146.     {Write_Byte(*Array);
  147.  Array++;
  148.      Check_Ack();}           //检查应答位
  149.    Stop();                 
  150. }
  151. //****************************写一个字节子程序**********************//
  152. //函数参数说明:
  153. //Slave:IIC器件地址,如上文定义的SD2303
  154. //Address:IIC器件寄存器地址
  155. //Data:数据
  156. void Write_1byte(uchar Slave,uchar Address,uchar Data)
  157. {writ:do                     //开始->写IIC器件地址->检查应答位
  158.     {Start();
  159.      Write_Byte(Slave);
  160.      Check_Ack();
  161.     }while(F_Flag==1);
  162.    do
  163.     {Write_Byte(Address<<4); //送起始地址->检查应答位
  164.      Check_Ack();
  165.     }while(F_Flag==1);
  166.    Write_Byte(Data);
  167.    Check_Ack();              //检查应答位
  168.    Stop();                   //停止信号
  169. }
  170. //***************************读N个字节子程序***********************//
  171. //函数参数说明:
  172. //Slave:IIC器件地址,如上文定义的SD2303
  173. //Address:起始地址
  174. //Array:读数据存放的数组
  175. //Number:读取的字节数
  176. void Read_Nbyte(uchar Slave,uchar Address,uchar *Array,uchar Number)
  177. {uchar data0,x;
  178.     //第一步:开始信号->写IIC器件地址->检查应答位
  179. do{Start();Write_Byte(Slave);Check_Ack();}while(F_Flag==1);
  180.     //第二步:写起始地址->检查应答位
  181.     do {Write_Byte(Address<<4);Check_Ack();}while(F_Flag==1);
  182.     //第三步:开始信号->写IIC器件地址+1(表示读)->检查应答位
  183.     do{Start();Write_Byte(Slave+1);Check_Ack();}while(F_Flag==1);
  184.     //第四步:读N字节,每读完一字节发一个Ack应答,最后一字节发Nack
  185.     for(x=0;x<Number;x++)
  186.      {data0=Read_Byte();*Array=data0;Array++;
  187.   if(x<(Number-1)) { Ack(); }}
  188.     Nack();
  189.     //第五步:发停止信号,结束读操作
  190.     Stop();
  191. }
  192. //***************************按键处理程序**************************//
  193. //说明:为简化程序设计,此程序不保证输入的时间数据的合理性。
  194. void Key_Process(void)
  195. {uchar temp1[17]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  196.   //输入数据格式依次为年、月、日、星期、小时和分钟
  197.  uchar temp2[7]={0,0,0,0,0,0,0,};
  198.  uchar temp3[3]={0,0,0xff};
  199.   //输入数据格式依次为小时和分钟
  200.  uchar Key;
  201.  uchar *Flag;
  202.  uchar i;
  203.  Flag=temp1;
  204.  if(PIND!=0xff)
  205.   {DelayMs(20);                        //延时去抖
  206.    if(PIND!=0xff)
  207.    Key=PINB;
  208.    if(Key==0xfe)                       //"时间设置"键按下
  209.     {temp1[0]|=0x80;                   //年高位设置提示
  210.  while(!Enter_Flag)                //直到按下确定键方停止
  211.        {for(i=0;i<50;i++)
  212.       Display(temp1);              //显示和延时
  213. Key=~PIND;
  214. switch(Key)
  215.  {case 0x04:                   //"+"键处理
  216.        (*Flag)++;
  217.    if(((*Flag)&0x7f)==10) *Flag=0|0x80;
  218.        break;
  219.   case 0x08:                   //"-"键处理
  220.         if(((*Flag)&0x7f)==0) *Flag=10|0x80; 
  221. (*Flag)--;
  222. break;
  223.   case 0x10:                   //"下一位"键处理
  224.         Flag++;
  225. (*(Flag-1))&=0x7f;     //上一位去掉小数点显示
  226. (*Flag)|=0x80;         //当前位加上小数点显示
  227. if(Flag==temp1+13) 
  228.  {Flag=temp1;
  229.   (*Flag)|=0x80;
  230.   (*(Flag+13))&=0x7f;}
  231. break;
  232.   case 0x20:                   //"上一位"键处理
  233.         if(Flag==temp1) 
  234.     {(*Flag)&=0x7f;
  235.  Flag=temp1+13;
  236.  (*Flag)|=0x80;} 
  237. else Flag--;           
  238. (*Flag)|=0x80;         //当前位加上小数点显示
  239. (*(Flag+1))&=0x7f;     //下一位去掉点小数点显示
  240. break;
  241.   case 0x40:Enter_Flag=1;break;//"确定"键处理
  242. //   case 0x80:Enter_Flag=1;break;  //测试用
  243.   default:break;}
  244.     
  245.    }
  246.  Enter_Flag=0;                     //按键状态恢复
  247.      temp2[0]=0x00;                    //秒,默认从00开始计时
  248.  temp2[1]=(temp1[11]<<4)|temp1[12];//分
  249.  temp2[2]=(temp1[9]<<4)|temp1[10]; //时
  250.  temp2[3]=temp1[8];                //周
  251.  temp2[4]=(temp1[6]<<4)|temp1[7];  //日
  252.  temp2[5]=(temp1[4]<<4)|temp1[5];  //月
  253.  temp2[6]=(temp1[2]<<4)|temp1[3];  //年
  254.  Write_Nbyte(SD2303,0x00,temp2,7); //初始化设定时间
  255.     }
  256.    if(Key==0xfd)                       //"闹铃设置"键按下
  257.     {temp1[9]|=0x80;
  258.  Flag=temp1+9;                     //定时小时高位设置提示
  259.  while(!Enter_Flag)                //直到按下确定键方停止
  260.        {for(i=0;i<50;i++)
  261.       Display(temp1);
  262. Key=~PINB;
  263. switch(Key)
  264.  {case 0x04:                   //"+"按键处理
  265.        (*Flag)++;
  266.    if(((*Flag)&0x7f)==10) *Flag=0|0x80;
  267.        break;
  268.   case 0x08:                   //"-"按键处理
  269.         if(((*Flag)&0x7f)==0) *Flag=10|0x80; 
  270. (*Flag)--;
  271. break;
  272.   case 0x10:                   //"下一位"按键处理
  273.         Flag++;
  274. (*(Flag-1))&=0x7f;     //上一位去掉小数点显示
  275. (*Flag)|=0x80;         //当前位加上小数点显示
  276. if(Flag==temp1+13) 
  277.  {(*Flag)&=0x7f;
  278.   Flag=temp1+9;
  279.   (*Flag)|=0x80;}
  280. break;
  281.   case 0x20:                   //"上一位"按键处理
  282.         if(Flag==temp1+9) 
  283.  {(*Flag)&=0x7f;
  284.   Flag=temp1+13;
  285.   (*Flag)|=0x80;}
  286. else Flag--;
  287. (*Flag)|=0x80;         //当前位加上小数点显示
  288. (*(Flag+1))&=0x7f;     //下一位去掉小数点显示
  289. break;
  290.   case 0x40:Enter_Flag=1;break;//"确定"键处理
  291. //  case 0x80:Enter_Flag=1;break;//测试用
  292.   default:break;}
  293.     
  294.    }
  295.  Enter_Flag=0;
  296.      temp3[0]=((temp1[11]<<4)|temp1[12])&0x7f; //分数据处理,去掉小数点
  297.  temp3[1]=((temp1[9]<<4)|temp1[10])&0x7f;  //时数据处理,去掉小数点
  298.  if((temp3[0]<0x60)&&(temp3[1]<0x24))      //判断是否为合法时间
  299.    {Write_1byte(SD2303,0x0e,0b10110000);   //开启闹铃使能
  300.     Write_1byte(SD2303,0x0f,0b00101000);   //开始中断使能
  301. Write_Nbyte(SD2303,0x08,temp3,3);}     //初始化闹铃设置
  302.  else  
  303.     Write_1byte(SD2303,0x0e,0b00110000);   //取消闹铃功能
  304.     }
  305.   }
  306. }
  307.  
  308.  
  309. //***************************DS1722函数开始************************//
  310. void Convert(uchar p1,uchar *p2)
  311. {uchar temp;
  312.  if(p1&0x80)   
  313.    {p2[13]=10;               //零下温度用10表示                    
  314.     p1=0xff-p1;}             //温度绝对值
  315.  else
  316.    p2[13]=11;                //零上温度用11表示
  317.    p2[14]=p1/10;             //温度十位
  318.    p2[15]=p1-p2[14]*10;      //温度个位
  319. }
  320. //***************************通过SPI接口写数据函数*****************//
  321. //函数参数说明:
  322. //Address:DS1722寄存器地址
  323. //Data:写入的数据
  324. void DSWrite_Byte(uchar Address,uchar Data)
  325. {uchar clear;
  326.  PORTB=PORTB|0x10;           //使能SPI器件
  327.  SPDR=Address;
  328.  while(!(SPSR&0x80)) {;}
  329.  clear=SPSR;
  330.  clear=SPDR;
  331.  SPDR=Data;
  332.  while(!(SPSR&0x80)) {;}
  333.  clear=SPSR;
  334.  clear=SPDR;
  335.  PORTB=PORTB&0xef;
  336. }
  337. //***************************通过SPI接口读数据函数*****************//
  338. //函数参数说明:
  339. //Address:DS1722寄存器地址
  340. //返回值:读取的温度数据
  341. uchar DSRead_Byte(uchar Address)
  342. {uchar clear;
  343.  uchar Data;
  344.  PORTB=PORTB|0x10;
  345.  SPDR=Address;
  346.  while(!(SPSR&0x80)) {;}
  347.  clear=SPSR;
  348.  clear=SPDR;
  349.  SPDR=Address;               //发空数据
  350.  while(!(SPSR&0x80)) {;}
  351.  clear=SPSR;
  352.  Data=SPDR;
  353.  PORTB=PORTB&0xef;
  354.  return(Data);
  355. }
  356.  
  357. void main(void)
  358. {uchar i;
  359.  uchar time[16]={2,0,0,4,1,2,2,7,1,1,7,3,0,0,0,0};
  360.  uchar Set_Time[7]={0x50,0x30,0x20,0x03,0x05,0x01,0x05};
  361.      //初始化时间   2005-01-05 Wed 20-30-50
  362.  uchar SD,DS; 
  363.  uchar SD2303_Controller1=0x00;              //禁止中断
  364.  uchar SD2303_Controller2=0x20;              //时间格式:24小时制
  365.  DDRA=0xff;                                  //A口输出
  366.  DDRC=0xff;                                  //C口输出
  367.  DDRD=0x80;                                  //D口最高位输出,其他带上拉输入
  368.  PORTD=0x7F;
  369.  DDRB=0xF3;                                  //B口带第2、3位带上拉输入,其他输出
  370.  PORTB=0xF3;
  371.  Write_1byte(SD2303,0x0e,SD2303_Controller1);//写控制字
  372.  Write_1byte(SD2303,0x0f,SD2303_Controller2);//写控制字
  373.  Write_Nbyte(SD2303,0x00,Set_Time,7);        //初始化时间
  374.  SPCR=0b01011100;
  375.  DSWrite_Byte(0x80,0xf0);                      //DS1722 8位分辨率自由转换模式
  376.  while(1)
  377. {Key_Process();                          //按键处理
  378.  Read_Nbyte(SD2303,0x00,Set_Time,7);     //读取时间
  379.      time[2]=Set_Time[6]>>4;                 //年高位;
  380.  time[3]=Set_Time[6]&0x0f;               //年低位;
  381.  time[4]=Set_Time[5]>>4;                 //月高位;
  382.      time[5]=Set_Time[5]&0x0f;               //月低位;
  383.  time[6]=Set_Time[4]>>4;                 //日高位;
  384.  time[7]=Set_Time[4]&0x0f;               //日低位;
  385.  time[8]=Set_Time[3];                    //星期;
  386.  time[9]=Set_Time[2]>>4;                 //时高位;
  387.  time[10]=Set_Time[2]&0x0f;              //时低位;
  388.  time[11]=Set_Time[1]>>4;                //分高位;
  389.      time[12]=Set_Time[1]&0x0f;              //分低位;
  390.  time[13]=Set_Time[0]>>4;                //秒高位;
  391.  time[14]=Set_Time[0]&0x0f;              //秒低位;
  392.  Read_Nbyte(SD2303,0x0f,&SD,1);          //读取中断标志位
  393.  if(SD&0x02)  PORTD=PORTD|0x80;          //响铃1分钟
  394.  else            PORTD=PORTD&0x7F;       //关闭闹铃 
  395.      DS=DSRead_Byte(0x02);                   //读取温度值
  396.      Convert(DS,time);
  397.      Display(time);                          //时间显示
  398.    }
  399. }