新闻  |   论坛  |   博客  |   在线研讨会
使用LCD1602、DS1302时钟芯片、DS18B20温度传感器完成该日历
0750long | 2009-06-17 12:51:32    阅读:2479   发布文章

使用LCD1602、DS1302时钟芯片、DS18B20温度传感器完成该日历

 

/***********************************************************************************/
/************使用LCD1602、DS1302时钟芯片、DS18B20温度传感器完成该日历**************/
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit rs="P2"^0; // 数据/命令选择端
sbit rw="P2"^1; //读写选择端
sbit e="P2"^2; //使能信号
sbit rst="P2"^5; //时钟芯片复位端
sbit sck="P2"^6; // 时钟信号
sbit io="P2"^7; // 输入/输出端
sbit ds="P2"^3;  //温度传感器信号线
sbit led="P2"^4;  //小灯位定义
uint temp;    // 整型温度值
float f_temp;  //浮点型温度值 
void init();     // 初始化函数
void  delay(uchar z); //延时函数
void write_com(uchar com); //LCD写命令
void write_date(uchar date); //LCD写数据
uint get_temp();    //获得温度
void tempchange(void);   //转换温度
void dsreset(void);    //DS18B20复位
bit tempreadbit(void);   //读DS118B20一位
uchar tempreadbyte(void);   //读DS18B20一个字节
void tempwritebyte(uchar dat);
void deal();   //温度处理函数
void Write_Ds1302_Byte(uchar temp);//写入一个字节
void Write_Ds1302(uchar address,uchar dat);//写入
uchar Read_Ds1302 ( uchar address );   //读取时间 
void Read_RTC(void);  //读取 日历
void Set_RTC(void);  //设定 日历
void time_date();  //时间数据处理
void display(uchar *lp,uchar lc); //显示时间 
void Temp_Display();   //温度显示
uchar table[]="0123456789.C";
uchar table0[]="0123456789-";
uchar table1[]="MONTUEWEDTHUFRISATSUN";
uchar table2[]="0123456789:!";
uchar l_tmpdate[7]={21,59,23,28,10,2,8};
/*初始化时钟芯片,依次是秒分时日月星期年,用十六进制表示十进制,如0x1c表示
1*16+12即28,所以显示出来的就是28*/
uchar l_tmpdisplay[18];
code uchar write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//以上是写入时钟芯片的地址,顺序同上
code uchar read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//读出数据的地址

/******************************日历主函数************************************/
void main()
{
  init();    //初始化LCD
 Set_RTC();//初始化时钟芯片
 while(1)

 tempchange();//温度转换命令 
    time_date();//显示时间
 Temp_Display(); //显示温度
    deal();    //温度处理
 
 
  P1=0xf0;
   IT0=1;  // 选择外部中断0为电平触发方式(1为跳变沿触发方式)
   EX0=1; 
      EA="1";

  

}
void inter0() interrupt 0    //外部中断0
{
 P1=0xfe;
 if(P1!=0xfe)
 
 delay(10);
 if(P1==0xee)
  {  led=~led;
  write_com(0x1c);
  }
   if(P1==0xde)
  {  led=~led;
  write_com(0x18);
  }

 
}
/***************************以下为温度传感器相关程序************************/

void dsreset(void)  //DS18B20复位,初始化函数
{
 uint i;
 ds=0;
 i=103;
 while(i>0)i--;
 ds=1;
 i=4;
 while(i>0)i--; 
}
bit tempreadbit(void) //读一位数据函数
{
 uint i;
 bit dat;
 ds=0;i++;     //i++起延时的作用
 ds=1;i++;i++;
 dat=ds;
 i=8;while(i>0)i--;
 return(dat); 
}
uchar tempreadbyte(void) //读一个字节数据函数
{
 uchar i,j,dat;
 dat=0;
 for(i=1;i<=8;i++)
 {
  j=tempreadbit();
  dat=(j<<7)|(dat>>1);  //读出的数据最低位在最前面
 }
 return(dat);
}
void tempwritebyte(uchar dat)
{         //写一个字节数据函数
 uint i;
 char j;
 bit testb;
 for(j=1;j<=8;j++)
 {
  testb=dat&0x01;
  dat=dat>>1;
  if(testb)   //写1
  {
   ds=0;
   i++;i++;
   ds=1;
   i=8;while(i>0)i--;
  }
  else       //写0
  {
   ds=0;
   i=8;while(i>0)i--;
   ds=1;
   i++;i++;
  }
 } 
}
void tempchange(void)  //DS18B20开始获取温度并转换
{
 dsreset();
 delay(1);
 tempwritebyte(0xcc);   //写跳过读ROM指令
 tempwritebyte(0x44);  //写温度转换指令  
}
uint get_temp()    //读取寄存器中存储的温度数据
{
 uchar a,b;
 dsreset();
 delay(1);
 tempwritebyte(0xcc);
 tempwritebyte(0xbe);  //读RAM内部9字节的温度数据
 a=tempreadbyte();    //读低8位
 b=tempreadbyte();   //读高8位
 temp=b;
 temp<<=8;
 temp=temp|a;     //两个字节组合为一个字节
 f_temp=temp*0.0625;    // 温度在寄存器中为12位,分辨率为0.0625
 temp=f_temp*10+0.5;    //乘以10表示小数点后面只取1位,加0.5时四舍五入
 f_temp=f_temp+0.05;
 return temp; 
}

void Temp_Display()    //温度显示函数
{
 write_com(0x80+0x40+0x0b);  
 write_date(table[get_temp()/100]);
 write_com(0x80+0x40+0x0c);  
 write_date(table[get_temp()%100/10]);
 write_com(0x80+0x40+0x0d);  
 write_date(table[10]);
 write_com(0x80+0x40+0x0e);  
 write_date(table[get_temp()%10]);
 write_com(0x80+0x40+0x0f);  
 write_date(table[11]); 
}
void deal()   //温度处理函数
{
 uint i;
 i=get_temp();
 if(i>300||i<200) //当温度低于20度或大于30度时小灯闪烁
 {
  led=0;
  delay(100);
  led=1;
 // write_com(0x80+12);
 // write_date(table2[11]);
 }

// else led="1";
  
}


/***********************以上为温度传感器相关程序***********************/

/***********************以下为时钟芯片相关程序***********************/

void Write_Ds1302_Byte(uchar temp) //写入一字节数据
{
 uchar i;
 for (i=0;i<8;i++)      //循环8次 写入数据 ,上升沿写入
  {
     sck="0";
     io="temp"&0x01;      //每次传输低字节
     temp>>=1;    //右移一位
     sck="1";
   }
}
void Write_Ds1302(uchar address,uchar dat)//写入    
{
 
  rst=0;
 delay(1);
  sck=0;
 delay(1);
  rst=1; 
    delay(1);   //启动
  Write_Ds1302_Byte(address); //发送地址
  Write_Ds1302_Byte(dat);  //发送数据
  rst=0;    //恢复
}
uchar Read_Ds1302 (uchar address)   //读取时间
{
  uchar i,time=0x00;
  rst=0;
 delay(1);
  sck=0;
 delay(1);
  rst=1;
 delay(1);
  Write_Ds1302_Byte(address);
  for (i=0;i<8;i++)   //循环8次 读取数据
  {  
   if(io)
   time|=0x80;   //每次传输低字节
  sck=1;      //时钟下降沿读入数据?????????
  time>>=1;   //右移一位 
      sck=0;
 
  
 }
  rst=0;
 delay(1);  //以下为DS1302复位的稳定时间
  rst=0;
 sck=0;
 delay(1);
 sck=1;
 delay(1);
 io=0;
 delay(1);
 io=1;
 delay(1);
 return (time);  

void Read_RTC()  //读取 日历
{
 uchar i,*p;
 p=read_rtc_address;  //地址传递
 for(i=0;i<7;i++)  //分7次读取 年月日时分秒星期
 {
  l_tmpdate[i]=Read_Ds1302(*p);
  p++;
 }
}
void Set_RTC(void)  //设定 日历
{
 uchar i,*p,tmp;
  for(i=0;i<7;i++)
 {
  tmp=l_tmpdate[i]/10;
  l_tmpdate[i]=l_tmpdate[i]%10;
  l_tmpdate[i]=l_tmpdate[i]+tmp*16;
 }
  Write_Ds1302(0x8E,0X00);   //允许写入
 
  p=write_rtc_address; //传地址 
  for(i=0;i<7;i++)  //7次写入 年月日时分秒星期
  {
    Write_Ds1302(*p,l_tmpdate[i]);
      p++; 
  }
  Write_Ds1302(0x8E,0x80); //禁止写入
}

void time_date()  //时间数据处理  
{   
         Read_RTC();
   l_tmpdisplay[0]=l_tmpdate[2]/16;//时    
   l_tmpdisplay[1]=l_tmpdate[2]&0x0f;
   l_tmpdisplay[2]=10;   //加入":"
   l_tmpdisplay[3]=l_tmpdate[1]/16;//分
   l_tmpdisplay[4]=l_tmpdate[1]&0x0f;
   l_tmpdisplay[5]=10;
   l_tmpdisplay[6]=l_tmpdate[0]/16;//秒
   l_tmpdisplay[7]=l_tmpdate[0]&0x0f; 
 
   l_tmpdisplay[8]=2;    //显示2008的2
   l_tmpdisplay[9]=0;   //显示2008的第一个0
   l_tmpdisplay[10]=l_tmpdate[6]/16; //年
   l_tmpdisplay[11]=l_tmpdate[6]&0x0f;
   l_tmpdisplay[12]=10;     //加入“-”
   l_tmpdisplay[13]=l_tmpdate[4]/16;//月
   l_tmpdisplay[14]=l_tmpdate[4]&0x0f;
   l_tmpdisplay[15]=10;
   l_tmpdisplay[16]=l_tmpdate[3]/16;//日
   l_tmpdisplay[17]=l_tmpdate[3]&0x0f;
  
  display(l_tmpdisplay,8);
}

void display(uchar *lp,uchar lc)   //显示时间
{
 unsigned char i;  //定义变量
 
 write_com(0x80);  //液晶第一行显示时间和星期
 for(i=0;i<lc;i++)
 { 
 write_date(table2[lp[i]]);  
 delay(1);  
 }
 write_com(0x80+0x09);
 switch(l_tmpdate[5]) //用英文缩写显示星期
 {
  case 0: write_date(table1[0]);
    write_date(table1[1]);
    write_date(table1[2]);
    break;
  case 1: write_date(table1[3]);
    write_date(table1[4]);
    write_date(table1[5]);
    break;
  case 2: write_date(table1[6]);
    write_date(table1[7]);
    write_date(table1[8]);
    break;
  case 3: write_date(table1[9]);
    write_date(table1[10]);
    write_date(table1[11]);
    break;

  case 4: write_date(table1[12]);
    write_date(table1[13]);
    write_date(table1[14]);
    break;
  case 5: write_date(table1[15]);
    write_date(table1[16]);
    write_date(table1[17]);
    break;
  case 6: write_date(table1[18]);    
    write_date(table1[19]);
    write_date(table1[20]);
    break;
 }  
 write_com(0x80+0x40);  //第二行显示年
 for(i=8;i<lc+10;i++)
 { 
 write_date(table0[lp[i]]);  
 delay(1);  
 }
}
/********************以上为时钟芯片相关程序***************************/

void init()     //LCD初始化函数
{
 e=0;
 write_com(0x38);//显示模式的设置
 delay(1);
 write_com(0x0c);//开显示,光标显示
 delay(1);
 write_com(0x06);//光标位置
 delay(1);
 write_com(0x01);   //清显示
 delay(1);
}
void write_com(uchar com)    //LCD写命令
{
 rs=0;
 rw=0;
 P0=com;
 delay(1);
 e=1;
 delay(1);
 e=0; 
}
void write_date(uchar date)    //LCD写数据
{
 rs=1;
 rw=0;
 P0=date;
 delay(1);
 e=1;
 delay(1);
 e=0; 
}
void  delay(uchar z) //延时函数
{
 uchar x,y;
 for(x=0;x<z;x++)
  for(y=0;y<110;y++);
}
/***************END***********END******************************/ 

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客