touch 34 Posted February 18, 2012 Share Posted February 18, 2012 Anyone done anything with this sensor? They're insanely cheap at 3 dollars each (http://www.suntekstore.com/goods.php?id=14002854), but they use a really funky (imo) one wire (not dallas one wire) data line. It's so frustrating!!! I can get them to read the data out, I can even read the data they are sending manually using my oscilloscope, but damn If I can write any code to read it.. Guess I just don't have enough knowledge yet. This is the datasheet for it http://www.micropik.com/PDF/dht11.pdf Anyone want to give them a try? I have an extra one somewhere around here I could send out if someone wanted to try it. Quote Link to post Share on other sites
SugarAddict 227 Posted February 18, 2012 Share Posted February 18, 2012 So you have a while loop that measures how long a pin is held high.. put a 5us delay (or 10us?) inside the loop and increment a counter every time it loops, then it's no longer high your counter is *delay = result, shift and append value. Rinse, repeat.... I'm too tired, but I know there's code on here for it... Quote Link to post Share on other sites
touch 34 Posted February 18, 2012 Author Share Posted February 18, 2012 I'd post my code... But I managed to overwrite it accidentally...DERP. I was actually doing that but could not get it to work out with the timings, it would randomly get stuck in the loop. I made a timeout for the while loop, but was still having problems. I was actually thinking about having using a timer to increment 1us and then counting the length of pulses, but didn't have any luck with this. Quote Link to post Share on other sites
oPossum 1,083 Posted February 18, 2012 Share Posted February 18, 2012 They also have a 10 pack for 16.37. That price was too good to refuse, so I ordered some. The TimerA capture/compare could be used to accurately time the edges. That would be the easy way to do it in C, but it limits what pins can be used. Polling or port interrupts can be used to allow the use of any pin. Just configure TimerA for continuous mode and read TAR when a transition is detected. Subtract the previous TAR value, and you know the elapsed time. I will probably write some assembly code once I get the sensors. Quote Link to post Share on other sites
displacedtexan 1 Posted February 18, 2012 Share Posted February 18, 2012 Here is a link on how a guy bit banged the protocol using an arduino: http://sheepdogguides.com/arduino/ar3ne1humDHT11.htm The tutorial is written at a level that I think I could even do it given enough free time. Unfortunately free time is at a premium these days.... Good luck! Quote Link to post Share on other sites
touch 34 Posted February 23, 2012 Author Share Posted February 23, 2012 Encase anyone was wondering, I got some working code for this now: viewtopic.php?f=10&t=2339 Quote Link to post Share on other sites
oPossum 1,083 Posted March 8, 2012 Share Posted March 8, 2012 I got the DHT11 sensors from SunTek today and wrote some C code to read it. This uses TimerA for accurate time measurement, and polling to allow use on any pin. The internal pullup resistor is used, so an external one is not needed.A six byte array passed to read_dht() will be filled with the start bit, 4 data bytes, and the checksum. Return is 0 for success, or a negative value for failure. This code can run at 1 MHz or higher.The DHT11 seems to need about 300 ms between readings, less time will result in the sensor sometimes being non-responsive. The fractional bytes are always 0 for the DHT11. int read_dht(unsigned char *p) { // Note: TimerA must be continuous mode (MC_2) at 1 MHz const unsigned b = BIT4; // I/O bit const unsigned char *end = p + 6; // End of data buffer register unsigned char m = 1; // First byte will have only start bit register unsigned st, et; // Start and end times // p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0; // Clear data buffer // P1OUT &= ~b; // Pull low P1DIR |= b; // Output P1REN &= ~b; // Drive low st = TAR; while((TAR - st) < 18000); // Wait 18 ms P1REN |= b; // Pull low P1OUT |= b; // Pull high P1DIR &= ~b; // Input // st = TAR; // Get start time for timeout while(P1IN & if((TAR - st) > 100) return -1; // Wait while high, return if no response et = TAR; // Get start time for timeout do { // st = et; // Start time of this bit is end time of previous bit while(!(P1IN & ) if((TAR - st) > 100) return -2; // Wait while low, return if stuck low while(P1IN & if((TAR - st) > 200) return -3; // Wait while high, return if stuck high et = TAR; // Get end time if((et - st) > 110) *p |= m; // If time > 110 us, then it is a one bit if(!(m >>= 1)) m = 0x80, ++p; // Shift mask, move to next byte when mask is zero } while(p < end); // Do until array is full // p -= 6; // Point to start of buffer if(p[0] != 1) return -4; // No start bit if(((p[1] + p[2] + p[3] + p[4]) & 0xFF) != p[5]) return -5; // Bad checksum // return 0; // Good read } displacedtexan, touch, Rickta59 and 1 other 4 Quote Link to post Share on other sites
touch 34 Posted March 8, 2012 Author Share Posted March 8, 2012 Glad to see you got them working with timerA, I like your solution a lot more than mine! Quote Link to post Share on other sites
displacedtexan 1 Posted April 4, 2012 Share Posted April 4, 2012 oPossum, Great stuff! Once again, this forum has allowed me to do things that I am not smart enough to do on my own! So, I am trying to use oPossum's code and am having troubling displaying the values using the UART from a 2553. dht_buffer should hold an array of 6 bytes, the start bit, the 4 data bytes, and the checksum. It's my understanding the first data byte holds the left hand side of the decimal point of the humidity value, the next the right hand side, the third the left hand side of the temp in celsius and finally the right hand side of the temp all in binary. I am trying to display via the hardware UART. The included function takes strings and is giving me jibberish. What's the best way to get the data to something I can display via the hardware UART? Anything else I am doing wrong? Thanks for help out a newbie who is learning! /* * ======== Standard MSP430 includes ======== */ #include /* * ======== Grace related includes ======== */ #include /* * VARIABLES */ unsigned char dht_buffer[6]; /* * PROTOTYPES */ int read_dht(unsigned char *p); void TXString( char* string, int length ); /* * ======== main ======== */ int main(int argc, char *argv[]) { CSL_init(); // Activate Grace-generated configuration // >>>>> Fill-in user code here <<<<< while (1) { read_dht(dht_buffer); TXString(dht_buffer, 6); TXString("\r\n", 2); _delay_cycles(500000); // 500 ms - delay } return (0); } int read_dht(unsigned char *p) { // Note: TimerA must be continuous mode (MC_2) at 1 MHz const unsigned b = BIT0; // I/O bit const unsigned char *end = p + 6; // End of data buffer register unsigned char m = 1; // First byte will have only start bit register unsigned st, et; // Start and end times // memset(p, 0, 6); // Clear data buffer // P1OUT &= ~b; // Pull low P1DIR |= b; // Output P1REN &= ~b; // Drive low _delay_cycles(18000); // 18 ms - change this for faster CPU clock P1REN |= b; // Pull low P1OUT |= b; // Pull high P1DIR &= ~b; // Input // st = TAR; // Get start time for timeout while(P1IN & if((TAR - st) > 100) return -1; // Wait while high, return if no response et = TAR; // Get start time for timeout do { // st = et; // Start time of this bit is end time of previous bit while(!(P1IN & ) if((TAR - st) > 100) return -2; // Wait while low, return if stuck low while(P1IN & if((TAR - st) > 200) return -3; // Wait while high, return if stuck high et = TAR; // Get end time if((et - st) > 110) *p |= m; // If time > 110 us, then it is a one bit if(!(m >>= 1)) m = 0x80, ++p; // Shift mask, move to next byte when mask is zero } while(p < end); // Do until array is full // p -= 6; // Point to start of buffer if(p[0] != 1) return -4; // No start bit if(((p[1] + p[2] + p[3] + p[4]) & 0xFF) != p[5]) return -5; // Bad checksum // return 0; // Good read } void TXString( char* string, int length ) { int pointer; for( pointer = 0; pointer < length; pointer++) { volatile int i; UCA0TXBUF = string[pointer]; while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? } } Quote Link to post Share on other sites
mekanoo 0 Posted April 6, 2012 Share Posted April 6, 2012 I'm also having some issues using this with the built in UART to display the values through the USB port. I have tried touch's code (here) without modifications and have a few times got output at the USB serial console. Normally it doesn't output anything at all, but if I switch the jumpers on the launchpad from software to hardware UART when it is already powered and connected to USB, it has a few times shown the output on the console just fine. Then if I closed the terminal on the pc, and opened it again, it didn't work anymore. Does anyone know what I could be missing..? Quote Link to post Share on other sites
oPossum 1,083 Posted April 9, 2012 Share Posted April 9, 2012 This code will display the DHT11 hex data, and humidity and temperature in decimal.It uses software UART so it will work on all versions of the Launchpad.DHT11 is connect to P1.4 #include <msp430.h> #include <stdlib.h> volatile unsigned txdata = 0; #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer0_A0(void) { if(txdata) { (txdata & 1) ? (CCTL0 &= ~OUTMOD2) : (CCTL0 |= OUTMOD2); txdata >>= 1; CCR0 += 104; } else { CCTL0 &= ~CCIE; } } void putc(const char c) { while(CCTL0 & CCIE); txdata = 0x0200 | (c << 1); CCR0 = TAR + 16; CCTL0 = OUTMOD0 | CCIE; } void print(const char *s) { while(*s) putc(*s++); } void print_hex_digit(unsigned n) { putc("0123456789ABCDEF"[n & 0x0F]); } void print_hex_byte(unsigned n) { print_hex_digit(n >> 4); print_hex_digit(n); } void print_dec2(int n) { // Print 2 decimal digits 0 to 99 const div_t d = div(n, 10); if(d.quot) putc('0' + d.quot); putc('0' + d.rem); } int read_dht(unsigned char *p) { // Note: TimerA must be continuous mode (MC_2) at 1 MHz const unsigned b = BIT4; // I/O bit const unsigned char *end = p + 6; // End of data buffer register unsigned char m = 1; // First byte will have only start bit register unsigned st, et; // Start and end times // p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0; // Clear data buffer // P1OUT &= ~b; // Pull low P1DIR |= b; // Output P1REN &= ~b; // Drive low st = TAR; while((TAR - st) < 18000); // Wait 18 ms P1REN |= b; // Pull low P1OUT |= b; // Pull high P1DIR &= ~b; // Input // st = TAR; // Get start time for timeout while(P1IN & if((TAR - st) > 100) return -1; // Wait while high, return if no response et = TAR; // Get start time for timeout do { // st = et; // Start time of this bit is end time of previous bit while(!(P1IN & ) if((TAR - st) > 100) return -2; // Wait while low, return if stuck low while(P1IN & if((TAR - st) > 200) return -3; // Wait while high, return if stuck high et = TAR; // Get end time if((et - st) > 110) *p |= m; // If time > 110 us, then it is a one bit if(!(m >>= 1)) m = 0x80, ++p; // Shift mask, move to next byte when mask is zero } while(p < end); // Do until array is full // p -= 6; // Point to start of buffer if(p[0] != 1) return -4; // No start bit if(((p[1] + p[2] + p[3] + p[4]) & 0xFF) != p[5]) return -5; // Bad checksum // return 0; // Good read } void main(void) { unsigned char dht[6]; // Data from DHT11 int err; // unsigned n; // // WDTCTL = WDTPW | WDTHOLD; // Disable watchdog reset DCOCTL = 0; // Run at 1 MHz BCSCTL1 = CALBC1_1MHZ; // DCOCTL = CALDCO_1MHZ; // CCTL0 = OUT; // Setup serial tx I/O P1SEL = BIT1; // P1DIR = BIT1; // TACTL = TASSEL_2 | MC_2; // TimerA SMCLK, continuous __enable_interrupt(); // // for(; { // for-ever while(CCTL0 & CCIE); // Wait for any serial tx to finish err = read_dht(dht); // Read DHT11 if(err) { // If error... print("Error -"); // putc('0' - err); // print("\r\n"); // } else { // No error... for(n = 0; n < sizeof(dht); ++n) { // Show hex data print_hex_byte(dht[n]); // putc(' '); // } // print(" "); // print_dec2(dht[1]); // Show humimidy print(" RH "); // print_dec2(dht[3]); // Show temperature print(" C\r\n"); // } // __delay_cycles(1000000); // Wait a while } // } YanuarPrijadi, lehongkhai, xpg and 6 others 9 Quote Link to post Share on other sites
deepesh 0 Posted November 10, 2012 Share Posted November 10, 2012 Hi, I am a newbie and just started to learn things with my recently orered cheap Stellaris Launcpad EK-LM4F120XL, Googling for things to get started I found this excellent form. I have two questions : 1). Will the above DHT11 code work with my version of Launchpad ? 2). If yes, any pointer to how to connect it and read data on a PC ? Thanks Quote Link to post Share on other sites
spirilis 1,265 Posted August 4, 2013 Share Posted August 4, 2013 Got the DHT22 (actually AM2302, with built in 5.1K pullup on DATA) working with oPossum's TA0 code in conjunction with ladyada's code for the Arduino library. Bravo! retval = 0: 01 01 97 01 00 99 RH: 40%, Temp: 25 degC Looks like my dehumidifiers are working correctly! Quote Link to post Share on other sites
spirilis 1,265 Posted August 4, 2013 Share Posted August 4, 2013 For what it's worth, my exact code: uartcli.c and uartcli.h from my mspuartcli lib -- https://github.com/spirilis/mspuartcli (just using the basic uart I/O primitives with no CLI input, someday I'll replace it with oPossum's printf() too) dht22.c: /* Code from oPossum @ 43oh */ #include <msp430.h> #include <stdint.h> int read_dht(uint8_t *p) { const uint8_t b = BIT4; const uint8_t *end = p + 6; register uint8_t m = 1; register uint16_t st, et; p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0; P1OUT &= ~b; // Pull low P1DIR |= b; // Output P1REN &= ~b; // Drive low st = TA0R; while((TA0R - st) < 18000); // Wait 18ms P1REN |= b; // Pull low P1OUT |= b; // Pull high P1DIR &= ~b; // Input st = TA0R; // Get start time for timeout while (P1IN & { // Wait while high, return if no response if ((TA0R - st) > 100) return -1; } et = TA0R; // Get start time for timeout do { st = et; // Start time of this bit is end time of previous bit while ( !(P1IN & ) { // Wait while low, return if stuck low if ((TA0R - st) > 100) return -2; } while (P1IN & { // Wait while high, return if stuck high if ((TA0R - st) > 200) return -3; } et = TA0R; // Get end time if ((et - st) > 110) // If time > 110uS, then it is a "one" bit. *p |= m; if (!(m >>= 1)) { // Shift mask, move to next byte when mask is zero m = 0x80; ++p; } } while (p < end); // Do until array is full p -= 6; // Point to start of buffer if (p[0] != 1) // No start bit return -4; if ( ((p[1] + p[2] + p[3] + p[4]) & 0xFF) != p[5] ) // Bad checksum return -5; return 0; // Good read } main.c: #include <msp430.h> #include <stdint.h> #include "uartcli.h" #include "dht22.h" char inbuf[16]; // CLI input, not actually used... volatile uint16_t sleep_counter; int main() { uint8_t dht22buf[6]; int i; WDTCTL = WDTPW | WDTHOLD; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; BCSCTL2 = DIVS_1; BCSCTL3 = LFXT1S_2; TA0CTL = TASSEL_2 | MC_2 | ID_3; uartcli_begin(inbuf, 16); sleep_counter = 0; IFG1 &= ~WDTIFG; IE1 |= WDTIE; _EINT(); while (1) { TA0CTL |= TACLR; i = read_dht(dht22buf); /* Buffer contents: * dht22buf[0] = Start Bit (0x01) * dht22buf[1:2] = Big-Endian 16-bit Unsigned Integer for Relative Humidity, Times 10 * dht22buf[3:4] = Big-Endian 16-bit Signed Integer for Temperature, Times 10 * dht22buf[5] = Checksum (dht22buf[1:4] summed and & 0xFF) */ uartcli_print_str("retval = "); uartcli_print_int(i); uartcli_print_str(": "); for (i=0; i < 6; i++) { uartcli_printhex_byte(dht22buf[i]); uartcli_print_str(" "); } uartcli_print_str("RH: "); uartcli_print_int( (dht22buf[1]*256+dht22buf[2]) / 10 ); uartcli_print_str("%, Temp: "); uartcli_print_int( ((int) ((dht22buf[3] << 8) | dht22buf[4])) / 10 ); uartcli_println_str(" degC"); WDTCTL = WDT_ADLY_250; // VLOCLK = ~744ms per tick sleep_counter = 4; // 744ms * 4 = ~3 seconds LPM3; WDTCTL = WDTPW | WDTHOLD; } } #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { IFG1 &= ~WDTIFG; if (sleep_counter) sleep_counter--; else __bic_SR_register_on_exit(LPM3_bits); } Current output: retval = 0: 01 01 A0 00 F9 9A RH: 41%, Temp: 24 degC retval = 0: 01 01 A0 00 F9 9A RH: 41%, Temp: 24 degC retval = 0: 01 01 9F 00 F9 99 RH: 41%, Temp: 24 degC retval = 0: 01 01 9D 00 F9 97 RH: 41%, Temp: 24 degC Quote Link to post Share on other sites
spirilis 1,265 Posted August 4, 2013 Share Posted August 4, 2013 I've noticed with this sensor, it does take a while for the humidity readings to change; breathing on it directly until it registers 99%, it took quite a while and a bit of blowing to get it to drop below 99%. Probably something you want to sample every 10+ minutes in the field. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.