簡體   English   中英

使用超聲波和 ATMEGA32 進行距離測量

[英]Distance measurement using Ultrasonic and ATMEGA32

我正在使用 AVR 微控制器開發距離測量程序。 我使用 16x2 LCD 和超聲波傳感器以及 ATMEGA32A。 我寫了一個代碼來在 LCD 屏幕上顯示與超聲波 HC-SR04 的距離,但它給了我錯誤的讀數,當物體非常近時它會增加距離,反之亦然。 我只是想要一個准確的讀數。

超聲波數據表ATMEGA32A 數據表在此處輸入圖像描述

#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM