c++程序设计_基于proteus的51单片机开发实例30-模块化程序设计
1. 基于proteus的51單片機開發實例30-模塊化程序設計
1.1. 實驗目的
模塊化程序設計
不知不覺我們的51單片機開發實例已經進行到第三十篇了,是時候進行一個總結和反思了,總結什么?反思什么呢?我們先從程序結構開始吧。
總結在前面的29個例子中的程序,我們會發現:所有的程序都在一個main.c文件中,第一個程序只有不到20行,電腦屏幕上直接能夠從頭看到尾,這個程序看起來非常直觀,所有程序語句都是一目了然的。隨著學習的深入,我們編寫的程序是越來越復雜了,程序的長度是瘋狂地增加。到了第29個實例,我們的程序量已經接近500行了,假設我們要找最后一個函數的內容,那就要用鼠標撥拉好一會才能找到這個函數,是不是會有“好長啊”的感慨?
更為致命的是,我們這個程序中既有延時程序、又有液晶顯示程序、還有DS18B20的讀寫程序。所有這個程序都擠在一個main.c文件中,即使我們已經按照延時、顯示、讀寫進行了劃分,整體感覺是不是有些亂?
現在我們看看DS18B20學習實驗的第三個程序,這個程序里面有很多函數,這些函數的聲明和定義在整個程序里面占了很大的比例。我們在編寫和使用這些函數的時候,需要不停的翻找相關的程序部分。顯得很麻煩。而且整個程序顯得有些亂。那么能不能把程序精簡一下,能不能把具有相關功能的函數放在一起,能不能向我們使用頭文件的時候,直接使用一個包含命令就把一些相關功能包含到程序里,而我們在程序里只要調用我們用到的函數就能夠實現我們想要達到的目的呢?
答案是肯定的!
那么該怎么辦?今天我們就學習一下模塊化程序設計,把程序進行合理的規劃!
本實例的目的:了解模塊化程序設計的思路和方法。
1.2. 設計思路
本實例的設計思路是:將《基于proteus的51單片機開發實例29-單總線DS18B20的讀寫》中的程序代碼按照延時功能、LCD1602液晶顯示功能、DS18B20的讀寫控制功能這三個部分,使用模塊化程序設計的方法,將這三個部分分別封裝為三個.c和.h文件,然后在main.c文件中使用宏定義語句調用。從而完成模塊化程序設計。
模塊化程序設計
1.3. 基礎知識
現在我們看看《基于proteus的51單片機開發實例29-單總線DS18B20的讀寫》中的程序代碼,這個程序里面有很多函數,這些函數的聲明和定義在整個程序里面占了很大的比例。我們在編寫和使用這些函數的時候,因為很多函數都不是獨立,需要不停的翻找相關的程序部分。顯得很麻煩。而且整個程序顯得有些亂。
那么能不能把程序精簡一下,能不能把具有相關功能的函數放在一起,能不能像我們使用頭文件的時候,直接使用一個包含命令就把一些相關功能包含到程序里,而我們在程序里只要調用我們用到的函數就能夠實現我們想要達到的目的呢?
答案是肯定的!
解決方法是:化整為零,把負載的程序按照功能分解成不同的小模塊,分別實現。
1.3.1. 模塊化程序設計簡介
模塊化程序設計是指將實現同一功能的程序整合起來,封裝到一個程序模塊中,這樣在使用該功能的時候,可以直接調用該模塊中的相關函數進行操作。
在進行程序設計時把一個大的程序按照功能劃分為若干小的程序,每個小的程序完成一個確定的功能,在這些小的程序之間建立必要的聯系,互相協作完成整個程序要完成的功能。通常我們稱這些小的程序為程序的模塊。
模塊化程序設計
具體到程序來說,模塊通常是指可以用一個名字調用的一個程序段。對于不同的程序設計語言,模塊的實現和名稱也不相同,在BASIC,FORTRAN語言中的模塊稱作子程序;C語言中的模塊叫函數
1.3.2. 2、模塊化程序設計思路
模塊化程序設計的思路是這樣的:將一個大的程序按功能分割成一些小模塊。
即:把具有相同功能的函數放在一個文件中,然后在主程序里面用#include指令把這個文件包含到主程序文件中,那么在主程序中就可以直接調用這個文件中定義好的函數來實現特定的功能,而在主程序中不用聲明和定義這些函數。這樣就使主程序顯得更加精煉,可讀性也會增強。同時,我們把具有相同功能的函數放在同一個文件中,這樣有一個很大的優點是便于移植,可以將這個模塊化的函數文件很輕松的移植到別的程序中。
綜合上述,模塊化程序設計的優點是:
●各模塊相對獨立,功能單一,結構清晰,接口簡單.
●控制了程序設計的復雜性.
●縮短了開發周期.
●避免程序開發的重復勞動.
●易于維護和功能擴充.
模塊化程序設計
3、模塊化程序設計的實現
模塊化程序的實現是:
一般的做法是:將不同模塊(如LCD1602,DS18B20等)都封裝成一個文件,然后在主程序中包含這些文件。
將具有相同功能的函數聲明以及該模塊涉及的端口定義、初始化設置、宏定義等內容編寫成一個xxx.h文件文件,將函數的定義、變量的聲明及初始化等內容編寫為一個xxx.c文件;注意最好把xxx.c文件和xxx.h文件的名稱定義成相同的名稱。然后在主程序文件中使用#include預編譯命令包含xxx.h文件,這樣在主程序中就可以調用這個文件中的函數了,同樣的,在其它.c文件中,也可以使用#include預編譯命令包含xxx.h文件。(就像我們調用編譯器中的各種應用庫文件一樣,比如在keil c51中要調用I/O定義頭文件是我們要使用“#include
這樣做的優點是,我們可以直接在“.h”文件中查找到我們需要的函數名稱,從而在主程序里面直接調用,而不用去關心“.c”文件中的具體內容。如果我們要將該程序移植到不同型號的單片機上,我們同樣只需在“.h”文件中修改相應的端口定義即可。
1.3.3. 不同模塊之間的函數調用
一般情況下,程序中定義的函數和變量是有一定的作用域的,也就是說,我們在一個模塊中定義的變量和函數,它的作用域只限于本模塊文件和調用它的程序文件范圍內,而在沒有調用它的模塊程序里面,如果調用它,編譯器是會提示錯誤的,它的函數是不能被使用的。
在對較為復雜的程序進行模塊化設計的時候,經常會遇到這樣一種情況:一個函數在不同的模塊之間都會用到,舉例來說,幾乎每一個程序中都會用到延時函數,也就是說一般的程序中都需要調用延時函數。出現這種情況該怎么辦?難道需要在每個模塊中都定義相同的函數?但是我們都知道,程序中,不同的變量和函數只能使用不同的名稱,如果一個程序中有兩個名稱相同的變量或者函數的話,那程序編譯的時候會提示我們有重復定義的函數。難道要在不同的模塊中為相同功能的函數(功能相同,函數體的內容也相同)起不同的名字,這樣豈不是做了很多重復勞動,這樣的重復勞動還會造成程序的可讀性變得很差。怎么辦?
模塊化程序設計
同樣的情況也會出現在不同模塊程序之間傳遞數據變量的時候。
在這樣的情況下,一種比較好的解決辦法是:使用文件包含命令“#include”將一個模塊的文件包含到另一個模塊文件中,這種方法在只包含很少的模塊文件的時候是很方便的,對于比較大的、很復雜的包含很多模塊文件的單片機應用程序中,在每一個模塊里面都使用包含命令就很麻煩了,并且很容易出錯。
出現這種情況的原因是我們在編寫單片機程序的時候,我們所定義的函數和變量都被默認為是局部函數和變量,那么它們的作用范圍當然是在調用他們的程序之間了。如果我們將這些函數和變量定義為全局的函數和變量,那么,在整個單片機系統程序中,所有的模塊之間都可以使用這些函數和變量。
所以,針對這種情況,最好的解決方法是:將需要在不同模塊之間互相調用的文件聲明為外部函數、變量(或者全局函數、變量)。
將函數和變量聲明為全局函數和變量的方法是:在該函數和變量前面加“extern”修飾符?!癳xtern”的英文意思就是“全局”,這樣我們就可以將加了“extern”修飾符的函數和變量聲明為全局函數和變量,那么在整個單片機系統程序的任何地方,我們都可以隨意調用這些全局函數和變量。
例如:
extern void Usart0_Init(void); //USART寄存器設置
extern void Usart0_PutString(unsigned char *pcString);
在這里,我們將這4個函數都定義成為全局函數,那么,在一個單片機系統中,在整個程序的任何地方,我們都可以直接調用這些函數。
注意:在調用的時候直接使用函數名稱即可,“extern”這個修飾符不必再調用的時候寫上。
同樣的,對于變量的定義我們可以使用同樣的方法:
extern int second;
在這里,我們定義了一個全局的整形變量second;
1.4. 電路設計
本實例沿用實例29的電路。
1.5. 程序設計
本實例中,我們分別按照功能劃分,將程序中的延時程序中的函數聲明封裝在Delay.h文件中,變量聲明和函數定義封裝在Delay.c文件中;
液晶顯示程序中的端口定義、函數聲明封裝在LCD1602.h文件中,變量聲明和函數定義封裝在LCD1602.c文件中,DS18B20讀寫程序中的端口定義、函數聲明封裝在DS18B20.h文件中,變量聲明和函數定義封裝在DS18B20.c文件中。
按照我們說的步驟建好上面程序文件后,按照下圖進行操作。
添加.c文件的方法
在主程序以及各個.c文件中,使用下面的預編譯命令將不同程序模塊中的函數“包含”進來。
#include"LCD1602.h" ?//#include"DS18B20.h" ?//#include"Delay.h" ?//?也許有細心的朋友會發現,不同的#include與編譯指令還有細微的差別,例如,調用51單片機頭文件和C語言庫函數使用的是下面的語句
#include ???//包含單片機寄存器的頭文件#include ?//包含_nop_()函數定義的頭文件而針對我們自己編寫的.h文件,使用的是下面的語句
#include"LCD1602.h" ?//#include"DS18B20.h" ?//#include"Delay.h" ?//看出來了吧?調用keil里面自帶的頭文件時,文件名是用尖括號<>括起來的,而調用我們自己編寫的頭文件時,文件名是用""括起來的。這是為什么呢?簡單說,使用尖括號<>括起來的頭文件,編譯器在編譯時,先從編譯器安裝的目錄下開始搜索這個文件,而用""括起來的頭文件,編譯的時候,先從我們建立的單片機項目文件中搜索該文件。
下面是Delay.h文件的代碼。
?//Delay.h/*****************************************************函數功能:延時1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以認為是1毫秒***************************************************/void delay1ms();/*****************************************************函數功能:延時若干毫秒入口參數:n***************************************************/ void delaynms(unsigned int n);下面是Delay.c文件的代碼。
//Delay.c#include //包含單片機寄存器的頭文件#include //包含_nop_()函數定義的頭文件#include"LCD1602.h" //#include"DS18B20.h" //#include"Delay.h" ///*****************************************************函數功能:延時1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以認為是1毫秒***************************************************/void delay1ms(){ unsigned char i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; }/*****************************************************函數功能:延時若干毫秒入口參數:n***************************************************/ void delaynms(unsigned int n) { unsigned int i;for(i=0;i下面是LCD1602.h文件的代碼。
?/*****************************************************函數功能:判斷液晶模塊的忙碌狀態返回值:result。result=1,忙碌;result=0,不忙***************************************************/bit BusyTest(void);/*****************************************************函數功能:將模式設置指令或顯示地址寫入液晶模塊入口參數:dictate***************************************************/void WriteInstruction (unsigned char dictate);/*****************************************************函數功能:指定字符顯示的實際地址入口參數:x***************************************************/ void WriteAddress(unsigned char x); /*****************************************************函數功能:將數據(字符的標準ASCII碼)寫入液晶模塊入口參數:y(為字符常量)***************************************************/ void WriteData(unsigned char y); /*****************************************************函數功能:對LCD的顯示模式進行初始化設置***************************************************/void LcdInitiate(void);/******************************************************************************以下是與溫度有關的顯示設置 ******************************************************************************/ /*****************************************************函數功能:顯示沒有檢測到DS18B20***************************************************/ void display_error(void);/*****************************************************函數功能:顯示說明信息***************************************************/ void display_explain(void);/*****************************************************函數功能:顯示溫度符號***************************************************/ void display_symbol(void);/*****************************************************函數功能:顯示溫度的小數點***************************************************/ void display_dot(void);/*****************************************************函數功能:顯示溫度的單位(Cent)***************************************************/ void display_cent(void);/*****************************************************函數功能:顯示溫度的整數部分入口參數:x***************************************************/ void display_temp1(unsigned char x); /*****************************************************函數功能:顯示溫度的小數數部分入口參數:x***************************************************/ void display_temp2(unsigned char x);下面是LCD1602.c文件的代碼。
//LCD1602.c#include //包含單片機寄存器的頭文件#include //包含_nop_()函數定義的頭文件#include"LCD1602.h" //#include"DS18B20.h" //#include"Delay.h" //unsigned char code digit[10]={"0123456789"}; //定義字符數組顯示數字unsigned char code Str[]={"laomashitu MCU"}; //說明顯示的是溫度unsigned char code Error[]={"Check Error!"}; //說明沒有檢測到DS18B20unsigned char code Temp[]={"wendu:"}; //說明顯示的是溫度unsigned char code Cent[]={"du"}; //溫度單位/*******************************************************************************以下是對液晶模塊的操作程序*******************************************************************************/sbit RS=P2^4; //寄存器選擇位,將RS位定義為P2.0引腳sbit RW=P2^5; //讀寫選擇位,將RW位定義為P2.1引腳sbit E=P2^6; //使能信號位,將E位定義為P2.2引腳sbit BF=P0^7; //忙碌標志位,,將BF位定義為P0.7引腳/*****************************************************函數功能:判斷液晶模塊的忙碌狀態返回值:result。result=1,忙碌;result=0,不忙***************************************************/bit BusyTest(void) { bit result;RS=0; //根據規定,RS為低電平,RW為高電平時,可以讀狀態 RW=1; E=1; //E=1,才允許讀寫 _nop_(); //空操作 _nop_(); _nop_(); _nop_(); //空操作四個機器周期,給硬件反應時間 result=BF; //將忙碌標志電平賦給result E=0; //將E恢復低電平 return result; }/*****************************************************函數功能:將模式設置指令或顯示地址寫入液晶模塊入口參數:dictate***************************************************/void WriteInstruction (unsigned char dictate){ while(BusyTest()==1); //如果忙就等待 RS=0; //根據規定,RS和R/W同時為低電平時,可以寫入指令 RW=0; E=0; //E置低電平(根據表8-6,寫指令時,E為高脈沖, // 就是讓E從0到1發生正跳變,所以應先置"0" _nop_(); _nop_(); //空操作兩個機器周期,給硬件反應時間 P0=dictate; //將數據送入P0口,即寫入指令或地址 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四個機器周期,給硬件反應時間 E=1; //E置高電平 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四個機器周期,給硬件反應時間 E=0; //當E由高電平跳變成低電平時,液晶模塊開始執行命令 }/*****************************************************函數功能:指定字符顯示的實際地址入口參數:x***************************************************/ void WriteAddress(unsigned char x) { WriteInstruction(x|0x80); //顯示位置的確定方法規定為"80H+地址碼x" }/*****************************************************函數功能:將數據(字符的標準ASCII碼)寫入液晶模塊入口參數:y(為字符常量)***************************************************/ void WriteData(unsigned char y) { while(BusyTest()==1); RS=1; //RS為高電平,RW為低電平時,可以寫入數據 RW=0; E=0; //E置低電平(根據表8-6,寫指令時,E為高脈沖, // 就是讓E從0到1發生正跳變,所以應先置"0" P0=y; //將數據送入P0口,即將數據寫入液晶模塊 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四個機器周期,給硬件反應時間 E=1; //E置高電平 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四個機器周期,給硬件反應時間 E=0; //當E由高電平跳變成低電平時,液晶模塊開始執行命令 }/*****************************************************函數功能:對LCD的顯示模式進行初始化設置***************************************************/void LcdInitiate(void){ delaynms(15); //延時15ms,首次寫指令時應給LCD一段較長的反應時間 WriteInstruction(0x38); //顯示模式設置:16×2顯示,5×7點陣,8位數據接口delaynms(5); //延時5ms ,給硬件一點反應時間 WriteInstruction(0x38);delaynms(5); //延時5ms ,給硬件一點反應時間WriteInstruction(0x38); //連續三次,確保初始化成功delaynms(5); //延時5ms ,給硬件一點反應時間WriteInstruction(0x0c); //顯示模式設置:顯示開,無光標,光標不閃爍delaynms(5); //延時5ms ,給硬件一點反應時間WriteInstruction(0x06); //顯示模式設置:光標右移,字符不移delaynms(5); //延時5ms ,給硬件一點反應時間WriteInstruction(0x01); //清屏幕指令,將以前的顯示內容清除delaynms(5); //延時5ms ,給硬件一點反應時間 } /******************************************************************************以下是與溫度有關的顯示設置 ******************************************************************************/ /*****************************************************函數功能:顯示沒有檢測到DS18B20***************************************************/ void display_error(void) { unsigned char i; WriteAddress(0x00); //寫顯示地址,將在第1行第1列開始顯示 i = 0; //從第一個字符開始顯示while(Error[i] != '0') //只要沒有寫到結束標志,就繼續寫{WriteData(Error[i]); //將字符常量寫入LCDi++; //指向下一個字符delaynms(100); //延時100ms較長時間,以看清關于顯示的說明}while(1) //進入死循環,等待查明原因 ;}/*****************************************************函數功能:顯示說明信息***************************************************/ void display_explain(void) { unsigned char i; WriteAddress(0x00); //寫顯示地址,將在第1行第1列開始顯示 i = 0; //從第一個字符開始顯示while(Str[i] != '0') //只要沒有寫到結束標志,就繼續寫{WriteData(Str[i]); //將字符常量寫入LCDi++; //指向下一個字符delaynms(100); //延時100ms較長時間,以看清關于顯示的說明}}/*****************************************************函數功能:顯示溫度符號***************************************************/ void display_symbol(void) { unsigned char i; WriteAddress(0x40); //寫顯示地址,將在第2行第1列開始顯示 i = 0; //從第一個字符開始顯示while(Temp[i] != '0') //只要沒有寫到結束標志,就繼續寫{WriteData(Temp[i]); //將字符常量寫入LCDi++; //指向下一個字符delaynms(50); //延時1ms給硬件一點反應時間}}/*****************************************************函數功能:顯示溫度的小數點***************************************************/ void display_dot(void){ WriteAddress(0x49); //寫顯示地址,將在第2行第10列開始顯示 WriteData('.'); //將小數點的字符常量寫入LCD delaynms(50); //延時1ms給硬件一點反應時間}/*****************************************************函數功能:顯示溫度的單位(Cent)***************************************************/ void display_cent(void){ unsigned char i; WriteAddress(0x4c); //寫顯示地址,將在第2行第13列開始顯示 i = 0; //從第一個字符開始顯示 while(Cent[i] != '0') //只要沒有寫到結束標志,就繼續寫{WriteData(Cent[i]); //將字符常量寫入LCDi++; //指向下一個字符delaynms(50); //延時1ms給硬件一點反應時間}}/*****************************************************函數功能:顯示溫度的整數部分入口參數:x***************************************************/ void display_temp1(unsigned char x){ unsigned char j,k,l; //j,k,l分別儲存溫度的百位、十位和個位j=x/100; //取百位k=(x%100)/10; //取十位l=x%10; //取個位 WriteAddress(0x46); //寫顯示地址,將在第2行第7列開始顯示WriteData(digit[j]); //將百位數字的字符常量寫入LCDWriteData(digit[k]); //將十位數字的字符常量寫入LCDWriteData(digit[l]); //將個位數字的字符常量寫入LCDdelaynms(50); //延時1ms給硬件一點反應時間 } /*****************************************************函數功能:顯示溫度的小數數部分入口參數:x***************************************************/ void display_temp2(unsigned char x){ WriteAddress(0x4a); //寫顯示地址,將在第2行第11列開始顯示WriteData(digit[x]); //將小數部分的第一位數字字符常量寫入LCDdelaynms(50); //延時1ms給硬件一點反應時間}?下面是DS18B20.h文件的代碼。
//DS18B20.hsbit DQ=P3^3;/*****************************************************函數功能:將DS18B20傳感器初始化,讀取應答信號出口參數:flag ***************************************************/bit Init_DS18B20(void);/*****************************************************函數功能:從DS18B20讀取一個字節數據出口參數:dat***************************************************/ unsigned char ReadOneChar(void);/*****************************************************函數功能:向DS18B20寫入一個字節數據入口參數:dat***************************************************/ WriteOneChar(unsigned char dat);/*****************************************************函數功能:做好讀溫度的準備***************************************************/ void ReadyReadTemp(void);?下面是DS18B20.c文件的代碼。
//DS18B20.c#include //包含單片機寄存器的頭文件#include //包含_nop_()函數定義的頭文件#include"LCD1602.h" //#include"DS18B20.h" //#include"Delay.h" //extern unsigned char time; //設置全局變量,專門用于嚴格延時/*****************************************************函數功能:將DS18B20傳感器初始化,讀取應答信號出口參數:flag ***************************************************/bit Init_DS18B20(void){ bit flag; //儲存DS18B20是否存在的標志,flag=0,表示存在;flag=1,表示不存在 DQ = 1; //先將數據線拉高 for(time=0;time<2;time++) //略微延時約6微秒 ; DQ = 0; //再將數據線從高拉低,要求保持480~960us for(time=0;time<200;time++) //略微延時約600微秒 ; //以向DS18B20發出一持續480~960us的低電平復位脈沖 DQ = 1; //釋放數據線(將數據線拉高) for(time=0;time<10;time++) ; //延時約30us(釋放總線后需等待15~60us讓DS18B20輸出存在脈沖) flag=DQ; //讓單片機檢測是否輸出了存在脈沖(DQ=0表示存在) for(time=0;time<200;time++) //延時足夠長時間,等待存在脈沖輸出完畢 ; return (flag); //返回檢測成功標志}/*****************************************************函數功能:從DS18B20讀取一個字節數據出口參數:dat***************************************************/ unsigned char ReadOneChar(void) {unsigned char i=0;unsigned char dat; //儲存讀出的一個字節數據for (i=0;i<8;i++) { DQ =1; // 先將數據線拉高 _nop_(); //等待一個機器周期 DQ = 0; //單片機從DS18B20讀書據時,將數據線從高拉低即啟動讀時序dat>>=1; _nop_(); //等待一個機器周期 DQ = 1; //將數據線"人為"拉高,為單片機檢測DS18B20的輸出電平作準備 for(time=0;time<2;time++) ; //延時約6us,使主機在15us內采樣 if(DQ==1) dat|=0x80; //如果讀到的數據是1,則將1存入datelsedat|=0x00;//如果讀到的數據是0,則將0存入dat //將單片機檢測到的電平信號DQ存入r[i] for(time=0;time<8;time++) ; //延時3us,兩個讀時序之間必須有大于1us的恢復期 } return(dat); //返回讀出的十進制數據}/*****************************************************函數功能:向DS18B20寫入一個字節數據入口參數:dat***************************************************/ WriteOneChar(unsigned char dat){unsigned char i=0;for (i=0; i<8; i++) { DQ =1; // 先將數據線拉高 _nop_(); //等待一個機器周期 DQ=0; //將數據線從高拉低時即啟動寫時序 DQ=dat&0x01; //利用與運算取出要寫的某位二進制數據, //并將其送到數據線上等待DS18B20采樣 for(time=0;time<10;time++) ;//延時約30us,DS18B20在拉低后的約15~60us期間從數據線上采樣 DQ=1; //釋放數據線 for(time=0;time<1;time++) ;//延時3us,兩個寫時序間至少需要1us的恢復期 dat>>=1; //將dat中的各二進制位數據右移1位 } for(time=0;time<4;time++) ; //稍作延時,給硬件一點反應時間}/************************************************函數功能:做好讀溫度的準備***************************************************/ void ReadyReadTemp(void){ Init_DS18B20(); //將DS18B20初始化WriteOneChar(0xCC); // 跳過讀序號列號的操作WriteOneChar(0x44); // 啟動溫度轉換 for(time=0;time<100;time++) ; //溫度轉換需要一點時間Init_DS18B20(); //將DS18B20初始化WriteOneChar(0xCC); //跳過讀序號列號的操作WriteOneChar(0xBE); //讀取溫度寄存器,前兩個分別是溫度的低位和高位}下面是主程序文件的代碼。
//實例72:DS18B20溫度檢測及其液晶顯示#include //包含單片機寄存器的頭文件#include //包含_nop_()函數定義的頭文件#include"LCD1602.h" //#include"DS18B20.h" //#include"Delay.h" //unsigned char time; //設置全局變量,專門用于嚴格延時/*****************************************************函數功能:主函數***************************************************/ void main(void) { unsigned char TL; //儲存暫存器的溫度低位 unsigned char TH; //儲存暫存器的溫度高位 unsigned char TN; //儲存溫度的整數部分 unsigned int TD; //儲存溫度的小數部分 LcdInitiate(); //將液晶初始化 delaynms(5); //延時5ms給硬件一點反應時間if(Init_DS18B20()==1) display_error();display_explain(); display_symbol(); //顯示溫度說明 display_dot(); //顯示溫度的小數點 display_cent(); //顯示溫度的單位 while(1) //不斷檢測并顯示溫度 {ReadyReadTemp(); //讀溫度準備 TL=ReadOneChar(); //先讀的是溫度值低位TH=ReadOneChar(); //接著讀的是溫度值高位TN=TH*16+TL/16; //實際溫度值=(TH*256+TL)/16,即:TH*16+TL/16 //這樣得出的是溫度的整數部分,小數部分被丟棄了 TD=(TL%16)*10/16; //計算溫度的小數部分,將余數乘以10再除以16取整, //這樣得到的是溫度小數部分的第一位數字(保留1位小數) display_temp1(TN); //顯示溫度的整數部分 display_temp2(TD); //顯示溫度的小數部分 delaynms(10); } }1.6. 實例仿真
根據前面的說明,按照步驟建立起模塊化程序結構。編譯后,按照上一實例的方法進行仿真,觀察非模塊化方法編寫的程序,以及用模塊化方法編寫的程序在運行結果上是完全一樣的。
1.7. 總結
通過本實例,我們學習了如何將功能眾多,程序量大的單片機程序分成不同的模塊,從而使單片機程序看起來結構清晰,可讀性強,可移植性強。
總結
以上是生活随笔為你收集整理的c++程序设计_基于proteus的51单片机开发实例30-模块化程序设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql semisync 恢复_my
- 下一篇: python条件语句练习题_python