Motor paso a paso con el L298N y AccelStepper.

Esta vez, usaremos el L298N, este driver para motores es uno de los más populares entre los aficionados a la electrónica y la robótica.
 
Pero en lugar de utilizar la librería habitual, utilizaremos la librería AccelStepper.
 
La librería AccelStepper escrita por Mike McCauley es una librería impresionante para usar en tu proyecto. Una de las ventajas es que soporta la aceleración y la desaceleración, pero tiene un montón de otras funciones.

 l294n

Sensor capacitivo

Los sensores capacitivos se utilizan comúnmente para la detección de objetos. Pueden utilizarse, por ejemplo, para detectar el paso de un objeto en una cinta transportadora o para detectar el nivel de un líquido en un tanque. Los sensores capacitivos se usan en pantallas táctiles o como interruptores. En esta entrada veremos cómo crear un sensor capacitivo utilizando un simple conductor y un microcontrolador.

Principio de funcionamiento

Un sensor capacitivo funciona como una antena que genera un campo eléctrico. Cuando un material se acerca a la antena, cambiará la capacidad de este campo. El microcontrolador detecta esta diferencia y puede determinar la proximidad del objeto. Con esta tecnología, es posible transformar cualquier objeto conductor en un sensor.

capacitive-touch-principle

Sigue leyendo

Motor paso a paso 28BYJ-48 y AccelStepper

Objetivos

  • Montar un pequeño motor paso a paso 28BYJ-48 con su adaptador.
  • Escribir un primer programa de control utlizando la librería AccelStepper.

Material requerido

 arduino
  • Arduino Uno o similar. Esta sesión acepta cualquier otro modelo de Arduino.
 Img_3_4
  •  Una Protoboard.
 Img_3_6-300x185
  • Algunos cables de Protoboard.
FT68TVVHMMF4Z5P.LARGE_
  • Motor paso a paso 28BYJ-48 y adaptador

Motor paso a paso

Vamos a usar un pequeño motor paso a paso unipolar, muy común en el mundo Arduino por su pequeño tamaño y bajo coste, el 28BYJ-48 y el adaptador  que suele venir con él, basado en el chip ULN2003A.

FT68TVVHMMF4Z5P.LARGE_

El 28BYJ-48 tiene 64 pasos por vuelta y un reductor interno con una relación de 1/64. En conjunto hacen 4096 pasos por vuelta

Ya vimos como utilizar estos motores de forma manual en otra entrada, en ese caso se mandaban las señales una a una a cada bobina.

Ahora veremos como utilizar este motor paso a paso utilizando la librería AccelStepper.

Instalación de la biblioteca AccelStepper

Para controlar el motor paso a paso con lArduino, utilizaremos la librería AccelStepper. Esta librería permite mover fácilmente el motor un número definido de pasos, establecer su velocidad, aceleración y mucho más.

Puede consultar la documentación de la biblioteca AccelStepper aquí.

Pasos para instalar la librería AccelStepper en el IDE de Arduino:

Haz clic en el menú “Programa” -> Incluir librería -> Administrar bibliotecas… Busca “AccelStepper”. Instala la biblioteca AccelStepper de Mike McCauley. En este ejercicio se utilizó la versión 1.64.0.

image-1

Primer ejemplo de código

#include <AccelStepper.h>
#include <MultiStepper.h>

const int vuelta = 2048; // Cambia esto para ajustar el número de pasos por revolución.

// ULN2003 Motor Driver Pins
#define IN1 5 // puedes usar D1
#define IN2 4 // puedes usar D2
#define IN3 14 // puedes usar D5
#define IN4 12 // puedes usar D6

// initialize the stepper library
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);

void setup() {
    // initialize the serial port
    Serial.begin(115200);

    // set the speed and acceleration
    stepper.setMaxSpeed(500);
    stepper.setAcceleration(100);
    // set target position
    stepper.moveTo(vuelta);
}

void loop() {
    // check current stepper motor position to invert direction
    if(stepper.distanceToGo() == 0){
        stepper.moveTo(-stepper.currentPosition());
        Serial.println(«Changing direction»);
    }
    // move the stepper motor (one step at a time)
    stepper.run();
}

Explicación del código

En el código, primero se debe incluir la biblioteca AccelStepper.h.

#include <AccelStepper.h>

Se debe definir el número de pasos por revolución del motor paso a paso, en este caso es de 2048:

const int stepsPerRevolution = 2048; // cambiar esto para ajustar el número de pasos por revolución

Luego se deben definir los pines de entrada del motor. En este ejemplo, se conectan a los pines 5, 4, 14 y 12, pero se pueden usar cualquier pin.

Se debe inicializar una instancia de la biblioteca AccelStepper llamada stepper. Pasa como argumentos: AccelStepper::HALF4WIRE para indicar que se está controlando el motor paso a paso con cuatro cables y los pines de entrada. En el caso del motor paso a paso 28BYJ-48, el orden de los pines es IN1, IN3, IN2, IN4, puede ser diferente para otros motores.

AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);

En el setup(), inicializa el Monitor Serial a una velocidad de baudios de 115200.

Usa el método setMaxSpeed() para establecer la velocidad máxima del motor paso a paso. Pasa como argumento la velocidad en pasos por segundo. La función run() acelerará hasta la velocidad establecida por esta función.

Se establece la aceleración usando el método setAcceleration(). Pasa como argumento la aceleración en pasos por segundo.

Luego, se usa el método moveTo() para establecer una posición objetivo. Luego, la función run() intentará mover el motor (como máximo un paso por llamada) desde la posición actual a la posición objetivo establecida por la llamada más reciente a esta función. Estamos estableciendo la posición objetivo en 2048 (que es una vuelta completa en el caso de este motor).

stepper.moveTo(vuelta);

En el loop(), haremos girar el motor paso a paso en sentido horario y antihorario.

Primero, verificamos si el motor ya ha alcanzado su posición objetivo. Para hacer eso, podemos usar la función distanceToGo() que devuelve los pasos desde la posición actual hasta la posición objetivo.

Cuando el motor alcanza su posición objetivo, significa que la función distanceToGo() devolverá 0 y la siguiente declaración if será verdadera.

if (stepper.distanceToGo() == 0){

Cuando el motor alcanza su posición objetivo, establecemos una nueva posición objetivo, que es la misma que la posición actual pero en dirección opuesta.

stepper.moveTo(-stepper.currentPosition());

Finalmente, llama a stepper.run() para mover el motor un paso a la vez en el loop().

stepper.run();

La función run() sondea el motor y lo mueve si es necesario, implementando aceleraciones y desaceleraciones para alcanzar la posición deseada. Debes llamar a esta función tan frecuentemente como sea posible, pero al menos una vez por el intervalo de tiempo mínimo de paso, preferiblemente en el loop().

Segundo ejemplo de código

#include <AccelStepper.h>

const int stepsPerRevolution = 2048;
// ULN2003 Motor Driver Pins
#define IN1 5 // puedes usar D1
#define IN2 4 // puedes usar D2
#define IN3 14 // puedes usar D5
#define IN4 12 // puedes usar D6
// Define el motor paso a paso y los pines que se utilizarán
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);

void setup() {
// Establece la velocidad máxima y la aceleración del motor
stepper.setMaxSpeed(1000);
stepper.setAcceleration(100);
}

void loop() {
// Mueve el motor 2048 pasos en una dirección
stepper.move(stepsPerRevolution );
stepper.runToPosition();

// Espera 1 segundo
delay(1000);

// Mueve el motor 2048 pasos en la dirección opuesta
stepper.move(-stepsPerRevolution );
stepper.runToPosition();

// Espera 1 segundo
delay(1000);
}

runToPosition()

Mueve el motor (con aceleración/desaceleración) a la posición objetivo y lo bloquea hasta que esté en la posición. No utilizar este método en bucles, ya que bloquea.

runToNewPosition()

runToNewPosition( long position)

Mueve el motor (con aceleración/desaceleración) a la nueva posición objetivo y lo bloquea hasta que esté en posición. No utilizar este método en bucles, ya que bloquea.
 

Sensor Óptico infrarrojo TCRT5000

El  Sensor Óptico TCRT5000 es un sensor ideal para detectar un cambio en la superficie sobre la cual está trabajando, El módulo incluye un sensor TCRT5000 óptico reflectivo infrarrojo, incluye el circuito Integrado LM393 como comparador de voltaje, es ideal para la detección de productos en bandas transportadoras y líneas de producción, líneas en robots de carreras seguidores de línea y sumos, aunque podemos encontrarle utilidad en cualquier otro proyecto electrónico que deseemos realizar.

Captura de pantalla 2023-11-01 a las 12.40.03

El TCRT5000 es un sensor que incluye el emisor y el receptor en el mismo empaquetado. El módulo funciona con IR lo que lo hace inmune a la luz visible.

Sigue leyendo

Módulo de pantalla de matriz de puntos LED I2C

El HT16K33 es un pequeño chip que tiene la capacidad de controlar una matriz multiplexada de 16×8 (es decir, 128 LED individuales). El protocolo de comunicación es I2C, por lo que utiliza solo 2 pines y puede tener hasta 8 direcciones I2C seleccionables, lo que da un total de 8 matrices, cada una de las cuales controla 16×8 LED para un total de 1024 LED.

matriz leds 16x8

A diferencia otros shield de LED, este módulo no tiene salidas para conectar otro módulo de LEDs.

Todo el control de LED se realiza a través de I2C utilizando la librería de interfaz HT16K33. Esto significa que SDA y SCL deben estar conectados con los pines A4 y A5.

La dirección predeterminada es 0x70 pero puede cambiar la dirección a 0x71-0x77 mediante un puente y soldando en los pines de dirección.

Software

Deberás instalar las siguientes librerías para utilizar este módulo.

Abra el administrador de librerías del IDE de Arduino:

Captura de pantalla 2023-11-01 a las 9.28.37

Sigue leyendo

Robot Mecanum (Karla y Alberto)

Vamos a construir un robot con las siguientes caracteristicas:

-Impreso en 3D

-Tendra ruedas mecanum

-Sensor de distancia

-Display 16×8 leds

-2 sensores de proximidad

-Bluetooth

-2 baterias de 9v

-4 motores servo 360º

processed-CC8B5502-4DF3-4866-B66C-8FEF69C51C55

El robot tiene que realizar tres pruebas:

-Prueba de recorrer el laberinto.

La prueba constará de un laberinto diseñado con trozos de cartón que servirán como paredes. Para montarlo usaremos unas piezas que servirán como puente de unión diseñadas en 3D. 

El objetivo principal del robot será salir del laberinto, controlado por el usuario, desde el inicio del laberinto. Para hacerlo, usará los sensores que detectarán los huecos de pared libre y así, dirigirse hacia ellos, hasta llegar a la salida.

MATERIAL:

– Shield para arduino nano

UNO-Shield-Nano-Shield-para-placa-de-expansi-n-NANO-3-0-y-UNO-R3-duemilanove.jpg_Q90.jpg_

– Arduino nano

arduino-nano

-4 servo motores sg90 de 360º

índice

-Sensor de distancia HC-SR04

índicere

-Display

matriz leds 16x8

-Bluetooth HC-06

hc-06-wireless-serial-4-pin-bluetooth-rf-transceiver-module-rs232-ttl-500x500

-4 ruedas mecanum

rueda-mecanum-d60mm-kit-x4

-Cables dupont

Img_3_6-300x185

-2 conectores de baterias de 9V

conector-led-bateria-9v-monocolor

-Interruptor

inter

-2 baterias de 9V

pila

Material 3D:

 
-Acople ruedas
 
 
 
Captura de pantalla 2023-11-29 133619
 
-Segunda pieza diseñada del robot (base)
 
 
Captura de pantalla 2023-11-29 134341
 
Diseño final del robot:
 
Captura de pantalla 2024-04-09 114504
 
 
ESTRUCTURA INTERNA DEL ROBOT:
 
IMG_20240218_075330
 
processed-D9A2C16B-3F72-467E-B090-F3D44C2BAA3F
 
processed-B84E6D2D-D3C9-4EDF-B65B-9F230161A23B
 
 
FOTOS DEL ROBOT TERMINADO:
 
processed-BD64EB1A-608A-436A-885E-61154F52BACB
processed-4726AD3B-1924-45F2-84B1-126BDB27893A
 
processed-AC767BC7-0540-4B50-B9B1-3315DD467AB0
 
 
ESQUEMA DE CONEXIONES:
 
RobotMecanum_bb
 
 
CÓDIGO (PROGRAMA):
 
#include <SoftwareSerial.h>
SoftwareSerial BT(13, 12);

 

#include <Adafruit_LEDBackpack.h>
Adafruit_8x16matrix matrix = Adafruit_8x16matrix();
static const uint8_t PROGMEM
  smile_bmp[] = { B00000000, B00000000, B00000000, B10000001, B10000001, B01000010, B00100100, B00011000 },
  frown_bmp[] = { B0000000, B00000000, B00000000, B00011000, B00100100, B01000010, B10000001, B10000001 };

 

#include <Servo.h>
Servo servoDI, servoDD, servoTI, servoTD;

 

#define trigPin 7
#define echoPin 6
int limite = 200;
x = 50;

 

char r;

 

void setup() {
  servoDI.attach(2);
  servoDI.write(90);
  servoDD.attach(3);
  servoDD.write(90);
  servoTI.attach(4);
  servoTI.write(90);
  servoTD.attach(5);
  servoTD.write(90);

 

  Serial.begin(9600);
  BT.begin(9600);
  matrix.begin(0x70);

 

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

 

void loop() {

 

  if (BT.available()) {
    r = BT.read();
  }
  if (r == ‘1’) {
    avance(x);
  } else {
    if (r == ‘2’) {
      atras(x);
    } else {
      if (r == ‘3’) {
        izquierda(x);
      } else {
        if (r == ‘4’) {
          derecha(x);
        } else {
          if (r == ‘5’) {
            parar();
          } else {
            if (r == ‘6’) {
              esquina_izquierda_sup(x);
            } else {
              if (r == ‘7’) {
                esquina_derecha_sup(x);
              } else {
                if (r == ‘8’) {
                  esquina_izquierda_inf(x);
                } else {
                  if (r == ‘9’) {
                    esquina_derecha_inf(x);
                  } else {
                    if (r == ‘B’) {
                      giro_eje_izquierda(x);
                    } else {
                      if (r == ‘A’) {
                        giro_eje_derecha(x);
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

 

void cara_feliz() {
  matrix.setRotation(1);
  matrix.clear();
  delay(10);
  matrix.drawBitmap(4, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(10);
}

 

void cara_triste() {
  matrix.setRotation(1);
  matrix.clear();
  delay(10);
  matrix.drawBitmap(4, 0, frown_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(10);
}

 

void no_cara() {
  matrix.clear();
  delay(500);
}

 

void parar() {
  servoDI.write(90);
  servoDD.write(90);
  servoTI.write(90);
  servoTD.write(90);
}

 

void avance(int v) {
  cara_feliz();
  servoDI.write(90 + v + 7);
  servoDD.write(90 – v);
  servoTI.write(90 + v + 7);
  servoTD.write(90 – v);
}

 

void atras(int v) {
  cara_triste();
  servoDI.write(90 – v);
  servoDD.write(90 + v);
  servoTI.write(90 – v);
  servoTD.write(90 + v);
}

 

void izquierda(int v) {
  servoDI.write(90 – v);
  servoDD.write(90 – v);
  servoTI.write(90 + v);
  servoTD.write(90 + v);
}

 

void derecha(int v) {
  servoDI.write(90 + v);
  servoDD.write(90 + v);
  servoTI.write(90 – v);
  servoTD.write(90 – v);
}

 

void esquina_derecha_inf(int v) {
  servoDI.write(90);
  servoDD.write(90 + v);
  servoTI.write(90 – v);
  servoTD.write(90);
}

 

void esquina_izquierda_sup(int v) {
  servoDI.write(90);
  servoDD.write(90 – v);
  servoTI.write(90 + v);
  servoTD.write(90);
}

 

void esquina_izquierda_inf(int v) {
  servoDI.write(90 – v);
  servoDD.write(90);
  servoTI.write(90);
  servoTD.write(90 + v);
}

 

void esquina_derecha_sup(int v) {
  servoDI.write(90 + v);
  servoDD.write(90);
  servoTI.write(90);
  servoTD.write(90 – v);
}

 

void giro_eje_izquierda(int v) {
  servoDI.write(90 – v);
  servoDD.write(90 – v);
  servoTI.write(90 – v);
  servoTD.write(90 – v);
}

 

void giro_eje_derecha(int v) {
  servoDI.write(90 + v);
  servoDD.write(90 + v);
  servoTI.write(90 + v);
  servoTD.write(90 + v);
}

 

long dist() {
  long duracion, distancia;

 

  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);

 

  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

 

  duracion = pulseIn(echoPin, HIGH);
  distancia = duracion * 0.017;

 

  return distancia;
}
 
 

Robot Mecanum (Ianna+ClaudiaM)

 

 

Vamos a construir un robot con las siguientes caracteristicas:

-Impreso en 3D

-Tendra ruedas mecanumWhatsApp Image 2024-04-17 at 13.12.54

-Sensor de distancia

-Display 16×8 leds

-2 sensores de proximidad

-Bluetooth

-2 baterias de 9v

-4 motores servo 360º

 

LOS ROBOTS DEBERÁN REALIZAR LA SIGUIENTE PRUEBA:

El robot será guiado a través del móvil por Bluetooth para que salga de un laberinto en el menor tiempo posible. Ganará el que, cronometrándolo, sea el más rápido y ocupe el menor tiempo. 

El laberinto estará diseñado con trozos de cartón que servirán de paredes, para poder montarlo contendrá unas piezas que servirán como puente de unión diseñadas en 3D. 

El objetivo principal del robot será salir de forma autónoma desde el inicio del laberinto. Para hacerlo, usará los sensores que detectarán los huecos de pared libre y así, dirigirse hacia ellos, hasta llegar a la salida.

PARTES DEL ROBOT:

  1. Shield nano:UNO-Shield-Nano-Shield-para-placa-de-expansi-n-NANO-3-0-y-UNO-R3-duemilanove.jpg_Q90.jpg_
  2. Arduino nano: parte programada:arduino-nano
  3. Servo motor de 360º(x4):img_341_a5a1570bcf75651a91f8894db99bffe0_1
  4. Sensor de distancia HC-SR04:índicere
  5. Módulo de sensor sigue-líneas:modulasensorsiguelineas
  6. Sensor de proximidad (x4):sensordeproximidad
  7. Display 16×8 LEDS:matriz leds 16x8
  8. Módulo Bluetooth  HC-06:hc-06-wireless-serial-4-pin-bluetooth-rf-transceiver-module-rs232-ttl-500x500
  9. Ruedas Mecanum (x4):rueda-mecanum-d48mm-kit-x4
  10. Cables dupont:Img_3_6-300x185
  11. Conectores de batería de 9V (x2):conectorbateria9v
  12. Batería de 9V (x2):pila
  13. Interruptor:inter

Sigue leyendo

Robot Mecanum Claudia y Santi

Este robot consta de unas ruedas mecanum como base de diseño. Además llevará un sensor de distancia y otros dos sensoremecanums de proximidad para poder llevar a cabo todas las pruebas propuestas, junto con dos baterías de 9 v, 4 motores de servo 360 y Display 16*8. Estará impreso en 3D y se podrá usar mediante Bluetooth.

La prueba que realizara constará de un laberinto diseñado con trozos de cartón que servirán de paredes, para poder montarlo contendrá unas piezas que servirán como puente de unión diseñadas en 3D.

El objetivo principal del robot será salir de forma autónoma desde el inicio del laberinto. Para hacerlo, usará los sensores que detectarán los huecos de pared libre y así, dirigirse hacia ellos, hasta llegar a la salida. Se tendrá que hacer en el tiempo mínimo posible.

Los materiales que usaremos serán los siguientes:

Un shield nano, donde pondremos el arduino nano para introducir hacer funcionar el código que será introducido en el arduino nano. De esta forma será más fácil de conectar.UNO-Shield-Nano-Shield-para-placa-de-expansi-n-NANO-3-0-y-UNO-R3-duemilanove.jpg_Q90.jpg_

Un arduino nano donde pondremos el código que programaremos.

ardino nano

 4 servo motores SG90 de 360º

índice

Sensor de distancia HC-SR04

índicere

Módulo de sensor (sigue líneas)

TCRT5000 3 Channel Infrared Line Track Sensor - Pixel Electric Company  Limited

2 sensores de proximidad

Sensor de proximidad infrarrojo IR, módulo de Sensor de evitación de  obstáculos Compatible con Arduino - AliExpress

Un display de 16×8 leds.

Módulo de pantalla de matriz de puntos LED Pantalla de celosía DC 3.3V 5V  HT16K33 Driver 168 Cascada Compatible 16x8 IIC Interfaz

Un módulo BlueTooth HC-06.

hc-06-wireless-serial-4-pin-bluetooth-rf-transceiver-module-rs232-ttl-500x500

4 ruedas mecanum 48 mm.

mec

cables DuPont.

cable

2 conectores para batería de 9 V.

conector

Dos baterías de 9 v.

pila

Un interruptor.

inter

Sigue leyendo

ESP8266-12E Interrupciones y temporizadores

Las interrupciones nos permiten detectar cambios en el estado de GPIO sin la necesidad de verificar constantemente su valor actual. Con las interrupciones, cuando se detecta un cambio, se activa un evento (se llama a una función).

Como ejemplo, detectaremos movimiento usando un sensor de movimiento PIR: cuando se detecta movimiento, el ESP8266 inicia un temporizador y enciende un LED durante una cantidad predefinida de segundos. Cuando el temporizador termina la cuenta regresiva, el LED se apaga automáticamente.

Para crear una interrupción, hay que llamar a attachInterrupt() y pasarle como argumentos el pin de interrupción GPIO, la ISR (función a llamar) y el modo. La función ISR debe tener declarado el atributo ICACHE_RAM_ATTR. El modo puede ser CAMBIO, ASCENSO o DESCENSO.

attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode);

Las interrupciones ESP8266

Las interrupciones son útiles para hacer que las cosas sucedan automáticamente en los programas de microcontroladores y pueden ayudar a resolver problemas de temporización.

Con las interrupciones, no se necesita verificar constantemente el valor del pin actual. Cuando se detecta un cambio, se activa un evento: se llama a una función. Esta función se llama rutina de servicio de interrupción (ISR).

Cuando ocurre una interrupción, el procesador detiene la ejecución del programa principal para ejecutar una tarea y luego regresa al programa principal.

Esto es especialmente útil para activar una acción cuando se detecta movimiento o cuando se presiona un botón sin la necesidad de verificar constantemente su estado.

 

Función attachInterrupt()

Para configurar una interrupción en el IDE de Arduino, se utiliza la función attachInterrupt(), que acepta como argumentos: el pin de interrupción GPIO, el nombre de la función a ejecutar y el modo:

attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode);

El primer argumento es una interrupción GPIO. Se debe usar digitalPinToInterrupt(GPIO) para configurar el GPIO real como un pin de interrupción. Por ejemplo, si se desea utilizar GPIO 14 como interrupción, escribir en el setup():

digitalPinToInterrupt(14);

El ESP8266 admite interrupciones en cualquier GPIO, excepto GPIO16.

El segundo argumento de la función attachInterrupt() es el nombre de la función que se llamará cada vez que se active la interrupción: la rutina de servicio de interrupción (ISR).

La función ISR debe ser lo más simple posible, para que el procesador vuelva rápidamente a la ejecución del programa principal.

El mejor enfoque es señalar al código principal que la interrupción ha ocurrido mediante el uso de una variable global y dentro del bucle () verificar y borrar esa bandera y ejecutar el código.

Los ISR deben tener ICACHE_RAM_ATTR antes de la definición de la función para ejecutar el código de interrupción en la RAM.

Modos de interrupción

El tercer argumento es el modo y hay 3 modos diferentes:

  1. CHANGE: para activar la interrupción siempre que el pin cambie de valor, por ejemplo, de ALTO a BAJO o de BAJO a ALTO;
  2. FALLING: para cuando el pin pasa de HIGH a LOW;
  3. RISING: para disparar cuando el pin va de BAJO a ALTO.

Para nuestro ejemplo, usaremos el modo RISING, porque cuando el sensor de movimiento PIR detecta movimiento, el GPIO al que está conectado pasa de BAJO a ALTO.

Los temporizadores ESP8266 NodeMCU.

Queremos que el LED permanezca encendido durante un número predeterminado de segundos después de que se detecte movimiento. En lugar de usar una función de retraso dela() que bloquea su código y no le permite hacer nada más durante un número determinado de segundos, usaremos un temporizador.

delay() vs millis()

La función delay() acepta un solo número int como argumento. Este número representa el tiempo en milisegundos que el programa debe esperar hasta pasar a la siguiente línea de código.

delay (tiempo en milisegundos);

Cuando se llama a delay(1000), el programa se detiene en esa línea durante 1 segundo. delay() es una función de bloqueo. Las funciones de bloqueo evitan que un programa haga cualquier otra cosa hasta que se complete esa tarea en particular. Si necesita que se realicen varias tareas al mismo tiempo, no puede usar delay(). Para la mayoría de los proyectos, debe evitar el uso de retrasos y utilizar temporizadores en su lugar.

Usando una función llamada millis(), podemos devolver la cantidad de milisegundos que han pasado desde que se inició el programa por primera vez.

milis();

¿Por qué es útil esa función? Porque al usar algunas matemáticas, puede verificar fácilmente cuánto tiempo ha pasado sin bloquear su código.

Parpadeando un LED usando millis() (sin demora)

El siguiente fragmento de código muestra cómo se puede usar la función millis() para crear un proyecto de parpadeo. Enciende un LED durante 1000 milisegundos y luego lo apaga.

// constants won't change. Used here to set a pin number :
const int ledPin =  26;      // the number of the LED pin

// Variables will change :
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Esquema

Montar el sensor de movimiento PIR y un LED en el ESP8266. Conectaremos el LED a GPIO 12 (D6) y el pin de datos del sensor de movimiento PIR a GPIO 14 (D5).

esp8266_interrupts_pir_sensor_bb

Importante: el sensor de movimiento PIR Mini AM312 utilizado en este proyecto funciona a 3,3 V. Sin embargo, si está utilizando otro sensor de movimiento PIR como el HC-SR501, funciona a 5V. Puede modificarlo para que funcione a 3,3 V o simplemente alimentarlo con el pin Vin.

Código:

Se puede cargar el código tal como está, o se puede modificar la cantidad de segundos que se enciende el LED después de detectar movimiento. Simplemente cambie la variable timeSeconds con la cantidad de segundos que desee.

#define timeSeconds 10

// Set GPIOs for LED and PIR Motion Sensor
const int led = 12;
const int motionSensor = 14;

// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;

// Checks if motion was detected, sets LED HIGH and starts a timer
ICACHE_RAM_ATTR void detectsMovement() {
  Serial.println("MOTION DETECTED!!!");
  digitalWrite(led, HIGH);
  startTimer = true;
  lastTrigger = millis();
}

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);
  
  // PIR Motion Sensor mode INPUT_PULLUP
  pinMode(motionSensor, INPUT_PULLUP);
  // Set motionSensor pin as interrupt, assign interrupt function and set RISING mode
  attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

  // Set LED to LOW
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
}

void loop() {
  // Current time
  now = millis();
  // Turn off the LED after the number of seconds defined in the timeSeconds variable
  if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
    Serial.println("Motion stopped...");
    digitalWrite(led, LOW);
    startTimer = false;
  }
}

ESP8266-12E (NodeMCU) ADC – Leer valores analógicos.

Entradas analógicas (ADC)

Tanto ESP8266-12E como ESP8266-07 tienen un pin ADC al que se puede acceder fácilmente. Esto significa que esas placas ESP8266 pueden leer señales analógicas.

ESP8266 ADC Especificaciones

Cuando se refiera al pin ADC ESP8266, a menudo escuchará estos diferentes términos indistintamente:

  • ADC (Convertidor de analógico a digital)
  • TOUT
  • Pin6
  • A0
  • Pin analógico 0

Todos estos términos se refieren al mismo pin en el ESP8266.

Resolución ADC ESP8266

El pin ADC tiene una resolución de 10 bits, lo que significa que obtendrá valores entre 0 y 1023.

Rango de voltaje de entrada ESP8266

El rango de voltaje de entrada del pin ADC ESP8266 es de 0 a 1 V si está utilizando el chip de forma independiente. Sin embargo, la mayoría de las placas de desarrollo ESP8266 vienen con un divisor de voltaje interno, por lo que el rango de entrada es de 0 a 3,3 V. Entonces, en resumen:

Leer un valor analógico con el ESP32 significa medir niveles de voltaje variables entre 0 V y 3,3 V.

A la tensión medida se le asigna entonces un valor entre 0 y 4095, en el que 0 V corresponde a 0 y 3,3 V corresponde a 4095. Cualquier tensión entre 0 V y 3,3 V recibirá el valor correspondiente en el medio.

ADC es no lineal

Idealmente, esperaría un comportamiento lineal al usar los pines ESP32 ADC. Sin embargo, eso no sucede. Lo que obtendrá es un comportamiento como se muestra en el siguiente gráfico:

ADC-non-linear-ESP32

Este comportamiento significa que su ESP32 no puede distinguir 3,3 V de 3,2 V. Obtendrá el mismo valor para ambos voltajes: 4095.

Lo mismo sucede para valores de voltaje muy bajos: para 0 V y 0.1 V obtendrá el mismo valor: 0. Debe tener esto en cuenta cuando use los pines ESP32 ADC.

Como ejemplo, mostraremos cómo leer valores analógicos de un potenciómetro.

Pin analógico ESP8266

Con el kit ESP8266 12-E NodeMCU y otras placas de desarrollo ESP8266, es muy fácil acceder al A0, simplemente conecte un cable de puente al pin.

s-l500

Función analogRead()

Leer una entrada analógica usando el IDE de Arduino es tan simple como usar la función analogRead(). Acepta como argumento, el GPIO que se quiere leer:

analogRead (GPIO);

Esquema

Si está utilizando una placa de desarrollo ESP8266, siga el siguiente diagrama esquemático.

analog_input_pot_esp8266_bb

Código

const int analogInPin = A0;  // ESP8266 Analog Pin ADC0 = A0

int sensorValue = 0;  // value read from the pot

void setup() {
  // initialize serial communication at 115200
  Serial.begin(115200);
}

void loop() {
  // read the analog in value
  sensorValue = analogRead(analogInPin);
 
  // print the readings in the Serial Monitor
  Serial.print("sensor = ");
  Serial.print(sensorValue);
  
  delay(1000);
}