日程生活中,时间和温度是我们比较关心的两个量。我们通过DS1302和DS18B20这两个简单的传感器,就可以获取我们想知道的两个量。
本次我们通过DS18B20获取当前环境温度,DS1302获取时间,8位数码管显示时间和温度。
1、8位数码管
本次我们选择8位共阴数码管作为显示,如图1-1所示。A-DP是数据显示,1-8是位选。共阴数码管的段码如下,上一行为不带小数点,下一行为带小数点。位选为,当1接的引脚为低电平时,第一个数码管显示。
u8 code SMG_NODOT[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
u8 code SMG_DOT[10]= {0xbf,0x86,0xdb,0xcf,0x6e6,0xed,0xfd,0x87,0xff,0xef};
图1-1
2.DS18B20
DS18B20是一款比较常用的温度传感器,它采取单总线传输数据,接线简单,使用非常方便。但总线对时序要求是比较严格的,我们应关注其底层驱动。底层驱动代码如下(本次借鉴蓝桥杯单片机组的底层代码)。
#include <reg52.h>
#include "INTRINS.H"
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t)
{
while(t --);
}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
3.DS1302
DS1302是一款常用的时间芯片。它的结构也是比较简单的,一个数据引脚,一个时钟引脚,一个数据引脚。底层驱动如下( 本次借鉴蓝桥杯单片机组的底层代码)。
#include "reg52.h"
#include "INTRINS.H"
sbit RST = P1^0;
sbit SCK = P1^1;
sbit SDA = P1^2;
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
4.总体设计,代码如下。通过按键可以切换界面,初始界面为温度界面,显示温度,2位小数(C做标志符)。之后为时分秒界面、年月日界面、星期界面(E做标志符)
/**********************************************************************
Author : sakura
Time : 2023/4/20
***********************************************************************/
#include <reg52.h>
#include "ds1302.h"
#include "onewire.h"
#include "main.h"
void main()
{
DS1302_Init();
while(1)
{
Clock_Read();
Temp_Read();
display();
key_proc();
}
}
//温度读取函数
void Temp_Read()
{
u8 MSB;
u8 LSB;
u16 TEMP;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
TEMP = MSB;
TEMP = (TEMP << 8) | LSB; //数据合成
if((TEMP & 0xf8000) == 0x0000) //正数判断
{
temp = TEMP * 0.0625; //温度值(0.0625为分辨率)
temp_symbol = 0;
}
else
{
temp = (65535-TEMP)*0.0625;
temp_symbol = 1;
}
SMG_temp = temp * 100; //数码管显示2位小数
}
void DS1302_Init()
{
u8 i = 0;
Write_Ds1302_Byte(0x8e,0x00);
for (i = 0;i < 7;i++)
{
Write_Ds1302_Byte(WRITE[i],TIME[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
//时钟读取函数
void Clock_Read()
{
sec = Read_Ds1302_Byte(READ[0]);
min = Read_Ds1302_Byte(READ[1]);
hour = Read_Ds1302_Byte(READ[2]);
day = Read_Ds1302_Byte(READ[3]);
month = Read_Ds1302_Byte(READ[4]);
week = Read_Ds1302_Byte(READ[5]);
year = Read_Ds1302_Byte(READ[6]);
}
void delay(u16 t)
{
while(t--);
}
//数码管初始化函数
void SMG_Init(u8 pos,u8 value)
{
P2 = ~(0x01 << pos);
P0 = value;
delay(600);
P2 = ~(0x01 << pos);
P0 = 0x00;
}
void display()
{
switch(interface)
{
case 0:
{
SMG_Init(0,0x39);
if(temp_symbol == 0)
{
if(SMG_temp >= 1000)
{
SMG_Init(4,SMG_NODOT[SMG_temp/1000]);
}
SMG_Init(5,SMG_DOT[(SMG_temp%1000)/100]);
SMG_Init(6,SMG_NODOT[(SMG_temp%100)/10]);
SMG_Init(7,SMG_NODOT[SMG_temp%10]);
}
else
{
SMG_Init(3,0x40);
if(SMG_temp >= 1000)
{
SMG_Init(4,SMG_NODOT[SMG_temp/1000]);
}
SMG_Init(5,SMG_DOT[(SMG_temp%1000)/100]);
SMG_Init(6,SMG_NODOT[(SMG_temp%100)/10]);
SMG_Init(7,SMG_NODOT[SMG_temp%10]);
}
break;
}
case 1:
{
SMG_Init(0,SMG_NODOT[hour >> 4]);
SMG_Init(1,SMG_NODOT[hour & 0x0f]);
SMG_Init(2,0x40);
SMG_Init(3,SMG_NODOT[min >> 4]);
SMG_Init(4,SMG_NODOT[min & 0x0f]);
SMG_Init(5,0x40);
SMG_Init(6,SMG_NODOT[(sec >> 4) & 0x07]);
SMG_Init(7,SMG_NODOT[sec & 0x0f]);
break;
}
case 2:
{
SMG_Init(0,SMG_NODOT[year >> 4]);
SMG_Init(1,SMG_NODOT[year & 0x0f]);
SMG_Init(2,0x40);
SMG_Init(3,SMG_NODOT[month >> 4]);
SMG_Init(4,SMG_NODOT[month & 0x0f]);
SMG_Init(5,0x40);
SMG_Init(6,SMG_NODOT[day >> 4]);
SMG_Init(7,SMG_NODOT[day & 0x0f]);
break;
}
case 3:
{
SMG_Init(0,0x79);
SMG_Init(7,SMG_NODOT[week & 0x0f]);
break;
}
}
}
void key_proc()
{
u8 time_object = 0;
if(P32 == 0)
{
delay(600);
if(P32 == 0)
{
while(P32 == 0);
interface ++;
if(interface == 4)
interface = 0;
}
}
}
5.其余头文件
(1)ds1302.h
#ifndef __DS1302_H
#define __DS1302_H
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
#endif
(2)onewire.h
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
unsigned char rd_temperature(void);
bit init_ds18b20(void);
unsigned char Read_DS18B20(void);
void Write_DS18B20(unsigned char dat);
void Delay_OneWire(unsigned int t);
#endif
(3)main.h
#include <reg52.h>
#define u8 unsigned char
#define u16 unsigned int
sbit P32 = P3^2;
//数码管 0 - 9,NODOT表示无小数点,DOT表示有小数点
u8 code SMG_NODOT[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
u8 code SMG_DOT[10]= {0xbf,0x86,0xdb,0xcf,0x6e6,0xed,0xfd,0x87,0xff,0xef};
//ds1302 秒、分、时、日、月、周、年
u8 code READ[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
u8 code WRITE[7] ={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
u8 TIME[7] = {0x45,0x59,0x23,0x03,0x01,0x04,0x20};
float temp = 0; //实际温度值
u16 SMG_temp = 0; //数码管显示值
u8 sec = 0; //秒
u8 min = 0; //分
u8 hour = 0; //时
u8 week = 0; //周
u8 day = 0; //日
u8 month = 0; //月
u8 year = 0; //年
u8 interface = 0; //界面切换
bit temp_symbol = 0; //温度正负标志
//函数声明
void display();
void Temp_Read();
void DS1302_Init();
void Clock_Read();
void delay(u16 t);
void SMG_Init(u8 pos,u8 value);
void key_proc();
6.仿真测试
链接:https://pan.baidu.com/s/1hCZCc-i6afVDqIBIdB_b9Q?pwd=96pn
提取码:96pn