毕业设计 超声波红外自动调速风扇系统
文章目錄
- 1 簡介
- 1 設計概要
- 2 系統設計
- 2.1 系統供電問題
- 2.2 自動/手動模式的切換
- 2.3 PWM信號的產生
- 2.4 單片機內部資源的分配
- 三、硬件搭建
- 3.1 單片機最小系統
- 3.2 電機驅動模塊
- 3.3 超聲波測距模塊
- 3.4 紅外遙控模塊
- 3.5 液晶顯示模塊
- 3.6 供電模塊
- 4 工程代碼(全開源)
- 4.1 總頭文件
- 4.2 電機驅動及頭文件
- 4.3 超聲波驅動及頭文件
- 4.4 紅外遙控驅動及頭文件
- 4.5 液晶顯示驅動及頭文件
- 4.6 延時函數及頭文件
- 4.7 主函數
- 5 最后
1 簡介
Hi,大家好,學長今天向大家介紹一個 單片機項目,大家可用于 課程設計 或 畢業設計
基于超聲波與紅外的自動調速風扇系統
1 設計概要
本系統為基于紅外和超聲波的手動/自動調速風扇系統,風扇轉速的調節模式可分為自動模式與手動模式:在自動模式下,由超聲波檢測人與風扇的距離,根據距離調節風扇轉速;在手動模式下,可通過紅外遙控的按鍵調節風扇轉速。相應參數信息通過LCD液晶顯示屏顯示。本系統的主控芯片采用STC89C52單片機,測距采用HC-SR04超聲波模塊,風扇電機由L298N電機驅動模塊驅動,遙控部分用傳統的紅外遙控器,顯示部分用LCD1602液晶顯示屏。電機驅動模塊采用12V供電,單片機及其他各部分采用5V供電。
2 系統設計
2.1 系統供電問題
STC89C52單片機及超聲波傳感器、紅外遙控接收頭、液晶顯示屏均為+5V標準供電,可以直接使用電腦USB接口引出電壓。但考慮到電機用到PWM調速,需要大電壓和大電流,因此決定使用電池盒額外供電。
2.2 自動/手動模式的切換
主函數內部用一個while大循環,超聲波數據采集及電機驅動等程序均放在循環內部。在while內部有兩段程序,一段為手動模式,一段為自動模式,分別放在if…else…的兩個分支內。定義全局變量flag,在紅外遙控中斷內部可改變flag的值,通過flag的值控制if…else…選擇結構的走向,進而實現兩種模式的切換。
2.3 PWM信號的產生
電機轉速調節需用到PWM信號,需由單片機內部產生。有兩種可行方案:其一為通過軟件延時,不斷地改變某一引腳電平的高低,由該引腳向外輸出PWM信號;其二為通過中斷計時,計滿后進入中斷服務程序,在中斷服務程序中改變某一引腳電平的高低,由該引腳向外輸出PWM信號。考慮到系統較為復雜,用方案一在時間上會占用單片機的大量資源,影響到系統的穩定性和實時性,因此采用方案二。
2.4 單片機內部資源的分配
在本系統中,用到兩個定時器和兩個中斷:超聲波測距時等待返回波用到一個定時器,控制PWM信號的發生用到一個定時器;紅外遙控的響應用到一個外部中斷,PWM信號的發生用到定時器中斷。考慮到系統的實時性,給紅外遙控分配優先級最高的外部中斷0,PWM信號發生使用定時器T0并開中斷,超聲波測距使用定時器T1,不開中斷。
三、硬件搭建
由于硬件部分中的很多模塊在仿真軟件中都沒有,且各模塊之間的連接關系比較簡單,因此在這里不提供電路圖,僅用語言描述各引腳之間的連接關系。
3.1 單片機最小系統
對51 系列單片機來說, 最小系統一般應該包括: 單片機、時鐘電路、復位電路、輸入/ 輸出設備等。最小系統的焊接有一套標準的流程,為基本功,這里不做贅述。
3.2 電機驅動模塊
本系統電機驅動模塊使用常見的L298N電機驅動模塊。L298N芯片可以驅動兩個二相電機,也可以驅動一個四相電機,輸出電壓最高可達50V,可以直接通過電源來調節輸出電壓;可以直接用單片機的IO口提供信號;而且電路簡單,使用比較方便。
在本系統中,只使能了EnA來驅動一個電機,其中EnA接單片機引腳P20,IN1接P21,IN2接P22。L298N電機驅動模塊實物圖如下所示:
3.3 超聲波測距模塊
在自動調速模式下,需用到超聲波模塊采集距離信息。本系統采用HC-SR04超聲波模塊, HC-SR04超聲波測距模塊可提供2cm-400cm的非接觸式距離感測功能,測距精度可達高到3mm;模塊包括超聲波發射器、接收器與控制電路。基本工作原理:
-
(1)采用I0口TRIG觸發測距,給至少10us的高電平信號;
-
(2)模塊自動發送8個40khz的方波,自動檢測是否有信號返回;
-
(3)有信號返回,通過I0口ECHO輸出一個高電平,高電平持續的時間就是超聲往返所用的時間。
-
(4)根據聲音在空氣中的速度為344米/秒,即可計算出所測的距離。
在本系統中,超聲波模塊的Trig腳接單片機引腳P36,Echo腳接單片機引腳P22。HC-SR04工作時序圖如下所示:
3.4 紅外遙控模塊
根據使用的編碼芯片不同,紅外遙控編碼的格式也不同,較普遍的有NEC標準和PHILIPS標準。最常用的是NEC標準,本系統采用的也是NEC標準。
NEC標準:遙控載波的頻率為38KHz(占空比1:3)當某個鍵按下時,發射端首先發射一個完整的全碼,如果按鍵超過108ms仍未松開,接下來發射的代碼(連發代碼)將由起始碼(9ms)和結束碼(2.5ms)組成,并每隔108ms重復。
一個完整的全碼由引導碼、用戶碼、用戶碼、數據碼、數據碼以及數據反碼共同組成。其中,引導碼高電平9ms,低電平4.5ms;系統碼8位,數據碼8位,共32位;其中前16位為用戶識別碼,能區別不同的紅外遙控設備,以防止不同的機種遙控碼互相干擾。后16位為8位的操作碼和8位的操作反碼,用于核對數據是否接收準確。收端根據數據碼做出應該執行上面動作的判斷。連發代碼是在持續按鍵時發送的碼。它告知接收端。某鍵是在被連續的按著。
NEC標準下的發射碼表示:發射數據0時用“0.56ms高電平 + 0.565ms低電平 = 1.125ms”表示;發射數據1用“0.56ms高電平 + 1.69ms低電平 = 2.25ms”表示。
在本系統中,紅外接收器的INIR腳接單片機引腳P32。NEC標準完整碼組成及NEC標準發射碼如下所示:
3.5 液晶顯示模塊
本系統的液晶顯示部分采用LCD1602液晶顯示屏。1602液晶也叫1602字符型液晶,它是一種專門用來顯示字母、數字、符號等的點陣型液晶模塊 它有若干個5X7或者5X11等點陣字符位組成,每個點陣字符位都可以顯示一個字符。每位之間有一個點距的間隔,每行之間也有也有間隔,起到了字符間距和行間距的作用。
LCD1602是指顯示的內容為16X2,即可以顯示兩行,每行16個字符液晶模塊(顯示字符和數字)。目前市面上字符液晶絕大多數是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780寫的控制程序可以很方便地應用于市面上大部分的字符型液晶。
在本系統中,液晶顯示屏接法如下所示:
3.6 供電模塊
為了驅動電機,需采用+12V供電,結合手上現有資源,決定采用4節3.7V的鋰電池串聯供電。串聯后的輸出電壓在+15V左右,使用LM2596S直流降壓模塊,將電壓降至+12V后提供給電機驅動模塊L298N,單片機所需的+5V電可直接從電機驅動模塊中引出。
4 工程代碼(全開源)
代碼用C語言編寫,在Keil5環境下開發的。給每個模塊都寫了驅動,每個模塊的驅動拿出后略加改動,都能單獨使用。代碼工程結構如下所示:
4.1 總頭文件
把常用的宏定義和硬件的引腳連接定義到了reg52.h里面,更名為my52.h。所以整個工程代碼中每個文件都#include "my52.h"而不是 #include “reg52.h”。
#ifndef __MY52_H__ #define __MY52_H__/* BYTE Registers */ sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0xA0; sfr P3 = 0xB0; sfr PSW = 0xD0; sfr ACC = 0xE0; sfr B = 0xF0; sfr SP = 0x81; sfr DPL = 0x82; sfr DPH = 0x83; sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A; sfr TL1 = 0x8B; sfr TH0 = 0x8C; sfr TH1 = 0x8D; sfr IE = 0xA8; sfr IP = 0xB8; sfr SCON = 0x98; sfr SBUF = 0x99;/* 8052 Extensions */ sfr T2CON = 0xC8; sfr RCAP2L = 0xCA; sfr RCAP2H = 0xCB; sfr TL2 = 0xCC; sfr TH2 = 0xCD;/* BIT Registers */ /* PSW */ sbit CY = PSW^7; sbit AC = PSW^6; sbit F0 = PSW^5; sbit RS1 = PSW^4; sbit RS0 = PSW^3; sbit OV = PSW^2; sbit P = PSW^0; //8052 only/* TCON */ sbit TF1 = TCON^7; sbit TR1 = TCON^6; sbit TF0 = TCON^5; sbit TR0 = TCON^4; sbit IE1 = TCON^3; sbit IT1 = TCON^2; sbit IE0 = TCON^1; sbit IT0 = TCON^0;/* IE */ sbit EA = IE^7; sbit ET2 = IE^5; //8052 only sbit ES = IE^4; sbit ET1 = IE^3; sbit EX1 = IE^2; sbit ET0 = IE^1; sbit EX0 = IE^0;/* IP */ sbit PT2 = IP^5; sbit PS = IP^4; sbit PT1 = IP^3; sbit PX1 = IP^2; sbit PT0 = IP^1; sbit PX0 = IP^0;/* P3 */ sbit RD = P3^7; sbit WR = P3^6; sbit T1 = P3^5; sbit T0 = P3^4; sbit INT1 = P3^3; sbit INT0 = P3^2; sbit TXD = P3^1; sbit RXD = P3^0;/* SCON */ sbit SM0 = SCON^7; sbit SM1 = SCON^6; sbit SM2 = SCON^5; sbit REN = SCON^4; sbit TB8 = SCON^3; sbit RB8 = SCON^2; sbit TI = SCON^1; sbit RI = SCON^0;/* P1 */ sbit T2EX = P1^1; // 8052 only sbit T2 = P1^0; // 8052 only/* T2CON */ sbit TF2 = T2CON^7; sbit EXF2 = T2CON^6; sbit RCLK = T2CON^5; sbit TCLK = T2CON^4; sbit EXEN2 = T2CON^3; sbit TR2 = T2CON^2; sbit C_T2 = T2CON^1; sbit CP_RL2 = T2CON^0;/*------------------一下為添加部分---------------------*/#define uint unsigned int #define uchar unsigned char#define HighGear 4 #define MiddleGear 3 #define LowGear 2//電機驅動 sbit ENA = P2^0; //PWM輸入端口 sbit IN1 = P2^1; //0 sbit IN2 = P2^2; //1//超聲波 sbit Trig=P3^6; sbit Echo=P3^7;//LCD1602 sbit RS=P1^2; // 數據/命令選擇端(H/L) sbit RW=P1^1; //讀寫選擇端(H/L) sbit E=P1^0; //使能信號//紅外遙控 sbit IRIN=P3^2;// 紅外接收器端口定義,外部中斷0優先級最高#endif4.2 電機驅動及頭文件
電機驅動文件motor_driver.c:
#include "my52.h"uchar motor_gear,pwm_num;void motor_run(uchar gear) {motor_gear = gear; //擋位設置,分2,3,4檔TMOD = 0x11; //設置定時器1為工作方式1TH1 = (65536-100)/256; //裝初值,每0.1ms中斷一次TL1 = (65536-100)%256;ET1 = 1; //開定時器1中斷TR1 = 1; //啟動定時器1 }void T1_PWM() interrupt 3 {TH1 = (65536-100)/256; //裝初值TL1 = (65536-100)%256;pwm_num++;if(pwm_num == 5)pwm_num = 0;if(pwm_num <= motor_gear)ENA = 1;elseENA = 0; }電機驅動頭文件motor_driver.h
1 #ifndef __MOTOR_DRIVER_C__ 2 #define __MOTOR_DRIVER_C__ 3 extern motor_run(uchar gear); //可填2,3,4,占空比分別為0.6,0.8,1 4 #endif4.3 超聲波驅動及頭文件
超聲波驅動文件sr04_driver.c:
#include "my52.h" #include "motor_driver.h" #include <intrins.h> // _nop_()延時extern uchar InfraredGear;uint distance() //HC-SR04超聲波測距模塊工作函數 {uint dis = 0;uint time = 0;uchar i = 10;Trig = 0;//初始化Echo = 0;TMOD = 0x11;TH0=0;//給T0裝初值0TL0=0;Trig = 1;while(i--)_nop_();while(Echo==0);TR0=1;//啟動T0while(Echo==1);//等待返回信號的接收完畢time=TH0*256+TL0;//微秒dis=(time*1.7+5)/10;//340米每秒即0.34毫米每微秒,1.7=0.34/2×10,來回除2,四舍五入先乘10TR0=0;//關閉T0return dis; }void sr04_motor(uint dist) {if(dist <= 300)InfraredGear = LowGear;else if(dist > 600)InfraredGear = HighGear;elseInfraredGear = MiddleGear; }超聲波驅動頭文件sr04_driver.h:
4.4 紅外遙控驅動及頭文件
紅外遙控驅動文件infrared_driver.c:
#include "my52.h" #include "delay.h"extern uchar InfraredGear; extern uchar Flag ;uchar IrValue[4];//兩位用戶碼,一位數據碼,一位數據反碼 uchar num;void read() interrupt 0{//紅外中斷讀取檔位數據uchar j,k,t;uint i;num=0;t=IrValue[2];delay_ms(7);//起始碼前9ms為低電平,在這里等待7msif(IRIN==0){//確認真的收到信號后執行以下程序i=1000; //如果出錯利用i跳出以下等待,以免程序在這里死循環while((IRIN==0)&&(i>0)){ //等待前9ms結束delay_10us(1);i--;}if(IRIN==1){//起始碼前9ms結束,后4.5ms為高電平i=500; //用i防止死循環while((IRIN==1)&&(i>0)){//等待起始碼的后4.5ms高電平delay_10us(1);i--;}for(k=0;k<4;k++){//2個用戶碼,1個數據碼,1個數據反碼,共4個字節for(j=0;j<8;j++){ //每個字節8位,以下程序用于確定每位電平的高低i=60;while((IRIN==0)&&(i>0)){//等待0.56ms的低電平,每位前面都有0.56ms的低電平delay_10us(1); //后面高電平0.565ms(565us)為0, 1.69ms(1690us)為1i--;}i=500;while((IRIN==1)&&(i>0)){//低電平結束,高電平到來后進入,用于計算高電平持續時間delay_10us(10);//延時100usnum++;i--;if(num>30){//超出3000us(3ms),本程序出錯(最大不能超過2.25ms),返回主調函數return;}}IrValue[k]>>=1;//騰出最高位用于接收本位數據if(num>=8){//高電平持續時間大于800us,該位為1IrValue[k]|=0x80; //給最高位寫1}num=0; //計數變量清零}}}if(IrValue[2]!=~IrValue[3]){//數據位校驗IrValue[2]=t;return;}}if(IrValue[2]==69)InfraredGear=LowGear;else if(IrValue[2]==70)InfraredGear=MiddleGear;else if(IrValue[2]==71)InfraredGear=HighGear;else if(IrValue[2]==68) //切換自動模式Flag = 0;else if(IrValue[2]==67) //切換手動模式Flag = 1;else if(IrValue[2]==64) //急停IN1 = 1;else if(IrValue[2]==21)IN1 = 0; }紅外遙控驅動頭文件infrared_driver.h
1 #ifndef __INFRARED_DRIVER_C__ 2 #define __INFRARED_DRIVER_C__ 3 4 #endif4.5 液晶顯示驅動及頭文件
液晶顯示驅動文件lcd1602_driver.c:
#include "my52.h"extern uchar InfraredGear;void delays(uint i) {uchar j;while(i--)for(j=50;j>0;j--); } void write_com(uchar com) {RS=0;P0=com;delays(1);E=1;delays(1);E=0; } void write_date(uchar date) {RS=1;P0=date;delays(1);E=1;delays(1);E=0; } void lcdinit() {RW=0;E=0;write_com(0x38); //設置16X2顯示,5X7點陣,8位數據接口write_com(0x0c); //設置開顯示,不顯示光標write_com(0x06); //寫一個字符后地址指針加1write_com(0x01); //顯示清零,數據指針清零 }void display0(uint dis) //手動調速下1602顯示 {uchar g1,g2,g3,g4;g1=dis%10;g2=(dis/10)%10;g3=(dis/100)%10;g4=dis/1000;lcdinit();write_com(0x80);write_date('M');write_date('o');write_date('d');write_date('e');write_date('l');write_date(':');write_date('A');write_date('U');write_date('T');write_date('O');write_date(' ');//擋位顯示write_date(0x30+InfraredGear-1);write_com(0x80+0x40);//換行顯示write_date('D');//距離顯示write_date('i');write_date('s');write_date(':');write_date(0x30+g4);write_date(0x30+g3);write_date(0x30+g2);write_date(0x30+g1);write_date('m');write_date('m'); }void display1() {lcdinit();write_com(0x80);write_date('M');write_date('o');write_date('d');write_date('e');write_date('l');write_date(':');write_date('M');write_date('A');write_date('N');write_date('U');write_date(' ');//擋位顯示write_date(0x30+InfraredGear-1); }液晶顯示驅動頭文件lcd1602_driver.h:
#ifndef __LCD1602_DRIVER_C__ #define __LCD1602_DRIVER_C__ extern void delays(uint i); extern void write_com(uchar com); extern void write_date(uchar date); extern void lcdinit(); extern void display0(uint dis); extern void display1(); #endif4.6 延時函數及頭文件
延時函數所在文件delay.c:
#include "my52.h"void delay_ms(uint t) {uint i,j;for(i=0;i<t;i++)for(j=0;j<114;j++); }void delay_10us(uint t) //延時函數,t=1延時10us {while(t--); }4.7 主函數
#include "my52.h" #include "motor_driver.h" #include "sr04_driver.h" #include "delay.h" #include "lcd1602_driver.h" #include "infrared_driver.h"uchar InfraredGear = LowGear;//手動調節擋位,紅外驅動文件中改變該值 uchar Flag = 0;//自動0/手動1模式void main() {uint dis;ENA = 1;IN1 = 0;IN2 = 1;EA = 1;//開總中斷EX0 = 1; //開外部中斷0,接收紅外信號while(1){if(Flag == 0) //自動{dis = distance(); //超聲波測距sr04_motor(dis); //根據距離調節擋位motor_run(InfraredGear);display0(dis); //液晶顯示delay_ms(100); //延時,每100ms更新一次數據}else{motor_run(InfraredGear); //手動調節轉速display1(); //液晶顯示delay_ms(100); //延時,每100ms更新一次液晶內容}} }5 最后
總結
以上是生活随笔為你收集整理的毕业设计 超声波红外自动调速风扇系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Saleae Logic USB逻辑分析
- 下一篇: saleae逻辑分析仪-串口