Setting Pin to Input Delievering Unexpected Results

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First, here is the code I am playing with:

#include "DHT.h"

uint8_t DHT_Read_Data(uint8_t select){

    //data[5] is 8byte table where data come from DHT are stored
    //laststate holds laststate value
    //counter is used to count microSeconds
    uint8_t data[5], laststate = 0, counter = 0, j = 0, i = 0;
    
    //Clear array
    data[0] = data[1] = data[2] = data[3] = data[4] = 0;
    
    cli();                              //Disable interrupts
    
    //Prepare the bus
    DDRC   |= (1<<PC0);    //Set pin Output
    PORTC        |= (1<<PC0);    //Pin High
    _delay_ms(250);                     //Wait for 250mS
    
    //Send Request Signal
    PORTC        &=~(1<<PC0);    //Pin Low
    _delay_ms(20);                      //20ms Low 
    
    PORTC        |= (1<<PC0);    //Pin High
    _delay_us(40);                      //40us High
	
    //Set pin Input to read Bus
    DDRC   &=~(1<<PC0);    //Set pin Input

    laststate=DHT_Read_Pin;             //Read Pin value
    
    //Repeat for each Transistions
    for (i=0; i 2)) {
            //Save bits in segments of bytes
            //Shift data[] value 1 position left
            //Example. 01010100 if we shift it left one time it will be
            //10101000
            data[j/8]<<=1;
            if (counter >= 40) {    //If it was high for more than 40uS
                data[j/8]|=1;       //it means it is bit '1' so make a logic
            }                       //OR with the value (save it)
            j++;                    //making an OR by 1 to this value 10101000
        }                           //we will have the resault 10101001
                                    //1 in 8-bit binary is 00000001
        //j/8 changes table record every 8 bits which means a byte has been saved
        //so change to next record. 0/8=0 1/8=0 ... 7/8=0 8/8=1 ... 15/8=1 16/8=2
        laststate=DHT_Read_Pin;     //save current state
        counter=0;                  //reset counter
        
    }
    sei();                          //Enable interrupts
    
    //Check if DHT-11 is connected
    if (data[0]==0 && data[1]==0 && data[2]==0 && data[3]==0) {
        //uart_puts("\r\nDHT not pluged!");
        return(4);
    }
    //Check if data received are correct by checking the CheckSum
    if (data[0] + data[1] + data[2] + data[3] == data[4]) {
        if (select==DHT_Temp) {     //Return the value has been choosen
            return(data[2]);
        }else if(select==DHT_RH){
            return(data[0]);
        }
    }else{
		return(8);
        //uart_puts("\r\nCheck Sum Error");
    }
}

Here is the header file:

#include 
#include 
#include 
#include 
 
//DHT Pin and Port
#define DHT_PORT    PORTC
#define DHT_PIN     0

//The packet size is 40bit but each bit consists of low and high state
//so 40 x 2 = 80 transitions. Also we have 2 transistions DHT response
//and 2 transitions which indicates End Of Frame. In total 84
#define MAXTIMINGS  84

//Select between Temp and Humidity Read
#define DHT_Temp    0
#define DHT_RH      1

#define DHT_Read_Pin    (PORTC & _BV(PC0))

#define F_CPU 1000000

//This is the main function which requests and reads the packet
uint8_t DHT_Read_Data(uint8_t select);

It's code to read values from a temperature sensor (DHT-11) which follows the 1-wire protocol. Anyhow, to cut a long story short, it's not working. I have been playing with it for hours, and have triangulated the problem and here is what I know:

1. The code is getting stuck in the first while loop

while (laststate==DHT_Read_Pin)

2. Something funny is happening with the pin reading. You'll notice I added some UART commands to the while loop to get some feedback and understand what's going on (those functions are defined in another file). Well, what I notice is that just before I switch PC0 to input, I set it HIGH one last time. It seems like after switching it to input, it perpetually gets stuck in this HIGH state because the UART keeps giving me a value of 1. To test this theory, I changed the value of the PC0 to LOW, and then set it to input and let the rest of the code run. Well, the UART output now becomes zero. So I suspect something odd is happening when I switch the pin modes.

In any case, my code seems to just be stuck in this while loop and can't move forward. Any ideas? I'm at a complete loss.

Oh ya, I'm running this on an ATMega8, default 1MHz clock.

Many thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define DHT_Read_Pin    (PORTC & _BV(PC0)) 

To read a port you need PINx, not PORTx.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Well, what I notice is that just before I switch PC0 to input, I set it HIGH one last time. It seems like after switching it to input, it perpetually gets stuck in this HIGH state because the UART keeps giving me a value of 1. To test this theory, I changed the value of the PC0 to LOW, and then set it to input and let the rest of the code run. Well, the UART output now becomes zero. So I suspect something odd is happening when I switch the pin modes.

This symptom would be normal for a floating input pin--it will tend--at least for a while--to stay at whatever level it is at.

What is on PC0? Are you positive about that?

Is one-wire always driven?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Setting PORTxn high for an input enables the internal pullup.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks guys, so using PINC instead of PORTC did get me further. But it still doesn't seem to be working. I have a hunch that my clock speed might be an issue. This code was originally designed for 16MHz, but I'm using the internal 1MHz. I made sure I defined F_CPU appropriately, so should this still be causing any problems? I mean 20us, or 40ms are the same regardless of clock speed right?

Sorry, I'm quite new to all this, and appreciate all your help so much.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The delay functions will work pretty much the same when you change F_CPU to match your uC/fuses, but other things may need to be changed too. E.g. the setup of timers, adc and uart stuff.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChaunceyGardiner wrote:
The delay functions will work pretty much the same when you change F_CPU to match your uC/fuses, but other things may need to be changed too. E.g. the setup of timers, adc and uart stuff.

I don't think any of those exist in my project though.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What does USARTWriteChar() do, then ?

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChaunceyGardiner wrote:
What does USARTWriteChar() do, then ?

It's defined in main.c like this:

void USARTWriteChar(char data)
{
   //Wait untill the transmitter is ready
   while(!(UCSRA & (1<<UDRE))){}
   UDR=data;
}

FYI, my ATMega8 is running at 1MHz at a baud rate of 4800 for the UART. I keep checking to make sure the sensor works, and it works perfectly with my Arduino (using a different library built for it). It has to be something with my code then. If you want me to post a zipped folder with my project files, let me know. Thanks for your help!

P.S. I desperately need a logic analyzer :x

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One thing that is definitely going to be off after the transition from 16 to 1 MHz is your us counter. While it wasn't very accurate before, it is now going to be way too low to provide you with an accurate measurement.

You may want to use a timer to measure time with us resolution.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Alright, I'll bite. I switched to a 16 MHz crystal, and it works now. Yeesh, I guess it was too imprecise with the internal 1 MHz eh? Do you know why, and how I can identify this threshold for future devices (i.e. what clock speed is ideal for a certain device)?

Many thanks for walking me through a solution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The point really is that there is overhead in your loop - code that is executed in addition to the 1 us delay - and this overhead takes 16 times as long when you reduce the speed from 16 to 1 MHz.

The overhead is significant - one clock cycle is 1 us at 1 MHz - and you have many instructions in there, each taking 1-2 clock cycles.

I would use a timer to measure this sort of thing.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Make sense, thanks a lot!