仿真圖proteus 7.8
程序編譯器:keil 4/keil 5
編程語言:C語言
設(shè)計編號C0043
主要功能:
本設(shè)計由STC89C52單片機(jī)+溫濕度傳感器電路+按鍵電路+液位傳感器電路+液晶1602顯示電路+LED指示燈電路+蜂鳴器報警電路+電源電路組成。
1、液晶實(shí)時顯示濕度值(濕度范圍10%-95%)和濕度閾值。
2、有2個按鍵,可通過按鍵設(shè)置濕度閾值范圍。
3、當(dāng)濕度值小于閾值,綠燈亮,否則綠燈不亮。
4、通過液位傳感器檢測液位,液位有3種狀態(tài):低(L)、高(H)、正常(N),并在液晶實(shí)時顯示。并用3個指示燈模擬顯示。低液位時黃燈亮,正常液位藍(lán)燈亮,高液位是紅燈亮(仿真時液位用按鍵模擬)。
5、當(dāng)液位低于低液位時,停止加濕即綠燈滅,同時蜂鳴器報警。否則蜂鳴器不報警。
仿真圖(提供源文件)
仿真圖講解:
單片機(jī)最小系統(tǒng)介紹
單片機(jī)(Microcontrollers)是一種集成電路芯片,是采用超大規(guī)模集成電路技術(shù)把具有數(shù)據(jù)處理能力的中央處理器CPU、隨機(jī)存儲器RAM、只讀存儲器ROM、多種I/O口和中斷系統(tǒng)、定時器/計數(shù)器等功能(可能還包括顯示驅(qū)動電路、脈寬調(diào)制電路、模擬多路轉(zhuǎn)換器、A/D轉(zhuǎn)換器等電路)集成到一塊硅片上構(gòu)成的一個小而完善的微型計算機(jī)系統(tǒng),在工業(yè)控制領(lǐng)域廣泛應(yīng)用。從上世紀(jì)80年代,由當(dāng)時的4位、8位單片機(jī),發(fā)展到現(xiàn)在的300M的高速單片機(jī)。本文的單片機(jī)特指51單片機(jī),具體芯片型號是STC89C52RC。需注意STC89C51,STC89C52,AT89C51,AT89C52都是51單片機(jī)的一種具體芯片型號。
最小系統(tǒng)組成:
51單片機(jī)最小系統(tǒng):單片機(jī)、復(fù)位電路、晶振(時鐘)電路、電源
最小系統(tǒng)用到的引腳
1、主電源引腳(2根)
VCC:電源輸入,接+5V電源
GND:接地線
2、外接晶振引腳(2根)
XTAL1:片內(nèi)振蕩電路的輸入端
XTAL2:片內(nèi)振蕩電路的輸出端
3、控制引腳(4根)
RST/VPP:復(fù)位引腳,引腳上
復(fù)位電路
在電路圖中,電容的的大小是10uf,電阻的大小是0.56k。
在5V正常工作的51單片機(jī)中小于1.5V的電壓信號為低電平信號,而大于1.5V的電壓信號為高電平信號??梢运愠鲭娙莩潆姷诫娫措妷旱?.7倍,即電容兩端電壓為3.5V、電阻兩端電壓為1.5V時,需要的時間約為T=RC=0.56K*10UF=0.056S。
也就是說在單片機(jī)上電啟動的0.1S內(nèi),電容兩端的電壓從0-3.5V不斷增加,這個時候10K電阻兩端的電壓為從5-1.5V不斷減少(串聯(lián)電路各處電壓之和為總電壓),所以RST引腳所接收到的電壓是5V-1.5V的過程,也就是高電平到低電平的過程。
單片機(jī)RST引腳是高電平有效,即復(fù)位;低電平無效,即單片機(jī)正常工作。所以在開機(jī)0.056內(nèi),單片機(jī)系統(tǒng)RST引腳接收到了時間為0.056S左右的高電平信號,所以實(shí)現(xiàn)了自動復(fù)位。
在單片機(jī)啟動0.056S后,電容C兩端的電壓持續(xù)充電為5V,這是時候10K電阻兩端的電壓接近于0V,RST處于低電平所以系統(tǒng)正常工作。當(dāng)按鍵按下的時候,開關(guān)導(dǎo)通,這個時候電容兩端形成了一個回路,電容被短路,所以在按鍵按下的這個過程中,電容開始釋放之前充的電量。隨著時間的推移,電容的電壓在0.056S內(nèi),從5V釋放到變?yōu)榱?.5V,甚至更小。根據(jù)串聯(lián)電路電壓為各處之和,這個時候10K電阻兩端的電壓為3.5V,甚至更大,所以RST引腳又接收到高電平。單片機(jī)系統(tǒng)自動復(fù)位。
晶振基本概念 晶振全名叫晶體振蕩器,每個單片機(jī)系統(tǒng)里都有晶振,晶振是由石英晶體經(jīng)過加工并鍍上電極而做成的,主要的特性就是通電后會產(chǎn)生機(jī)械震蕩,可以給單片機(jī)提供穩(wěn)定的時鐘源,晶振提供時鐘頻率越高,單片機(jī)的運(yùn)行速度也就越快。 晶振用一種能把電能和機(jī)械能相互轉(zhuǎn)化的晶體在共振的狀態(tài)下工作,以提供穩(wěn)定,精確的單頻振蕩。
晶振起振后, 產(chǎn)生的振動信號會通過XTAL1引腳, 依次經(jīng)過振蕩器和時鐘發(fā)生器的處理,得到機(jī)器周期信號,作為指令操作的依據(jù)。51單片機(jī)常用的晶振是12M和11.0592M。本設(shè)計使用12M晶振
LCD1602顯示
第1引腳:GND為電源地
第2引腳:VCC接5V電源正極
第3引腳:V0為液晶顯示器對比度調(diào)整端,接正電源時對比度最弱,接地電源時對比度最高(對比度過高時會 產(chǎn)生“鬼影”,使用時可以通過一個10K的電位器調(diào)整對比度)。
第4引腳:RS為寄存器選擇,高電平1時選擇數(shù)據(jù)寄存器、低電平0時選擇指令寄存器。
第5引腳:RW為讀寫信號線,高電平(1)時進(jìn)行讀操作,以51為例的簡單原理圖低電平(0)時進(jìn)行寫操作。
第6引腳:E(或EN)端為使能(enable)端,高電平(1)時讀取信息,負(fù)跳變時執(zhí)行指令。
第7~14引腳:D0~D7為8位雙向數(shù)據(jù)端。第15~16腳:空腳或背燈電源。第15引腳背光正極,第16引腳背光負(fù)極。
SHT11溫濕度傳感器
仿真圖中各引腳的功能如下:
其中DA-TA為數(shù)據(jù)線,SCK為時鐘線;
蜂鳴器電路
通過三極管控制,P12給高電平導(dǎo)通,蜂鳴器響。
指示燈電路
灌電流設(shè)計,單片機(jī)給低電平點(diǎn)亮LED燈。
原理圖(提供源文件,僅供參考)
程序(提供源文件源碼)
LCD1602顯示驅(qū)動函數(shù)
/*********************************************************/
// 毫秒級的延時函數(shù),time是要延時的毫秒數(shù)
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 1602液晶寫命令函數(shù),cmd就是要寫入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{
LcdRs_P = 0;
LcdRw_P = 0;
LcdEn_P = 0;
P0=cmd;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶寫數(shù)據(jù)函數(shù),dat就是要寫入的數(shù)據(jù)
/*********************************************************/
void LcdWriteData(uchar dat)
{
LcdRs_P = 1;
LcdRw_P = 0;
LcdEn_P = 0;
P0=dat;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶初始化函數(shù)
/*********************************************************/
void LcdInit()
{
LcdWriteCmd(0x38); // 16*2顯示,5*7點(diǎn)陣,8位數(shù)據(jù)口
LcdWriteCmd(0x0C); // 開顯示,不顯示光標(biāo)
LcdWriteCmd(0x06); // 地址加1,當(dāng)寫入數(shù)據(jù)后光標(biāo)右移
LcdWriteCmd(0x01); // 清屏
}
/*********************************************************/
// 液晶光標(biāo)定位函數(shù)
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
// 第一行
if(line==0)
LcdWriteCmd(0x80+column);
// 第二行
if(line==1)
LcdWriteCmd(0x80+0x40+column);
}
/*********************************************************/
// 液晶輸出字符串函數(shù)
/*********************************************************/
void LcdPrintStr(uchar *str)
{
while(*str!='?') // 判斷是否到字符串的盡頭了
LcdWriteData(*str++);
}
/*********************************************************/
// 液晶輸出數(shù)字
/*********************************************************/
void LcdPrintNum(uchar num)
{
LcdWriteData(num/10+48); // 十位
LcdWriteData(num%10+48); // 個位
}
SHT11溫濕度傳感器驅(qū)動
/*********************************************************/
// 往SHT11寫入一個字節(jié)
/*********************************************************/
char ShtWriteByte(uchar value)
{
uchar i,error=0;
for(i=128;i>0;i>>=1) // 高位為1,循環(huán)右移
{
if (i&value)
Data_P=1; // 和要發(fā)送的數(shù)相與,結(jié)果為發(fā)送的位
else
Data_P=0;
Sck_P=1;
_nop_(); // 延時3us
_nop_();
_nop_();
Sck_P=0;
}
Data_P=1; // 釋放數(shù)據(jù)線
Sck_P=1;
error=Data_P; // 檢查應(yīng)答信號,確認(rèn)通訊正常
_nop_();
_nop_();
_nop_();
Sck_P=0;
Data_P=1;
return error; // error=1 通訊錯誤
}
/*********************************************************/
// 從SHT11讀出一個字節(jié)
/*********************************************************/
char ShtReadByte(uchar ack)
{
unsigned char i,val=0;
Data_P=1; // 釋放數(shù)據(jù)線
for(i=0x80;i>0;i>>=1) // 高位為1,循環(huán)右移
{
Sck_P=1;
if(Data_P)
val=(val|i); // 讀一位數(shù)據(jù)線的值
Sck_P=0;
}
Data_P=!ack; // 如果是校驗(yàn),讀取完后結(jié)束通訊
Sck_P=1;
_nop_(); // 延時3us
_nop_();
_nop_();
Sck_P=0;
_nop_();
_nop_();
_nop_();
Data_P=1; // 釋放數(shù)據(jù)線
return val;
}
/*********************************************************/
// SHT11啟動傳輸
/*********************************************************/
void ShtTransStart(void)
{
Data_P=1;
Sck_P=0;
_nop_();
Sck_P=1;
_nop_();
Data_P=0;
_nop_();
Sck_P=0;
_nop_();
_nop_();
_nop_();
Sck_P=1;
_nop_();
Data_P=1;
_nop_();
Sck_P=0;
}
/*********************************************************/
// SHT11連接復(fù)位
/*********************************************************/
void ShtConnectReset(void)
{
unsigned char i;
Data_P=1; //準(zhǔn)備
Sck_P=0;
for(i=0;i<9;i++) //DATA保持高,SCK時鐘觸發(fā)9次,發(fā)送啟動傳輸,通迅即復(fù)位
{
Sck_P=1;
Sck_P=0;
}
ShtTransStart(); //啟動傳輸
}
/*********************************************************/
// SHT11溫濕度檢測
/*********************************************************/
char ShtMeasure(unsigned char *p_value, unsigned char *p_checksum, uchar mode)
{
unsigned error=0;
unsigned int i;
ShtTransStart(); // 啟動傳輸
switch(mode) // 選擇發(fā)送命令
{
case 1 : // 測量溫度
error+=ShtWriteByte(0x03);
break;
case 2 : // 測量濕度
error+=ShtWriteByte(0x05);
break;
default:
break;
}
for(i=0;i<65535;i++)
if(Data_P==0)
break; // 等待測量結(jié)束
if(Data_P)
error+=1; // 如果長時間數(shù)據(jù)線沒有拉低,說明測量錯誤
*(p_value) =ShtReadByte(1); // 讀第一個字節(jié),高字節(jié) (MSB)
*(p_value+1)=ShtReadByte(1); // 讀第二個字節(jié),低字節(jié) (LSB)
*p_checksum =ShtReadByte(0); // read CRC校驗(yàn)碼
return error; // error=1 通訊錯誤
}
/*********************************************************/
// SHT11溫濕度值標(biāo)度變換及溫度補(bǔ)償
/*********************************************************/
void CalcSHT11(float *p_humidity ,float *p_temperature)
{
const float C1=-4.0; // 12位濕度精度 修正公式
const float C2=+0.0405; // 12位濕度精度 修正公式
const float C3=-0.0000028; // 12位濕度精度 修正公式
const float T1=+0.01; // 14位溫度精度 5V條件 修正公式
const float T2=+0.00008; // 14位溫度精度 5V條件 修正公式
float rh=*p_humidity; // rh: 12位 濕度
float t=*p_temperature; // t: 14位 溫度
float rh_lin; // rh_lin: 濕度 linear值
float rh_true; // rh_true: 濕度 ture值
float t_C; // t_C : 溫度 ℃
t_C=t*0.01 - 40; //補(bǔ)償溫度
rh_lin=C3*rh*rh + C2*rh + C1; //相對濕度非線性補(bǔ)償
rh_true=(t_C-25)*(T1+T2*rh)+rh_lin; //相對濕度對于溫度依賴性補(bǔ)償
*p_temperature=t_C; //返回溫度結(jié)果
*p_humidity=rh_true; //返回濕度結(jié)果
}
/*********************************************************/
// 溫度校正
/*********************************************************/
uchar TempCorrect(int temp)
{
if(temp<0) temp=0;
if(temp>970) temp=970;
if(temp>235) temp=temp+10;
if(temp>555) temp=temp+10;
if(temp>875) temp=temp+10;
temp=(temp%1000)/10;
return temp;
}
/*********************************************************/
// 濕度校正
/*********************************************************/
uchar HumiCorrect(uint humi)
{
if(humi>999) humi=999;
if((humi>490)&&(humi<951)) humi=humi-10;
humi=(humi%1000)/10;
return humi;
}
/*********************************************************/
// 讀取SHT11的溫濕度數(shù)據(jù)
/*********************************************************/
void ReadShtData()
{
value humi_val,temp_val; // 定義兩個共同體,一個用于濕度,一個用于溫度
uchar error; // 用于檢驗(yàn)是否出現(xiàn)錯誤
uchar checksum; // CRC
uint temp1,humi1; // 臨時讀取到的溫濕度數(shù)據(jù)
error=0; //初始化error=0,即沒有錯誤
error+=ShtMeasure((unsigned char*)&temp_val.i,&checksum,1); //溫度測量
error+=ShtMeasure((unsigned char*)&humi_val.i,&checksum,2); //濕度測量
if(error!=0) //如果發(fā)生錯誤,系統(tǒng)復(fù)位
ShtConnectReset();
else
{
humi_val.f=(float)humi_val.i; //轉(zhuǎn)換為浮點(diǎn)數(shù)
temp_val.f=(float)temp_val.i; //轉(zhuǎn)換為浮點(diǎn)數(shù)
CalcSHT11(&humi_val.f,&temp_val.f); //修正相對濕度及溫度
temp1=temp_val.f*10;
temp=TempCorrect(temp1);
humi1=humi_val.f*10-50;
humi=HumiCorrect(humi1);
}
}
主函數(shù)
/********************************************************
主函數(shù)
********************************************************/
void main(void)
{
LcdInit(); // 液晶功能初始化
ShtConnectReset(); // 啟動連接復(fù)位
LcdGotoXY(0,0); // 第0行的顯示內(nèi)容
LcdPrintStr(" my designer ");
LcdGotoXY(1,0); // 第1行的顯示內(nèi)容
LcdPrintStr("H: %RH S: ");
LcdGotoXY(1,4); // 溫度單位攝氏度上面的圓圈符號
while(1)
{
CheckKey(); //按鍵采集處理
DelayMs(5);
later++;
if(later>=50)
{
ReadShtData(); // 檢測溫濕度數(shù)據(jù)
humi = humi+2;//補(bǔ)償
// LcdGotoXY(1,2); // 定位到要顯示溫度的地方
// LcdPrintNum(temp); // 顯示溫度值
}
LcdGotoXY(1,2); // 定位到要顯示濕度的地方
LcdPrintNum(humi); // 顯示濕度值
LcdGotoXY(1,10); // 定位到要顯示濕度的地方
LcdPrintNum(setH); // 顯示濕度值
LcdGotoXY(1,14);
LcdWriteData(yeweiFlag);
if((yeweiG == 1)&&(yeweiD == 1))//上下液位都無有水 低于低液位)
{
buzzer = 0;//蜂鳴器報警
led_gre =1 ; //不亮
}
else
{
buzzer = 1; //不報警
if(humi< setH) //小于閾值
{
led_gre = 0; //綠燈亮
}
else
{
led_gre =1 ; //不亮
}
}
if((yeweiG == 0)&&(yeweiD == 0))//上下液位有水
{
yeweiFlag = 'H';
led_red = 0 ; led_blu =1;led_yel =1; //紅燈亮
}
else if((yeweiG == 1)&&(yeweiD == 0))//只有低液位有水
{
yeweiFlag = 'N';
led_red = 1 ; led_blu =0;led_yel =1; //藍(lán)燈亮
}
else if((yeweiG == 1)&&(yeweiD == 1))//上下液位都無有水 低于低液位
{
yeweiFlag = 'L';
led_red = 1 ; led_blu =1;led_yel =0; //藍(lán)燈亮
}
else if((yeweiG == 0)&&(yeweiD == 1)) //異常現(xiàn)象 只有高液位有水
{
yeweiFlag = 'E';
led_red = 1 ; led_blu =1;led_yel =1; //都不亮
}
// Buzzer_P=0;
// DelayMs(100);
// Buzzer_P=1;
// DelayMs(100);
}
}