新闻中心

EEPW首页>嵌入式系统>设计应用> 1602液晶显示DS1302+S51时钟+温度显示

1602液晶显示DS1302+S51时钟+温度显示

作者: 时间:2016-11-10 来源:网络 收藏
/*============================================================

使用1602液晶显示DS1302+S51时钟+温度显示zhaojun 2007/06/29

本文引用地址://m.amcfsurvey.com/article/201611/317334.htm

==============================================================
声明:1.1602驱动程序照搬 明皓 的,非常好用
2. DS1302驱动程序是参考网友修改而来

NS1602R(16*2)模拟口线接线方式
连接线图:
---------------------------------------------------
| LCM-----51  | LCM-----51  | LCM------51 |
| ----------------------------------------------- |
| DB0-----P0.0 | DB4-----P0.4 | RS-------P2.0 |
| DB1-----P0.1 | DB5-----P0.5 | RW-------P2.1 |
| DB2-----P0.2 | DB6-----P0.6 | E--------P2.2 |
| DB3-----P0.3 | DB7-----P0.7 | VLCD接1K电阻到GND |
---------------------------------------------------
DS1302 接线图

Vcc2 CLK I/O /RST

| | | |
---------------
| 8 7 6 5 |
| DS1302 |
| |
| 1 2 3 4 |
---------------
| | | |
VCC1 GND

1. 脚接+5V 2,3. 脚32768HZ晶振 4. 脚接地 5. 脚接S51的P1.2 6. 脚接S51的P1.1 7. 接S51的P1.0
8. 脚接后备电源,可以接老计算机主板上的3.6V电池,也可以通过二级管隔离接一个大容量电解电容
电压在2.5V以上即可维持

按键说明:1. 共三个键,低电平有效
2. P1.4 和 P1.5 同时按:初始化
3. P1.6 端口按键:选择要调整的项目
4. P1.5 端口按键:增加;P1.4端口按键:减少


[注:AT89S51使用12M晶振]
原理图:

源代码:

=================定义与申明=============================================================*/

#include "regx51.h"
#include "string.h"
#include "intrins.h"

#define uchar unsigned char
#define uint unsigned int
typedef unsigned char byte;
typedef unsigned int word;

//*********** 1602引脚定义引脚
#define LCM_RS P2_0 // 数据/命令选择信号
#define LCM_RW P2_1 // 读/写选择信号
#define LCM_E P2_2 // 使能信号

//*********** DS1302 时间显示定义部分
sbit T_CLK=P1^0; //串行时钟输入
sbit T_IO =P1^1; //串行数据端口
sbit T_RST=P1^2; //复位端口

//*********** 18B20温度显示定义部分
sbit DQ=P3^3; //18B20 接P33口

sbit ACC0=ACC^0;
sbit ACC7=ACC^7;

#define LCM_Data P0 //显示数据端口
#define Busy 0x80 //用于检测LCM状态字中的Busy标识

uchar id,timecount; //全局变量
bit flag,sflag; //flag是时钟冒号闪烁标志,sflag是温度负号显示标志
bit sec,min,hour,year,mon,day,weekk; //闪烁标志位

//*********************函数申明
void Disp_line1(void); // 显示屏幕第一行
void Disp_line2(void); // 显示屏幕第二行
void id_case1_key(); // id为1时的下一级选择
void Set(uchar,uchar); // 根据选择调整相应项目
void RTInputByte(uchar); /* 输入 1Byte */
uchar RTOutputByte(void); /* 输出 1Byte */
void W1302(uchar, uchar); // 向DS1302写入一个字节
uchar R1302(uchar); // 从DS1302读出一个字节
void Set1302(uchar * ); // 设置时间

//******* 1602LCD驱动 **********************************************************
void WriteDataLCM(uchar WDLCM); //写数据
void WriteCommandLCM(uchar WCLCM,BuysC); //写指令
uchar ReadStatusLCM(void); //读状态
void LCMInit(void); //LCM初始化
void DisplayOneChar(uchar X, uchar Y, uchar DData); //按指定位置显示一个字符
void DisplayListChar(uchar X, uchar Y, uchar code *DData); //按指定位置显示一串字符
void Delay5Ms(void); //5ms延时
void Delay400Ms(void); //400ms延时
Read_Temperature(char,char);//温度显示
void mychar(void); //显示自定义字符
void adjust_res(char res); //res 分别等于 0x1f, 0x3f, 0x5f 温度读数分辨率分别对应
// 0.5, 0.25, 0.125
//初始化后设置为:07年07月04日 星期3 12点00分00秒
// 12:00:00 XX. C
// 07/07/04 Week.3
unsigned char inittime[7]={0x00,0x00,0x12,0x04,0x07,0x03,0x07};
// 秒 分钟 小时 日 月 星期 年

uchar code week[]={"Week."};//星期显示

//========================= 主函数 =======================================================

/*****************************************************
函 数 名:main()
功 能:主函数
说 明:
入口参数:无
返 回 值:无
*****************************************************/
void main(void)
{
Delay400Ms(); //启动等待,等LCM讲入工作状态
LCMInit(); //LCM初始化
Delay5Ms(); //延时片刻(可不要)
mychar(); //显示自定义字符

TMOD=0x01; //选择定时模式
TH0=(65535-50000)/256;//取定时初值
TL0=(65535-50000)%256;
EA=1; //开中断
TR0=1;
ET0=1;
W1302(0x90,0xa5); //打开充电二级管 一个二级管串联一个2K电阻
W1302(0x8e,0x80); //写保护,禁止写操作
adjust_res(0x5f); //调整18B20的分辨率 0x1f:0.5; 0x3f:0.25; 0x5f:0.125

while(1)
{
if ((P1_4|P1_5)==0) // 初始化 同时按下P1_4、P1_5
{
Delay5Ms(); // 适当延时,消除抖动
if ((P1_4|P1_5)==0) Set1302(inittime); // 显示初始值
}
if (P1_6==0) // 设置和选择项目键
{
Delay5Ms(); // 适当延时,消除抖动
if(P1_6==0){id++;if(id>7) id=0;} // 7个可调节项目循环调节
while(P1_6==0);
}
switch(id) // 跳转到对应的项目进行设置
{
case 0:
sec=0;
Disp_line1(); Disp_line2();
break;
case 1: //调节年
year=1;//设置年闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
case 2: //调节月
year=0;mon=1;//设置月闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
case 3: //调节日
mon=0;day=1;//设置日闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
case 4: //调节星期
day=0;weekk=1;//设置星期闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
case 5: //调节小时
weekk=0;hour=1;//设置小时闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
case 6: //调节分钟
hour=0;min=1;//设置分钟闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
case 7: //调节秒
min=0;sec=1;//设置秒钟闪烁标志位
Disp_line1(); Disp_line2();
id_case1_key();
break;
}
}
}
//================================== 定时中断 =============================================

/*****************************************************
函 数 名:void t0()
功 能:时间工作时,冒号闪烁
说 明:T0中断入口,方式1
入口参数:无
返 回 值:无
*****************************************************/
void t0(void)interrupt1 using 0
{
TH0=(65535-50000)/256; //取50ms定时初值
TL0=(65535-50000)%256;
timecount++;
if(timecount>9)
{
timecount=0; //计时到,从先开始
flag=~flag; //标志位取反
}
}
//==================================== 项目设置 ===========================================

/*****************************************************
函 数 名:void id_case1_key()
功 能:项目设置加减控制
说 明:P1.5和P1.4 <==> +和-
入口参数:无
返 回 值:无
*****************************************************/
//id为1时的下一级选择
void id_case1_key()
{
if (P1_5==0) //P1_5有按下,则数值增加(+)
{
Delay5Ms(); //适当延时,消除抖动
if(P1_5==0) Set(id,0); //根据选择调整相应项目
if(id!=7) while(P1_5==0);
}
if (P1_4==0) //P1_4有按下,则数值减少(-)
{
Delay5Ms(); //适当延时,消除抖动
if(P1_4==0) Set(id,1); //根据选择调整相应项目
if(id!=7) while(P1_4==0);
}
}
/*****************************************************
函 数 名:void Set()
功 能:项目设置
说 明:sel_1=0时,数值加;sel_1=1时,数值减
入口参数:sel和sel_1
返 回 值:无
*****************************************************/
//根据选择调整相应项目并写入DS1302
void Set(uchar sel,uchar sel_1)
{
signed char address,item;
signed char max,mini;
//偶数指令是写,奇数指令是读
//最大值与最小值限定
if(sel==7) {address=0x80; max=00;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=07;mini=1;} //星期
//先从1302中读出数据,把数据转换成十进制进行加减设置;后从先转换回来写入1302中
item=R1302(address+1)/16*10+R1302(address+1)%16;//从1302中读出1字节,再转换成十进制
if (sel_1==0) item++; else item--; //sel_1=0则加,sel_1=1则减
if(item>max) item=mini; //大于最大值,则赋最小值(循环)
if(item
W1302(0x8e,0x00); //允许写操作
W1302(address,item/10*16+item%10);//把调节好的十进制数据转换成十六进制后写入1302中
W1302(0x8e,0x80); //写保护,禁止写操作
}
//=======================================================================================

/*****************************************************
函 数 名:void Disp_line1()
功 能:显示时间和温度 (XX:XX:XX XX.X C)
说 明:第一行显示数据处理
入口参数:无
返 回 值:无
*****************************************************/
//屏幕显示第一行: 时间和温度显示
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()
功 能:显示日期和星期 (XX/XX/XX Week.X)
说 明:第二行显示数据处理
入口参数:无
返 回 值:无
*****************************************************/
// 屏幕显示第二行 日期和星期
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()
功 能:向LCM1602中写入数据
说 明:将形参WDLCM中的数据写入LCM中
入口参数:WDLCM
返 回 值:无
*****************************************************/
//写数据
void WriteDataLCM(uchar WDLCM)
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;//写入数据到LCM
LCM_RS = 1;
LCM_RW = 0;
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
LCM_E = 0; //延时
LCM_E = 1;
}
/*****************************************************
函 数 名:void WriteCommandLCM()
功 能:向LCM1602中写入指令
说 明:向LCM中写入指令;如果BuysC=0时,忽略忙检测,如果BuysC=1时,不忽略忙检测
入口参数:WCLCM,BuysC
返 回 值:无
*****************************************************/
//写指令
void WriteCommandLCM(uchar 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;
}
/*****************************************************
函 数 名:uchar ReadStatusLCM()
功 能:读状态
说 明:判断LCM的工作状态;也可以不用此函数,用一段延时程序代替
入口参数:无
返 回 值:LCM_Data
*****************************************************/
//读状态
uchar ReadStatusLCM(void)
{
LCM_Data = 0xFF; //LCM数据口先置1
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
while (LCM_Data & Busy); //检测忙信号.如果忙,则不执行
return(LCM_Data);//不忙返回读取数据
}
/*****************************************************
函 数 名:void LCMInit()
功 能:初始化LCM1602
说 明:LCM在工作前先要对显示屏初始化,否则模块无法正常工作
入口参数:无
返 回 值:五
*****************************************************/
//LCM初始化
void LCMInit(void)
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); // 三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommandLCM(0x38,0); // 0x38指令表示:8位数据显示模式,俩行多显示
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); // 显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); // 关闭显示
WriteCommandLCM(0x01,1); // 显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0C,1); // 显示开及光标设置
}
/*****************************************************
函 数 名:void DisplayOneChar()
功 能:按指定坐标中写入数据
说 明:X-横坐标,Y-纵坐标
入口参数:X,Y,DData
返 回 值:
*****************************************************/
//按指定位置显示一个字符
void DisplayOneChar(uchar X, uchar Y, uchar DData)
{
Y &= 0x01;
X &= 0x0F; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 0); //这里不检测忙信号,发送地址码
WriteDataLCM(DData);
}
/*****************************************************
函 数 名:void DisplayListChar()
功 能:向指定坐标中写入字符串
说 明:X-横坐标,Y-纵坐标
入口参数:X,Y,*DData
返 回 值:
*****************************************************/
//按指定位置显示一串字符 ***原来的遇到空格0x20就不显示***
void DisplayListChar(uchar X, uchar Y, uchar code *DData)
{
uchar ListLength,j;
ListLength = strlen(DData);//strlen:读取字符串的长度
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (X <= 0xF) //X坐标应小于0xF
{
for(j=0;j {
DisplayOneChar(X, Y, DData[j]); //显示单个字符
X++;//横坐标加1,纵坐标不变
}
}
}
//=================================== 自定义字符 ==========================================

/*****************************************************
函 数 名:void mychar()
功 能:自定义字符--CGRAM
说 明:LCM1602字符库中没有温度符号,自定义温度符号
入口参数:无
返 回 值:无
定义形式:1602中定义CGRAM的形式如下:
---------------------------------------------------------------------------
| CGRAM地址设置 | 自定义的代码 |
| DB7 DB6 | DB5 DB4 DB3 | DB2 DB1 DB0 | DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 |
| 0 1 | 0 0 0 | X X X | 0 0 0 0 * 0 0 0 |
| 0 1 | 0 0 1 | X X X | 0 0 0 0 * 0 0 1 |
| ... | ... | ... | ... ... |
| 0 1 | 1 1 0 | X X X | 0 0 0 0 * 1 1 0 |
| 0 1 | 1 1 1 | X X X | 0 0 0 0 * 1 1 1 |
---------------------------------------------------------------------------
1. 1602共能定义8个5x8字符;
2. CGRAM地址设置: X X X--DB2 DB1 DB0对应写入地址,1~8行;
DB5 DB4 DB3对应自定义字符代码;DB7 DB6为指令码,不可变.
3. 自定义的代码: 高4位DB7 DB6 DB5 DB4为0000时它的低3位DB2 DB1 DB0对应于第1-8个,DB3为无关项。
4. 自定义的代码的DB2 DB1 DB0对应于CGRAM地址的DB5 DB4 DB3。
*****************************************************/
void mychar()
{
//---------自定义字符代码--01H-------------------
WriteCommandLCM(0x48,0); //第1行
WriteDataLCM(0x02);//
WriteCommandLCM(0x49,0); //第2行
WriteDataLCM(0x05);//
WriteCommandLCM(0x4a,0); //第3行 1------**--
WriteDataLCM(0x05);// 2----**--**
WriteCommandLCM(0x4b,0); //第4行 3----**--**
WriteDataLCM(0x02);// 4------**--
WriteCommandLCM(0x4c,0); //第5行 5----------
WriteDataLCM(0x00);// 6----------
WriteCommandLCM(0x4d,0); //第6行 7----------
WriteDataLCM(0x00);// 8----------
WriteCommandLCM(0x4e,0); //第7行
WriteDataLCM(0x00);//
WriteCommandLCM(0x4f,0); //第8行
WriteDataLCM(0x00);//
//-----------------------------------------------
}
//======================================= 延时函数部分 ====================================

/*****************************************************
函 数 名:void Delay5Ms()
功 能:5ms延时
说 明:软件消除按键抖动和适当的延时
入口参数:无
返 回 值:无
*****************************************************/
//5ms延时
void Delay5Ms(void)
{
uint TempCyc = 5552; //放入延时数据
while(TempCyc--);
}
/*****************************************************
函 数 名:void Delay400Ms()
功 能:400ms延时
说 明:
入口参数:无
返 回 值:无
*****************************************************/
//400ms延时
void Delay400Ms(void)
{
uchar TempCycA = 5;
uint TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
//================================== 时钟芯片控制部分 ======================================

/*****************************************************
函 数 名: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
设 计:zhaojun 日 期:2007-06-29
修 改: 日 期:
*****************************************************/
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,写保护?*/
}
//================================= 温度显示控制部分 ===============================================

/*****************************************************
函 数 名:void delay()
功 能:DS18B20延时
说 明:DS18B20时序延时
入口参数:useconds
返 回 值:无
*****************************************************/
//*********** 18B20驱动 **************************
//延时
void delay(word useconds)
{
for(;useconds>0;useconds--);
}
/*****************************************************
函 数 名:byte ow_reset()
功 能:DS18B20复位
说 明:DS18B20使用时先要复位
入口参数:无
返 回 值:presence
*****************************************************/
//复位
byte ow_reset(void)
{
byte presence;
DQ = 0; //拉低总线
delay(29); // 保持 480us
DQ = 1; // 释放总线
delay(3); // 等待回复
presence = DQ; // 读取信号
delay(25); // 等待结束信号
return(presence); // 返回 0:正常 1:不存在
}
/*****************************************************
函 数 名:byte read_byte()
功 能:从 1-wire 总线上读取一个字节
说 明:读总线上的数据有严格的时序
入口参数:
返 回 值:value
*****************************************************/
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);
}
/*****************************************************
函 数 名:void write_byte()
功 能:向 1-WIRE 总线上写一个字节
说 明:写总线上的数据有严格的时序
入口参数:val
返 回 值:无
*****************************************************/
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()
功 能:读取和显示温度
说 明:
入口参数:xx,yy
返 回 值:无
*****************************************************/
Read_Temperature(char xx,char yy)
{
uchar i,tl_temp;
uint x;
uchar ct[8];
union //共用体
{
byte c[2];
int x;
}temp;

ow_reset(); // DS18B20复位
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()
功 能:温度分辨率调整
说 明:此函数可以对温度的显示进行精度调节.
入口参数:res
返 回 值:无
*****************************************************/
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(res); // 温度转换分辨率设置
ow_reset(); // 复位
write_byte(0xcc); // 跳过Rom
write_byte(0x48); // 把暂存器内容写到EPRam中
}
//==========================程序结束======================================================



评论


技术专区

关闭