模拟实时测温,1602显示,一个I/O口上挂两个温感DS18B20,实现于仿真上PROTEUS
2017-01-08 09:27
465 查看
DS1302 与微处理器进行数据交换时,首先由微处理器向电路发送命令字节,命令字节最高位Write
Protect(D7)必须为逻辑1,如果D7=0,则禁止写DS1302,即写保护;D6=0,指定时钟数据,D6=1,指定RAM数据;D5~D1指定输入或输出的特定寄存器;最低位LSB(D0)为逻辑0,指定写操作(输入),
D0=1,指定读操作(输出)。
在DS1302的时钟日历或RAM进行数据传送时,DS1302必须首先发送命令字节。若进行单字节传送,8位命令字节传送结束之后,在下2个SCLK周期的上升沿输入数据字节,或在下8个SCLK周期的下降沿输出数据字节。
DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;再一类为突发方式下的RAM寄存器,在此方式下可一次性读、写所有的RAM的31个字节。
DS18B20数字温度计是DALLAS公司生产的1-Wire,即单总线器件,具有线路简单,体积小的特点。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计,十分方便。
1、DS18B20产品的特点
(1)、只要求一个端口即可实现通信。
(2)、在DS18B20中的每个器件上都有独一无二的序列号。
(3)、实际应用中不需要外部任何元器件即可实现测温。
(4)、测量温度范围在-55。C到+125。C之间。
(5)、数字温度计的分辨率用户可以从9位到12位选择。
(6)、内部有温度上、下限告警设置。
2、DS18B20的使用方法
由于DS18B20采用的是1-Wire总线协议方式,即在一根数据线实现数据的双向传输,而对AT89S51单片机来说,硬件上并不支持单总线协议,因此,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。
由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。该协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。
1) DS18B20的读时序
对于DS18B20的读时序分为读0时序和读1时序两个过程。
对于DS18B20的读时隙是从主机把单总线拉低之后,在15秒之内就得释放单总线,以让DS18B20把数据传输到单总线上。DS18B20在完成一个读时序过程,至少需要60us才能完成。
2)DS18B20的写时序
对于DS18B20的写时序仍然分为写0时序和写1时序两个过程。
对于DS18B20写0时序和写1时序的要求不同,当要写0时序时,单总线要被拉低至少60us,保证DS18B20能够在15us到45us之间能够正确地采样IO总线上的“0”电平,当要写1时序时,单总线被拉低之后,在15us之内就得释放单总线。
源代码:
主函数:
#include <REG51.H>
#include <intrins.h>
#include "bianliang.h"
#include "lcd1602.h"
#include "ds18b20.h"
#include "ds1302.h"
#define Lcd_Data 1
#define uchar unsigned char
#define uint unsigned int
void show_time(unsigned int x,unsigned int y) //显示时间子函数
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
TimeToStr(&CurrentTime);
1a33c
//时间数据转换液晶字符
GotoXY(x,y);
Print(CurrentTime.TimeString); //显示时间
Delay1ms(50); //扫描延时
}
void show_date(unsigned int x,unsigned int y)
//显示日期子函数
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
DateToStr(&CurrentTime); //日期数据转换液晶字符
GotoXY(x,y);
Print(CurrentTime.DateString); //显示日期
Delay1ms(50); //扫描延时
}
void show_temp(unsigned int x,unsigned int y) //显示温度子函数
{
ReadTemp(); //开启温度采集程序
temp_to_str(); //温度数据转换成液晶字符
GotoXY(x,y); //液晶字符显示位置
Print(TempBuffer); //显示温度
Delay1ms(50); //扫描延时
}
void show_week(unsigned int x,unsigned int y)
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
DateToStr(&CurrentTime); //日期数据转换液晶字符
GotoXY(x,y);
Print(week_value); //显示星期
GotoXY(x-4,y);
Print("Week");//在液晶上显示 字母 week
Delay1ms(50); //扫描延时
}
void main()
{
//unsigned char i;
flag=1; //时钟停止标志
LCD_Initial(); //液晶初始化
init_ds18();
init_ds18(); //时钟芯片初始化
up_flag=0;
down_flag=0;
while(1)
{
if(done==1)
{
LCD_clear();
Delay1ms(50);
}
else
{
show_date(0,0); //显示日期
show_week(15,0); //显示星期
show_time(0,1); //显示时间
show_temp(9,1); //显示温度
flag=0;
}
}
//GotoXY(0,0);
// read_rom();
//for(i = 0;i<8;i++)
//{
// write_data(0x30+ds18b20_num1[i]/16);
//delay_50us1(1);
//write_data(0x30+ds18b20_num1[i]%16);
//delay_50us1(1);
//}
//write_data(0xc0);
//write_data('c');
}
BIANLIANG.H
#define uint unsigned int
#define uchar unsigned char
sbit DS1302_CLK = P1^2; //实时时钟时钟线引脚
sbit DS1302_IO = P1^1; //实时时钟数据线引脚
sbit DS1302_RST = P1^3; //实时时钟复位线引脚
sbit DQ = P1^0; //温度传送数据IO口
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数
char done,count,temp,flag,up_flag,down_flag;
uchar temp_value; //温度值
uchar temp_value1; //温度值
uchar TempBuffer[17],week_value[2];
uchar ds18b20_num1[8]={0xb9,0x00,0x00,0x00,0xb8,0xc5,0x31,0x28};
uchar ds18b20_num2[8]={0x8e,0x00,0x00,0x00,0xb8,0xc5,0x30,0x28};
sbit LcdRs= P3^7;
sbit LcdRw= P3^6;
sbit LcdEn = P3^5;
sfr DBPort
= 0xA0;//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
void time_set(void);
void set_date(void);
LCD1602.H
#ifndef LCD_CHAR_1602_2005_4_9
#define LCD_CHAR_1602_2005_4_9
#include <intrins.h>
unsigned char LCD_Wait(void)
{
LcdRs=0;
LcdRw=1;_nop_();
LcdEn=1;_nop_();
//while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环,
//可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80
//实际硬件时打开此语句
LcdEn=0;
return DBPort;
}
#define LCD_COMMAND0 // Command
#define LCD_DATA1 // Data
#define LCD_CLEAR_SCREEN0x01 // 清屏
#define LCD_HOMING 0x02 // 光标返回原点
void LCD_Write(bit style, unsigned char input)
{
LcdEn=0;
LcdRs=style;
LcdRw=0;_nop_();
DBPort=input;_nop_();//注意顺序
LcdEn=1;_nop_();//注意顺序
LcdEn=0;_nop_();
LCD_Wait();
}
#define LCD_SHOW0x04 //显示开
#define LCD_HIDE0x00 //显示关
#define LCD_CURSOR0x02
//显示光标
#define LCD_NO_CURSOR0x00 //无光标
#define LCD_FLASH0x01 //光标闪动
#define LCD_NO_FLASH0x00 //光标不闪动
void LCD_SetDisplay(unsigned char DisplayMode)
{
LCD_Write(LCD_COMMAND, 0x08|DisplayMode);
}
#define LCD_AC_UP0x02
#define LCD_AC_DOWN0x00 // default
#define LCD_MOVE0x01 // 画面可平移
#define LCD_NO_MOVE0x00 //default
void LCD_SetInput(unsigned char InputMode)
{
LCD_Write(LCD_COMMAND, 0x04|InputMode);
}
void LCD_Initial()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵
LCD_Write(LCD_COMMAND,0x38);
LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动
}
void LCD_clear()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
}
void GotoXY(unsigned char x, unsigned char y)
{
if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
void Print(unsigned char *str)
{
while(*str!='\0')
{
LCD_Write(LCD_DATA,*str);
str++;
}
}
#endif
DS1302.H
#define DS1302_WEEK0x8A
#define DS1302_DAY0x86
#define DS1302_MONTH0x88
#define DS1302_YEAR0x8C
void DS1302InputByte(unsigned char d)
//实时时钟写入一字节(内部函数)
{
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;
}
}
unsigned char DS1302OutputByte(void)
//实时时钟读取一字节(内部函数)
{
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;
}
return(ACC);
}
void Write1302(unsigned char ucAddr, unsigned char ucDa)//ucAddr: DS1302地址, ucData: 要写的数据
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
}
unsigned char Read1302(unsigned char ucAddr)//读取DS1302某地址的数据
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);
}
void DS1302_GetTime(SYSTEMTIME *Time) //获取时钟芯片的时钟数据到自定义的结构型数组
{
unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
}
void DateToStr(SYSTEMTIME *Time) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{ if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22
{
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] = Time->Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '\0';
Time->DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符
}
void TimeToStr(SYSTEMTIME *Time) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
{ 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->DateString[8] = '\0';
}
void Initial_DS1302(void) //时钟芯片初始化
{
unsigned char Second=Read1302(DS1302_SECOND);
if(Second&0x80) //判断时钟芯片是否关闭
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,0x10); //以下写入初始化时间 日期:07/07/25.星期: 3. 时间: 23:59:55
Write1302(0x88,0x10); //月
Write1302(0x86,0x20); //年
Write1302(0x8a,0x03); //周
Write1302(0x84,0x23); //时
Write1302(0x82,0x59); //分
Write1302(0x80,0x55); //秒
Write1302(0x8e,0x80); //禁止写入
}
}
DS18B20.H
void WriteOneChar(uchar dat);
unsigned char ReadOneChar(void);
void delay_18B20(unsigned int i)
{
while(i--);
}
void delay_50us1(uint t) //延时50us
{
uchar j;
for(;t>0;t--)
for(j = 15;j>0;j--);
}
void delay_5us1(uchar x) //延时5us子函数
{
while(--x);
}
void delay_1ms(uchar time) //时基1ms延时调用子函数
{
uchar a,b;
for(;time>0;time--)
{
for(a=195;a>0;a--)
for(b = 1;b>0;b--);
}
}
void init_ds18() //ds18b20初始化
{
DQ = 0; //拉低总线480--960us,
delay_5us1(250);
DQ = 1; //释放总线60--120us,
delay_5us1(30);
if(DQ == 0) //总线响应低电平,初始化成功
{
delay_5us1(200);
DQ = 1; //延时480us内,释放总线
WriteOneChar(0xcc); //初始化
DQ = 0; //拉低总线480--960us
delay_5us1(255);
DQ = 1; //释放总线,且延时480us以内
delay_5us1(240);
DQ = 1; //释放总线
}
}
void write_com(uchar com) //ds1302写入命令
{
LcdRs = 0;
LcdRw = 0;
LcdEn = 0;
P2 = com;
delay_50us1(10);
LcdEn = 1;
delay_50us1(10);
LcdEn = 0;
}
//void write_data(uchar dat) //ds1302写数据命令
//{
// LcdRs = 1;
//LcdRw = 0;
//LcdEn = 0;
//P2 = dat;
//delay_50us1(10);
//LcdEn = 1;
//delay_50us1(10);
//LcdEn = 0;
//}
void read_rom() //读ds18b20序列号
{
uchar i;
init_ds18();
delay_50us1(2);
WriteOneChar(0x33);
for(i = 0;i<8;i++)
{
ds18b20_num1[i] = ReadOneChar();
}
}
//void Init_DS18B20(void)
//{
// unsigned char x=0;
// delay_18B20(60);
// DQ = 1; //DQ复位
// delay_18B20(8); //稍做延时
// DQ = 0; //单片机将DQ拉低
// delay_18B20(80); //精确延时 大于 480us
// DQ = 1; //拉高总线
// delay_18B20(14);
// x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
// delay_18B20(20);
//}
unsigned char ReadOneChar(void)
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
dat>>=1;
DQ = 0; // 给脉冲信号
_nop_();
_nop_();
DQ = 1; // 给脉冲信号
_nop_();
_nop_();
if(DQ)
dat|=0x80;
delay_18B20(15);
DQ=1;
_nop_();
}
return(dat);
}
void WriteOneChar(uchar dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
_nop_();
_nop_();
DQ = dat&0x01;
delay_18B20(15);
DQ = 1;
_nop_();
dat>>=1;
}
}
bit match_rom(uchar *rom)
{
uchar i;
init_ds18();
WriteOneChar(0x55);
for(i=8;i>0;i--)
{
WriteOneChar(*(rom+i-1));;
}
return 1;
}
void get1_ds18b20(void)
{
unsigned char a=0;
unsigned char b=0,i;
match_rom(ds18b20_num1);
WriteOneChar(0x44);
DQ = 1;
delay_1ms(255);
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(30);
if(DQ == 0)
{
delay_5us1(200);
DQ = 1;
match_rom(ds18b20_num1);
WriteOneChar(0xbe); //读
delay_18B20(100);
a=ReadOneChar(); //读取温度值低位
b=ReadOneChar(); //读取温度值高位
temp_value1=b<<4;
temp_value1+=(a&0xf0)>>4;
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(240);
DQ = 1;
}
}
void get2_ds18b20(void)
{
unsigned char a=0;
unsigned char b=0,i;
match_rom(ds18b20_num2);
WriteOneChar(0x44);
DQ = 1;
delay_1ms(255);
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(30);
if(DQ == 0)
{
delay_5us1(200);
DQ = 1;
match_rom(ds18b20_num2);
WriteOneChar(0xbe); //读
a=ReadOneChar(); //读取温度值低位
b=ReadOneChar(); //读取温度值高位
temp_value=b<<4;
temp_value+=(a&0xf0)>>4;
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(240);
DQ = 1;
}
}
void ReadTemp(void)
{
get1_ds18b20();
get2_ds18b20();
}
void temp_to_str() //温度数据转换成液晶字符显示
{
TempBuffer[0]=temp_value/10+'0'; //十位
TempBuffer[1]=temp_value%10+'0'; //个位;
TempBuffer[2]=',';
TempBuffer[3]=temp_value1/10+'0'; //十位
TempBuffer[4]=temp_value1%10+'0'; //个位
TempBuffer[5]=0xdf; //温度符号
TempBuffer[6]='C';
TempBuffer[7]='\0';
}
void Delay1ms(unsigned int count)
{
unsigned int i,j;
for(i=0;i<count;i++)
for(j=0;j<120;j++);
}
void mdelay(uint delay)
{uint i;
for(;delay>0;delay--)
{for(i=0;i<62;i++) //1ms延时.
{;}
}
}
电路连线图:
Protect(D7)必须为逻辑1,如果D7=0,则禁止写DS1302,即写保护;D6=0,指定时钟数据,D6=1,指定RAM数据;D5~D1指定输入或输出的特定寄存器;最低位LSB(D0)为逻辑0,指定写操作(输入),
D0=1,指定读操作(输出)。
在DS1302的时钟日历或RAM进行数据传送时,DS1302必须首先发送命令字节。若进行单字节传送,8位命令字节传送结束之后,在下2个SCLK周期的上升沿输入数据字节,或在下8个SCLK周期的下降沿输出数据字节。
DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;再一类为突发方式下的RAM寄存器,在此方式下可一次性读、写所有的RAM的31个字节。
DS18B20数字温度计是DALLAS公司生产的1-Wire,即单总线器件,具有线路简单,体积小的特点。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计,十分方便。
1、DS18B20产品的特点
(1)、只要求一个端口即可实现通信。
(2)、在DS18B20中的每个器件上都有独一无二的序列号。
(3)、实际应用中不需要外部任何元器件即可实现测温。
(4)、测量温度范围在-55。C到+125。C之间。
(5)、数字温度计的分辨率用户可以从9位到12位选择。
(6)、内部有温度上、下限告警设置。
2、DS18B20的使用方法
由于DS18B20采用的是1-Wire总线协议方式,即在一根数据线实现数据的双向传输,而对AT89S51单片机来说,硬件上并不支持单总线协议,因此,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。
由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。该协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。
1) DS18B20的读时序
对于DS18B20的读时序分为读0时序和读1时序两个过程。
对于DS18B20的读时隙是从主机把单总线拉低之后,在15秒之内就得释放单总线,以让DS18B20把数据传输到单总线上。DS18B20在完成一个读时序过程,至少需要60us才能完成。
2)DS18B20的写时序
对于DS18B20的写时序仍然分为写0时序和写1时序两个过程。
对于DS18B20写0时序和写1时序的要求不同,当要写0时序时,单总线要被拉低至少60us,保证DS18B20能够在15us到45us之间能够正确地采样IO总线上的“0”电平,当要写1时序时,单总线被拉低之后,在15us之内就得释放单总线。
源代码:
主函数:
#include <REG51.H>
#include <intrins.h>
#include "bianliang.h"
#include "lcd1602.h"
#include "ds18b20.h"
#include "ds1302.h"
#define Lcd_Data 1
#define uchar unsigned char
#define uint unsigned int
void show_time(unsigned int x,unsigned int y) //显示时间子函数
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
TimeToStr(&CurrentTime);
1a33c
//时间数据转换液晶字符
GotoXY(x,y);
Print(CurrentTime.TimeString); //显示时间
Delay1ms(50); //扫描延时
}
void show_date(unsigned int x,unsigned int y)
//显示日期子函数
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
DateToStr(&CurrentTime); //日期数据转换液晶字符
GotoXY(x,y);
Print(CurrentTime.DateString); //显示日期
Delay1ms(50); //扫描延时
}
void show_temp(unsigned int x,unsigned int y) //显示温度子函数
{
ReadTemp(); //开启温度采集程序
temp_to_str(); //温度数据转换成液晶字符
GotoXY(x,y); //液晶字符显示位置
Print(TempBuffer); //显示温度
Delay1ms(50); //扫描延时
}
void show_week(unsigned int x,unsigned int y)
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
DateToStr(&CurrentTime); //日期数据转换液晶字符
GotoXY(x,y);
Print(week_value); //显示星期
GotoXY(x-4,y);
Print("Week");//在液晶上显示 字母 week
Delay1ms(50); //扫描延时
}
void main()
{
//unsigned char i;
flag=1; //时钟停止标志
LCD_Initial(); //液晶初始化
init_ds18();
init_ds18(); //时钟芯片初始化
up_flag=0;
down_flag=0;
while(1)
{
if(done==1)
{
LCD_clear();
Delay1ms(50);
}
else
{
show_date(0,0); //显示日期
show_week(15,0); //显示星期
show_time(0,1); //显示时间
show_temp(9,1); //显示温度
flag=0;
}
}
//GotoXY(0,0);
// read_rom();
//for(i = 0;i<8;i++)
//{
// write_data(0x30+ds18b20_num1[i]/16);
//delay_50us1(1);
//write_data(0x30+ds18b20_num1[i]%16);
//delay_50us1(1);
//}
//write_data(0xc0);
//write_data('c');
}
BIANLIANG.H
#define uint unsigned int
#define uchar unsigned char
sbit DS1302_CLK = P1^2; //实时时钟时钟线引脚
sbit DS1302_IO = P1^1; //实时时钟数据线引脚
sbit DS1302_RST = P1^3; //实时时钟复位线引脚
sbit DQ = P1^0; //温度传送数据IO口
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数
char done,count,temp,flag,up_flag,down_flag;
uchar temp_value; //温度值
uchar temp_value1; //温度值
uchar TempBuffer[17],week_value[2];
uchar ds18b20_num1[8]={0xb9,0x00,0x00,0x00,0xb8,0xc5,0x31,0x28};
uchar ds18b20_num2[8]={0x8e,0x00,0x00,0x00,0xb8,0xc5,0x30,0x28};
sbit LcdRs= P3^7;
sbit LcdRw= P3^6;
sbit LcdEn = P3^5;
sfr DBPort
= 0xA0;//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
void time_set(void);
void set_date(void);
LCD1602.H
#ifndef LCD_CHAR_1602_2005_4_9
#define LCD_CHAR_1602_2005_4_9
#include <intrins.h>
unsigned char LCD_Wait(void)
{
LcdRs=0;
LcdRw=1;_nop_();
LcdEn=1;_nop_();
//while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环,
//可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80
//实际硬件时打开此语句
LcdEn=0;
return DBPort;
}
#define LCD_COMMAND0 // Command
#define LCD_DATA1 // Data
#define LCD_CLEAR_SCREEN0x01 // 清屏
#define LCD_HOMING 0x02 // 光标返回原点
void LCD_Write(bit style, unsigned char input)
{
LcdEn=0;
LcdRs=style;
LcdRw=0;_nop_();
DBPort=input;_nop_();//注意顺序
LcdEn=1;_nop_();//注意顺序
LcdEn=0;_nop_();
LCD_Wait();
}
#define LCD_SHOW0x04 //显示开
#define LCD_HIDE0x00 //显示关
#define LCD_CURSOR0x02
//显示光标
#define LCD_NO_CURSOR0x00 //无光标
#define LCD_FLASH0x01 //光标闪动
#define LCD_NO_FLASH0x00 //光标不闪动
void LCD_SetDisplay(unsigned char DisplayMode)
{
LCD_Write(LCD_COMMAND, 0x08|DisplayMode);
}
#define LCD_AC_UP0x02
#define LCD_AC_DOWN0x00 // default
#define LCD_MOVE0x01 // 画面可平移
#define LCD_NO_MOVE0x00 //default
void LCD_SetInput(unsigned char InputMode)
{
LCD_Write(LCD_COMMAND, 0x04|InputMode);
}
void LCD_Initial()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵
LCD_Write(LCD_COMMAND,0x38);
LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动
}
void LCD_clear()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
}
void GotoXY(unsigned char x, unsigned char y)
{
if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
void Print(unsigned char *str)
{
while(*str!='\0')
{
LCD_Write(LCD_DATA,*str);
str++;
}
}
#endif
DS1302.H
#define DS1302_WEEK0x8A
#define DS1302_DAY0x86
#define DS1302_MONTH0x88
#define DS1302_YEAR0x8C
void DS1302InputByte(unsigned char d)
//实时时钟写入一字节(内部函数)
{
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;
}
}
unsigned char DS1302OutputByte(void)
//实时时钟读取一字节(内部函数)
{
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;
}
return(ACC);
}
void Write1302(unsigned char ucAddr, unsigned char ucDa)//ucAddr: DS1302地址, ucData: 要写的数据
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
}
unsigned char Read1302(unsigned char ucAddr)//读取DS1302某地址的数据
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);
}
void DS1302_GetTime(SYSTEMTIME *Time) //获取时钟芯片的时钟数据到自定义的结构型数组
{
unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
}
void DateToStr(SYSTEMTIME *Time) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{ if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22
{
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] = Time->Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '\0';
Time->DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符
}
void TimeToStr(SYSTEMTIME *Time) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
{ 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->DateString[8] = '\0';
}
void Initial_DS1302(void) //时钟芯片初始化
{
unsigned char Second=Read1302(DS1302_SECOND);
if(Second&0x80) //判断时钟芯片是否关闭
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,0x10); //以下写入初始化时间 日期:07/07/25.星期: 3. 时间: 23:59:55
Write1302(0x88,0x10); //月
Write1302(0x86,0x20); //年
Write1302(0x8a,0x03); //周
Write1302(0x84,0x23); //时
Write1302(0x82,0x59); //分
Write1302(0x80,0x55); //秒
Write1302(0x8e,0x80); //禁止写入
}
}
DS18B20.H
void WriteOneChar(uchar dat);
unsigned char ReadOneChar(void);
void delay_18B20(unsigned int i)
{
while(i--);
}
void delay_50us1(uint t) //延时50us
{
uchar j;
for(;t>0;t--)
for(j = 15;j>0;j--);
}
void delay_5us1(uchar x) //延时5us子函数
{
while(--x);
}
void delay_1ms(uchar time) //时基1ms延时调用子函数
{
uchar a,b;
for(;time>0;time--)
{
for(a=195;a>0;a--)
for(b = 1;b>0;b--);
}
}
void init_ds18() //ds18b20初始化
{
DQ = 0; //拉低总线480--960us,
delay_5us1(250);
DQ = 1; //释放总线60--120us,
delay_5us1(30);
if(DQ == 0) //总线响应低电平,初始化成功
{
delay_5us1(200);
DQ = 1; //延时480us内,释放总线
WriteOneChar(0xcc); //初始化
DQ = 0; //拉低总线480--960us
delay_5us1(255);
DQ = 1; //释放总线,且延时480us以内
delay_5us1(240);
DQ = 1; //释放总线
}
}
void write_com(uchar com) //ds1302写入命令
{
LcdRs = 0;
LcdRw = 0;
LcdEn = 0;
P2 = com;
delay_50us1(10);
LcdEn = 1;
delay_50us1(10);
LcdEn = 0;
}
//void write_data(uchar dat) //ds1302写数据命令
//{
// LcdRs = 1;
//LcdRw = 0;
//LcdEn = 0;
//P2 = dat;
//delay_50us1(10);
//LcdEn = 1;
//delay_50us1(10);
//LcdEn = 0;
//}
void read_rom() //读ds18b20序列号
{
uchar i;
init_ds18();
delay_50us1(2);
WriteOneChar(0x33);
for(i = 0;i<8;i++)
{
ds18b20_num1[i] = ReadOneChar();
}
}
//void Init_DS18B20(void)
//{
// unsigned char x=0;
// delay_18B20(60);
// DQ = 1; //DQ复位
// delay_18B20(8); //稍做延时
// DQ = 0; //单片机将DQ拉低
// delay_18B20(80); //精确延时 大于 480us
// DQ = 1; //拉高总线
// delay_18B20(14);
// x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
// delay_18B20(20);
//}
unsigned char ReadOneChar(void)
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
dat>>=1;
DQ = 0; // 给脉冲信号
_nop_();
_nop_();
DQ = 1; // 给脉冲信号
_nop_();
_nop_();
if(DQ)
dat|=0x80;
delay_18B20(15);
DQ=1;
_nop_();
}
return(dat);
}
void WriteOneChar(uchar dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
_nop_();
_nop_();
DQ = dat&0x01;
delay_18B20(15);
DQ = 1;
_nop_();
dat>>=1;
}
}
bit match_rom(uchar *rom)
{
uchar i;
init_ds18();
WriteOneChar(0x55);
for(i=8;i>0;i--)
{
WriteOneChar(*(rom+i-1));;
}
return 1;
}
void get1_ds18b20(void)
{
unsigned char a=0;
unsigned char b=0,i;
match_rom(ds18b20_num1);
WriteOneChar(0x44);
DQ = 1;
delay_1ms(255);
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(30);
if(DQ == 0)
{
delay_5us1(200);
DQ = 1;
match_rom(ds18b20_num1);
WriteOneChar(0xbe); //读
delay_18B20(100);
a=ReadOneChar(); //读取温度值低位
b=ReadOneChar(); //读取温度值高位
temp_value1=b<<4;
temp_value1+=(a&0xf0)>>4;
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(240);
DQ = 1;
}
}
void get2_ds18b20(void)
{
unsigned char a=0;
unsigned char b=0,i;
match_rom(ds18b20_num2);
WriteOneChar(0x44);
DQ = 1;
delay_1ms(255);
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(30);
if(DQ == 0)
{
delay_5us1(200);
DQ = 1;
match_rom(ds18b20_num2);
WriteOneChar(0xbe); //读
a=ReadOneChar(); //读取温度值低位
b=ReadOneChar(); //读取温度值高位
temp_value=b<<4;
temp_value+=(a&0xf0)>>4;
DQ = 0;
delay_5us1(255);
DQ = 1;
delay_5us1(240);
DQ = 1;
}
}
void ReadTemp(void)
{
get1_ds18b20();
get2_ds18b20();
}
void temp_to_str() //温度数据转换成液晶字符显示
{
TempBuffer[0]=temp_value/10+'0'; //十位
TempBuffer[1]=temp_value%10+'0'; //个位;
TempBuffer[2]=',';
TempBuffer[3]=temp_value1/10+'0'; //十位
TempBuffer[4]=temp_value1%10+'0'; //个位
TempBuffer[5]=0xdf; //温度符号
TempBuffer[6]='C';
TempBuffer[7]='\0';
}
void Delay1ms(unsigned int count)
{
unsigned int i,j;
for(i=0;i<count;i++)
for(j=0;j<120;j++);
}
void mdelay(uint delay)
{uint i;
for(;delay>0;delay--)
{for(i=0;i<62;i++) //1ms延时.
{;}
}
}
电路连线图:
相关文章推荐
- ATMEGA16读取DS18B20温度,1602显示,并用proteus仿真,成功。
- DS18B20多点测温(读序列,匹配序列,51 C程序,1602显示)
- C#--第11周实验--任务3--设计一个窗体,窗体上有两个文本框,一个按钮,2个单选按钮--实现单击按钮后,根据单选按钮,将对应文本框中内容显示在标签。
- 基于proteus的51单片机仿真实例七十八、使用BCD译码器实现8位数码管显示应用实例
- 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示"××年还剩××天××时××分××秒"
- 实现一个模拟CMD.exe命令编辑模式执行与显示的Delphi控件
- 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示"××年还剩××天××时××分××秒"
- 窗体上有两个文本框:一个文本框中最多输入字符6个;一个文本框中输入任何内容都显示*号。再添加一个按钮、2个单选按钮。实现单击按钮后,根据单选按钮,将对应文本框中内容显示在标签
- 用两个队列模拟实现一个栈的过程
- 实现一个模拟动画显示控件
- c++实现两个堆栈模拟一个队列
- Delphi组件开发教程指南(6)实现一个模拟动画显示控件
- 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示“××年还剩××天××时××分××秒”
- 实现一个模拟CMD.exe命令编辑模式执行与显示的Delphi控件
- 两个单选按钮(一个是,一个否 ),一个div层,实现点击隐藏,显示div
- 实现一个计算器,界面包括10个数字按钮(0至9)和四个运算符(加减乘除)按钮,以及等号和清空两个辅助按钮,还有一个用于显示输入输出的文本框。
- 汇编语言学习——通过两个开关实现一个数码管的数字显示
- 两个栈模拟一个队列和两个队列模拟一个栈(c++实现)
- 剑指offer面试题java实现之题7:用两个栈模拟一个队列的入队和出队操作
- 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示“××年还剩××天××时××分××秒”