基于ATMEGA32A与HC-SR04的超声波测距读数异常求助
AVR单片机HC-SR04测距程序异常问题排查
问题概述
开发基于ATMEGA32A芯片的测距程序,搭配16x2 LCD与HC-SR04超声波传感器,遇到两类问题:
- 初始问题:测距读数异常,物体极近时显示距离偏大,较远时显示偏小,无法获取准确值
- 更新问题:修改代码后,距离数值大于9时,LCD显示十六进制值(例如数值10显示为
1e)
硬件配置
- 主控芯片:ATMEGA32A
- 显示模块:16x2 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; } }
Initialise初始化函数代码
void Initialise(void) { DataDir_MrLCDsControl|=1<<LightSwitch|1<<ReadWrite|1<<BipolarMood; //配置LCD控制引脚方向 _delay_ms(15); //等待LCD启动 Send_A_Command(0x01); //清屏 _delay_ms(2); Send_A_Command(0x38); //设置LCD为8位数据、2行显示模式 _delay_us(50); Send_A_Command(0b00001110); //开启显示、显示光标、光标不闪烁 _delay_us(50); }
已尝试操作
修改触发引脚定义,问题未解决
问题分析与解决建议
1. 测距读数不准问题
- 定时器配置缺失:当前仅开启定时器1的
CS10分频(无分频),但未初始化定时器模式。需在main函数初始化阶段添加TCCR1A = 0;,确保定时器处于普通计数模式,避免波形生成配置干扰计时。 - 中断触发逻辑优化:当前
MCUCR设置为任意电平变化触发INT0,易出现误触发。建议改为上升沿启动计时、下降沿停止计时,动态切换中断触发方式:ISR(INT0_vect) { if(i == 0) { TCNT1 = 0; TCCR1B |= (1<<CS10); //无分频启动定时器 //切换为下降沿触发 MCUCR &= ~(1<<ISC00); MCUCR |= (1<<ISC01); i = 1; } else { TCCR1B = 0; //停止定时器 pulse = TCNT1; //切换回上升沿触发 MCUCR &= ~(1<<ISC01); MCUCR |= (1<<ISC00); i = 0; } } - 计时精度验证:F_CPU为1MHz时,定时器1每计数1次对应1us,
距离(cm) = pulse / 58的公式正确,但需确保pulse变量未被其他逻辑篡改。
2. LCD显示十六进制值问题
- 字符串缓冲区清理:
show_a数组未手动添加结束符,残留旧数据可能导致显示异常,转换后需补充:itoa(count_a,show_a,10); show_a[3] = '\0'; //最大距离不超过400cm,最多3位数字,手动截断避免溢出 - LCD字符发送函数检查:确认
Send_A_String是否正确发送ASCII字符,而非将字符值当作十六进制指令发送。可单独测试发送固定字符串(如"10"),验证LCD是否正常显示十进制数字。
内容的提问来源于stack exchange,提问作者Anonymous Stress
相关产品推荐
相关产品推荐

