C語言微控制器專案實戰超聲波雷達測距
本實驗是基於MSP430利用HC-SR04超聲波感測器進行測距,測距範圍是3-65cm,講得到的資料顯示在LCD 1602液晶屏上。
模組工作原理如下
(1)採用 IO 觸發測距,給至少 10us 的高電平訊號;
(2)模組自動傳送 8 個 40khz 的方波,自動檢測是否有訊號返回;
(3)有訊號返回,通過 IO 輸出一高電平,高電平持續的時間就是超聲波從發射到返回的時間
(4計算測試距離測試距離=(高電平時間*聲速(340M/S))/2;
根據工作原理,我們可以選擇兩種模式驅動
1. 採用中斷+定時器方式,將ECHO定義為上升沿下降沿都能觸發中斷,trig觸發之後,echo高電平進中斷開啟定時器,echo低電平關閉定時器並統計定時器計數值
2. 採用普通IO+定時器模式,觸發之後等待echo響應,響應時開啟定時器,直到echo恢復低關閉定時器,獲取時間
此處我採用的是第一種模式,利用MSP430的timerA 的捕獲比較模式,在程式的中斷中處理得到的資料,並轉化成距離。
1:此模組不宜帶電連線,如果要帶電連線,則先讓模組的 Gnd 端先連線。否則會影響
模組工作。
2:測距時,被測物體的面積不少於0.5平方米且要儘量平整。否則會影響測試結果。在下載程式的時候建議將連線echo的一端斷開,避免出現不必要的問題。
可以參考這個視訊資料
/**********************************************************下邊是程式碼***************************************************/
//功能說明: 1602顯示 超聲波模組測距 串列埠傳送至上位機 #include #include "Config.h" #include "1602.c" #include "UART.h" int count = 0; int flag = 0; #define uchar unsigned char #define uint unsigned int /***************????*******************************/ #define trig_H P2OUT|=BIT0 //???? #definetrig_L P2OUT&=~BIT0 #define echo P2IN & BIT1 //???? uint cnt; unsigned long int tim_data,dista_data,dista_data_all,dista_data_sum; /***************??*******************************/ void delay(uint n) { uchar i; for(;n>0;n--) for(i=10;i>0;i--); } /********************??,????????***************/ void dista_f(unsigned long int distance_data) { dista_data_all=dista_data_all+distance_data; cnt=cnt+1; if(cnt==16) { cnt=0; dista_data_sum=dista_data_all>>4; dista_data_all=0; LCD1602_write_double(13,1,dista_data_sum); //?1602????? LCD1602_write_char(14,1,'m'); LCD1602_write_char(15,1,'m'); //Print_float(dista_data_sum, 2); } } /**************???io?********************/ void Init_IO() { P2DIR = 0XFD; P2OUT |= 0XFF; P2IE |= BIT1; //??P2???? P2IES &=~BIT1; //???????? } /**************??????******************/ void Init_Timer() { TACTL|=TACLR+TASSEL_2+ID_3; //???A??? //TACTL |= TASSEL1 + TACLR + ID0 + ID1 + MC0 + TAIE; //TACCR0 = 9999; } void InitTimerB(){ TBCTL=TBSSEL1+ID1+ID0+MC0+TBCLR;//選擇1/8SMCLK 增計數 清除TAR TBCCTL0=CCIE;//CCR0中斷允許 比較模式 TBCCR0=10000;//時間間隔10ms } /************???**************************/ void main( void ) { WDTCTL = WDTPW + WDTHOLD; //????? Clock_Init(); InitTimerB(); Init_IO(); UART_Init(); Start_1602(); //??1602 tim_data=0;cnt=0;dista_data=0; delay(1000); //???? uchar string[] = "distance:"; LCD1602_write_str(0, 0, string); _EINT(); //????? while(1) { /*if(flag == 1) { Print_float(dista_data_sum, 2); flag = 0; }*/ trig_H; //????? delay(2); //??15us trig_L; //????? delay(50); //???? while(echo); //???? delay(1000); //???? } } /*****************************P2???*******************/ #pragma vector=PORT2_VECTOR __interrupt void port_init(void) { if(echo) //????? { TACTL|=TACLR+TASSEL_2+ID_3; TACTL|=MC_2; //?????,????????? P2IES|=BIT1; //??P2?????? } else //????? { TACTL=0; //????,???? TACTL|=TASSEL_2+ID_3; P2IES&=~BIT1; //??P2?????? tim_data=TAR; //???? dista_data=(tim_data*1000/58); //?????(??=us/58) //dista_data=(tim_data*17/100); dista_f(dista_data); //?????? } P2IFG&=~BIT1; // P2??????? } #pragma vector=TIMERB0_VECTOR __interrupt void TimerBINT() { count++; if(count>=300) { Print_float(dista_data_sum, 2); //flag = 1; count = 0; } }
/*********************************clock.c**********************************/ //**************************************************** //*************時鐘源模組 //**************************************************** #include #include "config.h" #include "clock.h" /********************系統時鐘初始化****************/ void init_clk(void) //初始化系統時鐘 { uchar i; BCSCTL1 &=~XT2OFF; //開啟XT2振盪器 BCSCTL2 |=SELM_2+SELS; do { IFG1 &=~OFIFG; //清除錯誤標誌 for(i=0;i<0xff;i++); //延時等待 } while((IFG1 & OFIFG)!=0); IFG1 &=~ OFIFG; }
/*******************************************1602.c***********************************/ #include #include "Config.h" #include "clock.h" #include "1602.h" //************************************************************************* // 初始化IO口子程式 //************************************************************************* void LCD1602Port_init() { P4SEL = 0x00; P4DIR = 0xFF; //資料口輸出模式 P5SEL = 0x00; P5DIR|= BIT5 + BIT6 + BIT7; //控制口設定為輸出模式 } //*********************************************************************** // 顯示屏命令寫入函式 //*********************************************************************** void LCD1602_write_com(unsigned char com) { RS_CLR; RW_CLR; EN_SET; DataPort = com; //命令寫入埠 delay_ms(5); EN_CLR; } //*********************************************************************** // 顯示屏資料寫入函式 //*********************************************************************** void LCD1602_write_data(unsigned char data) { RS_SET; RW_CLR; EN_SET; DataPort = data; //資料寫入埠 delay_ms(5); EN_CLR; } //*********************************************************************** // 顯示屏清空顯示 //*********************************************************************** void LCD1602_clear(void) { LCD1602_write_com(0x01); //清螢幕顯示 delay_ms(5); } //*********************************************************************** // 顯示屏字串寫入函式 //*********************************************************************** void LCD1602_write_str(unsigned char x,unsigned char y,unsigned char *s) { if (y == 0) { LCD1602_write_com(0x80 + x); //第一行顯示 } else { LCD1602_write_com(0xC0 + x); //第二行顯示 } while (*s) { LCD1602_write_data( *s); s ++; } } //*********************************************************************** // 顯示屏單字元寫入函式 //*********************************************************************** void LCD1602_write_char(unsigned char x,unsigned char y,unsigned char data) { if (y == 0) { LCD1602_write_com(0x80 + x); //第一行顯示 } else { LCD1602_write_com(0xC0 + x); //第二行顯示 } LCD1602_write_data( data); } //*********************************************************************** // 顯示屏初始化函式 //*********************************************************************** void LCD1602_init(void) { LCD1602_write_com(0x38); //顯示模式設定 delay_ms(5); LCD1602_write_com(0x08); //顯示關閉 delay_ms(5); LCD1602_write_com(0x01); //顯示清屏 delay_ms(5); LCD1602_write_com(0x06); //顯示游標移動設定 delay_ms(5); LCD1602_write_com(0x0C); //顯示開及游標設定 delay_ms(5); } void LCD1602_write_double(unsigned char x,unsigned char y,unsigned int data) { uchar i; for(i=0;i<6;i++) { if(i==2) LCD1602_write_char( x--, y, '.'); else { LCD1602_write_char( x--, y, 0x30+data%10); data=data/10; } } } void LCD1602_write_int(unsigned char x,unsigned char y,unsigned int data) { uchar i; for(i=0;i<2;i++) { LCD1602_write_char( x--, y, 0x30+data%10); data=data/10; } } void Start_1602() { LCD1602Port_init(); //系統初始化,設定IO口屬性 delay_ms(100); //延時100ms LCD1602_init(); //液晶引數初始化設定 }
uart.h #ifndef _UART_H_ #define _UART_H_ #include "msp430x14x.h" void Print_Str(uchar *s); //************************************************************************* // MSP430????? //************************************************************************* void UART_Init() { U0CTL|=SWRST + CHAR; //??SWRST,8????? U0TCTL|=SSEL1; //SMCLK????? U0BR1=baud_h; //BRCLK=8MHZ,Baud=BRCLK/N U0BR0=baud_l; //N=UBR+(UxMCTL)/8 U0MCTL=0x00; //??????0,???9600bps ME1|=UTXE0; //UART0???? ME1|=URXE0; //UART0???? U0CTL&=~SWRST; IE1|=URXIE0; //??????? P3SEL|= BIT4 + BIT5; //??IO????????,??UART?? P3DIR|= BIT4; //??TXD0?????? } //************************************************************************* // ??0?????? //************************************************************************* void Send_Byte(uchar data) { while(!(IFG1&UTXIFG0)); //????????????? U0TXBUF=data; } //***************************************// void Print_float(unsigned int t, unsigned char position)//????? position ??????? { unsigned int s_int[5] = {0}; int i = 0; while(t>0) { s_int[i++] = t%10; t=t/10; } for(i=4;i>=0;i--) { if(i==position) { Send_Byte(0x30 + s_int[i]); Send_Byte(0x2E); } else { Send_Byte(0x30 + s_int[i]); } } //delay_ms(100); Send_Byte('m'); Send_Byte('m'); Send_Byte(' '); delay_ms(100); } //************************************************************************* // ??0??int??? //************************************************************************* void Print_int(unsigned int t) { unsigned int s_int[5]; unsigned int i = 1; while(t>0) { s_int[i] = t%10; t=t/10; i++; } i--; while(i) { Send_Byte(0x30 + s_int[i]); i--; } } //************************************************************************* // ??0??????? //************************************************************************* void Print_Str(uchar *s) { while(*s != '\0') { Send_Byte(*s++); } } #endif
也歡迎進球球裙技術交流
點選連結加入群聊【嵌入式微控制器LinuxC交流群②】https://jq.qq.com/?_wv=1027&k=FW2qSMZ4