Author Topic: DHT22/CCP Interrupt Woes  (Read 2064 times)

0 Members and 1 Guest are viewing this topic.

Offline jrandombobTopic starter

  • Contributor
  • Posts: 16
  • Country: au
DHT22/CCP Interrupt Woes
« on: January 11, 2016, 11:06:12 pm »
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
Code: [Select]
#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
Code: [Select]
#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


Thanks,

-J
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: DHT22/CCP Interrupt Woes
« Reply #1 on: January 11, 2016, 11:59:25 pm »
I have never used your sensor so just some quick commwnts.

I was glad to see your use of a config.h file to handle fuse settings. I uae that approach as well, even the same file name. I would suggest that you use conditional compilation so that you can put fuse settings for all of your chips in one file.

"Data is transferred by pulling low for ~50us followed by high for either ~26us for a 0 or ~70us for a 1"

It seems to be one way to approach it is to initialize the ccp on the falling edge and capture on the rising edge. Then test to see if it 0 or 1. Didn't get a chance to go through your code however.
================================
https://dannyelectronics.wordpress.com/
 

Offline jrandombobTopic starter

  • Contributor
  • Posts: 16
  • Country: au
Re: DHT22/CCP Interrupt Woes
« Reply #2 on: January 12, 2016, 01:45:48 am »
I was glad to see your use of a config.h file to handle fuse settings. I uae that approach as well, even the same file name. I would suggest that you use conditional compilation so that you can put fuse settings for all of your chips in one file.

Yeah, it's less painful than having a wall of text at the start of your code also means I can stick global defines in there.

Eh, I prefer not to have "one config.h to rule them all", makes it harder to figure out what's going on when I've been away from the project for a few months ;) I also put project specific defines in there as well.

It seems to be one way to approach it is to initialize the ccp on the falling edge and capture on the rising edge. Then test to see if it 0 or 1. Didn't get a chance to go through your code however.

I'm happier with the falling-edge to falling-edge capture, it gives me all the information I need and is more straight forward than juggling modes on the CCP register. Just gotta get the damn interrupt to fire, on a related sidenote, I flipped over to rising edge capture to see if there was some oddball thing about falling edge capture I was missing, same result, no interrupt.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf