HC-SR04

简介

HC-SR04超声波模块可提供2cm~400cm的距离感测功能,测量精度可以达到3mm。模块包括超声波发射器,接收器与控制电路。

基本工作原理

1) 采用Trig引脚触发,给至少10us的高电平脉冲信号
2) 模块自动发送8个40kHz的方波,自动检测是否有信号返回
3) 有信号返回,通过Echo引脚输出一个高电平脉冲,高电平脉冲持续的时间就是超声波从发射到反射返回的时间。距离=(高电平脉冲时间*340)/2

实物图与电气参数

超声波模块_寄存器

实际操作

下面这个代码其实只要PORTA.0不断输出10us以上的高电平脉冲信号就行了,多余的加上了通过OCR0(PORTB.3)输出40kHz的方波的功能。

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 2015-9-6
Author :
Company :
Comments:


Chip type : ATmega16L
Program type : Application
Clock frequency : 12.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/

#include <mega16.h>
#include <delay.h>

// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{

}

void main(void)
{
PORTB=0x00;
DDRB=0x08;
PORTA = 0x00;
DDRA = 0x01;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 12000.000 kHz
// Mode: CTC top=OCR0
// OC0 output: Toggle on compare match
TCCR0=0x19;
TCNT0=0x00;
OCR0=0x96;//当TCNT0达到OCR0的值,进入比较匹配中断,触发OCR0管脚取反,并且硬件清0 TCNT0,12M/0x96=40kHz

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// Global enable interrupts
#asm("sei")

//每隔1s会向超声波模块发射一次10us长度以上的高电平脉冲信号
//当超声波模块检测到反射信号之后,会在Echo引脚输出高电平脉冲信号,高电平脉冲时间长度代表发射与反射之间的时间差。
while (1)
{
PORTA.0 = 1;
delay_us(100);
PORTA.0 = 0;
delay_ms(1000);
};
}

通过示波器观察单片机给出的Trig脉冲信号(蓝色)和超声波模块接收成功的Echo脉冲信号(紫色),Trig信号在前,后面有Echo信号,Echo脉冲信号高电平时间代表发射与发射之间的时间差,可以算出传输的距离。

超声波模块_正弦波_02


TCT40-16


超声波传感器分为发送和接收两个感应器,
发送的感应器是两根脚,有大黑点的是发送引脚,可以灌给他40kHz的方波;另外一个引脚可以和外壳相连,作为地。
接收的感应器是两根脚,有大黑点的是接收引脚,接受感应器将声能转换为电信号,通过这根引脚输出;另外一个引脚和外壳相连,作为地。
当发送头非常靠近接收头的时候,接收头输出的正弦波信号幅度此时很大,随着距离慢慢变大,则接收头输出的信号幅度越来越小。


放大接收信号

超声波模块_寄存器_03


超声波接收器输出的正弦波信号幅度会随反射距离的变大而变小,所以需要对接收器输出的正弦波信号进行放大。

简单的三极管放大电路,我这里尽量将输入的正弦波信号放大到最大以致失真得到了方波类似的信号。

超声波模块_引脚_04


正如我所愿,得到的方波信号可以送到单片机的外部中断引脚,通过判断是否有上升沿来决定接收器已经接收到反射信号。


单片机代码

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 2015-9-20
Author :
Company :
Comments:


Chip type : ATmega16L
Program type : Application
Clock frequency : 12.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/

#include <mega16.h>
#include <delay.h>

unsigned char flag = 0;
unsigned char count = 0;
unsigned int times = 0;
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
count++;
if (count > 10)
{
#asm("cli")
times = TCNT1;
#asm("sei")

TCCR0 = 0x18;
TCCR1B = 0x00;

PORTA.0 = 0;
count = 0;
flag = 1;
}
}

// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
// Place your code here

}

void main(void)
{
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=Out Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=0 State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x08;
DDRA = 0x01;
PORTA = 0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 12000.000 kHz
// Mode: CTC top=OCR0
// OC0 output: Toggle on compare match
TCCR0=0x18; //T0 timer启动控制
TCNT0=0x00;
OCR0=0x96;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 12000.000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00; //T1 timer启动控制
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: Off
// INT2: Off
GICR|=0x40;
MCUCR=0x03;
MCUCSR=0x00;
GIFR=0x40;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x4D;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;

// Global enable interrupts
#asm("sei")

while (1)
{
#asm("cli")
TCNT1 = 0x0000;
#asm("sei")
TCCR0 = 0x19;
TCCR1B = 0x02;//来自clk(12000kHz)的8分频,即1500kHz
PORTA.0 = 1;
flag = 0;
while(!flag);

UDR = times >> 8;
while(!(UCSRA & (1 << 5)));
UDR = times % 256;
while(!(UCSRA & (1 << 5)));
UDR = ' ';
while(!(UCSRA & (1 << 5)));

delay_ms(1000);
delay_ms(1000);
};
}

系统流程图:

超声波模块_寄存器_05


1、设置T0定时器使输出40kHz的信号供给超声波发生器

PORTB=0x00; 
DDRB=0x08; //配置OC0(PB3)引脚输出
TCCR0=0x18; //控制T0 timer启动
TCNT0=0x00;
OCR0=0x96; //比较匹配输出,OC0引脚输出40kHz的方波信号

2、设置T1定时器进行计数

TCCR1A=0x00;

TCCR1B=0x00; //控制T1 timer启动

TCNT1H=0x00; 
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

3、添加INT0中断配置和中断处理函数

GICR|=0x40; 
MCUCR=0x03;
MCUCSR=0x00;
GIFR=0x40;
interrupt [EXT_INT0] void ext_int0_isr(void)
{

4、PORTA.0引脚

PORTA.0引脚,当超声波发射器发射信号时拉高,当超声波接收器接收到信号后拉低,高电平时间代表发射的时间。

5、TCNT1

T1定时器的计数值的寄存器,在读取TCNT1时要注意关闭所有中断,因为TCNT1是16位的寄存器,高8位的读写和TEMP寄存器相关,容易被中断打断导致TEMP寄存器值在读写前后不一样。


实验

红色的代表PORTA.0引脚,当超声波发射器发射信号时拉高,当超声波接收器接收到信号后拉低,高电平时间代表发射的时间。

蓝色的是超声波接收信号经过三极管放大之后的信号。由于时间轴的原因示波器这么显示,如果将时间轴拉开就是一个一个方波信号。

超声波模块_引脚_06

超声波模块_引脚_07

超声波模块_正弦波_08

以上3幅图分别对应的串口输出是06A2,09BA,1298
第一幅图输出的06A2,可以计算传输距离:
0x06A2/1500kHz/s=1.132ms
而由于在INT0中计算第10个接收信号的方波(40kHz),浪费的时间是25us * 10 = 250us
所以传输的距离:(1.132ms - 250us) * 340M/s = 29.988cm
最终距离为:29.988/2 = 14.994cm


实物图

超声波模块_引脚_09