FPWM para simular el sensor DHT11

Electrónica: 

En el post anterior Trasteando con el FPWM de Arduino daba "unas claves" para utilizar el FPWM del Atmel que viene en Arduino. Aunque expuse unos ejemplos, no tenían utilidad física (sí permitían entender el funcionamiento, eso sí).

Bueno, para que se vea más claramente, he simulado el funcionamiento del sensor DHT11. En realidad lo he dejado como un mini ejercicio, puesto que está hecho el 95%, sólo falta:

  • Crear el ACK del DHT11 (80us + 80us: nivel bajo + nivel alto)
  • Una vez creados los datos al azar, crear el checksum correspondiente

Deberías refrescar la memoria consultado el post del DHT11 para ver cómo se codifican los datos.

/**
 * Este programa "casi" simula el funcionamiento del sensor DHT11.
 *
 * ¿Que falta?
 *  -Enviar el ACK del DHT11: 80us + 80us (0 + 1)
 *  -Enviar los 40 bits con el checksum correcto
 *
 *
 *       ___
 * _____/           0
 *  50us  26us
 *       ________
 * _____/           1
 *  50us    70us
 *
 * En realidad, como los ultimos 8bits son el CHKSUM y yo voy a enviar datos de forma aleatoria solo voy ha enviar los primeros 32bits.
 *
 */
static const int pinFPWMB = 45;
static const unsigned int NUMDAT = 10;  // En realidad son 32 (sin contar el checksum), pero para verlo mejor en el osciloscopio pongo 10
static long NUM = 1000.0;
static unsigned int _50us = 100;  // Para el timer5, con preescalado 8, 50us = 100 ticks
static unsigned int _26us = 52;   // idem
static unsigned int _70us = 140;  // idem
volatile boolean datos[NUMDAT];
volatile boolean generando = false;

/**
 * FPWM modo 15, no invertido.
 *
 * __
 *   \_____     0
 * 26us  50us
 * ______
 *       \____  1
 *  70us   50us
 */
ISR(TIMER5_OVF_vect) {
  volatile static unsigned int i = 0;
 
  if (datos[i] == 0) {
    OCR5A = _26us + _50us;
    OCR5B = _26us;
  }
  else {
    OCR5A = _70us + _50us;
    OCR5B = _70us;
  }
  i = (i + 1) % (NUMDAT + 1);
  if (i == 0) {
    generando = false;
    // Parar el reloj
    TCCR5B &= ~_BV(CS51);
  }
}
/**
 * Generar datos de forma aleatoria
 */
void generar_datos() {
  long numero = 0.0;
 
  for (unsigned int i = 0; i < NUMDAT; i++) {
    numero = random(NUM);
    datos[i] = (numero < (NUM / 2)) ? 0 : 1;
  }
}
/**
 * Simular la onda del DHT11 mediante FPWM
 */
void generar_fpwm() {
  // Iniciar
  TCNT5 = 0;
  generando = true;
  // Arrancar el reloj con preescalado 8
  TCCR5B |= _BV(CS51);
}
//----------------- Arduino ------------------------------
void setup() {
  // Iniciar Serial
  Serial.begin(9600);
  // Generar una semilla aleatoria utilizando un pin al aire
  pinMode(0, INPUT);
  randomSeed(analogRead(0));
  // FPWM
  // Preparar el temporizador 5 para generar la señal
  //
  // Activar el pin como salida
  pinMode(pinFPWMB, OUTPUT);
  // FPWM modo 15, B no invertido
  TCCR5A = _BV(COM5B1) | _BV(WGM51) | _BV(WGM50);
  TCCR5B = _BV(WGM53) | _BV(WGM52);
  // Habilitar la interrupcion OVF
  TIFR5 = _BV(TOV5);
  TIMSK5 = _BV(TOIE5);
}

void loop() {
  if (!generando) {
    delay(2000);
    generar_datos();
    for (unsigned int i = 0; i < NUMDAT; i++) {
      Serial.print(datos[i]);
      Serial.print(" ");
    }
    Serial.println("---");
    // FPWMM
    generar_fpwm();
  }
}

Como ves, la traducción física a software es inmediata. Si tienes curiosidad y realizas la simulación con CTC en lugar de FPWM verás que no es tan clara y directa (a ver si la semana que viene puedo publicar la solución con CTC).

Por cierto, no me olvido sobre crear un programa orientado a eventos para el data logger, pero ahora tengo un encargillo que me hace mucha ilusión.

¡¡Espero que experimentéis con Arduino!!

Social_buttons: