DHT11 Interfaz del sensor de humedad / temperatura con PIC18F4620

3

Estoy intentando conectar un PIC con el sensor DHT11 y no está funcionando. Siento que lo he intentado todo. A continuación se muestra una versión simplificada de mi código que debería al menos hacer que el sensor envíe un mensaje de respuesta.

Básicamente, un LED debería encenderse tan pronto como obtenga un valor ALTO del sensor. Pero no consigo nada ...

Si alguien pudiera ayudar a resolver esto sería realmente genial. También estoy adjuntando una imagen de mi configuración.

Muchas gracias!

#include <stdio.h>
#include <stdlib.h>
#include <delays.h>

// PIC18F4620 Configuration Bit Settings

#include <p18F4620.h>


#pragma config OSC = HSPLL      // Oscillator Selection bits (HS oscillator, PLL enabled (Clock Frequency = 4 x FOSC1))
#pragma config WDT = OFF 
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in #pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))

#define DHT11_TRIS  TRISDbits.RD1
#define DHT11_IO    PORTDbits.RD1  //READ USING THIS

#define LED0_TRIS   TRISDbits.RD0
#define LED0_IO     PORTDbits.RD0

int my_flag = 0,bit_counter=39,t1=0,t2=0;

int response[]={0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0};

void high_isr(void);
void low_isr(void);

#pragma code InterruptVectorHigh = 0x08
void interrupt_at_high_vector(void)
{
_asm GOTO high_isr _endasm
}

#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm GOTO low_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
// return from high priority interrupt

}

#pragma interruptlow low_isr
void low_isr (void)
{
// return from low priority interrupt        
}

#define GetSystemClock()    (32000000ul)
#define GetInstructionClock()   (GetSystemClock()/4)



void Delay10us(int us)  {
    Delay10TCYx(((GetInstructionClock()/1000000)*(us)));
}


void DelayMs(int ms){

    unsigned int _iTemp = (ms);     
    while(_iTemp--)         
    Delay1KTCYx((GetInstructionClock()+999999)/1000000);    

}


void main(void){
    int c=0;
    CMCON = 7;

    DHT11_TRIS = 0; //Set DATA OUTPUT
    DHT11_IO = 0;

    LED0_TRIS = 0; //Set LED as OUTPUT
    LED0_IO=0;


    DHT11_IO = 1;

    DelayMs(1000);
    DHT11_IO = 0; //Pull Low
    DelayMs(20);  //For 20ms
    DHT11_IO = 1; //Set HIGH
    Delay10us(3);// For 30us
    DHT11_IO = 0;

    DHT11_TRIS = 1; //Set as input

    while (DHT11_IO !=1){}
    LED0_IO = 1;
    DelayMs(5000);
}

Editar: publicaría mi configuración pero no estoy permitido debido a los puntos de repetición.

    
pregunta DimC

2 respuestas

1

Ok, lo encontré, fue un problema (vergonzoso, debo decirlo) con la fuente de alimentación.

Solo para el registro, aquí está el código completo para el PIC18F4620 usando el compilador C18.

Tenga en cuenta que uso TIMER_3 para medir el ancho de pulso, CCP2 en modo de captura para activar una interrupción en el flanco descendente y lo multiplexé con el PIN RB3.

Crystal Oscillator a 8MHz, con PLL (por lo tanto, el PIC se ejecuta a 40MHz).

También tenga en cuenta sobre el programa: El PIC se mantiene ALTO durante un segundo antes de enviar la señal de 'inicio' al sensor. Encenderá el LED si los valores del sensor se reciben correctamente.

#include <stdio.h>
#include <stdlib.h>
#include <delays.h>

// PIC18F4620 Configuration Bit Settings

#include <p18F4620.h>

// CONFIG1H
#pragma config OSC = HSPLL      // Oscillator Selection bits (HS oscillator, PLL enabled (Clock Frequency = 4 x FOSC1))

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))

// CONFIG3H
#pragma config CCP2MX = PORTBE   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)


#define DHT11_TRIS  TRISBbits.RB3
#define DHT11_IO    PORTBbits.RB3  //READ USING THIS

#define LED0_TRIS   TRISDbits.RD0
#define LED0_IO     PORTDbits.RD0

int bit_counter=39;

int response[]={0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0};

int state;
unsigned char HH=0,HL=0,TH=0,TL=0,CS=0;

void high_isr(void);
void low_isr(void);
void DelayMs(int ms);
void Delay10us(int us);
void init_interrupts(void);


#pragma code InterruptVectorHigh = 0x08
void interrupt_at_high_vector(void)
{
_asm GOTO high_isr _endasm
}

#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm GOTO low_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
// return from high priority interrupt

}

#pragma interruptlow low_isr
void low_isr (void)
{

    if (PIR2bits.CCP2IF && PIR2bits.TMR3IF !=1 ){ // on CCP2 interrupt
    switch(state){

        case 1 :
            PIR2bits.CCP2IF = 0;
            PIR2bits.TMR3IF = 0;
            TMR3H = 0xF6;         // preset for timer3 MSB register
            TMR3L = 0x80;         // preset for timer3 LSB register
            state++;
            break;

        case 2:
            PIR2bits.CCP2IF = 0;
            PIR2bits.TMR3IF = 0;

           if (CCPR2H <= 248) {
               response[bit_counter]= 0;   //Value is Zero

           }

            else if (CCPR2H > 248) {
                response[bit_counter]= 1;

                if (bit_counter>=32) HH |= 1<<(bit_counter-32);
                if (bit_counter<32 && bit_counter>=24) HL |= 1<<(bit_counter-24);
                if (bit_counter<24 && bit_counter>=16) TH |= 1<<(bit_counter-16);
                if (bit_counter<16 && bit_counter>=8)  TL |= 1<<(bit_counter-8);
                if (bit_counter<8 && bit_counter>=0)  CS |= 1<<(bit_counter-0);

            }

            bit_counter--;

           TMR3H = 0xF6;         // preset for timer3 MSB register
           TMR3L = 0x80;         // preset for timer3 LSB register
            break;
    }
    }

    if (PIR2bits.TMR3IF == 1){ //an error occured

        PIR2bits.TMR3IF = 0;
        state = 3;
    }

}

#define GetSystemClock()    (32000000ul)
#define GetInstructionClock()   (GetSystemClock()/4)



void Delay10us(int us)  {
    Delay10TCYx(((GetInstructionClock()/1000000)*(us)));
}


void DelayMs(int ms){

    unsigned int _iTemp = (ms);     
    while(_iTemp--)         
    Delay1KTCYx((GetInstructionClock()+999999)/1000000);    

}


void main(void){

    int c=0;
    HH=0,HL=0,TH=0,TL=0,CS=0;
    CMCON = 7;

    DHT11_TRIS = 0; //Set DATA OUTPUT
    DHT11_IO = 0;

    LED0_TRIS = 0; //Set LED as OUTPUT
    LED0_IO=0;


    DHT11_IO = 1;
    DelayMs(1000);
    DHT11_IO = 0; //Pull Low
    DelayMs(18);  //For 20ms
    DHT11_IO = 1; //Set HIGH
    Delay10us(2);// For 20us

    DHT11_TRIS = 1; //Set as input
    Delay10us(2);// For 20us

    state = 1; //Receive Response
    init_interrupts(); //Initialize Interrupts


    do {} while(bit_counter>=0 && state !=3); //Wait for all bits to be received. If state == 3, it means an error occured

    if (state!=3 &&((HH+HL+TH+TL)&0xFF) == CS){
        LED0_IO = 1;
        DelayMs(1000); //If data received OK blink LED for 1s
        LED0_IO = 0;
    }
    else {
        //Error Occured
         }


}

void init_interrupts(void){
     INTCON = 0b11000000; //Set INTCON <7> for global interrupts, <6> for peripheral interrupts
     RCONbits.IPEN = 1;    // Interrupt Priority Enable
     RCONbits.SBOREN = 0;  // Brown Out Detect Disable

     /*****CCP2 Set to Capture mode******/
     IPR2bits.CCP2IP = 0;  // Set CCP2 Low Priority Interrupt
     CCP2CON = 0b00000100; //Set CCP2 to capture on falling edge
     PIE2bits.CCP2IE = 1;   // CCP2 Interrupt Enable bit
     PIR2bits.CCP2IF = 0;

     /*****TMR3 Set to count to 130us******/
    IPR2bits.TMR3IP = 0;  // Set TMR3 Low Priority Interrupt


    T3CONbits.T3CCP2 = 1;  // bits 6,3  Timer3 is the capture/compare clock source for CCP2;
    T3CONbits.T3CCP1 = 1;
    T3CONbits.T3CKPS1 = 0;  // bits 5-4  Prescaler Rate Select bits
    T3CONbits.T3CKPS0 = 0;  // bit 4
    T3CONbits.T3SYNC  = 1;  // bit 2 Timer3 External Clock Input Synchronization Control bit: 1=Do not synchronize external clock input
    T3CONbits.TMR3CS  = 0;  // bit 1 Timer3 Clock Source Select bit: 0=Internal clock (FOSC/4)

    TMR3H = 0xF6;         // preset for timer3 MSB register
    TMR3L = 0x80;         // preset for timer3 LSB register
    //With these settings, interrupt/overflow occurs every 130us

    PIR2bits.TMR3IF = 0;
    PIE2bits.TMR3IE = 1;    //enable timer interrupt on overflow
    T3CONbits.TMR3ON  = 1;  // bit enables timer


}
    
respondido por el DimC
1

El sensor DHT11 que está utilizando parece usar un protocolo similar a 1-wire , aunque los tiempos parecen un poco diferente de un vistazo Esto fue inventado por Dallas (ahora Maxim) y se usa en muchos de sus dispositivos, el DS18S20 Es un ejemplo de un sensor de temperatura similar al DHT11 hecho por ellos.

Mi experiencia con 1 cable (y la parte máxima anterior) es que es un gran protocolo pero puede ser un poco complicado configurar un micro pequeño debido a la sincronización bastante rápida y no tan tolerante, especialmente si están usando un oscilador de baja velocidad y C. Sin embargo, esta parte de 1 cable parece tener tiempos más relajados y la dirección de los datos parece ser solo de una manera, por lo que las cosas deberían ser un poco más simples (aunque la parte máxima puede hacer más)

De todos modos, la detección de presencia inicial para su parte es fácil ya que solo tiene que mantener la línea presionada durante al menos 18 ms, elevarla a 20-40us y luego soltarla (configurada en entrada de alta impedancia)
No estoy seguro de por qué se dice que debe ser alto para los 20-40us, al soltarlo y hacer que el pullup haga esto (las partes de Maxim lo hacen de esta manera, y esto es estándar para la comunicación de drenaje abierto) tendría el mismo efecto y evitar posibles conflictos en el autobús, pero puede tener que ver con el tiempo de subida necesario. En cualquier caso, siempre que sueltes la línea antes de los 40, debería estar bien.

No lo he comprobado todo, pero en su código de señal de inicio parece que está haciendo las cosas correctamente (aunque evitaría establecer la salida baja antes de configurar el pin para la entrada), así que es probable que tenga que ver con la configuración micro o un problema de conexión (por ejemplo, pin mal conectado, circuito abierto)

Algunas cosas para verificar:

  • ¿Has probado una rutina simple de LED parpadeante para confirmar que tu LED está configurado correctamente?
  • ¿Está absolutamente seguro de que las rutinas de retardo producen el retraso correcto? ¿Has confirmado esto en un alcance?
  • ¿Ha confirmado que el pin PIC está emitiendo los niveles alto / bajo de manera correcta al DHT11? (es decir, el pin está configurado y conectado correctamente; pruebe en el pin DHT11 para asegurarse de que la señal está llegando)
  • ¿Está presente la resistencia pullup de 5kΩ (recomendada en la hoja de datos para las líneas < 20m, si es más tiempo que tiene que reducir el valor) presente en la línea?
respondido por el Oli Glaser

Lea otras preguntas en las etiquetas