打印

Edc190 & Ht1621(1)

[复制链接]
2151|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
/***********************************************************************
* 说明:这是用EDC190作为显示的电子钟和温度计的代码.它的功能是: 一 *
* 般状态下,它以24小时制显示时间(只显示时和分),并且小时和分钟之间的 *
* 冒号闪烁.板子正面的圆柱形晶振是32.768k,用于实时时钟芯片DS1302. *
* 板子背面的晶振是12M,用于单片机的起振.单片机采用的是STC89RC,  *
* LQFP44封装,体积较小.但因为没有编程器,所以板子上留下了四个插针,用 *
* 于给单片机下载程序.插针左边的是电位器,用于调节液晶屏的显示亮度,  *
* 如果知道HT1621B的VLCD的电压的话,可以选择一个合适的电阻, 一端  *
* 接VCC,另一端接VLCD引脚,这样的话,可以使板子做得更小一些. 左侧有  *
* 两个电源输入端,一个是DC2.1接口,另一个是MINI_USB接口, 任接一个   *
* 都可,输入电压是5V.时钟芯片和温度芯片分别是美国DALLAS公司的     *
* DS1302和NXP公司的温度范围在-55°C to 125°C的LM75A,.板子背面  *
* 还有一个芯片是台湾合泰公司的HT1621B,用于液晶的显示.板子下面的四个 *
* 按键有两个功能,一是用于调整时间,另一个用用于显示年月日等其它信息. *
* 四个按键从左到右分别是S1,S2,S3,S4.     *
* 先说S4,按下S4键液晶停止显示时间,开始依次显示年;月,日;星期;温度. *
* 每个项目显示时间大约两秒.然后又回到正常显示时间状态.S1是功能键, *
* S1键可以用来调整年月日星期和时间(时,分).S2和S3分别是加减键,当调 *
* 整时间时,可用S2进行加,S3进行减.下面说明如何调整时间.   *
* 第一次按下S1键,进入调整年的状态,可以用S2或S3进行加减的调整.  *
* 第二次按下S1键,进入调整月的状态,调整方法同上.    *
* 第三次按下S1键,进入调整日的状态,调整方法同上.    *
* 第四次按下S1键,进入调整星期的状态,调整方法同上.   *
* 第五次接下S1键,进入调整小时的状态,调整方法同上.   *
* 第六次接下S1键,进入调整分钟的状态,调整方法同上.   *
* 再次按下S1键,调整完毕,程序将调整好的现在的时间写入寄存器,时钟将   *
* 按现在调整好的时间进行走时.因为DS1302时钟芯片只支持2000~2099年, *
* 因此程序也只允许年的调整在这个范围内.DS1302有闰年和月的补偿功能   *
* ,能自动进行调整,因此,程序中也进行了大量的判断,以保证用户不能调整  *
* 出一个错误的时间,例如,4月31日,2月30日等等不可能出现的日期.但当用  *
* 户正确调整好年月日后,再调整星期时,如果用户调整的星期数不是正确的  *
* 星期数,那么程序将无法判断,比如某年某月某日是星期三,用户却把它调   *
* 整成星期四或星期一,那么程序将无法判断.因为程序也不知道那天到底是  *
* 星期几.它只是接用户的意愿将调整好的时间写入寄存器.至于DS1302声称  *
* 它有自动补偿功能,能否在一定时间后将错误修正,本人没有经过测试,尚   *
* 无从知晓.        *
* PS:经过测试,时钟行走正常,电位器可调整液晶屏对比度.走时偏快一些,大约 *
* 两天能差一分钟.温度显示正常,我把它放在冰霜里测试,能正常显示零下的 *
* 温度.         *
************************************************************************/
#include <reg52.h>
#include <intrins.h>     /* for _nop_() */
#include <string.h>     /* for strcpy etc. */
#include "Zh_Type.h"     /* for uint8, uint16 etc. */
#include "def.h"     /* for const, sbit definition */
/* clear display */
uint8 code Ht1621Tab[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
/************************************************************************
* 这个表要说明一下.编码是液晶主要显示用的编码0~9.这个编码是经过调 *
* 整过的,编码0本应是0xfc,编码1本应是0x60等等.由于硬件连接和移位  *
* 显示的需要,才把原来的编码的高四位和低四位对调.因为显示有用的位是 *
* D3 (00001000b,就是为1的位).为了显示时移位的方便和移位次数的最少,  *
* 编码就成了现在这个样子.      *
************************************************************************/
/* 0~9 */
uint8 code tab[]={
0xcf,0x06,0xad,0x2f,0x66,
0x6b,0xeb,0x0e,0xef,0x6f};
uint8 first,second,third,fourth;   /*每位液晶显示的数码0~9*/
bit egative;     /*温度正负的标志位*/
uint8  colon;      /*冒号*/
uint8  getTimebuf[7];     /*用于存放获取的时间数据*/
uint8  setTimebuf[7];     /*用于存放要设置的时间日期数据*/
uint8  dis[4];      /*BCD码翻译成显示数字*/
uint8  adj;      /*调节时间标志*/
/****************** OTHERS ***********************/
void delay()      /*延时*/
{;;}
void DelayMS(uint16 iMS)    /* delay ms */
{
uint16 i,j;
for(i=0;i<iMS;i++)
  for(j=0;j<65;j++)
   delay();
}
/************************************************************************
* 说明:先来说一下主函数中的对DS1302的初始化.DS1302工作前需要进行 *
* 初始化,调用的是Init1302函数.但初始化只能是一次,即如果时间没有走, *
* 就初始化,假如时钟在走,那么就不进行初始化.如何判断时钟是否在走呢?第 *
* 一次进行初始化时,就在芯片的RAM单元中写入数据,在这里写了两个单元, *
* 分别写入19和65.每次启动时,都去读这两个单元,如果这两个单元是19和  *
* 65,说明己经初始化过,此时就无须再初始化,否则,对DS1302进行初始化. *
* PS:很多**中说,靠读取秒寄存器也可以知道DS1302是否经过初始化,  *
*那就是判断它的D7位.       *
************************************************************************/
/****************** DS1302 *************************/
void WriteByte(uint8 ucData)   /*向DS1302写一个字节*/   
{         
uint8 i,dat;
dat=ucData;
DS1302_CLK = 0;
for(i=0;i<8;i++)
{
  dat=dat>>1;
  DS1302_IO = CY;
  DS1302_CLK = 1;
  DS1302_CLK = 0;
}
}
uint8 ReadByte(void)    /* 从DS1302读一个字节 */      
{
uint8 i,val;
for(i=0;i<8;i++)
{
  val = val>>1;
  if(DS1302_IO)
   val|=0x80;
  DS1302_CLK = 1;
  DS1302_CLK = 0;
}
return(val);
}
void Write1302(uint8 ucAddr, uint8 ucDa)/* 向DS1302指定地址写一个字节数据 */
{
DS1302_RST = 0;
DS1302_CLK = 0;    /* 只有在CLK为低电平时,才能将RST置为高电平 */
DS1302_RST = 1;
WriteByte(ucAddr);
WriteByte(ucDa);
DS1302_CLK = 1;
DS1302_RST =0;
}
uint8 Read1302(uint8 ucAddr)   /* 从DS1302指定地址读取一个字节数据 */
{
uint8 val;
DS1302_RST = 0;
DS1302_CLK = 0;    /* 只有在CLK为低电平时,才能将RST置为高电平 */
DS1302_RST = 1;
WriteByte(ucAddr);
val=ReadByte();
DS1302_CLK = 1;
DS1302_RST =0;
return(val);
}
/*******************************************
* 设置DS1302时间数据,传入的数组中    *
* 格式为:秒 分 时 日 月 星期 年    *
*******************************************/
void SetTime(uint8 *pTime)
{
uint8 i;
uint8 ucAddr = 0x80;
Write1302(0x8e,0x00);     /* 控制命令,WP=0,允许写操作 */
for(i=0;i<7;i++)
{
  Write1302(ucAddr,*pTime);   /* 秒 分 时 日 月 星期 年 */
  pTime++;
  ucAddr +=2;
}
Write1302(0x8e,0x80);     /* 控制命令,WP=1,写保护 */
}
/************************************************
* 从DS1302读取时间数据,返回到传入的数组   *
* 中格式为:秒 分 时 日 月 星期 年  *
************************************************/
void GetTime(uint8 ucCurtime[])
{
uint8 i,ucAddr;
ucAddr = 0x81;
for (i=0;i<7;i++)
{
  ucCurtime[i] = Read1302(ucAddr);
  ucAddr += 2;
}
}
void Init1302(void)     /*初始化DS1302*/
{
uint8 flag1,flag2;
flag1=Read1302(0xc1);    /*读取DS1302的RAM*/
flag2=Read1302(0xc3);   

if((flag1!=0x19)&&(flag2!=0x65))
{
  Write1302(0x8e,0x00);    /*控制写入WP=0*/
  //Write1302(0x90,0xa5);   /*辅助电源充电命令*/
  Write1302(0x80,0x00);    /*写秒*/
  Write1302(0x82,0x53);    /*写分*/
  Write1302(0x84,0x16);    /*写时*/
  Write1302(0x86,0x06);    /*写日*/
  Write1302(0x88,0x09);    /*写月*/
  Write1302(0x8a,0x05);    /*写星期*/
  Write1302(0x8c,0x13);    /*写年*/

  Write1302(0xc0,0x19);    /*写入标志位*/
  Write1302(0xc2,0x65);    /*写入标志位*/

  Write1302(0x8e,0x80);    /*写保护WP=1*/
}
}
/****************** LM75A *************************/
void start()        /*IIC开始*/
{
LM75A_SDA=1;
delay();
LM75A_SCL=1;
delay();
LM75A_SDA=0;
delay();
}
void stop()         /*IIC停止*/
{
LM75A_SDA=0;
delay();
LM75A_SCL=1;
delay();
LM75A_SDA=1;
delay();
}
void respons()       /*IIC从机应答*/
{
uint8 i;
LM75A_SCL=1;
delay();
while((LM75A_SDA==1)&&(i<250))
  i++;
LM75A_SCL=0;
delay();
}
void ack()      /*IIC主机应答*/
{
LM75A_SDA=0;
LM75A_SCL=1;
delay();
LM75A_SCL=0;
LM75A_SDA=1;
}
void nack()      /*主机非应答*/  
{
LM75A_SDA=1;
LM75A_SCL=1;
delay();
LM75A_SCL=0;
LM75A_SDA=0;
}
void write_byte(uint8 date)    /*IIC写一个字节*/
{
uint8 i,temp;
temp=date;
for(i=0;i<8;i++)
{
  temp=temp<<1;
  LM75A_SCL=0;
     delay();
  LM75A_SDA=CY;
  delay();
  LM75A_SCL=1;
  delay();
}
LM75A_SCL=0;
delay();
LM75A_SDA=1;
delay();
}
uint8 read_byte()     /*IIC读一个字节*/   
{
uint8 i,k;
LM75A_SCL=0;
delay();
LM75A_SDA=1;
delay();
for(i=0;i<8;i++)
{
  LM75A_SCL=1;
  delay();
  k=(k<<1)|LM75A_SDA;
  LM75A_SCL=0;
  delay();
}
return k;
}
void gettemp()        /*读取温度值*/
{
uint8 temph,templ;
uint16 temp,value;
float ftemp;
start();
write_byte(0x9e);    /*10011110*/
respons();
write_byte(0x00);
respons();
start();
write_byte(0x9f);    /*10011111*/
respons();
temph=read_byte();    /*先读到高字节*/
ack();
templ=read_byte();    /*再读到低字节*/
nack();
stop();

temp=temph;
temp<<=8;
temp=temp+templ;    /*合并*/
temp=temp>>7;     /*高9位有效*/

if(temp&0x100)     /*零下*/
{
   temp=~temp;
  temp&=0xff;
  temp++;
  ftemp=temp/2.0;
  negative=1;
}
else
{
  ftemp=(temp&0xff)/2.0;   /*LM75精度是0.5度*/
  negative=0;
}
value=ftemp*10;     /*得到每位数码*/
first=value/1000;
second=value%1000/100;
third=value%100/10;
fourth=value%10;
}
void initLM75A()     /*初始化LM75A*/  
{
LM75A_SDA=1;
delay();
LM75A_SCL=1;
delay();
}
/****************** EDC190 ***********************/
/************************************************
写数据函数,cnt为传送数据位数,数据传送为低位在前
************************************************/
void Ht1621Wr_Data(uint8 Data,uint8 cnt)
{
uint8 i;
for(i=0;i<cnt;i++)
{
  HT1621_WR=0;
  _Nop();
  HT1621_DAT=Data&0x80;
  _Nop();
  HT1621_WR=1;
  _Nop();
  Data<<=1;
}
}
/************************************
函数名称:void Ht1621WrCmd(uint8 Cmd)
功能描述:HT1621命令写入函数
全局变量:无
参数说明:Cmd为写入命令数据
返回说明:无
说明 :写入命令标识位100
************************************/
void Ht1621WrCmd(uint8 Cmd)
{
HT1621_CS=0;
_Nop();
Ht1621Wr_Data(0x80,4);    /* 写入命令标志100 */
Ht1621Wr_Data(Cmd,8);    /* 写入命令数据 */
HT1621_CS=1;
_Nop();
}
/********************************************************
函数名称:void Ht1621WrOneData(uint8 Addr,uint8 Data)
功能描述:HT1621在指定地址写入数据函数
全局变量:无
参数说明:Addr为写入初始地址,Data为写入数据
返回说明:无
说明 :因为HT1621的数据位4位,所以实际写入数据为参数的后4位
********************************************************/
void Ht1621WrOneData(uint8 Addr,uint8 Data)
{
HT1621_CS=0;
Ht1621Wr_Data(0xa0,3);    /* 写入数据标志101 */
Ht1621Wr_Data(Addr<<2,6);   /* 写入地址数据 */
Ht1621Wr_Data(Data<<4,4);   /* 写入数据 */
HT1621_CS=1;
_Nop();
}
/**************************************************************
函数名称:void Ht1621WrAllData(uint8 Addr,uint8 *p,uint8 cnt)
功能描述:HT1621连续写入方式函数
全局变量:无
参数说明:Addr为写入初始地址,*p为连续写入数据指针,
         cnt为写入数据总数
返回说明:无
说明 :HT1621的数据位4位,此处每次数据为8位,写入数据
      总数按8位计算
**************************************************************/
void Ht1621WrAllData(uint8 Addr, uint8 *p,uint8 cnt)
{
uint8 i;
HT1621_CS=0;
Ht1621Wr_Data(0xa0,3);    /* 写入数据标志101 */
Ht1621Wr_Data(Addr<<2,6);   /* 写入地址数据 */
for(i=0;i<cnt;i++)
{
  Ht1621Wr_Data(*p,8);   /* 写入数据 */
  p++;
}
HT1621_CS=1;
_Nop();
}
/***************************************
函数名称:void Ht1621_Init(void)
功能描述:HT1621初始化
全局变量:无
参数说明:无
返回说明:无
说明 :无
***************************************/
void Ht1621_Init(void)
{
HT1621_CS=1;
HT1621_WR=1;
HT1621_DAT=1;
DelayMS(2000);     /* 延时使LCD工作电压稳定 */
Ht1621WrCmd(BIAS);
Ht1621WrCmd(RC256);    /* 使用内部振荡器 */
Ht1621WrCmd(SYSDIS);
Ht1621WrCmd(WDTDIS);
Ht1621WrCmd(SYSEN);
Ht1621WrCmd(LCDON);
Ht1621WrAllData(0,Ht1621Tab,16);  /* 清除1621寄存器数据,即清屏 */
}
/***************************************
函数名称:void Ht1621write(uint8 loc,uint8 num)
功能描述:EDC190显示函数
全局变量:无
参数说明:
  loc:显示位置 1~4
  num:要显示的数 0~9
返回说明:无
***************************************/
void Ht1621write(uint8 loc,uint8 number)
{
uint8 shift;
shift=tab[number];
switch(loc)
{
  case 1:
   Ht1621WrOneData(0x00,(shift=_crol_(shift,0)));
   Ht1621WrOneData(0x01,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x02,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x03,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x04,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x05,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x06,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x07,(shift=_crol_(shift,1)));  //DP1
   break;
  case 2:
   Ht1621WrOneData(0x08,(shift=_crol_(shift,0)));
   Ht1621WrOneData(0x09,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x0A,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x0B,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x0C,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x0D,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x0E,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x0F,(shift=_crol_(shift,1)));  //DP2
   break;
  case 3:
   Ht1621WrOneData(0x10,(shift=_crol_(shift,0)));
   Ht1621WrOneData(0x11,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x12,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x13,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x14,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x15,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x16,(shift=_crol_(shift,1)));
   //Ht1621WrOneData(0x17,(shift=_crol_(shift,1))); //colon
   break;
  case 4:
   Ht1621WrOneData(0x18,(shift=_crol_(shift,0)));
   Ht1621WrOneData(0x19,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x1A,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x1B,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x1C,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x1D,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x1E,(shift=_crol_(shift,1)));
   Ht1621WrOneData(0x1F,(shift=_crol_(shift,1)));  //DP3
   break;
}
}
void Display()     /* 液晶显示 */
{
Ht1621write(1,dis[0]);
Ht1621write(2,dis[1]);
Ht1621write(3,dis[2]);
Ht1621write(4,dis[3]);
}
void ExtraDisplay()      /*装入显示数据(年月日星期温度)*/
{
Ht1621WrAllData(0,Ht1621Tab,16); /* 清除1621寄存器数据,即清屏 */

dis[0]=2;    /*year*/
dis[1]=0;
dis[2]=getTimebuf[6]/16;
dis[3]=getTimebuf[6]%16;
Display();
DelayMS(2000);  
dis[0]=getTimebuf[4]/16;  /*month,day*/
dis[1]=getTimebuf[4]%16;
dis[2]=getTimebuf[3]/16;
dis[3]=getTimebuf[3]%16;
Display();
DelayMS(2000);  
dis[0]=0;    /*week*/
dis[1]=0;
dis[2]=0;
dis[3]=getTimebuf[5];
Display();
DelayMS(2000);  
/*temperature*/
gettemp();  
if(negative)    /*如果是零下,显示负号*/
{
  Ht1621WrAllData(0,Ht1621Tab,16); /* 清除1621寄存器数据,即清屏 */
  dis[1]=second;
  dis[2]=third;
  dis[3]=fourth;
  Ht1621WrOneData(0x06,0x08);  /* 第一位写负号 */
  Ht1621write(2,dis[1]);
  Ht1621write(3,dis[2]);
  Ht1621write(4,dis[3]);
  Ht1621WrOneData(0x1F,0x08);  /* DP3 */
  DelayMS(2000);  
}
else      /*否则,显示一位小数*/
{  
  dis[0]=first;
  dis[1]=second;
  dis[2]=third;
  dis[3]=fourth;
  Display();
  Ht1621WrOneData(0x1F,0x08);  /* DP3 */
  DelayMS(2000);  
}
}
void NormalDisplay()       /*正常显示时间(时分)*/
{
dis[0]=(getTimebuf[2])/16;
dis[1]=(getTimebuf[2])%16;
dis[2]=(getTimebuf[1])/16;
dis[3]=(getTimebuf[1])%16;
Display();
}
uint8 BCDtoDEC(uint8 bcd)    /* 压缩BCD码转换为十进制数 */
{
return (bcd/16*10+bcd%16);
}
uint8 DECtoBCD(uint8 dec)    /* 十进制数转换为压缩BCD码 */
{
return (dec/10*16+dec%10);
}

IMAG0128.jpg (95.06 KB )

IMAG0128.jpg

IMAG0127_1.JPG (14.38 KB )

IMAG0127_1.JPG

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

8

帖子

0

粉丝