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

📄 clock.c

📁 具有温度控制功能的电子时钟
💻 C
📖 第 1 页 / 共 2 页
字号:
    timecount=0;    
    flag=~flag;             
   }  
}
//id为1时的下一级选择
void id_case1_key()
{
  if (P0_5==0) //增加
      {
       Delay5Ms();
       if(P0_5==0) Set(id,0);  
       if(id!=7)  while(P0_5==0);    
      }
   if (P0_4==0)  //减少
      {
       Delay5Ms();
       if(P0_4==0) Set(id,1);          
       if(id!=7) while(P0_4==0);    
      }
}

//根据选择调整相应项目并写入DS1302
void Set(uchar sel,uchar sel_1) 
{
  signed char address,item;
  signed char max,mini;
  if(sel==7)  {address=0x80; max=0;mini=0;}     //秒
  if(sel==6)  {address=0x82; max=59;mini=0;}    //分钟
  if(sel==5)  {address=0x84; max=23;mini=0;}    //小时
  if(sel==3)  {address=0x86; max=31;mini=1;}    //日
  if(sel==2)  {address=0x88; max=12;mini=1;}    //月
  if(sel==1)  {address=0x8c; max=99;mini=0;}    //年
  if(sel==4)  {address=0x8a; max=7; mini=1;}    //星期
  
  item=R1302(address+1)/16*10+R1302(address+1)%16;
  if (sel_1==0) item++;  else item--;
  if(item>max) item=mini;   
  if(item<mini) item=max;
           
  W1302(0x8e,0x00);//允许写操作
  W1302(address,item/10*16+item%10);
  W1302(0x8e,0x80);//写保护,禁止写操作  
}

//屏幕显示第一行 时间和温度
void Disp_line1(void) 
{  
  Read_Temperature(10,0); //温度显示
  //冒号闪烁     
  if(flag==0)
    {DisplayOneChar(3,0,0x3a); DisplayOneChar(6,0,0x3a);}
  else
    {DisplayOneChar(3,0,0x20); DisplayOneChar(6,0,0x20);}

  if(sec==1)  //秒闪烁标志位
    {
     if(flag==1)
       {    
        DisplayOneChar(7,0,R1302(0x81)/16+0x30); //显示秒
        DisplayOneChar(8,0,R1302(0x81)%16+0x30);        
       }
     else
       {
        DisplayOneChar(7,0,0x20); //显示秒
        DisplayOneChar(8,0,0x20);    
       }
    } 
  else
    {
     DisplayOneChar(7,0,R1302(0x81)/16+0x30); //显示秒
     DisplayOneChar(8,0,R1302(0x81)%16+0x30);         
    }    
   
  if(min==1)  //分钟闪烁标志位
    {
     if(flag==1)
       {    
        DisplayOneChar(4,0,R1302(0x83)/16+0x30); //显示分钟
        DisplayOneChar(5,0,R1302(0x83)%16+0x30);        
       }
     else
       {
        DisplayOneChar(4,0,0x20); //显示分钟
        DisplayOneChar(5,0,0x20);    
       }
    } 
  else
    {
     DisplayOneChar(4,0,R1302(0x83)/16+0x30); //显示分钟
     DisplayOneChar(5,0,R1302(0x83)%16+0x30);         
    } 

  if(hour==1)  //小时闪烁标志位
    {
     if(flag==1)
       {    
        DisplayOneChar(1,0,R1302(0x85)/16+0x30);//显示小时
        DisplayOneChar(2,0,R1302(0x85)%16+0x30); 
       }
     else
       {
        DisplayOneChar(1,0,0x20); //显示小时
        DisplayOneChar(2,0,0x20);    
       }
    } 
  else
   { 
    DisplayOneChar(1,0,R1302(0x85)/16+0x30);//显示小时
    DisplayOneChar(2,0,R1302(0x85)%16+0x30);
   }
}

// 屏幕显示第二行  日期和星期   
void Disp_line2(void)
{
  DisplayOneChar(3,1,0x2f); //显示固定字符
  DisplayOneChar(6,1,0x2f);
  DisplayListChar(10,1,week);
    
  if(year==1)  //年闪烁标志位
    {
     if(flag==1)
       {    
        DisplayOneChar(1,1,R1302(0x8d)/16+0x30);//显示年
        DisplayOneChar(2,1,R1302(0x8d)%16+0x30);
       }
     else
       {
        DisplayOneChar(1,1,0x20); //显示年
        DisplayOneChar(2,1,0x20);    
       }
    } 
  else
    { 
      DisplayOneChar(1,1,R1302(0x8d)/16+0x30);//显示年
      DisplayOneChar(2,1,R1302(0x8d)%16+0x30);
    }
     
  if(mon==1)  //月闪烁标志位
    {
     if(flag==1)
       {    
        DisplayOneChar(4,1,R1302(0x89)/16+0x30);//显示月 
        DisplayOneChar(5,1,R1302(0x89)%16+0x30);
       }
     else
       {
        DisplayOneChar(4,1,0x20); //显示月
        DisplayOneChar(5,1,0x20);    
       }
    } 
  else
    { 
      DisplayOneChar(4,1,R1302(0x89)/16+0x30);//显示月 
      DisplayOneChar(5,1,R1302(0x89)%16+0x30);
    }   

  if(day==1)  //日闪烁标志位
    {
     if(flag==1)
       {    
         DisplayOneChar(7,1,R1302(0x87)/16+0x30);//显示日
         DisplayOneChar(8,1,R1302(0x87)%16+0x30);
       }
     else
       {
        DisplayOneChar(7,1,0x20); //显示日
        DisplayOneChar(8,1,0x20);    
       }
    } 
  else
    { 
      DisplayOneChar(7,1,R1302(0x87)/16+0x30);//显示日
      DisplayOneChar(8,1,R1302(0x87)%16+0x30);
    }
    
   if(weekk==1)  //星期闪烁标志位
    {
     if(flag==1)
       {    
         DisplayOneChar(15,1,R1302(0x8b)%16+0x30);//显示星期
       }
     else
       {
        DisplayOneChar(15,1,0x20); //显示星期          
       }
    } 
  else
    { 
      DisplayOneChar(15,1,R1302(0x8b)%16+0x30);//显示星期
    }     
}

//********* LCM1602驱动程序 ***************
//写数据
void WriteDataLCM(unsigned char WDLCM)
{
  ReadStatusLCM(); //检测忙
  LCM_Data = WDLCM;
  LCM_RS = 1;
  LCM_RW = 0;
  LCM_E = 0; //若晶振速度太高可以在这后加小的延时
  LCM_E = 0; //延时
  LCM_E = 1;
}
//写指令
void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测
{
  if (BuysC) ReadStatusLCM(); //根据需要检测忙
  LCM_Data = WCLCM;
  LCM_RS = 0;
  LCM_RW = 0; 
  LCM_E = 0;
  LCM_E = 0;
  LCM_E = 1; 
}
//读状态
unsigned char ReadStatusLCM(void)
{
  LCM_Data = 0xFF; 
  LCM_RS = 0;
  LCM_RW = 1;
  LCM_E = 0;
  LCM_E = 0;
  LCM_E = 1;
  while (LCM_Data & Busy); //检测忙信号
  return(LCM_Data);
}
//LCM初始化
void LCMInit(void) 
{
  LCM_Data = 0;
  WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
  Delay5Ms(); 
  WriteCommandLCM(0x38,0);
  Delay5Ms(); 
  WriteCommandLCM(0x38,0);
  Delay5Ms(); 
  WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
  WriteCommandLCM(0x08,1); //关闭显示
  WriteCommandLCM(0x01,1); //显示清屏
  WriteCommandLCM(0x06,1); // 显示光标移动设置
  WriteCommandLCM(0x0C,1); // 显示开及光标设置
}
//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
  Y &= 0x1;
  X &= 0xF; //限制X不能大于15,Y不能大于1
  if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
  X |= 0x80; //算出指令码
  WriteCommandLCM(X, 0); //这里不检测忙信号,发送地址码
  WriteDataLCM(DData);
}
//按指定位置显示一串字符  ***原来的遇到空格0x20就不显示***
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
  unsigned char ListLength,j;
  ListLength = strlen(DData);
  Y &= 0x1;
  X &= 0xF; //限制X不能大于15,Y不能大于1
      if (X <= 0xF) //X坐标应小于0xF
        { 
		    for(j=0;j<ListLength;j++)
		      {
               DisplayOneChar(X, Y, DData[j]); //显示单个字符
               X++;
              }
        }
}
//5ms延时
void Delay5Ms(void)
{
  unsigned int TempCyc = 5552;
  while(TempCyc--);
}
//400ms延时
void Delay400Ms(void)
{
  unsigned char TempCycA = 5;
  unsigned int TempCycB;
  while(TempCycA--)
   {
    TempCycB=7269;
    while(TempCycB--);
   };
}

//********DS1302读写程序***************
/******************************************************************** 
 函 数 名:RTInputByte()
 功    能:实时时钟写入一字节
 说    明:往DS1302写入1Byte数据 (内部函数)
 入口参数:d 写入的数据 
 返 回 值:无  
 ***********************************************************************/
void RTInputByte(uchar d) 
{ 
    uchar i;
    ACC = d;
    for(i=8; i>0; i--)
    {
        T_IO = ACC0;           /*相当于汇编中的 RRC */
        T_CLK = 1;
        T_CLK = 0;
        ACC = ACC >> 1; 
    } 
}
/******************************************************************** 
 函 数 名:RTOutputByte()
 功    能:实时时钟读取一字节
 说    明:从DS1302读取1Byte数据 (内部函数)
 入口参数:无  
 返 回 值:ACC
 设    计:zhaojunjie           日    期:2002-03-19
 修    改:                     日    期: 
***********************************************************************/
uchar RTOutputByte(void) 
{ 
    uchar i;
    for(i=8; i>0; i--)
    {
        ACC = ACC >>1;         /*相当于汇编中的 RRC */
        ACC7 = T_IO;
        T_CLK = 1;
        T_CLK = 0;
    } 
    return(ACC); 
}
/******************************************************************** 
 函 数 名:W1302()
 功    能:往DS1302写入数据
 说    明:先写地址,后写命令/数据 (内部函数)
 调    用:RTInputByte() , RTOutputByte()
 入口参数:ucAddr: DS1302地址, ucData: 要写的数据
 返 回 值:无
 ***********************************************************************/
void W1302(uchar ucAddr, uchar ucDa)
{
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    RTInputByte(ucAddr);       /* 地址,命令 */
    RTInputByte(ucDa);       /* 写1Byte数据*/
    T_CLK = 1;
    T_RST = 0;
}
/******************************************************************** 
 函 数 名:R1302()
 功    能:读取DS1302某地址的数据
 说    明:先写地址,后读命令/数据 (内部函数)
 调    用:RTInputByte() , RTOutputByte()
 入口参数:ucAddr: DS1302地址
 返 回 值:ucData :读取的数据
***********************************************************************/
uchar R1302(uchar ucAddr)
{
    uchar ucData;
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    RTInputByte(ucAddr);             /* 地址,命令 */
    ucData = RTOutputByte();         /* 读1Byte数据 */
    T_CLK = 1;
    T_RST = 0;
    return(ucData);
}

/******************************************************************** 
 函 数 名:Set1302()
 功    能:设置初始时间
 说    明:先写地址,后读命令/数据(寄存器多字节方式)
 调    用:W1302()
 入口参数:pClock: 设置时钟数据地址 格式为: 秒 分 时 日 月 星期 年
                               7Byte (BCD码)1B 1B 1B 1B 1B  1B  1B
 返 回 值:无
***********************************************************************/
void Set1302(uchar *pClock) 
{
    uchar i;
    uchar ucAddr = 0x80; 
    W1302(0x8e,0x00);           /* 控制命令,WP=0,写操作?*/
    for(i =7; i>0; i--)
    { 
        W1302(ucAddr,*pClock);  /* 秒 分 时 日 月 星期 年 */ 
        pClock++;
        ucAddr +=2;
    }
    W1302(0x8e,0x80);           /* 控制命令,WP=1,写保护?*/
}

//*********** 18B20驱动 **************************
//延时
void delay(word useconds)
{
  for(;useconds>0;useconds--);
}

//复位
byte ow_reset(void)
{
  byte presence;
  DQ = 0;        //拉低总线
  delay(29);    // 保持 480us
  DQ = 1;       // 释放总线
  delay(3);     // 等待回复
  presence = DQ; // 读取信号
  delay(25);    // 等待结束信号
  return(presence); // 返回   0:正常 1:不存在
}     

//从 1-wire 总线上读取一个字节
byte read_byte(void)
{
  byte i;
  byte value = 0;
  for (i=8;i>0;i--)
  {
    value>>=1;
    DQ = 0; 
    DQ = 1;
    delay(1);  
    if(DQ)value|=0x80;
    delay(6); 
  }
  return(value);
}

//向 1-WIRE 总线上写一个字节
void write_byte(char val)
{
  byte i;
  for (i=8; i>0; i--) // 一次写一位
  {
    DQ = 0; // 
    DQ = val&0x01;
    delay(5); // 
    DQ = 1;
    val=val/2;
  }
  delay(5);
}

//读取和显示温度
Read_Temperature(char xx,char yy)
{
  unsigned char i,tl_temp;
  unsigned int  x;
  unsigned char ct[8];
  union{byte c[2]; int x;}temp;
  
  ow_reset();
  write_byte(0xCC); // Skip ROM
  write_byte(0x44); // 转换温度
  ow_reset();
  write_byte(0xCC); //Skip ROM
  write_byte(0xbe); // 读取寄存器
  temp.c[1]=read_byte();//读出温度低8位
  temp.c[0]=read_byte();//读出温度高8位
 
  // 零下温度判断
  sflag=0; //温度零下标志 0:零上,1:零下
  if((temp.c[0]&0xf8)!=0x00)
   {
    sflag=1; //零下标志位置1
    temp.c[1]=~temp.c[1]; //低8位取反
    temp.c[0]=~temp.c[0]; //高8位取反
    tl_temp=temp.c[1]+1;  //低8位加1 
    temp.c[1]=tl_temp;    //计算后重新存入数组
    if(tl_temp>255) temp.c[0]++;  //如果低8位大于255,向高8位进1
  }  

  x=((temp.c[0]&0x07)*256+temp.c[1])*.625;
  for(i=0;i<8;i++)
       {
         ct[i]=0;
       }
  i=0;
  while(x/10)
   {
    ct[i]=x%10;
    x=x/10;
    i++;
   }
  ct[i]=x;

  if(sflag==1) DisplayOneChar(xx-1,yy,0x2d);
  else         DisplayOneChar(xx-1,yy,0x20);
  DisplayOneChar(xx,  yy,ct[2]+0x30);//显示温度十位数
  DisplayOneChar(xx+1,yy,ct[1]+0x30);//显示温度个位数
  DisplayOneChar(xx+2,yy,0x2e);//显示小数点
  DisplayOneChar(xx+3,yy,ct[0]+0x30);//显示温度小数位
  DisplayOneChar(xx+4,yy,0x01);//显示自定义字符
  DisplayOneChar(xx+5,yy,0x43);//显示字符“C
}

//温度分辨率调整
void adjust_res(char res) ///res 分别等于 0x1f, 0x3f, 0x5f 温度读数分辨率分别对应
                           //              0.5, 0.25, 0.125   
{
  ow_reset();        //复位
  write_byte(0xcc);  //跳过Rom
  write_byte(0x4e);  //写暂存器
  write_byte(0x02);  //写TH 
  write_byte(0x01);  //写TL
  //write_byte(0x5f);  //写结构寄存器
  write_byte(res);
  ow_reset();       //复位
  write_byte(0xcc); //跳过Rom 
  write_byte(0x48); //把暂存器内容写到EPRam中
} 

void mychar()//自定义字符
{
///////////////////////自定义字符
 WriteCommandLCM(0x48, 0); //第一行
 WriteDataLCM(0x02);
 WriteCommandLCM(0x49, 0); //第2行
 WriteDataLCM(0x05);
 WriteCommandLCM(0x4a, 0); //第3
 WriteDataLCM(0x05);
 WriteCommandLCM(0x4b, 0); //第4
 WriteDataLCM(0x02);
 WriteCommandLCM(0x4c, 0); //第5
 WriteDataLCM(0x00);
 WriteCommandLCM(0x4d, 0); //第6
 WriteDataLCM(0x00);
 WriteCommandLCM(0x4e, 0); //第7
 WriteDataLCM(0x00);
 WriteCommandLCM(0x4f, 0); //第8
 WriteDataLCM(0x00);
}

⌨️ 快捷键说明

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