由于本程序使用了STC12C5A60S2單片機,最好不要使用太高的晶振,不然DS18B20延時部分太難調試(搞不好會顯示00.0度),一般12M以下相對好些.
制作出來的實物圖如下:
單片機源程序如下:
- //******************************************************************************
- //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();
- }
- }
復制代碼
|