les vencimos

Arduino · Proyectos

Eagle

Eagle · AP-EAG-01

Motor adelante y atrás con puente H

Objetivo

Vas a cambiar el sentido de un motor de corriente continua con el puente H L298N. Combinarás las dos entradas lógicas para avanzar, parar y retroceder, y separarás la alimentación del motor de la lógica de la placa. El motor va de 5 a 12 V en corriente continua. No conmutas la red de casa: este puente no debe ver la instalación eléctrica doméstica.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Placa de referencia. Usa esta o el clon, no las dos a la vez.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Clon equivalente para este montaje. Misma asignación de pines.
1L298Nmodulo-l298ngenérico / clonepoco (≈1–3 €)Puente H. La lógica va a 5 V y el motor a una fuente aparte de 5 a 12 V.
1Motor DCmodulo-motor-dcgenérico / clonepoco (≈1–3 €)Motor pequeño de corriente continua, nunca un motor de red.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D7 Uno D8 Uno D9 Uno 5 V Uno GND Fuente externa de 5 a 12 V L298N IN1 L298N IN2 L298N ENA L298N pin de lógica 5 V L298N GND Bornes de potencia del L298N

Código

// AP-EAG-01 Motor adelante y atras con puente H
// Pines: D7 IN1, D8 IN2, D9 ENA
const int PIN_IN1 = 7;
const int PIN_IN2 = 8;
const int PIN_ENA = 9;
const unsigned long TRAMO_MS = 2000;

void parar() {
  digitalWrite(PIN_IN1, LOW);
  digitalWrite(PIN_IN2, LOW);
  digitalWrite(PIN_ENA, LOW);
}

void sentido(bool adelante) {
  digitalWrite(PIN_ENA, HIGH);
  digitalWrite(PIN_IN1, adelante ? HIGH : LOW);
  digitalWrite(PIN_IN2, adelante ? LOW : HIGH);
}

void setup() {
  pinMode(PIN_IN1, OUTPUT);
  pinMode(PIN_IN2, OUTPUT);
  pinMode(PIN_ENA, OUTPUT);
  parar();
  Serial.begin(9600);
  Serial.println(F("Puente H listo. Motor de 5 a 12 V, sin red."));
}

void loop() {
  unsigned long fase = (millis() / TRAMO_MS) % 4;
  if (fase == 0) {
    sentido(true);
    Serial.println(F("adelante"));
  } else if (fase == 2) {
    sentido(false);
    Serial.println(F("atras"));
  } else {
    parar();
    Serial.println(F("parado"));
  }
  delay(50);
}

Pasos

  1. Coloca el L298N y el motor lejos de cualquier enchufe de la red. La fuente del motor es de corriente continua, entre 5 y 12 V.
  2. Une la masa de la placa, la del puente y la de la fuente. Sin masa común el sentido se vuelve aleatorio.
  3. Conecta D7 a IN1, D8 a IN2 y D9 a ENA. Revisa que ENA no se quede al aire, porque el canal quedaría apagado.
  4. Alimenta la lógica a 5 V. Si el motor va a 5 V, retira el jumper del regulador del módulo y no uses ese regulador.
  5. Sube el sketch y abre el monitor a 9600 baudios. Debes ver adelante, parado, atrás y parado, en ese orden.
  6. Si el motor gira al revés de como esperabas, invierte los dos cables del motor en los bornes OUT1 y OUT2, no el código, y vuelve a probar.
  7. Toca el disipador tras un minuto. Si quema, el motor pide más corriente de la que este puente puede dar con holgura: baja la carga.

Variantes

Depuración

Software: digitalwrite millis serial

Eagle · AP-EAG-02

Velocidad de un motor con PWM

Objetivo

Vas a regular la velocidad del mismo motor con una señal PWM en el enable del L298N, en el pin D9 del Uno, que admite analogWrite. Verás que el sentido sigue dependiendo de IN1 e IN2, y que el ciclo de trabajo solo cambia cuánta energía media llega al motor. La potencia sigue siendo de 5 a 12 V en continua. No conmutas la red.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Misma función PWM en D9.
1L298Nmodulo-l298ngenérico / clonepoco (≈1–3 €)ENA tiene que entrar en un pin con PWM, aquí D9.
1Motor DCmodulo-motor-dcgenérico / clonepoco (≈1–3 €)Motor de continua de baja tensión, acorde con la fuente de 5 a 12 V.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D7 Uno D8 Uno D9 Uno 5 V Uno GND Fuente de 5 a 12 V L298N IN1 L298N IN2 L298N ENA L298N lógica L298N GND y fuente Bornes de potencia del L298N

Código

// AP-EAG-02 Velocidad de un motor con PWM
// Pines: D7 IN1, D8 IN2, D9 ENA (PWM)
const int PIN_IN1 = 7;
const int PIN_IN2 = 8;
const int PIN_ENA = 9;
int orden = 0;
unsigned long anterior = 0;

void setup() {
  pinMode(PIN_IN1, OUTPUT);
  pinMode(PIN_IN2, OUTPUT);
  pinMode(PIN_ENA, OUTPUT);
  digitalWrite(PIN_IN1, HIGH);
  digitalWrite(PIN_IN2, LOW);
  analogWrite(PIN_ENA, 0);
  Serial.begin(9600);
  Serial.println(F("Rampa PWM en D9. Potencia 5 a 12 V, sin red."));
}

void loop() {
  if (millis() - anterior < 30) return;
  anterior = millis();
  orden += 2;
  if (orden > 400) orden = 0;
  int ciclo = orden <= 200 ? orden : 400 - orden;
  analogWrite(PIN_ENA, ciclo);
  Serial.print(F("PWM "));
  Serial.println(ciclo);
}

Pasos

  1. Parte del cableado de la práctica anterior. No cambies IN1 e IN2 de sitio.
  2. Confirma que ENA sale de D9. En el Uno, D9 es pin de PWM; D7 y D8 no te sirven para analogWrite con la misma calidad.
  3. Alimenta el motor entre 5 y 12 V en continua y deja la lógica a 5 V. No conectes la red.
  4. Sube el sketch. El motor debe arrancar suave, subir de velocidad y volver a bajar sin saltos bruscos de alimentación.
  5. Abre el monitor a 9600 baudios y comprueba que el número PWM recorre de 0 a 200 y baja otra vez.
  6. Pon la mano cerca del eje, sin pillártela, y nota que a ciclo bajo el motor puede zumbar y no llegar a vencer el rozamiento.
  7. Si quieres el otro sentido, intercambia los niveles de IN1 e IN2 y deja el PWM en ENA.

Variantes

Depuración

Software: analogwrite pwm millis serial digitalwrite

Eagle · AP-EAG-03

28BYJ-48: una vuelta

Objetivo

Vas a dar exactamente una vuelta con el motor paso a paso 28BYJ-48 y su driver ULN2003. En paso completo, la reductora interna deja 2048 pasos por revolución: el sketch cuenta esos pasos y se detiene. El motor se alimenta a 5 V. No lo pongas a 12 V ni lo relaciones con la red; es un actuador de prácticas, pequeño y lento.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines digitales.
1Stepper 28BYJ-48modulo-28byj-48genérico / clonepoco (≈1–3 €)Motor de 5 V con reductora. 2048 pasos por vuelta en paso completo.
1ULN2003modulo-uln2003genérico / cloneirrisorio (<1 €)Placa driver que suele venir con el motor. Conector blanco hacia el motor.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D8 Uno D9 Uno D10 Uno D11 Uno 5 V Uno GND Alimentación del motor ULN2003 IN1 ULN2003 IN2 ULN2003 IN3 ULN2003 IN4 ULN2003 +5 V ULN2003 GND ULN2003

Código

// AP-EAG-03 28BYJ-48: una vuelta
// Pines: D8 IN1, D9 IN2, D10 IN3, D11 IN4
const int PINES[4] = {8, 9, 10, 11};
const int PASOS_VUELTA = 2048;
const int SECUENCIA[4][4] = {
  {1, 0, 0, 0},
  {0, 1, 0, 0},
  {0, 0, 1, 0},
  {0, 0, 0, 1}
};

void aplicar(int indice) {
  for (int b = 0; b < 4; b++) {
    digitalWrite(PINES[b], SECUENCIA[indice][b]);
  }
}

void soltar() {
  for (int b = 0; b < 4; b++) digitalWrite(PINES[b], LOW);
}

void setup() {
  for (int b = 0; b < 4; b++) pinMode(PINES[b], OUTPUT);
  soltar();
  Serial.begin(9600);
  Serial.println(F("Una vuelta: 2048 pasos a 5 V."));
  for (int n = 0; n < PASOS_VUELTA; n++) {
    aplicar(n % 4);
    delay(3);
  }
  soltar();
  Serial.println(F("Vuelta hecha. Bobinas sueltas."));
}

void loop() {
}

Pasos

  1. Encaja el conector del 28BYJ-48 en la placa ULN2003. No lo fuerces al revés.
  2. Une D8, D9, D10 y D11 con IN1, IN2, IN3 e IN4, en ese orden.
  3. Alimenta el driver a 5 V. Este modelo no es de 12 V; subirle la tensión lo calienta y puede quemar una bobina.
  4. Sube el sketch y marca con un trozo de cinta el eje de salida antes de empezar.
  5. Al resetear, el motor debe recorrer una vuelta y pararse. Las bobinas se sueltan al final para no seguir consumiendo.
  6. Si se queda corto o se pasa un poco, no es magia: la holgura de la reductora cuenta. Vuelve a marcar y repite desde el mismo apoyo.
  7. Si vibra en el sitio, permuta IN2 e IN3 o revisa un cable suelto: la secuencia de cuatro fases está rota.

Variantes

Depuración

Software: digitalwrite serial

Eagle · AP-EAG-04

Paso a paso por grados

Objetivo

Vas a convertir un ángulo en pasos del 28BYJ-48. Con 2048 pasos por vuelta, los grados que escribas por el monitor se traducen a un número entero de pasos, con signo para el sentido. Así dejas de contar vueltas a ojo y pasas a una posición que puedes repetir. El motor sigue a 5 V, sin relación con la red.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)El monitor serie funciona igual.
1Stepper 28BYJ-48modulo-28byj-48genérico / clonepoco (≈1–3 €)2048 pasos por vuelta en el modo de este sketch.
1ULN2003modulo-uln2003genérico / cloneirrisorio (<1 €)Driver a 5 V.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D8 Uno D9 Uno D10 Uno D11 Uno 5 V Uno GND Entrada del monitor ULN2003 IN1 ULN2003 IN2 ULN2003 IN3 ULN2003 IN4 ULN2003 positivo ULN2003 GND Grados enteros con signo

Código

// AP-EAG-04 Paso a paso por grados
// Pines: D8 IN1, D9 IN2, D10 IN3, D11 IN4
const int PINES[4] = {8, 9, 10, 11};
const long PASOS_VUELTA = 2048;
const int SECUENCIA[4][4] = {
  {1, 0, 0, 0},
  {0, 1, 0, 0},
  {0, 0, 1, 0},
  {0, 0, 0, 1}
};
int indice = 0;

void aplicar(int i) {
  int k = (i % 4 + 4) % 4;
  for (int b = 0; b < 4; b++) digitalWrite(PINES[b], SECUENCIA[k][b]);
}

void moverGrados(long grados) {
  long pasos = grados * PASOS_VUELTA / 360;
  int dir = pasos >= 0 ? 1 : -1;
  long n = pasos >= 0 ? pasos : -pasos;
  Serial.print(F("pasos "));
  Serial.println(pasos);
  for (long k = 0; k < n; k++) {
    indice += dir;
    aplicar(indice);
    delay(3);
  }
  for (int b = 0; b < 4; b++) digitalWrite(PINES[b], LOW);
}

void setup() {
  for (int b = 0; b < 4; b++) pinMode(PINES[b], OUTPUT);
  Serial.begin(9600);
  Serial.println(F("Escribe grados, por ejemplo 90 o -180."));
}

void loop() {
  if (!Serial.available()) return;
  long grados = Serial.parseInt();
  while (Serial.available()) Serial.read();
  if (grados < -360 || grados > 360) {
    Serial.println(F("Limita a una vuelta, de -360 a 360."));
    return;
  }
  moverGrados(grados);
  Serial.println(F("hecho"));
}

Pasos

  1. Reutiliza el cableado de la vuelta completa: D8 a D11 hacia IN1 a IN4, alimentación a 5 V.
  2. Abre el monitor a 9600 baudios y elige salto de línea, para que el número llegue al terminar la línea.
  3. Escribe 90 y comprueba que el eje avanza un cuarto de vuelta respecto a tu marca.
  4. Escribe -90 y comprueba que vuelve al sitio. El signo negativo recorre la secuencia al revés.
  5. Prueba 360 y -360. Deben ser una vuelta en cada sentido, con 2048 pasos y -2048 pasos en el monitor.
  6. Si 90 se queda corto de forma repetible, no subas la tensión: revisa que no se pierdan pasos por un retardo demasiado bajo.
  7. Cuando acabes, deja las bobinas sueltas. El sketch ya las apaga al terminar el movimiento.

Variantes

Depuración

Software: digitalwrite serial

Eagle · AP-EAG-05

HC-05: mando local de un LED

Objetivo

Vas a encender y apagar un LED desde un teléfono emparejado por Bluetooth clásico con un HC-05, al lado de la placa. No hay cuenta, no hay servidor y no sale nada de tu mesa: el teléfono habla solo con el módulo. En modo datos el HC-05 usa 9600 baudios, que es lo que abre este sketch. El modo de comandos AT es otro ritmo, casi siempre 38400, y aquí no lo necesitas porque no vas a cambiar el nombre ni la clave.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon. No ocupes D0 ni D1: el USB los necesita.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Misma precaución con el puerto serie del USB.
1HC-05modulo-hc-05genérico / clonepoco (≈1–3 €)Bluetooth clásico, enlace local. VCC del módulo a 5 V si tu placa de breakout trae regulador, lógica de recepción a 3,3 V.
1Level shiftermodulo-level-shiftergenérico / cloneirrisorio (<1 €)Baja de 5 V a 3,3 V la línea que entra en el RX del HC-05.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)LED de prueba.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios en serie con el LED.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza HC-05 TX Uno D3 Uno 5 V Uno 3,3 V Uno GND Uno D8 Teléfono emparejado Uno D2 Level shifter HV y de ahí al RX del HC-05 HC-05 VCC y HV del shifter LV del level shifter HC-05 GND y GND del shifter Resistencia y LED hacia GND HC-05

Código

// AP-EAG-05 HC-05 mando local de un LED
// Pines: D2 RX del enlace, D3 TX del enlace, D8 LED
// Datos a 9600 baudios. El modo AT del HC-05, si lo usaras, iria a 38400.
#include <SoftwareSerial.h>
const int PIN_BT_RX = 2;
const int PIN_BT_TX = 3;
const int PIN_LED = 8;
SoftwareSerial bt(PIN_BT_RX, PIN_BT_TX);

void setup() {
  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);
  Serial.begin(9600);
  bt.begin(9600);
  Serial.println(F("HC-05 en datos a 9600. Enlace local, sin cuenta."));
  Serial.println(F("Envia 1 para encender y 0 para apagar."));
}

void loop() {
  if (bt.available()) {
    char c = bt.read();
    Serial.print(F("recibido "));
    Serial.println(c);
    if (c == '1') digitalWrite(PIN_LED, HIGH);
    else if (c == '0') digitalWrite(PIN_LED, LOW);
  }
}

Pasos

  1. Alimenta el HC-05 a 5 V en su VCC de breakout y une las masas. La patilla RX del módulo se queda detrás del level shifter.
  2. Conecta TX del HC-05 a D2 y D3 al lado de alta del shifter, y el lado de baja del shifter al RX del HC-05.
  3. Pon el LED con su resistencia en D8. No uses D13 si te confunde el LED de la placa.
  4. Sube el sketch con el módulo ya cableado, pero no enlazado todavía al monitor por D0 y D1.
  5. En el teléfono, empareja el HC-05 como cualquier Bluetooth clásico. La clave de fábrica suele ser 1234 o 0000, y es una clave del propio módulo, no una cuenta en internet.
  6. Abre un terminal Bluetooth serie en el teléfono, a 9600 baudios, y manda el carácter 1 y luego el 0.
  7. En el monitor USB, también a 9600, debes ver el carácter que llegó. Si abres AT por error, recuerda que esa velocidad es 38400 y aquí no la usamos.

Variantes

Depuración

Software: softwareserial digitalwrite serial

Eagle · AP-EAG-06

Receptor IR de un mando

Objetivo

Vas a leer un mando infrarrojo doméstico con un receptor TSOP de 38 kHz y a quedarte con un código concreto grabado en el sketch. La primera vez el monitor te enseña el número que llega; luego lo copias a la constante y el LED solo obedece a esa tecla. El decodificado es local, en la propia placa, sin enviar nada a ningún sitio. El sensor deja la línea en reposo a nivel alto y la baja mientras recibe la portadora.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Misma entrada digital.
1IR obstáculo / TSOPsensor-irgenérico / cloneirrisorio (<1 €)Receptor TSOP de 38 kHz, no el módulo de obstáculo por reflexión. Patilla de salida hacia D2.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Indicador de tecla reconocida.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios con el LED.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Salida del sensor-ir Uno 5 V Uno GND Uno D8 Mando IR Uno D2 VCC del receptor IR GND del receptor IR Resistencia y LED a GND Cúpula del receptor

Código

// AP-EAG-06 Receptor IR de un mando
// Pines: D2 receptor, D8 LED
// Sustituye TECLA por el valor que veas en el monitor.
const int PIN_IR = 2;
const int PIN_LED = 8;
const uint32_t TECLA = 0x00FFA25DUL;

bool medir(int nivel, unsigned long tMin, unsigned long tMax) {
  unsigned long t0 = micros();
  while (digitalRead(PIN_IR) == nivel) {
    if (micros() - t0 > tMax + 1500UL) return false;
  }
  unsigned long dt = micros() - t0;
  return dt >= tMin && dt <= tMax;
}

bool leerNec(uint32_t &codigo) {
  if (digitalRead(PIN_IR) != LOW) return false;
  if (!medir(LOW, 8000, 10000)) return false;
  if (!medir(HIGH, 4000, 5200)) return false;
  uint32_t v = 0;
  for (int i = 0; i < 32; i++) {
    if (!medir(LOW, 250, 900)) return false;
    unsigned long t0 = micros();
    while (digitalRead(PIN_IR) == HIGH) {
      if (micros() - t0 > 2500UL) return false;
    }
    unsigned long espacio = micros() - t0;
    v >>= 1;
    if (espacio > 1000UL) v |= 0x80000000UL;
  }
  codigo = v;
  return true;
}

void setup() {
  pinMode(PIN_IR, INPUT);
  pinMode(PIN_LED, OUTPUT);
  Serial.begin(9600);
  Serial.println(F("Pulsa una tecla. Copia el codigo a TECLA."));
}

void loop() {
  uint32_t codigo = 0;
  if (!leerNec(codigo)) return;
  Serial.println(codigo, HEX);
  digitalWrite(PIN_LED, codigo == TECLA ? HIGH : LOW);
  delay(150);
}

Pasos

  1. Identifica el receptor de mando, el de tres patillas con cúpula, no el de obstáculo con potenciómetro.
  2. Conecta su salida a D2, la alimentación a 5 V y la masa a GND.
  3. Pon el LED en D8 con la resistencia en serie.
  4. Sube el sketch, abre el monitor a 9600 baudios y pulsa una tecla del mando apuntando al sensor.
  5. Anota el número hexadecimal que se repite. Ignora lecturas sueltas distintas: son rebotes o repeticiones del mando.
  6. Pega ese número en la constante TECLA, vuelve a subir el sketch y comprueba que solo esa tecla enciende el LED.
  7. Aleja el mando hasta que falle. Esa distancia es el límite real de tu sensor, no una cifra de catálogo.

Variantes

Depuración

Software: digitalread digitalwrite serial

Eagle · AP-EAG-07

Enlace IR entre dos placas

Objetivo

Vas a pasar un byte de una placa a otra por luz infrarroja, sin cables de datos entre ellas. La emisora modula a 38 kHz con tone en el pin del LED infrarrojo, y la receptora, con un TSOP, mide los pulsos y reconstruye el byte. Es un enlace de mesa, óptico y local. Cada placa lleva su propio sketch: no sirven intercambiados.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
2Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Una emite y otra recibe. Puedes mezclar con clones.
2Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Sirven igual. Programa cada una con su sketch.
2LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Uno infrarrojo de 5 mm en la emisora y uno visible en la receptora como testigo.
2Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios con el LED infrarrojo y otros 220 con el LED visible.
1IR obstáculo / TSOPsensor-irgenérico / cloneirrisorio (<1 €)TSOP de 38 kHz en la placa receptora.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno emisor D3 Uno emisor 5 V Uno emisor GND Salida del sensor-ir Uno receptor 5 V Uno receptor GND Uno receptor D8 LED infrarrojo Resistencia y LED infrarrojo hacia GND Nada del LED de datos Cátodo del LED infrarrojo Uno receptor D2 VCC del TSOP GND del TSOP LED visible y resistencia a GND Cúpula del TSOP

Código

// AP-EAG-07 Enlace IR entre dos placas
// Hay dos sketches. Graba cada uno en su placa.

// ===== Placa emisora. Pines: D3 LED infrarrojo =====
const int PIN_IR = 3;
const byte MENSAJE = 0xA5;

void marca(int us) {
  tone(PIN_IR, 38000);
  delayMicroseconds(us);
  noTone(PIN_IR);
}
void espacio(int us) { delayMicroseconds(us); }

void enviarByte(byte dato) {
  marca(2400);
  espacio(1200);
  for (int b = 0; b < 8; b++) {
    marca(600);
    espacio((dato & 1) ? 1600 : 600);
    dato >>= 1;
  }
  marca(600);
}

void setup() { pinMode(PIN_IR, OUTPUT); Serial.begin(9600); }
void loop() {
  enviarByte(MENSAJE);
  Serial.println(F("enviado A5"));
  delay(400);
}

// ===== Placa receptora. Pines: D2 TSOP, D8 LED =====
/*
const int PIN_IR = 2;
const int PIN_LED = 8;

bool pulsoAlto(unsigned long &ancho) {
  unsigned long t0 = micros();
  while (digitalRead(PIN_IR) == HIGH) {
    if (micros() - t0 > 6000UL) return false;
  }
  ancho = micros() - t0;
  return true;
}

bool leerByte(byte &dato) {
  if (digitalRead(PIN_IR) != LOW) return false;
  unsigned long t0 = micros();
  while (digitalRead(PIN_IR) == LOW) {
    if (micros() - t0 > 5000UL) return false;
  }
  if (micros() - t0 < 1800UL) return false;
  unsigned long espacioCab = 0;
  if (!pulsoAlto(espacioCab)) return false;
  if (espacioCab < 800UL) return false;
  byte v = 0;
  for (int b = 0; b < 8; b++) {
    t0 = micros();
    while (digitalRead(PIN_IR) == LOW) {
      if (micros() - t0 > 2000UL) return false;
    }
    unsigned long espacio = 0;
    if (!pulsoAlto(espacio)) return false;
    if (espacio > 1000UL) v |= (1 << b);
  }
  dato = v;
  return true;
}

void setup() {
  pinMode(PIN_IR, INPUT);
  pinMode(PIN_LED, OUTPUT);
  Serial.begin(9600);
  Serial.println(F("Esperando byte IR"));
}
void loop() {
  byte dato = 0;
  if (!leerByte(dato)) return;
  Serial.println(dato, HEX);
  digitalWrite(PIN_LED, dato == 0xA5 ? HIGH : LOW);
  delay(50);
  digitalWrite(PIN_LED, LOW);
}
*/

Pasos

  1. Monta la emisora: LED infrarrojo y resistencia desde D3 hacia GND. D3 es el pin donde tone genera 38 kHz.
  2. Monta la receptora en la otra placa: TSOP a 5 V, GND y salida a D2, LED visible en D8.
  3. Graba en la primera placa solo el sketch emisor. En la segunda, copia el bloque receptor, quita los comentarios de bloque y no dejes las dos lógicas a la vez.
  4. Enfrenta el LED infrarrojo a la cúpula, a unos cinco centímetros, en la misma mesa.
  5. Abre el monitor de la receptora a 9600 baudios. Debe aparecer A5 varias veces por segundo y el LED debe parpadear.
  6. Tapa el haz con la mano. El monitor tiene que callarse. Si sigue imprimiendo, está leyendo ruido de una lámpara.
  7. Separa las placas hasta que falle y anota la distancia. Este enlace no atraviesa una pared.

Variantes

Depuración

Software: tone digitalwrite digitalread serial

Eagle · AP-EAG-08

NRF24L01: un mensaje entre dos Unos

Objetivo

Vas a enviar un texto corto de un Uno a otro con dos módulos nRF24L01 y la librería RF24. Cada placa lleva su sketch, emisor o receptor, y comparten canal y dirección. El módulo se alimenta solo a 3,3 V y quiere un condensador pegado entre su alimentación y masa, porque el pico de emisión tira la tensión abajo. Los datos pueden pasar por un level shifter desde el Uno de 5 V. No hay red Wi-Fi ni ningún servicio fuera de las dos placas.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
2Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Una envía y otra recibe.
2Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Puedes usar clones en los dos lados.
2nRF24L01+modulo-nrf24l01genérico / cloneirrisorio (<1 €)Alimentación estricta a 3,3 V. Un condensador de 10 microfaradios entre VCC y GND del módulo, lo más corto posible.
2Level shiftermodulo-level-shiftergenérico / cloneirrisorio (<1 €)Uno en cada placa, en las líneas que salen del Uno hacia el módulo.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D9 Uno D10 Uno D11 nRF24 MISO Uno D13 Uno pin de 3,3 V Uno 5 V Uno GND Condensador de 10 microfaradios CE del nRF24 a través del shifter CSN del nRF24 a través del shifter MOSI del nRF24 a través del shifter Uno D12 SCK del nRF24 a través del shifter VCC del nRF24 y LV del shifter HV del level shifter GND del nRF24 y del shifter Patillas VCC y GND del nRF24

Código

// AP-EAG-08 NRF24L01 un mensaje entre dos Unos
// Pines en las dos placas: D9 CE, D10 CSN, D11 MOSI, D12 MISO, D13 SCK
// Alimentacion del radio: 3,3 V y condensador de 10 microfaradios.
// Libreria RF24. Dos sketches, uno por placa.

// ===== Placa emisora =====
#include <SPI.h>
#include <RF24.h>
const int PIN_CE = 9;
const int PIN_CSN = 10;
const int PIN_MOSI = 11;
const int PIN_MISO = 12;
const int PIN_SCK = 13;
RF24 radio(PIN_CE, PIN_CSN);
const byte DIRECCION[6] = "EAG08";

void setup() {
  Serial.begin(9600);
  Serial.print(F("SPI D11 D12 D13, CE D9, CSN D10, VCC 3,3 V. MOSI "));
  Serial.println(PIN_MOSI);
  if (!radio.begin()) {
    Serial.println(F("Radio no responde. Revisa 3,3 V y el condensador."));
    while (true) {}
  }
  radio.setChannel(76);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.openWritingPipe(DIRECCION);
  radio.stopListening();
}
void loop() {
  char texto[8] = "hola";
  bool ok = radio.write(texto, sizeof(texto));
  Serial.println(ok ? F("enviado") : F("sin ack"));
  delay(500);
}

// ===== Placa receptora: mismo cableado, otro sketch =====
/*
#include <SPI.h>
#include <RF24.h>
const int PIN_CE = 9;
const int PIN_CSN = 10;
const int PIN_MOSI = 11;
const int PIN_MISO = 12;
const int PIN_SCK = 13;
RF24 radio(PIN_CE, PIN_CSN);
const byte DIRECCION[6] = "EAG08";

void setup() {
  Serial.begin(9600);
  if (!radio.begin()) {
    Serial.println(F("Radio no responde"));
    while (true) {}
  }
  radio.setChannel(76);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.openReadingPipe(1, DIRECCION);
  radio.startListening();
  Serial.println(F("Escuchando en canal 76"));
}
void loop() {
  if (!radio.available()) return;
  char texto[8] = {0};
  radio.read(texto, sizeof(texto));
  Serial.print(F("recibido "));
  Serial.println(texto);
}
*/

Pasos

  1. Instala la librería RF24 desde el gestor de librerías del IDE. No busques un servicio en internet dentro del sketch: la librería se queda en tu ordenador.
  2. Alimenta cada nRF24 desde el pin de 3,3 V, nunca desde 5 V. Suelda o pincha el condensador de 10 microfaradios junto al módulo, del lado correcto.
  3. Pasa CE, CSN, MOSI y SCK por el level shifter. MISO puede ir directo a D12.
  4. Graba el sketch emisor en la primera placa y el receptor, descomentando su bloque y quitando el emisor, en la segunda.
  5. Abre los dos monitores a 9600 baudios. Una debe decir enviado y la otra recibido hola.
  6. Si el emisor dice que el radio no responde, para y mide 3,3 V en el módulo antes de seguir probando canales.
  7. Separa las placas un metro, sin paredes, y confirma que el acuse sigue llegando con la potencia baja.

Variantes

Depuración

Software: spi serial

Eagle · AP-EAG-09

OLED SSD1306: gráfico de un sensor

Objetivo

Vas a dibujar en un OLED SSD1306 la lectura de un sensor Hall analógico, como una traza que avanza de izquierda a derecha. Usarás las librerías Adafruit_SSD1306 y Adafruit_GFX, y la dirección I2C 0x3C. El gráfico sale de una medida local: el imán acerca o aleja el valor y la curva se mueve. No se envía a ningún sitio. Aprenderás a escalar una lectura de 10 bits a la altura de 64 píxeles.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon. I2C en A4 y A5.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines de I2C.
1OLED SSD1306modulo-oled-ssd1306genérico / clonepoco (≈1–3 €)Pantalla de 128 por 64 en I2C, dirección 0x3C.
1Hallsensor-hallgenérico / cloneirrisorio (<1 €)Salida analógica del módulo hacia A0. Acerca un imán, no lo pegues de golpe al sensor.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno A4 Uno A5 Uno 5 V Uno GND Salida analógica del sensor-hall SDA del OLED SCL del OLED VCC del OLED GND del OLED y del Hall Uno A0 VCC del sensor Hall

Código

// AP-EAG-09 OLED SSD1306 grafico de un sensor
// Pines: A4 SDA, A5 SCL, A0 sensor Hall
// Librerias Adafruit_SSD1306 y Adafruit_GFX. Direccion 0x3C.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const int PIN_SDA = A4;
const int PIN_SCL = A5;
const int PIN_HALL = A0;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
int x = 0;
int yAnterior = 32;

void setup() {
  pinMode(PIN_SDA, INPUT);
  pinMode(PIN_SCL, INPUT);
  Serial.begin(9600);
  if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("OLED no responde en 0x3C"));
    while (true) {}
  }
  oled.clearDisplay();
  oled.setTextColor(SSD1306_WHITE);
  oled.display();
}

void loop() {
  int lectura = analogRead(PIN_HALL);
  int y = map(lectura, 0, 1023, 63, 0);
  oled.drawLine(x, yAnterior, x + 1, y, SSD1306_WHITE);
  yAnterior = y;
  x++;
  if (x >= 127) {
    x = 0;
    oled.clearDisplay();
  }
  oled.fillRect(0, 0, 40, 10, SSD1306_BLACK);
  oled.setCursor(0, 0);
  oled.print(lectura);
  oled.display();
  delay(40);
}

Pasos

  1. Instala Adafruit_SSD1306 y Adafruit_GFX con el gestor de librerías. Las dos hacen falta: la pantalla se apoya en GFX.
  2. Conecta SDA a A4 y SCL a A5. Si las cruzas, la pantalla no responde en 0x3C.
  3. Lleva la salida analógica del Hall a A0 y alimenta sensor y pantalla con masa común.
  4. Sube el sketch. Si se queda parado, el begin no encontró la dirección 0x3C: revisa alimentación y cables.
  5. Sin imán, la traza debe quedarse cerca de la mitad. Acerca un imán despacio y la línea sube o baja.
  6. Gira el imán. El sentido del campo invierte la desviación en muchos módulos analógicos.
  7. Deja que la traza llegue al borde y comprueba que la pantalla se limpia y el gráfico vuelve a empezar.

Variantes

Depuración

Software: i2c analogread serial

Eagle · AP-EAG-10

Tira de LEDs direccionables, un color

Objetivo

Vas a encender una tira WS2812 de un solo color con la librería Adafruit_NeoPixel. Todos los LED muestran el mismo rojo suave, sin animación de arcoíris ni mezcla de colores: así ves claro el protocolo de un hilo de datos. En ese hilo pones una resistencia en serie, y entre la alimentación de la tira y masa un condensador grande, cerca del primer LED. La tira va a 5 V. No la alimentes desde un pin de datos ni desde la red.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismo pin digital.
1WS2812 / NeoPixelmodulo-ws2812ambos (oficial y genérico)poco (≈1–3 €)Tira o anillo. Cuenta los LED reales y ponlos en NUM_LEDS.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)330 ohmios en serie en el cable de datos, junto al primer LED.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D6 Fuente de 5 V Uno GND Condensador de unos 1000 microfaradios Resistencia de 330 ohmios y de ahí a DIN de la tira 5 V de la tira GND de la tira y de la fuente 5 V y GND de la tira, junto al primer LED

Código

// AP-EAG-10 Tira de LEDs direccionables, un color
// Pin: D6 datos, con resistencia de 330 ohmios en serie.
// Libreria Adafruit_NeoPixel. Un solo color en toda la tira.
#include <Adafruit_NeoPixel.h>
const int PIN_DATOS = 6;
const int NUM_LEDS = 8;
Adafruit_NeoPixel tira(NUM_LEDS, PIN_DATOS, NEO_GRB + NEO_KHZ800);
const unsigned long PASO_MS = 40;
unsigned long anterior = 0;
int brillo = 10;
int dir = 1;

void setup() {
  tira.begin();
  tira.setBrightness(40);
  tira.clear();
  tira.show();
  Serial.begin(9600);
  Serial.println(F("Un solo color rojo en D6."));
}

void loop() {
  if (millis() - anterior < PASO_MS) return;
  anterior = millis();
  brillo += dir;
  if (brillo >= 80 || brillo <= 5) dir = -dir;
  uint32_t color = tira.Color(brillo, 0, 0);
  for (int i = 0; i < NUM_LEDS; i++) tira.setPixelColor(i, color);
  tira.show();
}

Pasos

  1. Instala Adafruit_NeoPixel desde el gestor de librerías.
  2. Pon la resistencia de 330 ohmios entre D6 y DIN del primer LED. No la olvides: sin ella es fácil estropear esa entrada.
  3. Coloca el condensador grande entre 5 V y GND de la tira, con la raya del electrolítico a masa, cerca del conector.
  4. Une las masas de la placa y de la tira antes de dar alimentación.
  5. Cuenta los LED y ajusta NUM_LEDS. Sube el sketch: todos deben verse del mismo rojo, respirando despacio.
  6. Si ves verde o azul, tu tira no es GRB. Cambia el flag a NEO_RGB y deja un solo color igualmente.
  7. No pidas blanco fuerte a una tira larga desde el USB. Baja el brillo o pasa a una fuente de 5 V.

Variantes

Depuración

Software: millis serial

Eagle · AP-EAG-11

Menú en OLED con pulsadores

Objetivo

Vas a moverte por un menú de tres líneas en el OLED SSD1306 con tres pulsadores, usando la dirección 0x3C y las librerías Adafruit_SSD1306 y Adafruit_GFX. El programa no lee el botón en crudo: espera a que lleve unos milisegundos estable, y distingue el estado de estar en la lista del estado de estar editando un valor. Todo ocurre en la placa, sin salir a ningún servicio externo.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines.
1OLED SSD1306modulo-oled-ssd1306genérico / clonepoco (≈1–3 €)I2C en 0x3C.
3Pulsadormodulo-pulsadorgenérico / cloneirrisorio (<1 €)Subir, bajar y aceptar. Se leen con pull-up interno, activos a nivel bajo.
1Proto shieldshield-protoambos (oficial y genérico)poco (≈1–3 €)Opcional, para dejar el menú soldado cuando dejes de usar la protoboard.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno A4 Uno A5 Uno D2 Uno D3 Uno D4 Uno 5 V Uno GND SDA del OLED SCL del OLED Pulsador subir, el otro extremo a GND Pulsador bajar, el otro extremo a GND Pulsador aceptar, el otro extremo a GND VCC del OLED GND del OLED y de los tres pulsadores

Código

// AP-EAG-11 Menu en OLED con pulsadores
// Pines: A4 SDA, A5 SCL, D2 subir, D3 bajar, D4 aceptar
// Adafruit_SSD1306 y Adafruit_GFX, direccion 0x3C.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const int PIN_SDA = A4;
const int PIN_SCL = A5;
const int PIN_SUBIR = 2;
const int PIN_BAJAR = 3;
const int PIN_OK = 4;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
const char* LINEAS[3] = {"Intervalo", "Umbral", "Salir"};
int valores[3] = {10, 50, 0};
int cursor = 0;
int estado = 0;
unsigned long estableDesde[3] = {0, 0, 0};
bool nivelEstable[3] = {HIGH, HIGH, HIGH};
bool pulsado[3];

bool leerEstable(int i, int pin) {
  bool ahora = digitalRead(pin);
  if (ahora != nivelEstable[i]) {
    if (millis() - estableDesde[i] > 25) {
      nivelEstable[i] = ahora;
      estableDesde[i] = millis();
      return ahora == LOW;
    }
  } else {
    estableDesde[i] = millis();
  }
  return false;
}

void pintar() {
  oled.clearDisplay();
  oled.setTextColor(SSD1306_WHITE);
  oled.setTextSize(1);
  for (int i = 0; i < 3; i++) {
    oled.setCursor(0, i * 12);
    oled.print(i == cursor ? ">" : " ");
    oled.print(LINEAS[i]);
    if (i < 2) {
      oled.print(estado == 1 && i == cursor ? " [" : " ");
      oled.print(valores[i]);
      if (estado == 1 && i == cursor) oled.print("]");
    }
  }
  oled.display();
}

void setup() {
  pinMode(PIN_SUBIR, INPUT_PULLUP);
  pinMode(PIN_BAJAR, INPUT_PULLUP);
  pinMode(PIN_OK, INPUT_PULLUP);
  Serial.begin(9600);
  if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("OLED ausente en 0x3C"));
    while (true) {}
  }
  pintar();
}

void loop() {
  pulsado[0] = leerEstable(0, PIN_SUBIR);
  pulsado[1] = leerEstable(1, PIN_BAJAR);
  pulsado[2] = leerEstable(2, PIN_OK);
  if (pulsado[2]) estado = estado == 0 ? 1 : 0;
  if (estado == 0) {
    if (pulsado[0]) cursor = (cursor + 2) % 3;
    if (pulsado[1]) cursor = (cursor + 1) % 3;
  } else if (cursor < 2) {
    if (pulsado[0]) valores[cursor] += 1;
    if (pulsado[1] && valores[cursor] > 0) valores[cursor] -= 1;
  }
  if (pulsado[0] || pulsado[1] || pulsado[2]) pintar();
}

Pasos

  1. Instala Adafruit_SSD1306 y Adafruit_GFX. La dirección de esta práctica es 0x3C.
  2. Conecta SDA a A4, SCL a A5, y los tres pulsadores de D2, D3 y D4 hacia masa. No añadas resistencia externa: el pull-up interno basta.
  3. Sube el sketch. Tienes que ver tres líneas y una marca en la primera.
  4. Pulsa bajar y subir. La marca se mueve y no debe repetir la orden si dejas el dedo un instante de más: el antirrebote es de 25 ms.
  5. Pulsa aceptar sobre Intervalo o Umbral. Aparecen corchetes y los mismos botones cambian el número.
  6. Vuelve a pulsar aceptar para regresar a la lista. En Salir, aceptar no cambia un número.
  7. Si sueldas la versión definitiva, pasa los mismos pines al shield proto sin cambiar el programa.

Variantes

Depuración

Software: debounce i2c digitalread maquina-estados serial

Eagle · AP-EAG-12

Báscula HX711, calibración local

Objetivo

Vas a leer una celda de carga con el HX711 y a convertir las cuentas en gramos con una constante que vive dentro del sketch. Primero taras en vacío, luego apoyas un peso que ya conoces y calculas la escala a mano: cuentas netas partido por los gramos de ese peso. Ese número lo escribes en el programa y vuelves a grabar. No se guarda en ningún servicio externo ni en una cuenta: si cambias de celda, repites la medida y actualizas la constante.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines.
1HX711 + celdasensor-hx711genérico / clonepoco (≈1–3 €)Módulo y celda. La celda de cuatro hilos va al HX711, no a la placa.
1Pulsadormodulo-pulsadorgenérico / cloneirrisorio (<1 €)Tara manual a masa, por si cambias el recipiente.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza HX711 DT HX711 SCK Uno 5 V Uno GND Uno D4 Peso conocido Uno D3 Uno D2 VCC del HX711 GND del HX711 Pulsador de tara hacia GND Plato de la celda

Código

// AP-EAG-12 Bascula HX711, calibracion local
// Pines: D3 DT, D2 SCK, D4 tara
// ESCALA sale de (lectura_con_peso - tara) / PESO_CONOCIDO_G
// y se queda escrita aqui. No se envia a ningun sitio.
const int PIN_DT = 3;
const int PIN_SCK = 2;
const int PIN_TARA = 4;
const float PESO_CONOCIDO_G = 200.0;
const float ESCALA = 430.0;
long tara = 0;

long leerCuentas() {
  while (digitalRead(PIN_DT) == HIGH) {}
  long v = 0;
  for (int i = 0; i < 24; i++) {
    digitalWrite(PIN_SCK, HIGH);
    delayMicroseconds(1);
    v = (v << 1) | digitalRead(PIN_DT);
    digitalWrite(PIN_SCK, LOW);
    delayMicroseconds(1);
  }
  digitalWrite(PIN_SCK, HIGH);
  delayMicroseconds(1);
  digitalWrite(PIN_SCK, LOW);
  if (v & 0x800000L) v |= ~0xFFFFFFL;
  return v;
}

void setup() {
  pinMode(PIN_DT, INPUT);
  pinMode(PIN_SCK, OUTPUT);
  pinMode(PIN_TARA, INPUT_PULLUP);
  digitalWrite(PIN_SCK, LOW);
  Serial.begin(9600);
  delay(300);
  tara = leerCuentas();
  Serial.println(F("Tara hecha. Peso conocido previsto: 200 g."));
  Serial.println(F("Si cambias ESCALA, vuelve a grabar el sketch."));
}

void loop() {
  if (digitalRead(PIN_TARA) == LOW) {
    delay(30);
    tara = leerCuentas();
    Serial.println(F("tara nueva en la placa"));
    delay(300);
  }
  long neto = leerCuentas() - tara;
  float gramos = neto / ESCALA;
  Serial.print(F("cuentas "));
  Serial.print(neto);
  Serial.print(F("  g "));
  Serial.println(gramos, 1);
  delay(400);
}

Pasos

  1. Conecta DT a D3, SCK a D2, alimentación y masa. La celda va solo al HX711, siguiendo su serigrafía de colores.
  2. Deja el plato vacío, sube el sketch y espera a la tara automática del arranque.
  3. Apoya el peso conocido, el de 200 g si no has cambiado la constante, y anota las cuentas netas del monitor.
  4. Calcula la escala: cuentas netas dividido entre 200. Ejemplo: si lees 86000 cuentas, la escala es 430.
  5. Escribe ese número en ESCALA, dentro del sketch, y graba otra vez. El dato se queda en la placa, no en un servicio.
  6. Quita el peso, pulsa la tara, vuelve a poner el peso y comprueba que te acercas a 200 g.
  7. Prueba otro objeto. Si se desvía mucho, la celda roza el soporte o la escala se calculó con el plato mal tarado.

Variantes

Depuración

Software: digitalread digitalwrite serial

Eagle · AP-EAG-13

Corriente con ACS712

Objetivo

Vas a medir la corriente continua de una carga de baja tensión con el ACS712, leyendo su salida analógica. A mitad de la alimentación el sensor marca cero amperios, y cada amperio se aparta de esa mitad según la versión del chip: 185 mV por amperio en el de 5 A. El ensayo se hace con una carga de pocos voltios, en serie con el sensor. No pongas este módulo en la red de casa: aquí no se mide ni se corta la instalación eléctrica.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon. La referencia del analogRead es 5 V.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Misma referencia si lo alimentas por USB a 5 V.
1ACS712sensor-acs712genérico / clonepoco (≈1–3 €)Elige el de 5 A para cargas pequeñas. Los de 20 A y 30 A son menos finos.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Carga mínima de prueba, mejor junto con una lámpara de 5 a 12 V si quieres ver amperios de verdad.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios si la carga es solo el LED a 5 V.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Salida del ACS712 Uno 5 V Uno GND Borne IP+ del ACS712 Borne IP- del ACS712 Uno A0 VCC del ACS712 GND del ACS712 Positivo de la fuente de la carga Positivo de la carga, y la carga vuelve a masa

Código

// AP-EAG-13 Corriente con ACS712
// Pin: A0 salida del sensor
// Version de 5 A: 0,185 V por amperio. Carga de baja tension, sin red.
const int PIN_SENSOR = A0;
const float VREF = 5.0;
const float V_POR_A = 0.185;
float ceroV = 2.5;

void setup() {
  Serial.begin(9600);
  Serial.println(F("Sin carga, calculo el cero durante un segundo."));
  long acum = 0;
  for (int i = 0; i < 50; i++) {
    acum += analogRead(PIN_SENSOR);
    delay(20);
  }
  ceroV = (acum / 50.0) * (VREF / 1023.0);
  Serial.print(F("cero V "));
  Serial.println(ceroV, 3);
}

void loop() {
  long acum = 0;
  for (int i = 0; i < 10; i++) acum += analogRead(PIN_SENSOR);
  float v = (acum / 10.0) * (VREF / 1023.0);
  float amperios = (v - ceroV) / V_POR_A;
  Serial.print(F("V "));
  Serial.print(v, 3);
  Serial.print(F("  A "));
  Serial.println(amperios, 3);
  delay(300);
}

Pasos

  1. Deja la carga desconectada. Alimenta el ACS712 a 5 V desde la placa y lleva su salida a A0.
  2. Sube el sketch y mira el cero que imprime. Debe quedar cerca de 2,5 V.
  3. Corta la alimentación de la carga. Inserta el sensor en serie: fuente, borne IP+, borne IP-, carga y vuelta a masa.
  4. Usa una fuente de continua de baja tensión, 5 o 12 V. No uses la red.
  5. Enciende la carga. La corriente debe subir en el sentido que hayas cableado. Si sale negativa, la estás midiendo al revés y basta con leer el valor absoluto o girar los bornes.
  6. Compara con una idea previa: un LED con 220 ohmios a 5 V anda por unos 15 mA, cerca del ruido de este sensor. Una lámpara pequeña de 12 V se ve mucho mejor.
  7. Si tu módulo es de 20 A, cambia V_POR_A a 0,100. Si es de 30 A, a 0,066. Anótalo en el sketch.

Variantes

Depuración

Software: analogread serial

Eagle · AP-EAG-14

Consumo de un relé en el tiempo

Objetivo

Vas a cerrar un relé de baja tensión de forma periódica y a integrar la corriente que mide el ACS712 mientras pasa el tiempo. El contacto del relé solo corta una carga de 5 a 12 V en continua, nunca la red. Verás la diferencia entre el consumo de la bobina, pequeño, y el de la carga, que es el que de verdad suma amperios por segundo. El acumulado se calcula en la placa con millis y se enseña por el monitor.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines.
1Relé 5 Vmodulo-relegenérico / clonepoco (≈1–3 €)Módulo de un canal. Muchos son activos a nivel bajo. La carga es de 5 a 12 V, no la red.
1ACS712sensor-acs712genérico / clonepoco (≈1–3 €)En serie con la carga de baja tensión, no con la red.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Carga visible a 5 V si no tienes una lámpara de 12 V.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios con el LED de carga.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D7 Uno 5 V Uno GND Salida del ACS712 Contacto COM del relé Contacto NO del relé IN del módulo de relé VCC del relé y del ACS712 GND del relé y del ACS712 Uno A0 Fuente de 5 a 12 V de la carga ACS712 en serie y luego la carga hacia masa

Código

// AP-EAG-14 Consumo de un rele en el tiempo
// Pines: D7 IN del rele, A0 ACS712
// Carga de 5 a 12 V. No se conmuta la red.
const int PIN_RELE = 7;
const int PIN_SENSOR = A0;
const int RELE_ON = LOW;
const int RELE_OFF = HIGH;
const float V_POR_A = 0.185;
float ceroV = 2.5;
unsigned long anterior = 0;
unsigned long fase = 0;
float amperiosSegundo = 0;

float leerAmperios() {
  long acum = 0;
  for (int i = 0; i < 8; i++) acum += analogRead(PIN_SENSOR);
  float v = (acum / 8.0) * (5.0 / 1023.0);
  return (v - ceroV) / V_POR_A;
}

void setup() {
  pinMode(PIN_RELE, OUTPUT);
  digitalWrite(PIN_RELE, RELE_OFF);
  Serial.begin(9600);
  delay(200);
  ceroV = (analogRead(PIN_SENSOR) * (5.0 / 1023.0));
  anterior = millis();
  fase = millis();
  Serial.println(F("Rele de baja tension. Acumulo A*s."));
}

void loop() {
  if (millis() - fase >= 5000) {
    fase = millis();
    bool encendido = digitalRead(PIN_RELE) == RELE_OFF;
    digitalWrite(PIN_RELE, encendido ? RELE_ON : RELE_OFF);
  }
  unsigned long ahora = millis();
  float dt = (ahora - anterior) / 1000.0;
  anterior = ahora;
  if (dt <= 0 || dt > 1) return;
  float a = leerAmperios();
  if (a < 0) a = 0;
  amperiosSegundo += a * dt;
  Serial.print(F("A "));
  Serial.print(a, 3);
  Serial.print(F("  A*s "));
  Serial.println(amperiosSegundo, 3);
  delay(200);
}

Pasos

  1. Apaga la fuente de la carga. Deja el relé en reposo: el sketch arranca con la salida en alto, que en estos módulos es bobina suelta.
  2. Cablea IN a D7, y alimentación y masa del módulo. El contacto COM irá a una fuente de 5 a 12 V, no a la red.
  3. Pon el ACS712 en serie con la carga, entre el contacto NO y la propia carga.
  4. Sube el sketch con la carga todavía apagada para que tome el cero.
  5. Enciende la fuente de baja tensión. Cada cinco segundos el relé cambia y la corriente debe subir solo en el tramo cerrado.
  6. Mira los amperios por segundo. Tienen que crecer casi solo cuando el contacto está cerrado.
  7. Si tu módulo de relé es activo a nivel alto, invierte RELE_ON y RELE_OFF. No inviertas la red: aquí no hay red.

Variantes

Depuración

Software: analogread millis digitalwrite digitalread serial

Eagle · AP-EAG-15

Alarma de reloj que activa un relé

Objetivo

Vas a leer la hora de un DS3231 por I2C y, cuando coincida con la hora y el minuto escritos en el sketch, cerrar un relé durante un rato corto. El reloj mantiene la hora con su pila aunque apagues la placa. El relé solo puede manejar una carga de 5 a 12 V en continua, por ejemplo un LED o un timbre de baja tensión. No conmutas la red: una alarma de práctica no es un programador de enchufes de casa.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)I2C también en A4 y A5.
1RTC DS3231modulo-ds3231genérico / clonepoco (≈1–3 €)Reloj I2C en la dirección 0x68. Ponle pila de botón si quieres que recuerde la hora.
1Relé 5 Vmodulo-relegenérico / clonepoco (≈1–3 €)Activo a nivel bajo. Carga de 5 a 12 V, nunca la red.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Carga segura para ver que el contacto cierra.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios con ese LED.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno A4 Uno A5 Uno D7 Uno 5 V Uno GND Contacto del relé SDA del DS3231 SCL del DS3231 IN del relé VCC del DS3231 y del relé GND del DS3231 y del relé Carga de 5 a 12 V

Código

// AP-EAG-15 Alarma de reloj que activa un rele
// Pines: A4 SDA, A5 SCL, D7 rele
// Carga de 5 a 12 V. No se conmuta la red.
#include <Wire.h>
const int PIN_SDA = A4;
const int PIN_SCL = A5;
const int PIN_RELE = 7;
const int RELE_ON = LOW;
const int RELE_OFF = HIGH;
const int HORA_ALARMA = 7;
const int MINUTO_ALARMA = 30;
const unsigned long DURACION_MS = 20000;
unsigned long activadaEn = 0;
bool sonando = false;

byte bcdAentero(byte b) { return (b >> 4) * 10 + (b & 0x0F); }
byte enteroAbcd(byte n) { return ((n / 10) << 4) | (n % 10); }

void leerHora(int &h, int &m, int &s) {
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 3);
  s = bcdAentero(Wire.read() & 0x7F);
  m = bcdAentero(Wire.read());
  h = bcdAentero(Wire.read() & 0x3F);
}

void fijarHora(int h, int m, int s) {
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.write(enteroAbcd(s));
  Wire.write(enteroAbcd(m));
  Wire.write(enteroAbcd(h));
  Wire.endTransmission();
}

void setup() {
  pinMode(PIN_RELE, OUTPUT);
  digitalWrite(PIN_RELE, RELE_OFF);
  Wire.begin();
  Serial.begin(9600);
  Serial.println(F("Alarma local. Ajusta HORA_ALARMA en el sketch."));
}

void loop() {
  int h, m, s;
  leerHora(h, m, s);
  Serial.print(h); Serial.print(':');
  Serial.print(m); Serial.print(':');
  Serial.println(s);
  if (!sonando && h == HORA_ALARMA && m == MINUTO_ALARMA && s < 5) {
    sonando = true;
    activadaEn = millis();
    digitalWrite(PIN_RELE, RELE_ON);
  }
  if (sonando && millis() - activadaEn > DURACION_MS) {
    sonando = false;
    digitalWrite(PIN_RELE, RELE_OFF);
  }
  delay(500);
}

Pasos

  1. Pon pila en el DS3231 si quieres que la hora sobreviva al USB. Conecta SDA a A4 y SCL a A5.
  2. Conecta el relé a D7 y deja su contacto solo para una carga de 5 a 12 V. No lo lleves a un enchufe.
  3. Si la hora del chip es absurda, llama una vez a fijarHora con la hora local y luego quita esa línea para no reescribirla en cada reset.
  4. Pon HORA_ALARMA y MINUTO_ALARMA a un minuto próximo, graba y espera mirando el monitor.
  5. Cuando coincida el minuto, el relé debe cerrar unos 20 segundos y volver a abrir aunque el minuto siga igual.
  6. Comprueba que al resetear, durante ese minuto, no vuelve a disparar en bucle: la ventana de segundos es corta a propósito.
  7. Vuelve a dejar una hora creíble antes de dar por cerrada la práctica, para no olvidar el reloj en una hora de ensayo.

Variantes

Depuración

Software: i2c digitalwrite rtc millis serial

Eagle · AP-EAG-16

Meteo local: BMP280 en OLED

Objetivo

Vas a mostrar temperatura y presión de un BMP280 en el OLED SSD1306, las dos cosas en la misma mesa y en el mismo bus I2C. El BMP280 trabaja a 3,3 V, así que sus datos pasan por un level shifter desde el Uno de 5 V. La pantalla se inicia en la dirección 0x3C con Adafruit_SSD1306 y Adafruit_GFX, y el sensor en la suya, normalmente 0x76. No hay cuenta ni envío: si desconectas el USB, la medida desaparece con la placa. Es meteo de escritorio, no una estación publicada.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)I2C en A4 y A5.
1BMP280sensor-bmp280genérico / clonepoco (≈1–3 €)Solo 3,3 V en su alimentación y en su lógica. Dirección habitual 0x76.
1OLED SSD1306modulo-oled-ssd1306genérico / clonepoco (≈1–3 €)Dirección 0x3C. No choca con el 0x76 del sensor.
1Level shiftermodulo-level-shiftergenérico / cloneirrisorio (<1 €)Obligatorio entre el Uno a 5 V y el BMP280 a 3,3 V.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno A4 Uno A5 Uno pin de 3,3 V Uno 5 V Uno GND Bus I2C HV del shifter y SDA del OLED HV del shifter y SCL del OLED VCC del BMP280 y LV del shifter VCC del OLED y HV del shifter GND del BMP280, del OLED y del shifter Solo la placa y estos dos módulos

Código

// AP-EAG-16 Meteo local: BMP280 en OLED
// Pines: A4 SDA, A5 SCL. OLED en 0x3C. BMP280 en 0x76.
// Adafruit_SSD1306, Adafruit_GFX y Adafruit_BMP280.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BMP280.h>
const int PIN_SDA = A4;
const int PIN_SCL = A5;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
Adafruit_BMP280 bmp;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("OLED no esta en 0x3C"));
    while (true) {}
  }
  if (!bmp.begin(0x76)) {
    Serial.println(F("BMP280 no esta en 0x76"));
    while (true) {}
  }
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,
                  Adafruit_BMP280::SAMPLING_X2,
                  Adafruit_BMP280::SAMPLING_X16,
                  Adafruit_BMP280::FILTER_X16,
                  Adafruit_BMP280::STANDBY_MS_500);
  oled.setTextColor(SSD1306_WHITE);
  oled.setTextSize(1);
}

void loop() {
  float t = bmp.readTemperature();
  float p = bmp.readPressure() / 100.0;
  oled.clearDisplay();
  oled.setCursor(0, 0);
  oled.print(F("Local, sin enviar"));
  oled.setCursor(0, 16);
  oled.print(F("T "));
  oled.print(t, 1);
  oled.print(F(" C"));
  oled.setCursor(0, 32);
  oled.print(F("P "));
  oled.print(p, 1);
  oled.print(F(" hPa"));
  oled.display();
  Serial.print(t, 1);
  Serial.print(F(" C  "));
  Serial.print(p, 1);
  Serial.println(F(" hPa"));
  delay(1000);
}

Pasos

  1. Instala Adafruit_SSD1306, Adafruit_GFX y Adafruit_BMP280.
  2. Alimenta el BMP280 solo a 3,3 V. Pasa SDA y SCL por el level shifter: lado alto hacia el Uno y el OLED, lado bajo hacia el sensor.
  3. Conecta el OLED a 5 V si su breakout lo permite, y la masa de todo junto.
  4. Sube el sketch. Si se para en el OLED, la dirección 0x3C no responde. Si se para en el BMP, prueba a cambiar 0x76 por 0x77 en begin.
  5. Debes ver grados y hectopascales en la pantalla, y el mismo texto en el monitor a 9600 baudios.
  6. Tapa el sensor con el dedo, sin apretar la placa. La temperatura sube despacio. La presión casi no se mueve: es normal.
  7. Apaga la placa. No queda ninguna copia de la medida en otro sitio, porque este montaje no transmite.

Variantes

Depuración

Software: i2c serial

Eagle · AP-EAG-17

Persiana con dos finales de carrera

Objetivo

Vas a mover un motor pequeño de persiana de prácticas, en continua y de 5 a 12 V, con dos finales de carrera que marcan arriba y abajo. Si el final de arriba ya está pulsado, el motor no sigue subiendo aunque mantengas el botón. Lo mismo hacia abajo. Si los dos finales están pulsados a la vez, se considera un fallo de cable y el motor se queda quieto. No conmutas la red: no es el motor tubular de una persiana de verdad.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines.
1L298Nmodulo-l298ngenérico / clonepoco (≈1–3 €)Puente H para el motor de maqueta, de 5 a 12 V.
1Motor DCmodulo-motor-dcgenérico / clonepoco (≈1–3 €)Motor de continua pequeño. No un motor de persiana de alterna.
2Final de carrerasensor-final-carreragenérico / clonepoco (≈1–3 €)Uno arriba y otro abajo, activos a nivel bajo con pull-up.
2Pulsadormodulo-pulsadorgenérico / cloneirrisorio (<1 €)Subir y bajar.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D2 Uno D3 Uno D4 Uno D5 Uno D7 Uno D8 Uno D9 Uno 5 V Uno GND Fuente de 5 a 12 V Final de carrera de arriba, el otro contacto a GND Final de carrera de abajo, el otro contacto a GND Pulsador subir hacia GND Pulsador bajar hacia GND L298N IN1 L298N IN2 L298N ENA Lógica del L298N GND del puente, finales y pulsadores Potencia del L298N

Código

// AP-EAG-17 Persiana con dos finales de carrera
// Pines: D2 fin arriba, D3 fin abajo, D4 subir, D5 bajar, D7 IN1, D8 IN2, D9 ENA
// Motor de 5 a 12 V. No se conmuta la red.
const int PIN_FIN_ARRIBA = 2;
const int PIN_FIN_ABAJO = 3;
const int PIN_SUBIR = 4;
const int PIN_BAJAR = 5;
const int PIN_IN1 = 7;
const int PIN_IN2 = 8;
const int PIN_ENA = 9;

void parar() {
  digitalWrite(PIN_IN1, LOW);
  digitalWrite(PIN_IN2, LOW);
  digitalWrite(PIN_ENA, LOW);
}

void setup() {
  pinMode(PIN_FIN_ARRIBA, INPUT_PULLUP);
  pinMode(PIN_FIN_ABAJO, INPUT_PULLUP);
  pinMode(PIN_SUBIR, INPUT_PULLUP);
  pinMode(PIN_BAJAR, INPUT_PULLUP);
  pinMode(PIN_IN1, OUTPUT);
  pinMode(PIN_IN2, OUTPUT);
  pinMode(PIN_ENA, OUTPUT);
  parar();
  Serial.begin(9600);
  Serial.println(F("Persiana de practica. Si ya llego, el motor no sigue."));
}

void loop() {
  bool arriba = digitalRead(PIN_FIN_ARRIBA) == LOW;
  bool abajo = digitalRead(PIN_FIN_ABAJO) == LOW;
  bool quiereSubir = digitalRead(PIN_SUBIR) == LOW;
  bool quiereBajar = digitalRead(PIN_BAJAR) == LOW;
  if (arriba && abajo) {
    parar();
    return;
  }
  if (quiereSubir && quiereBajar) {
    parar();
    return;
  }
  if (quiereSubir && !arriba) {
    digitalWrite(PIN_ENA, HIGH);
    digitalWrite(PIN_IN1, HIGH);
    digitalWrite(PIN_IN2, LOW);
    return;
  }
  if (quiereBajar && !abajo) {
    digitalWrite(PIN_ENA, HIGH);
    digitalWrite(PIN_IN1, LOW);
    digitalWrite(PIN_IN2, HIGH);
    return;
  }
  parar();
}

Pasos

  1. Monta el motor de maqueta en el L298N con fuente de 5 a 12 V. No uses el motor de una persiana real ni la red.
  2. Coloca un final de carrera al final de cada recorrido, de forma que la pieza lo pulse y lo mantenga pulsado al llegar.
  3. Conecta D2 y D3 a esos finales, y D4 y D5 a los botones, todos contra masa.
  4. Sube el sketch y, con la maqueta a mitad de recorrido, pulsa subir. Debe moverse solo mientras el botón siga pulsado y el final no.
  5. Cuando toque el final de arriba, suelta y vuelve a pulsar subir. El motor tiene que quedarse quieto: ya llegó.
  6. Repite hacia abajo. Luego pulsa los dos botones a la vez y comprueba que no hay movimiento.
  7. Pulsa los dos finales a la vez con la mano. También tiene que parar: es la alarma de cableado imposible.

Variantes

Depuración

Software: digitalread digitalwrite serial

Eagle · AP-EAG-18

Garaje: ultrasonidos, servo y semáforo

Objetivo

Vas a hacer la maqueta de una barrera de garaje: el ultrasonido mide si hay algo cerca, el servo levanta o baja la barrera y tres LED hacen de semáforo. Rojo con la barrera baja, ámbar mientras se mueve y verde cuando está abierta. El servo se alimenta a 5 V, no a 12 V, y no hay motor de puerta de comunidad ni red de por medio. La distancia se calcula con el tiempo del eco, en la propia placa.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)Mismos pines.
1HC-SR04sensor-hc-sr04genérico / cloneirrisorio (<1 €)Trig y Echo a 5 V, como el Uno.
1Servo SG90modulo-servogenérico / clonepoco (≈1–3 €)SG90 a 5 V. Si tirita, aliméntalo de una fuente de 5 V con la masa unida.
3LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Rojo, ámbar y verde.
3Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios, una por LED.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D9 Uno D8 Uno D6 Uno D2 Uno D3 Uno D4 Uno 5 V Uno GND Trig del HC-SR04 Echo del HC-SR04 Cable de señal del servo LED rojo y resistencia a GND LED ámbar y resistencia a GND LED verde y resistencia a GND VCC del HC-SR04 y del servo GND del sensor, del servo y de los LED

Código

// AP-EAG-18 Garaje: ultrasonidos, servo y semaforo
// Pines: D9 trig, D8 echo, D6 servo, D2 rojo, D3 ambar, D4 verde
#include <Servo.h>
const int PIN_TRIG = 9;
const int PIN_ECHO = 8;
const int PIN_SERVO = 6;
const int PIN_ROJO = 2;
const int PIN_AMBAR = 3;
const int PIN_VERDE = 4;
Servo barrera;
int angulo = 0;
int destino = 0;
unsigned long anterior = 0;

long distanciaCm() {
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  unsigned long eco = pulseIn(PIN_ECHO, HIGH, 30000UL);
  if (eco == 0) return 999;
  return (long)(eco * 0.0343 / 2.0);
}

void luces() {
  bool moviendo = angulo != destino;
  digitalWrite(PIN_ROJO, (!moviendo && angulo == 0) ? HIGH : LOW);
  digitalWrite(PIN_AMBAR, moviendo ? HIGH : LOW);
  digitalWrite(PIN_VERDE, (!moviendo && angulo >= 90) ? HIGH : LOW);
}

void setup() {
  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  pinMode(PIN_ROJO, OUTPUT);
  pinMode(PIN_AMBAR, OUTPUT);
  pinMode(PIN_VERDE, OUTPUT);
  barrera.attach(PIN_SERVO);
  barrera.write(0);
  Serial.begin(9600);
}

void loop() {
  long cm = distanciaCm();
  destino = (cm > 4 && cm < 18) ? 90 : 0;
  if (millis() - anterior > 20) {
    anterior = millis();
    if (angulo < destino) angulo++;
    if (angulo > destino) angulo--;
    barrera.write(angulo);
  }
  luces();
  Serial.print(cm);
  Serial.print(F(" cm  ang "));
  Serial.println(angulo);
  delay(30);
}

Pasos

  1. Conecta trig a D9, echo a D8, el servo a D6 y los tres LED a D2, D3 y D4, cada uno con su resistencia.
  2. Alimenta sensor y servo a 5 V. Si el servo tira del USB y la placa se reinicia, dale 5 V aparte y une las masas.
  3. Sube el sketch. En reposo la barrera está a 0 grados y el LED rojo encendido.
  4. Pon la mano entre 5 y 15 cm del sensor. El ámbar se enciende mientras el ángulo sube hasta 90, y al llegar se queda el verde.
  5. Retira la mano. Debe bajar con ámbar y terminar en rojo.
  6. Si la mano está demasiado pegada, por debajo de 4 cm, se ignora: muchos HC-SR04 mienten en ese rango.
  7. No acoples esto a una puerta real. El servo no tiene fuerza ni es un mando de red.

Variantes

Depuración

Software: servo digitalwrite millis serial

Eagle · AP-EAG-19

Vueltas con sensor Hall

Objetivo

Vas a contar vueltas de un eje con un sensor Hall y un imán, usando la interrupción del pin D2, y a pasar esas vueltas a revoluciones por minuto. El eje lo mueve el motor de continua a través del L298N, con alimentación de 5 a 12 V. No conmutas la red. Cada paso del imán delante del sensor suma una vuelta, así que el imán tiene que ir uno solo y bien sujeto. El cálculo se hace cada segundo, en la placa.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)Usa esta o el clon. D2 es la interrupción externa 0.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)También tiene INT0 en D2.
1Hallsensor-hallgenérico / cloneirrisorio (<1 €)Salida digital, un pulso por vuelta.
1L298Nmodulo-l298ngenérico / clonepoco (≈1–3 €)Para girar el eje a velocidad baja.
1Motor DCmodulo-motor-dcgenérico / clonepoco (≈1–3 €)Motor de 5 a 12 V. Pega el imán en un disco del eje, no en los dedos.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Parpadea una vez por vuelta, para ver el pulso sin mirar solo el número.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios con el LED.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Salida digital del sensor-hall Uno D6 Uno D7 Uno D8 Uno D9 Uno 5 V Uno GND Fuente de 5 a 12 V Uno D2 LED y resistencia a GND L298N IN1 L298N IN2 L298N ENA VCC del Hall y lógica del puente GND del Hall y del puente Potencia del L298N

Código

// AP-EAG-19 Vueltas con sensor Hall
// Pines: D2 Hall, D6 LED, D7 IN1, D8 IN2, D9 ENA
// Motor de 5 a 12 V. No se conmuta la red. Un iman, una vuelta.
const int PIN_HALL = 2;
const int PIN_LED = 6;
const int PIN_IN1 = 7;
const int PIN_IN2 = 8;
const int PIN_ENA = 9;
volatile unsigned int pulsos = 0;
unsigned long anterior = 0;

void contar() { pulsos++; }

void setup() {
  pinMode(PIN_HALL, INPUT_PULLUP);
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_IN1, OUTPUT);
  pinMode(PIN_IN2, OUTPUT);
  pinMode(PIN_ENA, OUTPUT);
  digitalWrite(PIN_IN1, HIGH);
  digitalWrite(PIN_IN2, LOW);
  analogWrite(PIN_ENA, 90);
  attachInterrupt(digitalPinToInterrupt(PIN_HALL), contar, FALLING);
  Serial.begin(9600);
  anterior = millis();
  Serial.println(F("Una bajada en D2 es una vuelta."));
}

void loop() {
  if (millis() - anterior < 1000) return;
  anterior = millis();
  noInterrupts();
  unsigned int n = pulsos;
  pulsos = 0;
  interrupts();
  unsigned int rpm = n * 60;
  digitalWrite(PIN_LED, n ? HIGH : LOW);
  Serial.print(F("vueltas/s "));
  Serial.print(n);
  Serial.print(F("  rpm "));
  Serial.println(rpm);
  delay(40);
  digitalWrite(PIN_LED, LOW);
}

Pasos

  1. Pega un solo imán en el disco del eje y fija el Hall a un par de milímetros, sin que roce.
  2. Alimenta el motor entre 5 y 12 V por el L298N. No conectes la red.
  3. Lleva la salida digital del Hall a D2 y el LED a D6.
  4. Sube el sketch. El motor gira despacio por el PWM de 90 en D9.
  5. Cada segundo el monitor enseña vueltas en ese segundo y las revoluciones por minuto, que son esas vueltas por 60.
  6. Frena el disco con un dedo, con cuidado. Las rpm tienen que caer. Si no caen, estás contando ruido, no el imán.
  7. Aleja el sensor hasta que pierda pulsos y vuelve a la distancia en la que el recuento sea estable.

Variantes

Depuración

Software: interrupciones millis analogwrite pwm digitalwrite serial

Eagle · AP-EAG-20

Rearranque seguro con watchdog

Objetivo

Vas a armar el perro guardián del Uno con avr/wdt.h para que, si el programa se cuelga, la placa se reinicie sola en menos de dos segundos. El rearranque no es ciego: al salir de un reset del watchdog el relé se queda apagado hasta que pulses una confirmación. Así una tarea que se quedó a medias no vuelve a excitar la salida por su cuenta. El relé, si lo usas, solo puede ver una carga de 5 a 12 V. No conmutas la red. El colgado de prueba lo provocas tú manteniendo un botón, para ver el ciclo completo.

Materiales

Cant.PiezaFichaOrigenPrecio relativoEn este montaje
1Arduino Uno R3placa-uno-r3original / oficialconsultar (>10 €)El sketch usa avr/wdt.h, pensado para el ATmega328P del Uno.
1Uno R3 clone CH340placa-uno-ch340genérico / clonepoco (≈1–3 €)También es un 328P. Sirve el mismo código.
1Relé 5 Vmodulo-relegenérico / clonepoco (≈1–3 €)Sale apagado tras un reinicio de watchdog. Carga de 5 a 12 V, nunca la red.
1LED 5 mmmodulo-ledgenérico / cloneirrisorio (<1 €)Late mientras el bucle está vivo.
1Resistenciasmodulo-resistenciagenérico / cloneirrisorio (<1 €)220 ohmios con el LED.
2Pulsadormodulo-pulsadorgenérico / cloneirrisorio (<1 €)Uno simula el cuelgue y otro confirma el rearranque.
1Proto shieldshield-protoambos (oficial y genérico)poco (≈1–3 €)Útil si dejas el ensayo fijo, con los dos pulsadores accesibles.

La franja sale del catálogo de Hardware. No es un precio de tienda.

Cableado

Placa Pieza Uno D8 Uno D7 Uno D2 Uno D4 Uno 5 V Uno GND Contacto del relé IN del relé LED y resistencia a GND Pulsador de cuelgue hacia GND Pulsador de confirmación hacia GND VCC del módulo de relé GND del relé y de los pulsadores Carga de 5 a 12 V

Código

// AP-EAG-20 Rearranque seguro con watchdog
// Pines: D8 rele, D7 LED, D2 cuelgue, D4 confirmar
// Libreria de nucleo avr/wdt.h. Carga del rele de 5 a 12 V, sin red.
#include <avr/wdt.h>
const int PIN_RELE = 8;
const int PIN_LED = 7;
const int PIN_CUELGUE = 2;
const int PIN_OK = 4;
const int RELE_ON = LOW;
const int RELE_OFF = HIGH;
uint8_t causaReset __attribute__((section(".noinit")));

void capturaCausa() __attribute__((naked, used, section(".init3")));
void capturaCausa() {
  causaReset = MCUSR;
  MCUSR = 0;
  wdt_disable();
}

bool vinoDelPerro = false;
bool confirmado = false;
unsigned long ultimoLatido = 0;
bool ledAlto = false;

void setup() {
  pinMode(PIN_RELE, OUTPUT);
  digitalWrite(PIN_RELE, RELE_OFF);
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_CUELGUE, INPUT_PULLUP);
  pinMode(PIN_OK, INPUT_PULLUP);
  vinoDelPerro = causaReset & _BV(WDRF);
  Serial.begin(9600);
  if (vinoDelPerro) {
    Serial.println(F("Reinicio por watchdog. Rele apagado hasta confirmar."));
  } else {
    Serial.println(F("Arranque normal. Watchdog a 2 s."));
    confirmado = true;
  }
  wdt_enable(WDTO_2S);
}

void loop() {
  if (digitalRead(PIN_CUELGUE) == LOW) {
    Serial.println(F("Cuelgue voluntario. Suelta el boton."));
    while (digitalRead(PIN_CUELGUE) == LOW) {}
  }
  wdt_reset();
  if (vinoDelPerro && !confirmado && digitalRead(PIN_OK) == LOW) {
    confirmado = true;
    Serial.println(F("Confirmado. Ya puedes armar el rele."));
  }
  if (confirmado && !vinoDelPerro) {
    digitalWrite(PIN_RELE, RELE_OFF);
  }
  if (millis() - ultimoLatido > 200) {
    ultimoLatido = millis();
    ledAlto = !ledAlto;
    digitalWrite(PIN_LED, ledAlto ? HIGH : LOW);
  }
}

Pasos

  1. Conecta el relé a D8, el LED a D7 y los pulsadores de cuelgue y confirmación a D2 y D4, contra masa.
  2. Deja el contacto del relé en una carga de 5 a 12 V, o sin carga la primera vez. No lo lleves a la red.
  3. Sube el sketch. El monitor debe decir arranque normal y el LED tiene que latir.
  4. Mantén el pulsador de cuelgue. El latido se para porque el programa se queda en el while y no llama a wdt_reset.
  5. En menos de dos segundos la placa reinicia. El mensaje tiene que decir que el reinicio viene del watchdog y que el relé sigue apagado.
  6. Pulsa confirmar. Solo entonces el programa da por bueno el rearranque. Suelta y comprueba que no se activa solo al volver de un cuelgue.
  7. Si un clon se queda reiniciando en bucle al grabar, el perro quedó armado durante la subida. Vuelve a grabar justo tras un reset manual y no armes el watchdog hasta que el programa ya esté estable.

Variantes

Depuración

Software: watchdog millis digitalwrite digitalread serial