Simulating ultrasonic ranging in Proteus with an 80C52 microcontroller requires precise timing to capture the ECHO pulse duration. This implementation utilizes a crystal frequency of 11.0592 MHz and leverages the hardware GATE control feature of the 8051 timers to measure the high-level duration of the pulse without CPU-intensive polling.
Measurement Principle
The HC-SR04 sensor triggers a measurement when a pulse of at least 10 microseconds is applied too the TRIG pin. Following this, the sensor emits eight 40 kHz ultrasonic bursts. The ECHO pin transitions to a high state at the start of the transmission and returns to low once the reflected signal is detected. The duration of this high signal represents the total travel time of the sound wave.
Efficient Pulse Capture with Hardware Gating
Instead of busy-waiting for the ECHO pin to toggle, which wastes CPU cycles, the 8051 Timer 0 can be configured in GATE mode. When the GATE bit (TMOD.3) is set, Timer 0 only increments if the TR0 bit is high AND the INT0 (P3.2) pin is high. By connecting the ECHO signal to P3.2 and configuring an external interrupt for the falling edge, we can accurately capture the pulse duration in hardware.
Hardware Logic Implementation
The following code demonstrates how to initialize the measurement and process the timing results using interrupts.
#include <reg52.h>
#include <intrins.h>
sbit HC_TRIG = P2^7;
sbit HC_ECHO = P3^2; // Connected to INT0
unsigned int capture_ticks = 0;
bit measure_ready = 0;
bit pulse_active = 0;
// External Interrupt 0 handles the end of the ECHO pulse
void echo_falling_edge_isr() interrupt 0 {
TR0 = 0; // Stop Timer 0
capture_ticks = (TH0 << 8) | TL0;
measure_ready = 1;
EX0 = 0; // Disable interrupt until next trigger
}
// Timer 2 controls the polling interval (approx. 200ms)
void refresh_timer_isr() interrupt 5 {
static unsigned char tick_count = 0;
TF2 = 0;
if (++tick_count >= 20) {
tick_count = 0;
pulse_active = 0;
TR2 = 0;
}
}
void trigger_ultrasonic() {
if (pulse_active) return;
// Reset Timer 0 state
TR0 = 0;
TMOD &= 0xF0;
TMOD |= 0x09; // Mode 1 (16-bit), GATE enabled
TH0 = 0;
TL0 = 0;
// Prepare External Interrupt 0 for falling edge
IT0 = 1;
IE0 = 0;
EX0 = 1;
// Start interval timer (Timer 2)
T2CON = 0;
RCAP2H = 0xDC; RCAP2L = 0x00; // 10ms at 11.0592MHz
TH2 = 0xDC; TL2 = 0x00;
ET2 = 1;
TR2 = 1;
// Fire Trigger Pulse
HC_TRIG = 1;
_nop_(); _nop_(); _nop_(); _nop_(); // Minimal delay
HC_TRIG = 0;
TR0 = 1; // Timer 0 starts when ECHO goes high via GATE
pulse_active = 1;
measure_ready = 0;
}
void main() {
unsigned int raw_val;
float cm_dist;
// UART and Global Interrupt setup
EA = 1;
while(1) {
trigger_ultrasonic();
if (measure_ready) {
// Distance calculation logic:
// Each tick = 12 / 11059200 Hz ≈ 1.085 us
// Speed of sound factor ≈ 58 us/cm
cm_dist = ((float)capture_ticks * 1.085f) / 58.0f;
measure_ready = 0;
// Result can now be sent to display or UART
}
}
}
Calculation and Scaling
With a crystal frequency of 11.0592 MHz, one machine cycle takes approximately 1.085 microseconds. To convert the timer ticks into centimeters, the formula applied is (ticks * 1.085) / 58. The constant 58 is derived from the speed of sound at standard temperature (approx. 340m/s), where 1 centimeter of distance requires a round-trip time of 58 microseconds. This hardware-gated approach ensures high accuracy while minimizing the impact on other system tasks during the measurement window.