[英]Distance measurement using Ultrasonic and ATMEGA32
I'm working on a Distance measurement program using an AVR microcontroller.我正在使用 AVR 微控制器开发距离测量程序。 I use a 16x2 LCD and an ultrasonic sensor along with ATMEGA32A.
我使用 16x2 LCD 和超声波传感器以及 ATMEGA32A。 I wrote a code to display the distance from the Ultrasonic HC-SR04 on the LCD screen, but it gives me false readings, it increases the distance when the object is very near and vice versa.
我写了一个代码来在 LCD 屏幕上显示与超声波 HC-SR04 的距离,但它给了我错误的读数,当物体非常近时它会增加距离,反之亦然。 I just want an accurate reading.
我只是想要一个准确的读数。
Ultrasonic datasheet ATMEGA32A Datasheet 超声波数据表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;
}
}
I tried to change the trigger pin definition and define it in the code itself but still no progress.我试图更改触发器引脚定义并在代码本身中定义它,但仍然没有进展。
Update: I changed a bit more in the code but I'm getting hex values when the distance is more than 9, for example, 10 is being displayed as 1e.更新:我在代码中做了更多更改,但当距离大于 9 时,我得到了十六进制值,例如,10 显示为 1e。
This is for initialise function这是用于初始化功能
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);
}
You are sending pulses at a very rapid rate (determined solely by the display update time), and they are asynchronous to the time/counter reset.您正在以非常快的速率发送脉冲(仅由显示更新时间决定),并且它们与时间/计数器重置异步。 You have no idea which pulse triggered the interrupt and it did not start at the same time as the timer.
您不知道哪个脉冲触发了中断,并且它没有与定时器同时启动。
I would suggest that you reset the counter at the start of the pulse, and capture the counter value on interrupt.我建议您在脉冲开始时重置计数器,并在中断时捕获计数器值。 When the time has exceeded the maximum range, send a new pulse:
当时间超过最大范围时,发送一个新的脉冲:
First define some constants:首先定义一些常量:
#define PULSES_PER_CMx100 (F_CPU * 100 / 68600)
#define MAX_RANGE_CM 300
#define MAX_RANGE_COUNT ((MAX_RANGE_CM * PULSES_PER_CMx100) / 100)
Then your measure/display loop might look like:然后你的测量/显示循环可能看起来像:
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 ;
}
}
And the ISR:和情报服务侦察:
ISR(INT0_vect)
{
pulse = TCNT1; // Capture time on interrupt
GICR &= ~(1<<INT0) ; // Disable further interrupts
}
Now bear in mind that that method will take measurements as fast as possible and since you are displaying them for human reading, that is rather unnecessary.现在请记住,该方法将尽可能快地进行测量,并且由于您正在显示它们以供人类阅读,因此这是不必要的。 You might simply put a delay in the loop - making the pulse timeout unnecessary, or better you could take the mean of multiple measurements to get a more robust measurement, or use a moving average window, with outlier rejection.
您可以简单地在循环中放置一个延迟 - 使脉冲超时变得不必要,或者更好的是您可以采用多次测量的平均值以获得更可靠的测量,或者使用移动平均窗口,并拒绝离群值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.