FPWM para simular el sensor DHT11

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();
 }
}