Hi All,
I'm currently working on a project which involves a couple of DHT22 humidity and temperature sensors.
I've done some digging online but I've not found any interrupt driven code to read them, thus I'm writing my own.
I'm using a PIC18F2431 (mainly because I had it lying around, I'll probably port it to a 2550 for the final version, as USB might be useful), developing in MPLAB 8.92 against XC8 1.33.
The DHT22 is a bit odd vis-a-vis the way data is transferred, I suppose you'd call it PWM encoding, the datasheets for these sensors vary wildly in quality and readability, the best I've found is the AM2302 datasheet, in a nutshell;
- Pull data low for 1-10ms
- Release data
- DHT22 asserts the bus by pulling the data line low for ~80us then high for ~80us
- Data is transferred by pulling low for ~50us followed by high for either ~26us for a 0 or ~70us for a 1
This is pretty clearly a job for the CCP module in my PIC, the plan is;
- Set Timer 1 prescaler to 8:1 for a 1us count (8MHz clock frequency).
- Set CCP module to trigger on every falling edge.
- Reset the Timer 1 count on every first falling edge (the low period at the start of a 0 or 1 is always the same so period from falling edge to falling edge tells me what I need to know).
- Read the Timer 1 count on every second falling edge to translate to bus assert/0/1.
So I've thrown together a quick project to test the theory but I've run into issues, it appears that my CCP is never firing the interrupt, as an idiot check I threw in a Timer0 interrupt to confirm that my ISR was actually being hit, confirmed working, logic analyser shows that I'm actually getting the data transfer from the sensor.
It's entirely possible I've done something utterly stupid, I may have been slightly delirious yesterday...
core.c
#include <xc.h>
#include <stdint.h>
#include "config.h"
#define SENSOR_PIN LATCbits.LATC2 // CCP1
#define SENSOR_TRIS TRISCbits.TRISC2
void __interrupt global_isr(void)
{
if(CCP1IF && CCP1IE)
{
LATAbits.LATA1 = !LATAbits.LATA1; // Toggling RA1 to give us a correlation point for the logic analyser
CCP1IF = 0;
}
}
void start_signal()
{
SENSOR_TRIS = 0;
SENSOR_PIN = 0;
__delay_ms(5);
SENSOR_PIN = 1;
__delay_us(5);
SENSOR_TRIS = 1;
CCP1IF = 0; // Reset interrupt flag just in case
}
void init()
{
OSCCON = OSCCON | 0b01110000; // Set INTOSC to 8MHz
TRISCbits.TRISC3 = 0;
TRISAbits.TRISA1 = 0;
SENSOR_TRIS = 0; // Set output
SENSOR_PIN = 1; // Pull high
CCP1IE = 1;
CCP1CON = 0b00000100; // CCP, Capture mode, every falling edge
TMR1IE = 1; // Enable Timer0 Interrupt
T1CON = 0b10110001; // Configure Timer0 enabled, 16-bit, internal clock, falling edge, 1:8
ei(); // Enable interrupts
}
void delay()
{
for(uint8_t i = 0; i < 20; i++) __delay_ms(50); // ~1s delay
}
void main(void)
{
init();
while(1)
{
start_signal();
delay();
LATCbits.LATC3 = !LATCbits.LATC3; // Twiddle RC3 to show we're alive
}
}
config.h
#ifndef __CONFIG_H__
#define __CONFIG_H__
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 8000000
// CONFIG1H
#pragma config OSC = IRCIO // Oscillator Selection bits (Internal oscillator block, port function on RA6 and port function on RA7)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = ON // Internal External Oscillator Switchover bit (Internal External Switchover mode enabled)
// CONFIG2L
#pragma config PWRTEN = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled)
// BORV = No Setting
// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
#pragma config WINEN = OFF // Watchdog Timer Window Enable bit (WDT window disabled)
// CONFIG3L
#pragma config PWMPIN = OFF // PWM output pins Reset state control (PWM outputs disabled upon Reset (default))
#pragma config LPOL = HIGH // Low-Side Transistors Polarity (PWM0, 2, 4 and 6 are active-high)
#pragma config HPOL = HIGH // High-Side Transistors Polarity (PWM1, 3, 5 and 7 are active-high)
#pragma config T1OSCMX = ON // Timer1 Oscillator MUX (Low-power Timer1 operation when microcontroller is in Sleep mode)
// CONFIG3H
#pragma config MCLRE = ON // MCLR Pin Enable bit (Enabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Low-Voltage ICSP Enable bit (Low-voltage ICSP disabled)
// CONFIG5L
#pragma config CP0 = OFF // Code Protection bit (Block 0 (000200-000FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection bit (Block 1 (001000-001FFF) not code-protected)
#pragma config CP2 = OFF // Code Protection bit (Block 2 (002000-002FFFh) not code-protected)
#pragma config CP3 = OFF // Code Protection bit (Block 3 (003000-003FFFh) not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000200-000FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection bit (Block 1 (001000-001FFF) not write-protected)
#pragma config WRT2 = OFF // Write Protection bit (Block 2 (002000-002FFFh) not write-protected)
#pragma config WRT3 = OFF // Write Protection bit (Block 3 (003000-003FFFh) not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000200-000FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (001000-001FFF) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (002000-002FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (003000-003FFFh) not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from table reads executed in other blocks)
#endif // __CONFIG_H__
The logic analyser trace of the DHT22 data transfer
![](https://i.imgur.com/NiUM7ji.png)
Thanks,
-J