[英]Distance measurement using Ultrasonic and ATMEGA32
我正在使用 AVR 微控制器開發距離測量程序。 我使用 16x2 LCD 和超聲波傳感器以及 ATMEGA32A。 我寫了一個代碼來在 LCD 屏幕上顯示與超聲波 HC-SR04 的距離,但它給了我錯誤的讀數,當物體非常近時它會增加距離,反之亦然。 我只是想要一個准確的讀數。
#include <avr/io.h>
#include <avr/interrupt.h>
#include <MrLcd/MrLCDmega32.h>
#define F_CPU 1000000
#include <util/delay.h>
#include <stdlib.h>
#define Trigger_pin PD0 /* Trigger pin */
static volatile int pulse = 0;
static volatile int i = 0;
int main(void)
{
Initialise();
DDRD = 0b11111011;
_delay_ms(50);
GICR |= 1<<INT0;
MCUCR |= 1<<ISC00;
int16_t count_a = 0;
char show_a[16];
sei();
while(1)
{
PORTD |= (1<<Trigger_pin);
_delay_us(10);
PORTD &= ~(1<<Trigger_pin);
count_a = pulse/58;
Send_A_String("Distance Sensor");
GoToMrLCDLocation(1,2);
Send_A_String("Distance=");
itoa(count_a,show_a,10);
Send_A_String(show_a);
Send_A_String(" ");
GoToMrLCDLocation(13,2);
Send_A_String("cm");
GoToMrLCDLocation(1,1);
}
}
ISR(INT0_vect)
{
if(i == 1)
{
TCCR1B = 0;
pulse = TCNT1;
TCNT1 = 0;
i = 0;
}
if(i==0)
{
TCCR1B |= 1<<CS10;
i = 1;
}
}
我試圖更改觸發器引腳定義並在代碼本身中定義它,但仍然沒有進展。
更新:我在代碼中做了更多更改,但當距離大於 9 時,我得到了十六進制值,例如,10 顯示為 1e。
這是用於初始化功能
void Initialise(void)
{
DataDir_MrLCDsControl|=1<<LightSwitch|1<<ReadWrite|1<<BipolarMood; //these information will go towards the LCD
_delay_ms(15); // Wait for the LCD to start
Send_A_Command(0x01); // to clear the screen
_delay_ms(2);
Send_A_Command(0x38); // TO tell LCD about 8 data lines
_delay_us(50);
Send_A_Command(0b00001110); //Some cursor command
_delay_us(50);
}
您正在以非常快的速率發送脈沖(僅由顯示更新時間決定),並且它們與時間/計數器重置異步。 您不知道哪個脈沖觸發了中斷,並且它沒有與定時器同時啟動。
我建議您在脈沖開始時重置計數器,並在中斷時捕獲計數器值。 當時間超過最大范圍時,發送一個新的脈沖:
首先定義一些常量:
#define PULSES_PER_CMx100 (F_CPU * 100 / 68600)
#define MAX_RANGE_CM 300
#define MAX_RANGE_COUNT ((MAX_RANGE_CM * PULSES_PER_CMx100) / 100)
然后你的測量/顯示循環可能看起來像:
pulse = 1 ; // dummy start
GICR &= ~(1<<INT0) ; // Disable INT0
for(;;)
{
// Ready for new measurement?...
if( pulse != 0 )
{
// Send pulse and reset timer
PORTD |= (1<<Trigger_pin) ;
pulse = 0 ;
TCNT1 = 0 ;
_delay_us(10);
PORTD &= ~(1<<Trigger_pin) ;
// Wait for echo pulse interrupt...
GIFR |= 1<<INTF0; // Clear INT0 pending flag
GICR |= 1<<INT0 ; // Enable INT0
}
else // When measurement available...
{
int distance_cm = pulse * 100 / PULSES_PER_CMx100 ;
// display distance
...
}
// If out of range, timeout, send a new pulse
if( TCNT1 > MAX_RANGE_COUNT )
{
// Force a new pulse to be triggered
pulse = 1 ;
}
}
和情報服務偵察:
ISR(INT0_vect)
{
pulse = TCNT1; // Capture time on interrupt
GICR &= ~(1<<INT0) ; // Disable further interrupts
}
現在請記住,該方法將盡可能快地進行測量,並且由於您正在顯示它們以供人類閱讀,因此這是不必要的。 您可以簡單地在循環中放置一個延遲 - 使脈沖超時變得不必要,或者更好的是您可以采用多次測量的平均值以獲得更可靠的測量,或者使用移動平均窗口,並拒絕離群值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.