加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

AT89S52+12864+DS18B20+DS1302万年历(简单版)

(2010-04-25 13:15:58)
标签:

单片机

万年历

杂谈

一直想做一个万年历,看了一下硬件电路还是蛮简单的(AT89S52+12864+DS18B20+DS1302就这么几个芯片),主要还是程序难一点,因为没有一点思路,但那几个芯片的模块程序我以前研究过的,所以网上找了几个程序研究了下,编出了一个最简单的,没有农历,闹钟,这种东西,以后再加嘛,(*^__^*) 。

 

C语言代码如下(因为太大,部分代码再另一篇文章中)

//头文件
#include<AT89X52.h>
#include<intrins.h>
#include<string.h>  //字符串操作函数

//宏定义
#define uchar unsigned char
#define uint unsigned char

#define lcddata P0  //液晶8位并口数据

//定义全局变量

uchar hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;  //秒,分,时到日,月,年位闪的计数
uchar count,temp,up_flag,down_flag,done;
uchar flag;    //负温度标志
uchar tltemp;        //临时暂存变量

uchar temp_value,temp1_value;      //temp_value温度值正数部分 temp1_value温度值小数部分
uchar week_value[3];
uchar TempBuffer[6];
uchar week_value[3];

void show_all();

//定义特殊位

sbit lcd_rs=P2^0;  //H=data;L=command
sbit lcd_rw=P2^1;  //H=read;L=write
sbit lcd_e=P2^2;  //input enable
sbit lcd_psw=P2^3;  //H=Parallel Mode;L=Serial Mode
sbit lcd_rst=P2^4;  //Reset Signal,Low effective
sbit lcd_bf=P0^7;     //LCD Busy bit


sbit fmq=P3^6;


sbit DQ=P3^3;    //DS18B20 Data input/output Pin


sbit DS1302_SCLK=P1^0;   //实时时钟时钟引脚
sbit DS1302_DATA=P1^1;   //实时时钟数据引脚
sbit DS1302_RST=P1^2;   //实时时钟复位引脚


sbit Set=P1^4;
sbit Up=P1^5;
sbit Down=P1^6;
//sbit KEY_4=P1^7;

 



void delaynms(uint aa)
{
  uchar bb;
  while(aa--)
  {
   for(bb=0;bb<115;bb++)   //1ms基准延时程序
   {
    ;
   }
  }
}

 


/
void chkbusy_lcd(void)
{
  lcddata=0xff;              //把忙碌标志位BF置1
  lcd_rs=0;      //指令操作
  lcd_rw=1;      //读操作
  lcd_e=1;      //拉高使能,读取数据
  while(lcd_bf==1);    //判断忙碌位是否为0,若果为1,液晶忙,一直等待(BF=1,状态忙)
  lcd_e=0;      //拉低使能

}


void wr_lcd(uchar dat_comm,uchar content)
{
  chkbusy_lcd();
  if(dat_comm==1)
  {
   lcd_rs=1;   //data
 lcd_rw=0;   //write
  }
  else
  {
   lcd_rs=0;   //command
 lcd_rw=0;   //write
  }
  lcd_e=1;    //拉高使能
  lcddata=content;//放上数据
  _nop_();    //等待
  lcd_e=0;    //拉低使能,使数据写入
}


void init_lcd(void)
{
   wr_lcd(0,0x30);  //基本指令集
   delaynms(1);   //等待
   wr_lcd(0,0x30);  //再设置一次为基本指令集,因为ST7920中有2个寄存器用来设置使用哪个指令集
   delaynms(1);   //等待
   wr_lcd(0,0x0c);  //开显示,关游标,关游标位置
   delaynms(1);   //等待
   wr_lcd(0,0x01);  //清屏,地址指针指向00H
   delaynms(20);   //等待>10ms
   wr_lcd(0,0x06);  //光标右移,整体不移
}



void lcd_clr(void)
{
  wr_lcd(0,0x30);        //基本指令集
  wr_lcd(0,0x01);   //清除显示
  delaynms(1);
}


void gotoxy(unsigned char y, unsigned char x)
{
 if(y==1)
 wr_lcd(0,0x80|x);    //Line 1
 if(y==2)
    wr_lcd(0,0x90|x);    //Line 2
 if(y==3)
 wr_lcd(0,((0x80|x)+8));   //Line 3
 if(y==4)
    wr_lcd(0,((0x90|x)+8));   //Line 4
}


void print(uchar *str)
{
  while(*str!='\0')    //检查是否到字符串尾
  {
   wr_lcd(1,*str++);    //输入*str后str++
  }
}


/
bit Init_DS18B20(void)
{
  bit flag;
  DQ=1;
  _nop_();
  DQ=0;     //拉低,
  for(t=0;t<200;t++); //产生一个约600us低电平脉冲
  DQ=1;     //释放总线为高电平
  for(t=0;t<15;t++); //延时约45us
  flag=DQ;    //对总线检测
  for(t=0;t<200;t++);
  return flag;
}


uchar ReadOneChar(void)
{
  uchar dat;
  uchar i=0;
  for(i=0;i<8;i++)
  {
   DQ=1;
 _nop_();
 DQ=0;        //DQ拉低1us以后,
 _nop_();  //
 DQ=1;   //释放单总线为高电平,以让DS18B20把数据传到单总线上
 for(t=0;t<3;t++);   //延时9微妙
 dat>>=1;  //
 if(DQ==1)   //
 {
   dat|=0x80;  //数据采集
 }
 
 else
 dat|=0x00;
 for(t=0;t<1;t++); //延时3us,两个读时序间至少需要1us的恢复期
   }
   return dat;
}


void WriteOneChar(uchar dat)
{
   uchar i;
   for(i=0;i<8;i++)
   {
     DQ=1;
  _nop_();
  DQ=0;    //主机把总线拉低1us,表示写周期开始
  _nop_();   //
  DQ=dat&0x01;
  for(t=0;t<15;t++);  //延时约45秒,
  for(t=0;t<10;t++); //????
  DQ=1;               //释放总线
  for(t=0;t<1;t++);  //延时3us,两个写时序间至少需要1us的恢复期???
  dat>>=1;
   }
   for(t=0;t<4;t++);  //????
}

 


void ReadTemperature(void)
{
  uchar TH=0; //
  uchar TL=0; //
  flag=0;
  Init_DS18B20();
  WriteOneChar(0xCC); // 跳过读序号列号的操作
  WriteOneChar(0x44); // 启动温度转换

//  delaynms(1000);     //千万不能延时,(!!!!)

  Init_DS18B20();
  WriteOneChar(0xCC); //跳过读序号列号的操作
  WriteOneChar(0xBE); //读取温度寄存器

//   delaynms(500);  // 不延时(!!!!)

  TL=ReadOneChar();   //读低8位
  TH=ReadOneChar();   //读高8位
  if((TH&0xf8)!=0x00)      //是负温度
  {
    flag=1;
 TH=~TH;
 TL=~TL;
 tltemp=TL+1;
 if(tltemp>255)
 TH++;   
        //25.125
  temp_value=TH*16+TL/16;  //整数    25
  temp1_value=(TL%16)*10/16; //小数部分 1250
}

void Temp2Str(void)
{
  TempBuffer[0]=':';
  if(flag==1)   //是负温度
  {
   TempBuffer[1]='-';
  }
  else
  {
   TempBuffer[1]=temp_value/100+'0';
 if(TempBuffer[1]=='0')
 {
   TempBuffer[1]=' ';
 }
 else
 TempBuffer[1]='1';
  }
  TempBuffer[2]=temp_value%100/10+'0';
  TempBuffer[3]=temp_value%10+'0';
  TempBuffer[4]='.';
  TempBuffer[5]=temp1_value+'0';
  TempBuffer[6]='\0';
}

 

 


/
void DS1302InputByte(uchar d)
{
   uchar i;      
   DS1302_SCLK=0;    //拉低SCLK,为上升沿写入数据做好准备
   for(i=0;i<8;i++)    //连续写入8个二进制数据
   {
     DS1302_DATA=d&0x01;  //取出d的第0位,写入1302,  低位在前,高位在后
  _nop_();     //等待
  DS1302_SCLK=1;    // 拉高SCLK,上升沿写入数据
  _nop_();     // 等待
  DS1302_SCLK=0;    //拉低SCLK形成脉冲
  d>>=1;      //将d的数据向右移一位,准备写入下一个二进制数据
   }
}


uchar DS1302OutputByte(void)
{
  uchar i;
  uchar dat;
  for(i=0;i<8;i++)   //连续读出8个二进制数
  {
   dat>>=1;    //向右移一位
 if(DS1302_DATA==1)  //如果读出数据是1,(上一个写入控制字结束后,保存一个读出数据)
 {
   dat|=0x80;
 }
 DS1302_SCLK=1;   //拉高SCLK
 _nop_();
 DS1302_SCLK=0;   //拉低SCLK,读取数据

  }
  return dat;       //将读出的数据返回
}


void Write1302(uchar ADDRorCOMM,uchar DATA)
{
 DS1302_RST=0;   //禁止数据传输
 DS1302_SCLK=0;   //确保写写之前SCLK被拉低
    DS1302_RST=1;   //启动数据传输
 DS1302InputByte(ADDRorCOMM); //写入命令或地址
 DS1302InputByte(DATA);   //
 DS1302_SCLK=1;   //将时钟电平置于高电平状态 $$$$$$ 置高是为了让下次写的时候 能准确的被拉低 保证电平

状态的正确性
 DS1302_RST=0;   //禁止数据传输
}


uchar Read1302(uchar ADDRorCOMM)
{
    uchar dat;
 DS1302_RST=0;   //禁止数据传输
 DS1302_SCLK=0;   //确保写写之前SCLK被拉低
    DS1302_RST=1;   //启动数据传输
 DS1302InputByte(ADDRorCOMM); //写入命令或地址
 dat=DS1302OutputByte();   // 读出数据
 DS1302_SCLK=1;   //将时钟电平置于高电平状态 $$$$$$ 置高是为了让下次写的时候 能准确的被拉低 保证电平

状态的正确性
 DS1302_RST=0;   //禁止数据传输
 return(dat);
}


void Init_1302(void)    //(2008年7月12日12时00分00秒星期六)
{
  uchar flag;
  flag=Read1302(0x81);    //读秒寄存器
  if(flag&0x80)         //CH为0(flag最高位是0),时钟走动,不用初始化 。
  {
   Write1302(0x8e,0x00);  //允许写操作
 Write1302(0x8c,((8/10)<<4|(8%10)));  //YEAR
 Write1302(0x8a,0x01);  //DAY
 Write1302(0x88,((3/10)<<4|(3%10)));  //MONTH
 Write1302(0x86,((14/10)<<4|(14%10)));  //DATE
 Write1302(0x84,((12/10)<<4|(12%10)));  //HR
 Write1302(0x82,((0/10)<<4|(0%10)));  //MIN
 Write1302(0x80,((0/10)<<4|(0%10)));  //SEC
 Write1302(0x90,0xa5);  //打开充电功能
 Write1302(0x8e,0x80);  //禁止写操作
  }
}


typedef struct _SYSTEMTIME_
{
  uchar Second;
  uchar Minute;
  uchar Hour;
  uchar Week;
  uchar Day;
  uchar Month;
  uchar Year;
  uchar DateString[11];
  uchar TimeString[9];
}SYSTEMTIME;
SYSTEMTIME CurrentTime;


void DS1302_GetTime(SYSTEMTIME *Time)
{
  uchar ReadValue;
  ReadValue=Read1302(0x81);                           //从秒寄存器里读数据
  Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码
  ReadValue=Read1302(0x83);                           //从分寄存器里读数据
  Time->Minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码
  ReadValue=Read1302(0x85);                           //从小时寄存器里读数据
  Time->Hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码
  ReadValue=Read1302(0x8b);                           //从星期寄存器里读数据
  Time->Week=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码
  ReadValue=Read1302(0x87);                           //从日寄存器里读数据
  Time->Day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码
  ReadValue=Read1302(0x89);                           //从月寄存器里读数据
  Time->Month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码
  ReadValue=Read1302(0x8d);                           //从年寄存器里读数据
  Time->Year=((ReadValue&0xf0)>>4)*10+(ReadValue&0x0f);  //把读出的数据转换成BCD码  //注意是0xF0
}


void Date2Str(SYSTEMTIME *Time)
{
    uchar tab[]={0xd2,0xbb,0xbb6,0xfe,0xc8,0xfd,0xcb,0xc4,0xce,0xe5,0xc1,0xf9,0xc8,0xd5};//?????
//  uchar tab[]={"一二三四五六日"};

 


  if(hide_year<2)  ////这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,
  {
   Time->DateString[0]='2';
 Time->DateString[1]='0';
 Time->DateString[2]=Time->Year/10+'0';
 Time->DateString[3]=Time->Year%10+'0';
  }
  else
  {
    Time->DateString[0]=' ';
 Time->DateString[1]=' ';
 Time->DateString[2]=' ';
 Time->DateString[3]=' ';
  }

  Time->DateString[4]='-';

  if(hide_month<2)
  {
   Time->DateString[5]=Time->Month/10+'0';
 Time->DateString[6]=Time->Month%10+'0';
  }
  else
  {
   Time->DateString[5]=' ';
 Time->DateString[6]=' ';
  }

  Time->DateString[7]='-';

  if(hide_day<2)
  {
   Time->DateString[8]=Time->Day/10+'0';
 Time->DateString[9]=Time->Day%10+'0';
  }
  else
  {
   Time->DateString[8]=' ';
 Time->DateString[9]=' ';
  }

  if(hide_week<2)
  {
     
 week_value[0]=tab[2*(Time->Week%10)-2];  //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存

放,因为等一下要在最后显示
    week_value[1]=tab[2*(Time->Week%10)-1];
  }
  else
  {
   week_value[0]=' ';
 week_value[1]=' ';
  }
  week_value[2]='\0';

  Time->DateString[10]='\0';   //字符串末尾加 '\0' ,判断结束字符

}


void Time2Str(SYSTEMTIME *Time)
{
  if(hide_hour<2)
  {
   Time->TimeString[0]=Time->Hour/10+'0';
 Time->TimeString[1]=Time->Hour%10+'0';
  }
  else
  {
   Time->TimeString[0]=' ';
 Time->TimeString[1]=' ';
  }

  Time->TimeString[2]=':';

  if(hide_min<2)
  {
   Time->TimeString[3]=Time->Minute/10+'0';
 Time->TimeString[4]=Time->Minute%10+'0';
  }
  else
  {
   Time->TimeString[3]=' ';
 Time->TimeString[4]=' ';
  }

  Time->TimeString[5]=':';

  if(hide_sec<2)
  {
   Time->TimeString[6]=Time->Second/10+'0';
 Time->TimeString[7]=Time->Second%10+'0';
  }
  else
  {
   Time->TimeString[6]=' ';
 Time->TimeString[7]=' ';
  }

  Time->TimeString[8]='\0';
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有