📡 Sensor Ultrasónico HC-SR04

Cómo funciona, cómo se programa y qué corregir en el código

1 ¿Cómo funciona?

El sensor funciona como un murciélago: grita un sonido que no podemos oír (ultrasonido), espera a que rebote en un objeto y mide cuánto tardó en regresar.

Diagrama de tiempo Trigger 10 µs Ultrasonido 8 ciclos a 40 kHz (lo hace el sensor solo) Echo tiempo ← esto mide pulseIn()

La fórmula

distancia = tiempo × velocidad del sonido ÷ 2

velocidad del sonido = 343 m/s = 0.0343 cm/µs
÷ 2 porque el sonido va y regresa

distancia = tiempo × 0.0343 ÷ 2 = tiempo × 0.01715

Ejemplo: si el eco tardó 1166 µs → 1166 × 0.01715 = 20 cm.

2 Conexión al Arduino UNO

Pin del sensorPin del ArduinoPara qué sirve
VCC5VAlimentación
Trig2Recibe el pulso de disparo (salida del Arduino)
Echo3Devuelve el pulso con el tiempo (entrada del Arduino)
GNDGNDTierra

⚠️ En el código original el Echo estaba en A4. Funciona, pero A4 es el pin SDA del I2C (el que usan las pantallas LCD I2C). Por eso se recomienda el pin 3.

3 Código original con comentarios

El código sí funciona en condiciones normales. Estos comentarios marcan qué está bien y qué hay que cambiar:

✅ Correcto ⚠️ Mejora ❌ Error
codigo_original.ino
float tiempo;                    // ⚠️ CAMBIAR POR: unsigned long tiempo;  (#1)
float distancia;                 // ✅ Correcto: la distancia sí lleva decimales

void setup() {
  Serial.begin(115200);          // ✅ Correcto (Monitor Serie también en 115200)
  pinMode(2, OUTPUT);            // ✅ Correcto: Trig es salida
  pinMode(A4, INPUT);            // ⚠️ CAMBIAR POR: pinMode(3, INPUT);  (#2)
}

void loop() {
  digitalWrite(2, LOW);          // ✅ Correcto: Trig arranca en LOW
  delayMicroseconds(2);          // ✅ Correcto
  digitalWrite(2, HIGH);         // ✅ Correcto: inicia el pulso
  delayMicroseconds(10);         // ✅ Correcto: 10 us que pide la hoja de datos
  digitalWrite(2, LOW);          // ✅ Correcto: termina el pulso
  tiempo = pulseIn(A4, HIGH);    // ❌ CAMBIAR POR: tiempo = pulseIn(3, HIGH, 30000);  (#3)
  distancia = 0.01715 * tiempo;  // ✅ Correcto: (343 m/s ÷ 2) en cm/us
  Serial.println(distancia);     // ✅ Correcto

 if (distancia <=30){            // ❌ CAMBIAR POR: if (tiempo > 0 && distancia <= 30){  (#4)
    Serial.println("OBJETO EN ZONA DE 30cm");
  }
                                 // ❌ AGREGAR AQUÍ: delay(60);  (#5)
}

4 Tabla de cambios: qué, por qué y por cuál

#Línea originalReemplazar por¿Por qué?Tipo
1 float tiempo; unsigned long tiempo; pulseIn() entrega microsegundos: un número entero y siempre positivo. La documentación oficial de Arduino dice que su tipo es unsigned long. float es para números con decimales, y el tiempo nunca los trae.
🧠 Es como guardar litros en una caja de kilos: cabe, pero no es su lugar.
Mejora
2 pinMode(A4, INPUT); pinMode(3, INPUT); A4 sí sirve como pin digital, pero en el UNO es el pin SDA de la comunicación I2C. Si después se conecta una pantalla LCD I2C, choca con el sensor.
🔌 Hay que mover el cable de Echo de A4 al pin 3.
Mejora
3 tiempo = pulseIn(A4, HIGH); tiempo = pulseIn(3, HIGH, 30000); Sin el tercer número, pulseIn espera hasta 1 segundo si no llega el eco, y el programa se congela. Con 30000 espera máximo 30 ms, que alcanza para unos 5 m, más que el máximo del sensor (4 m). Error
4 if (distancia <=30){ if (tiempo > 0 && distancia <= 30){ Si el eco no llega (cable flojo, sensor dañado), pulseIn devuelve 0. Entonces distancia = 0, y como 0 ≤ 30, imprime "OBJETO EN ZONA" sin que haya nada. Con tiempo > 0 se ignoran esas lecturas falsas. Error
5 (no existe) delay(60); La hoja de datos del HC-SR04 recomienda más de 60 ms entre mediciones, para que los rebotes del pulso anterior no se confundan con el nuevo. También evita que el Monitor Serie se llene tan rápido que no se pueda leer. Error

❌ La falla más importante (#4), paso a paso:

Cable de Echo flojo→ tiempo = 0→ distancia = 0.01715 × 0 = 0→ 0 <= 30 ✔→ FALSA ALARMA

Error = puede dar lecturas falsas. Mejora = funciona igual, pero es la forma correcta o evita problemas en proyectos futuros.

5 Código final, ya corregido

Igual de sencillo que el original, solo con los 5 cambios:

codigo_corregido.ino
unsigned long tiempo;            // #1: antes float
float distancia;

void setup() {
  Serial.begin(115200);
  pinMode(2, OUTPUT);            // Trig
  pinMode(3, INPUT);             // #2: Echo, antes A4 (mover el cable)
}

void loop() {
  digitalWrite(2, LOW);
  delayMicroseconds(2);
  digitalWrite(2, HIGH);
  delayMicroseconds(10);
  digitalWrite(2, LOW);
  tiempo = pulseIn(3, HIGH, 30000);    // #3: timeout de 30 ms
  distancia = 0.01715 * tiempo;
  Serial.println(distancia);

  if (tiempo > 0 && distancia <= 30){  // #4: ignora lecturas en 0
    Serial.println("OBJETO EN ZONA DE 30cm");
  }

  delay(60);                           // #5: pausa entre mediciones
}

6 Prueba para hacer en clase

Así los alumnos ven la diferencia en lugar de solo creerla:

✅ Conclusión: el código original funciona, pero no se protege de errores. Los cambios separan un código que "funciona en la demo" de uno confiable.