标题:
51单片机+DS1302+DS18B20制作(程序开源)
[打印本页]
作者:
xiaoyuxinke
时间:
2022-5-8 14:01
标题:
51单片机+DS1302+DS18B20制作(程序开源)
由于本程序使用了STC12C5A60S2单片机,最好不要使用太高的晶振,不然DS18B20延时部分太难调试(搞不好会显示00.0度),一般12M以下相对好些.
制作出来的实物图如下:
51hei图片_20220508140028.jpg
(168.74 KB, 下载次数: 64)
下载附件
2022-5-8 14:01 上传
单片机源程序如下:
//******************************************************************************
//LCD12864行地址地址定义 *
//第一行地址:80H 81H 82H 83H 84H 85H 86H 87H *
//第二行地址:90H 91H 92H 93H 94H 95H 96H 97H *
//第三行地址:88H 89H 8AH 8BH 8CH 8DH 8EH 8FH *
//第四行地址:98H 99H 9AH 9BH 9CH 9DH 9EH 9FH *
//程序说明:本程序为带有字库汉字显示的12864液晶显示器源程序
//****************************************************************
//#include<stc12c5a60s2.h>表示头文件在keil5软件安装目录(根目录)下,编译时软件到安装目录找头文件。
//#include"stc12c5a60s2.h"表示头文件在当前的工程目录下,如果找不到头文件再到安装目录的根目录找。
//****************************************************************
#include<stc12c5a60s2.h> //载入STC12C5A60S2头文件
#include<intrins.h> //用到这个头文件表示你可以在程序中调用单片机中库文件中的函数
#define uchar unsigned char //用Uchar代替unsigned char
#define uint unsigned int //用uint代替unsigned int
//****************************************************************
//定义LCD12864的数据线和相关函数
//****************************************************************
sbit LCD_RS=P2^7; //模式位,低电平输入指令,高电平输入数据
sbit LCD_RW=P2^6; //读写位,低电平读,高电平写
sbit LCD_E =P2^5; //LCD12864使能位,低电平无效,高电平使能
#define Busy 0x80
#define LCD_Data P0 //LCD12864的8位数据总线,单片机的P0端口
void WriteDataLCD(unsigned char WDLCD); //给LCD12864写数据
void WriteCommandLCD(unsigned char WCLCD); //给LCD12864写指令
void LCDInit(void); //LCD12864初始化
void LCDClear(void); //LCD12864清屏
void CheckBusy(void); //忙检测
void LCDSendWord(unsigned char *p); //向LCD发送一个字符串
void LCDTestWord(bit i,unsigned char word);
//****************************************************************
//定义时间芯片DS1302的数据线及相关函数
//****************************************************************
void DisplaySec(void); //在LCD上显示秒钟
void DisplayMin(void); //在LCD上显示分钟
void DisplayHour(void); //在LCD上显示小时
unsigned char sec,min,hour; //秒,分,小时
sbit DS1302_CLK=P2^0; //DS1302的时钟信号线
sbit DS1302_IO =P2^1; //DS1302的数据端口线
sbit DS1302_RST=P2^2; //DS1302的片选信号线
void WriteDs1302byte(unsigned char temp); //给DS1302写一个字节
void WriteDs1302(unsigned char address,unsigned char dat); //给DS1302写入时间,先确定地址,再确定要写入的数据
unsigned char ReadDs1302(unsigned char address); //读取DS1302的数据
void InitDS1302();
//****************************************************************
//定义温度传感器DS18B20的数据线和相关函数
//****************************************************************
sbit DS18B20=P1^2; //DS18B20的数据线
int temp;
void DS18B20Init(void); //DS18B20初始化函数
int GetTemp(void);
void TempWriteByte(unsigned char dat);
unsigned char TempRead(void);
bit TempReadBit(void);
void TempChange(void);
//****************************************************************
//定义延时部分相关函数
//****************************************************************
void delayb(unsigned int count);
void DelayMs(unsigned int a);
void Delay(unsigned char num);
//****************************************************************
//定义开关按键的端口
//****************************************************************
sbit Key1 =P1^4; //按键功能:设置(本程序未使用按键)
sbit Key2 =P1^5; //按键功能:确认(本程序未使用按键)
sbit Key3 =P1^6; //按键功能:加 (本程序未使用按键)
sbit Key4 =P1^7; //按键功能:左移(本程序未使用按键)
void Key(void);
//****************************************************************
//定义提示音乐部分相关函数
//****************************************************************
#define Fosc 6000000 //定义晶振频率24000000HZ
sbit Speaker=P3^7; //定义输出管脚
void SpeakerDiDi(void)
{
unsigned char i; //整点报时延时
for(i=0;i<3;i++)
{
Speaker=0;
DelayMs(800);
Speaker=1;
DelayMs(800);
}
DelayMs(4000);
for(i=0;i<3;i++)
{
Speaker=0;
DelayMs(800);
Speaker=1;
DelayMs(800);
}
DelayMs(4000);
for(i=0;i<2;i++)
{
Speaker=0;
DelayMs(4000);
Speaker=1;
DelayMs(1000);
}
}
/******************忙检测函数***************/
void CheckBusy(void)
{
LCD_RS=0;
LCD_RW=1;
LCD_E=1;
LCD_Data=0xff;
while((LCD_Data&0x80)==0x80);
LCD_E=0;
}
/**********************给LCD写入数据*****************/
void WriteDataLCD(unsigned char WDLCD)
{
CheckBusy(); //检测忙
LCD_RS = 1; //RS为高电平,DB7----DB0为数据
LCD_RW = 0; //RW为低电平,E从高电平到低电平,则是把DB7----DB0的数据写到DR或者IR
LCD_E = 1;
LCD_Data = WDLCD; //传送数据WDLCD
Delay(40);
LCD_E = 0; //E从 高电平 到 低电平
Delay(40);
}
/******************给LCD写入指令**********************/
void WriteCommandLCD(unsigned char WCLCD) //BuysC为0时忽略忙检测
{
CheckBusy(); //检测忙
LCD_RS = 0; //RS为低,DB7----DB0为指令
LCD_RW = 0; //RW为低,E从高电平到低电平,则是把DB7----DB0的数据写到DR或者IR
LCD_E = 1;
LCD_Data = WCLCD; //传送数据
Delay(40);
LCD_E = 0; //E从 高电平到低电平
Delay(40);
}
/***************LCD初始化******************/
void LCDInit(void)
{
WriteCommandLCD(0x30); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCD(0x01); //显示清屏
WriteCommandLCD(0x06); // 显示光标移动设置
WriteCommandLCD(0x0C); // 显示开,无游标,不反白
}
/********************清屏***************************/
void LCDClear(void)
{
WriteCommandLCD(0x01); //显示清屏
WriteCommandLCD(0x34); // 显示光标移动设置
WriteCommandLCD(0x30); // 显示开及光标设置
}
void LCDSendWord(unsigned char *p) //向LCD发送一个字符串,
{
while(*p>0) //比如void LCDSendWord('你好');就是让LCD显示"你好"
{
WriteDataLCD(*p);
p++;
}
}
/************写数据或者指令***************/
void LCDTestWord(bit i,unsigned char word)
{
if(i==0)
{
WriteCommandLCD(word); //i=0;则写入指令
}
else
{
WriteDataLCD(word); //i=1;则写入数据
}
}
void Displayqt(void)
{
LCDTestWord(0,0x80);
LCDSendWord("如果你还在!");
}
void DisplayHour(void) //往LCD上填写小时数据
{
hour=ReadDs1302(0x85);
LCDTestWord(0,0x98);
LCDTestWord(1,(hour/16)+0x30);
LCDTestWord(1,hour%16+0x30);
}
void DisplayMin(void) //往LCD上填写分钟数据
{
min=ReadDs1302(0x83);
LCDTestWord(0,0x99);
LCDTestWord(1,0x3a);
LCDTestWord(1,(min/16)+0x30);
LCDTestWord(1,min%16+0x30);
LCDTestWord(1,0x3a);
}
void DisplaySec(void) //往LCD上填写秒钟数据
{
unsigned char i=0;
unsigned int a=0,b=0,c=0;
sec=ReadDs1302(0x81);
LCDTestWord(0,0x9b);
LCDTestWord(1,(sec/16)+0x30);
LCDTestWord(1,sec%16+0x30);
}
void DisplayTemp(void)
{
unsigned int i;
unsigned char a,b,c;
WriteCommandLCD(0x9c);
LCDTestWord(0,0x9d);
TempChange();
i=GetTemp();
a=i/100;
LCDTestWord(1,a+0x30);
b=i/10-a*10;
LCDTestWord(1,b+0x30);
LCDTestWord(1,0x2e);
c=i-a*100-b*10;
LCDTestWord(1,c+0x30);
LCDSendWord("度");
}
//****************************************************************
//DS1302部分子程序
//****************************************************************
/*********************写入操作*********************/
void WriteDs1302Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++) //循环8次 写入数据
{
DS1302_CLK=0;
DS1302_IO=temp&0x01; //每次传输低字节
temp>>=1; //右移一位
DS1302_CLK=1;
}
}
/*********************写入数据*******************/
void WriteDs1302( unsigned char address,unsigned char dat ) //先写地址,再写数据
{
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
_nop_(); //启动
WriteDs1302Byte(address); //发送地址
WriteDs1302Byte(dat); //发送数据
DS1302_RST=0; //恢复
}
/************************************************/
unsigned char ReadDs1302(unsigned char address) //先送地址,再读数据
{
unsigned char i,temp=0x00;
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
_nop_();
WriteDs1302Byte(address); //送地址函数
for (i=0;i<8;i++) //循环8次 读取数据
{
DS1302_CLK=1;
_nop_();
if(DS1302_IO)
temp|=0x80; //每次传输低字节
DS1302_CLK=0;
temp>>=1; //右移一位
}
DS1302_RST=0;
_nop_();
DS1302_CLK=1;
DS1302_IO=0;
return (temp); //返回
}
/*****************DS1302初始化********************/
void InitDS1302() //DS1302中秒,分,时,日期,月份,星期,年的地址分别是0x80,0x82,0x84,0x86,0x88,0x8a,0x8c
{ //初始化写入的时间是2010年4月1日15点整,星期六
WriteDs1302(0x8e,0x00); //控制命令,WP位为0,允许写操作 控制位地址是0x8e
DelayMs(5);
WriteDs1302(0x84,0x00); //写入小时 20点
DelayMs(5);
WriteDs1302(0x82,0x00); //写入分钟 03分
DelayMs(5);
WriteDs1302(0x80,0x00); //写入秒钟 00秒
DelayMs(5);
WriteDs1302(0x8e,0x80); //控制命令,WP为1,禁止写操作
}
//****************************************************************
//DS18B20部分子程序
//****************************************************************
void DS18B20Init(void) //DS18B20初始化
{
unsigned int i;
DS18B20=0;
i=103*8;
while(i>0)i--;
DS18B20=1;
i=103;
while(i>0)i--;
}
bit TempReadBit(void) // 读一位
{
unsigned int i;
bit dat;
DS18B20=0;i++; //小延时一下
DS18B20=1;i++;i++;
dat=DS18B20;
i=32;while(i>0)i--;
return (dat);
}
unsigned char TempRead(void) //读一个字节
{
unsigned char i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=TempReadBit();
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里
}
return(dat); //将一个字节数据返回
}
void TempWriteByte(unsigned char dat)
{ //写一个字节到DS18B20里
unsigned int i;
unsigned char j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb) // 写1部分
{
DS18B20=0;
i++;i++;
DS18B20=1;
i=32;while(i>0)i--;
}
else
{
DS18B20=0; //写0部分
i=32;while(i>0)i--;
DS18B20=1;
i++;i++;
}
}
}
void TempChange(void) //发送温度转换命令
{
DS18B20Init(); //初始化DS18B20
delayb(8); //延时
TempWriteByte(0xcc); // 跳过序列号命令
TempWriteByte(0x44); //发送温度转换命令
}
int GetTemp() //获得温度
{
float tt;
unsigned char a,b;
DS18B20Init();
delayb(1);
TempWriteByte(0xcc);
TempWriteByte(0xbe); //发送读取数据命令
a=TempRead(); //连续读两个字节数据
b=TempRead();
temp=b;
temp<<=8;
temp=temp|a; //两字节合成一个整型变量。
tt=temp*0.0625; //得到真实十进制温度值,因为DS18B20 可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度。
temp=tt*10+0.5; //放大十倍,这样做的目的将小数点后第一位 也转换为可显示数字,同时进行一个四舍五入操作。
return temp; //返回温度值
}
/****************************************************************************/
void UpDate(void)
{
DS18B20=1;
DisplayHour(); //显示时
DisplayMin(); //显示分
DisplaySec(); //显示秒
DisplayTemp(); //显示温度
}
//****************************************************************
//延时部分子程序
//****************************************************************
void delayb(unsigned int count) //delay
{
unsigned char i;
while(count)
{
i=200;
while(i>0)
i--;
count--;
}
}
void DelayMs(unsigned int a) //延时 1MS/次
{
unsigned char i;
while(--a!=0)
{
for(i=0;i<125;i++)
;
}
}
void Delay(unsigned char num)
{
while(num--)
;
}
void main()
{
LCDInit();
LCDClear();
InitDS1302();
while(1)
{
Displayqt();
UpDate();
}
}
复制代码
作者:
xiaoyuxinke
时间:
2022-5-8 15:44
本程序已实测无BUG,若温度不显示,要按你的晶振来调DS18B20读写部分的延时,本程序使用STC12C5A60S2单片机和6M晶振实测
作者:
xiaoyuxinke
时间:
2022-6-3 04:06
无事再来顶一下
作者:
captaine
时间:
2022-9-19 21:31
我用串口显示秒,部分出现了乱码,是什么原因,开始时间为0秒
unsigned int ReadTime() //接收并且转换为十进制
{
dat = ReadDs1302(0x81) ;
damp = (int)dat / 16*10 + (int)dat %16;
return damp;
}
void main()
{
uart_init();
SetTime(); //设置开始时间
while(1)
{
sec = ReadTime();
printf("%d ",sec);
Delay100ms(10);
}
}
例如: 1 0 3 0 1 2 7 0 1 0 1 0 3 0 1 2 7 8 9 0 1 0 3 0 1 2 7 0 1 10 11 8 13 8 9 10 17 18 19 0 1 0
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1