Ultrasonic Sensor

A guide to interfacing the HC-SR04 ultrasonic sensor with an STM32F072 Nucleo board.
Working Principle
Background on ultrasonic sensing: These are devices that use sound waves to detect objects and measure distances. This module contains a transmitter capable of emitting high frequency sound (40kHz). If an object is placed on the path of the travelling wave, it will be reflected back to the sensor. This reflection is caught by the receiver present on the module. The duration between transmission and reception of the signal is used to calculate the distance to the object.
Specifications
From the datasheet - HC-SR04
Range: 2cm to 400cm
Working voltage: 5V
Working current: 15mA
Measuring angle: 15 deg
Analyzing the circuit
I’m adding this section because I came across an interesting article by Emil’s Projects & Reviews who has reverse engineered the schematics of this device. The main components used in this circuit are:
Piezoelectric Transducers: Electrical signals are converted into mechanical vibrations to generate ultrasonic pulses. The signal caught by the receiver is in the range of mVs which is why an OPAMP is required for amplification
Level shifter: An IC like the MAX232 is used to produce +/-10V from the regular 5V. The main function of this chip is the conversion of the logic levels from TTL to its corresponding RS232 levels and vice versa. It is used for serial communication between TTL devices like microcontrollers (0V to 5V) and PC which operates according to RS232 which ranges between -25V to +25V. In context of the ultrasonic sensor, a high voltage pulse is required to drive the transducer to emit pulses which is why it is used as a level shifter.
OPAMP: Used on the receiver end to compare and amplify the received signals. In transmission mode, the comparator essentially ignores the transmitted pulses to prevent mistakenly picking up these signals. Once the ECHO signal is set, the comparator starts listening for pulses.
Microcontroller: The main control hub. Coordinates the entire process of transmission and reception. Receives the trigger pulse sent by external source, triggers the level shifter to apply voltage to the transducer for pulse generation, sets the ECHO pin on reception of signal.
Connections
Vcc: +5V
TRIG: Trigger input of sensor. Apply a 10us pulse to this pin to trigger the HC-SR04.
ECHO: Echo output of sensor. Capture the rising edge of this signal and begin timer till the falling edge.
GND: Ground
Timing Diagram
Start Condition: The TRIGGER pin receives a 10us high pulse from an external controller
This will trigger the HCSR04 module microcontroller to send the 8 cycle pulse.
The ECHO pin will be pulled high until the reflection is received by the transducer.
Distance (d) of the object can be calculated using the duration (t) of ECHO pin in logic high state and the speed of sound (s).
$$Distance(d) = {{Time(t)\times Speed(s)}\over 2}$$
$$Time = \text {Duration of high pulse at ECHO pin $$
$$\text {Speed of Sound} = 343 m/s$$
Distance is divided by two since it covers both transmission and reception duration.
Code Overview
void gpioInit()
Enable GPIOA peripheral clock
Set PA 4 in output mode
Set PA6 in input mode
void gpioInit() {
RCC->AHBENR |= (1<<17);
// PA 4 Trigger
GPIOA->MODER |= (1U<<(2*4));
// PA 6 Echo
GPIOA->MODER &= ~(3U<<(2*6));
}
timerInit()
Enable the TIMER 14 (16 bit timer) peripheral clock.
Set up the prescalar to generate 1us per counter tick.
Begin timer
void timerInit() {
/*
* TIMER 14
* 16 bit
* PSC = 8-1
* F = 8MHz
* ARR = 65536
*/
RCC->APB1ENR |= (1U<<8);
TIM14->PSC = 7;
TIM14->ARR = 0xFFFF;
TIM14->CR1 |= (1U<<0);
}
getCount()
- Returns the current count value of the timer
uint16_t getCount(void) {
return TIM14->CNT; // Return the current timer counter value
}
delay_us(uint16_t us)
- Generate a delay in us -> each tick is 1us
void delay_us(uint16_t us) {
TIM14->CNT = 0x0; // Reset the timer counter
while (getCount() < us); // Wait until the counter reaches the desired value
}
void distance()
- Returns the distance in centimeters.
void getDistance() {
int16_t time = 0;
while(!(GPIOA->IDR & (1U<<6)));
while((GPIOA->IDR & (1U<<6))) // Wait till ECHO pin is HIGH
{
time++;
delay_us(1);
}
int distance = time/55;
delay_us(10000000); // 10s delay
}
main()
int main(){
gpioInit(); // Initialize GPIO for TRIG and ECHO
timerInit(); // Initialize the timer
while (1) {
// Trigger the ultrasonic sensor
TRIG_PORT->ODR |= (1U<<4); // Set TRIG pin HIGH
delay_us(10); // Wait for 10 microseconds
TRIG_PORT->ODR &= ~(1U<<4); // Set TRIG pin LOW
getDistance();
}
References
These are links to resources I used.
Subscribe to my newsletter
Read articles from asher directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
