標題:
51單片機+DS1302+DS18B20制作(程序開源)
[打印本頁]
作者:
xiaoyuxinke
時間:
2022-5-8 14:01
標題:
51單片機+DS1302+DS18B20制作(程序開源)
由于本程序使用了STC12C5A60S2單片機,最好不要使用太高的晶振,不然DS18B20延時部分太難調試(搞不好會顯示00.0度),一般12M以下相對好些.
制作出來的實物圖如下:
51hei圖片_20220508140028.jpg
(168.74 KB, 下載次數(shù): 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> //用到這個頭文件表示你可以在程序中調用單片機中庫文件中的函數(shù)
#define uchar unsigned char //用Uchar代替unsigned char
#define uint unsigned int //用uint代替unsigned int
//****************************************************************
//定義LCD12864的數(shù)據(jù)線和相關函數(shù)
//****************************************************************
sbit LCD_RS=P2^7; //模式位,低電平輸入指令,高電平輸入數(shù)據(jù)
sbit LCD_RW=P2^6; //讀寫位,低電平讀,高電平寫
sbit LCD_E =P2^5; //LCD12864使能位,低電平無效,高電平使能
#define Busy 0x80
#define LCD_Data P0 //LCD12864的8位數(shù)據(jù)總線,單片機的P0端口
void WriteDataLCD(unsigned char WDLCD); //給LCD12864寫數(shù)據(jù)
void WriteCommandLCD(unsigned char WCLCD); //給LCD12864寫指令
void LCDInit(void); //LCD12864初始化
void LCDClear(void); //LCD12864清屏
void CheckBusy(void); //忙檢測
void LCDSendWord(unsigned char *p); //向LCD發(fā)送一個字符串
void LCDTestWord(bit i,unsigned char word);
//****************************************************************
//定義時間芯片DS1302的數(shù)據(jù)線及相關函數(shù)
//****************************************************************
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的數(shù)據(jù)端口線
sbit DS1302_RST=P2^2; //DS1302的片選信號線
void WriteDs1302byte(unsigned char temp); //給DS1302寫一個字節(jié)
void WriteDs1302(unsigned char address,unsigned char dat); //給DS1302寫入時間,先確定地址,再確定要寫入的數(shù)據(jù)
unsigned char ReadDs1302(unsigned char address); //讀取DS1302的數(shù)據(jù)
void InitDS1302();
//****************************************************************
//定義溫度傳感器DS18B20的數(shù)據(jù)線和相關函數(shù)
//****************************************************************
sbit DS18B20=P1^2; //DS18B20的數(shù)據(jù)線
int temp;
void DS18B20Init(void); //DS18B20初始化函數(shù)
int GetTemp(void);
void TempWriteByte(unsigned char dat);
unsigned char TempRead(void);
bit TempReadBit(void);
void TempChange(void);
//****************************************************************
//定義延時部分相關函數(shù)
//****************************************************************
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);
//****************************************************************
//定義提示音樂部分相關函數(shù)
//****************************************************************
#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);
}
}
/******************忙檢測函數(shù)***************/
void CheckBusy(void)
{
LCD_RS=0;
LCD_RW=1;
LCD_E=1;
LCD_Data=0xff;
while((LCD_Data&0x80)==0x80);
LCD_E=0;
}
/**********************給LCD寫入數(shù)據(jù)*****************/
void WriteDataLCD(unsigned char WDLCD)
{
CheckBusy(); //檢測忙
LCD_RS = 1; //RS為高電平,DB7----DB0為數(shù)據(jù)
LCD_RW = 0; //RW為低電平,E從高電平到低電平,則是把DB7----DB0的數(shù)據(jù)寫到DR或者IR
LCD_E = 1;
LCD_Data = WDLCD; //傳送數(shù)據(jù)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的數(shù)據(jù)寫到DR或者IR
LCD_E = 1;
LCD_Data = WCLCD; //傳送數(shù)據(jù)
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發(fā)送一個字符串,
{
while(*p>0) //比如void LCDSendWord('你好');就是讓LCD顯示"你好"
{
WriteDataLCD(*p);
p++;
}
}
/************寫數(shù)據(jù)或者指令***************/
void LCDTestWord(bit i,unsigned char word)
{
if(i==0)
{
WriteCommandLCD(word); //i=0;則寫入指令
}
else
{
WriteDataLCD(word); //i=1;則寫入數(shù)據(jù)
}
}
void Displayqt(void)
{
LCDTestWord(0,0x80);
LCDSendWord("如果你還在!");
}
void DisplayHour(void) //往LCD上填寫小時數(shù)據(jù)
{
hour=ReadDs1302(0x85);
LCDTestWord(0,0x98);
LCDTestWord(1,(hour/16)+0x30);
LCDTestWord(1,hour%16+0x30);
}
void DisplayMin(void) //往LCD上填寫分鐘數(shù)據(jù)
{
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上填寫秒鐘數(shù)據(jù)
{
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++) //循環(huán)8次 寫入數(shù)據(jù)
{
DS1302_CLK=0;
DS1302_IO=temp&0x01; //每次傳輸?shù)妥止?jié)
temp>>=1; //右移一位
DS1302_CLK=1;
}
}
/*********************寫入數(shù)據(jù)*******************/
void WriteDs1302( unsigned char address,unsigned char dat ) //先寫地址,再寫數(shù)據(jù)
{
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
_nop_(); //啟動
WriteDs1302Byte(address); //發(fā)送地址
WriteDs1302Byte(dat); //發(fā)送數(shù)據(jù)
DS1302_RST=0; //恢復
}
/************************************************/
unsigned char ReadDs1302(unsigned char address) //先送地址,再讀數(shù)據(jù)
{
unsigned char i,temp=0x00;
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
_nop_();
WriteDs1302Byte(address); //送地址函數(shù)
for (i=0;i<8;i++) //循環(huán)8次 讀取數(shù)據(jù)
{
DS1302_CLK=1;
_nop_();
if(DS1302_IO)
temp|=0x80; //每次傳輸?shù)妥止?jié)
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) //讀一個字節(jié)
{
unsigned char i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=TempReadBit();
dat=(j<<7)|(dat>>1); //讀出的數(shù)據(jù)最低位在最前面,這樣剛好一個字節(jié)在DAT里
}
return(dat); //將一個字節(jié)數(shù)據(jù)返回
}
void TempWriteByte(unsigned char dat)
{ //寫一個字節(jié)到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) //發(fā)送溫度轉換命令
{
DS18B20Init(); //初始化DS18B20
delayb(8); //延時
TempWriteByte(0xcc); // 跳過序列號命令
TempWriteByte(0x44); //發(fā)送溫度轉換命令
}
int GetTemp() //獲得溫度
{
float tt;
unsigned char a,b;
DS18B20Init();
delayb(1);
TempWriteByte(0xcc);
TempWriteByte(0xbe); //發(fā)送讀取數(shù)據(jù)命令
a=TempRead(); //連續(xù)讀兩個字節(jié)數(shù)據(jù)
b=TempRead();
temp=b;
temp<<=8;
temp=temp|a; //兩字節(jié)合成一個整型變量。
tt=temp*0.0625; //得到真實十進制溫度值,因為DS18B20 可以精確到0.0625度,所以讀回數(shù)據(jù)的最低位代表的是0.0625度。
temp=tt*10+0.5; //放大十倍,這樣做的目的將小數(shù)點后第一位 也轉換為可顯示數(shù)字,同時進行一個四舍五入操作。
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
我用串口顯示秒,部分出現(xiàn)了亂碼,是什么原因,開始時間為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.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1