Jump to content
43oh

Reading DS1821+ Temp Sensor


Recommended Posts

Here is some code I put together for reading the temp from a DS1281+ Sensor and outputting it over serial.

 

You will need to flash the missing 16Mhz DCO values to use this, as explained here: viewtopic.php?f=10&p=2954#p2954

 

#include 

#define UART_TXD   0x02             // TXD on P1.1 (Timer0_A.OUT0)
#define UART_RXD   0x04             // RXD on P1.2 (Timer0_A.CCI1A)
#define UART_TBIT_DIV_2 (16000000 / (9600 * 2))
#define UART_TBIT (16000000 / 9600)

#define delayMicroseconds(n) __delay_cycles(n<<4)

void OneWireOutByte(int _1W_Pin, char d);
char OneWireInByte(int _1W_Pin);
void OneWireReset(int _1W_Pin);
char digitalRead(char pin);
void pinMode(int pin, int out);
void digitalWrite(int pin, int low);
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);

unsigned int txData;	// UART internal variable for TX
unsigned char rxBuffer;  // Received UART character

#define LOW 0
#define HIGH 1

#define INPUT 0
#define OUTPUT 1	

#define WIRE_PORT 7 //Remember you need a 4.7k pullup resistor here.

void main(void)
{
WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer

BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;

P1OUT = UART_RXD;                       // RXD as IN
P1SEL = UART_TXD + UART_RXD;            // Timer function for TXD/RXD pins
P1DIR = UART_TXD;   

  __enable_interrupt();

  TimerA_UART_init();

for(;{
	OneWireReset(WIRE_PORT);
	OneWireOutByte(WIRE_PORT, 0xEE); // start temp conversion
	OneWireReset(WIRE_PORT);
	OneWireOutByte(WIRE_PORT, 0xAA); // read temp
	//this will print the tempature in an int8 over serial every 1 second.
	TimerA_UART_tx(OneWireInByte(WIRE_PORT));
	delayMicroseconds(1000000);
   }
}

void OneWireReset(int Pin) // Send 1Wire Reset
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(500);
pinMode(Pin, INPUT);
delayMicroseconds(500);
}

void OneWireOutByte(int Pin, char d)
{
char n;
for(n=8; n!=0; n--)
{
	if ((d & 0x01) == 1)
	{
		digitalWrite(Pin, LOW);
		pinMode(Pin, OUTPUT);
		delayMicroseconds(5);
		pinMode(Pin, INPUT);
		delayMicroseconds(60);
	}
	else
	{
		digitalWrite(Pin, LOW);
		pinMode(Pin, OUTPUT);
		delayMicroseconds(60);
		pinMode(Pin, INPUT);
	}
	d=d>>1;
}

}

char OneWireInByte(int Pin)
{
char d, n, b;

for (n=0; n<8; n++)
{
	digitalWrite(Pin, LOW);
       pinMode(Pin, OUTPUT);
       delayMicroseconds(5);
       pinMode(Pin, INPUT);
       delayMicroseconds(5);
       b = digitalRead(Pin);
       delayMicroseconds(50);
       d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
   }
return(d);
}

//------------------------------------------------------------------------------
// Arduino like digitalRead, pinMode, and digitalWrite helper functions.
//------------------------------------------------------------------------------
char digitalRead(char pin) {
return (P1IN &  1 << pin) >> pin;
}

void pinMode(int pin, int out){ 			
if(out){
	P1DIR |= (1 << pin);
} else{
	P1DIR &= (~(1 << pin));
} 
}

void digitalWrite(int pin, int low)
{
if (low){
	P1OUT |= ( 1 << pin);
}else{
	P1OUT &= (~(1 << pin));
}
}

//------------------------------------------------------------------------------
// Function configures Timer_A for full-duplex UART operation
//------------------------------------------------------------------------------
void TimerA_UART_init(void)
{
   TACCTL0 = OUT;                          // Set TXD Idle as Mark = '1'
   TACCTL1 = SCS + CM1 + CAP + CCIE;       // Sync, Neg Edge, Capture, Int
TACTL = TASSEL_2 + MC_2;                // SMCLK, start in continuous mode
}

//------------------------------------------------------------------------------
// Outputs one byte using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_tx(unsigned char byte)
{
   while (TACCTL0 & CCIE);                 // Ensure last char got TX'd
   TACCR0 = TAR;                           // Current state of TA counter
   TACCR0 += UART_TBIT;                    // One bit time till first bit
   TACCTL0 = OUTMOD0 + CCIE;               // Set TXD on EQU0, Int
   txData = byte;                          // Load global variable
   txData |= 0x100;                        // Add mark stop bit to TXData
   txData <<= 1;                           // Add space start bit
}

//------------------------------------------------------------------------------
// Prints a string over using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_print(char *string)
{
   while (*string) {
       TimerA_UART_tx(*string++);
   }
}

//------------------------------------------------------------------------------
// Timer_A UART - Transmit Interrupt Handler
//------------------------------------------------------------------------------
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
   static unsigned char txBitCnt = 10;

   TACCR0 += UART_TBIT;                    // Add Offset to CCRx
   if (txBitCnt == 0) {                    // All bits TXed?
       TACCTL0 &= ~CCIE;                   // All bits TXed, disable interrupt
       txBitCnt = 10;                      // Re-load bit counter
   }
   else {
       if (txData & 0x01) {
         TACCTL0 &= ~OUTMOD2;              // TX Mark '1'
       }
       else {
         TACCTL0 |= OUTMOD2;               // TX Space '0'
       }
       txData >>= 1;
       txBitCnt--;
   }
}     

//------------------------------------------------------------------------------
// Timer_A UART - Receive Interrupt Handler
//------------------------------------------------------------------------------
#pragma vector = TIMERA1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
   static unsigned char rxBitCnt = 8;
   static unsigned char rxData = 0;

   switch (__even_in_range(TAIV, TAIV_TAIFG)) { // Use calculated branching
       case TAIV_TACCR1:                        // TACCR1 CCIFG - UART RX
           TACCR1 += UART_TBIT;                 // Add Offset to CCRx
           if (TACCTL1 & CAP) {                 // Capture mode = start bit edge
               TACCTL1 &= ~CAP;                 // Switch capture to compare mode
               TACCR1 += UART_TBIT_DIV_2;       // Point CCRx to middle of D0
           }
           else {
               rxData >>= 1;
               if (TACCTL1 & SCCI) {            // Get bit waiting in receive latch
                   rxData |= 0x80;
               }
               rxBitCnt--;
               if (rxBitCnt == 0) {             // All bits RXed?
                   rxBuffer = rxData;           // Store in global variable
                   rxBitCnt = 8;                // Re-load bit counter
                   TACCTL1 |= CAP;              // Switch compare to capture mode
                   __bic_SR_register_on_exit(LPM0_bits);  // Clear LPM0 bits from 0(SR)
               }
           }
           break;
   }
}

 

I would like to point a few things that I will improve on this code one day, but don't have the knowledge to do at the moment (this is my first C code I've ever written.). USI could be used to send the temp readout because we don't really have any reason to receieve UART, the timer then could be used for timing of reading the sensor, rather than a delay.

 

I was also able to get it working in 1wire mode - I did not need to use a transistor, however I did not test programming the DS1821+, as my main goal was to readout the temperature.

 

You will also need to use something like Realterm that lets you view the serial output as an int8.

 

There is one question I have that I cannot seem to find an answer too, here or via google. If I wanted to convert the bytes received from OneWireInByte(WIRE_PORT) to an ASCII number format, so that you could view it in putty or whatnot, how would I go about doing that?

 

Also, a special thanks to zeke as he is the main reason this works, I could have not have gotten it properly working without him figuring out how to flash the 16Mhz DCO values.

Link to post
Share on other sites

I think I am going to go insane.

 

Touch, I tried your code and all I get is 0xFF. Sound familiar?

 

The only difference I can see is that I'm using a ds18b20 temp sensor instead of a ds1821 thermostat device.

 

I've determined that the problem is that I cannot get the msp430 to read the 1-wire bus.

 

Talk about frustrating.

:evil:

Link to post
Share on other sites

And I thought I am the only one getting Fn Fs, 0xFF that is :)

 

Data sheet tells me that I should read no later than 15us after falling edge of the read slot, but it also tells me that DS will pull wire down for 45us. It doesn't tell me when DS starts pulling, all I know is that it should be right after start of read slot.

I guess I will try to use touch's timing and see if that works. Also, I am wondering if by mistake I have written something to control register that I should have not. Maybe I should try to write 0x00 to control register first.

 

Also, it is not clear to me if initialization sequence is required before ALL commands, it appears that it is.

 

@zeke, looking at 18B20 data sheet, there are major differences.

Link to post
Share on other sites
And I thought I am the only one getting Fn Fs, 0xFF that is :)

There's enough for all to go around! Why should I have all the fun? ;)

 

Also, it is not clear to me if initialization sequence is required before ALL commands, it appears that it is.

I agree. It looks like that to me too.

 

@zeke, looking at 18B20 data sheet, there are major differences.

Yeah, I realized that after I took a mental health break. I have my face buried in the 18b20 datasheet right now.

 

I did finally get my reset function to detect the presence pulse. That's the only thing working for me at the moment.

 

I'm presently working out the write and read functions based upon the Read/Write Time Slot Timing Diagrams in the datasheet.

Link to post
Share on other sites

I've got some DS1820''s myself and have been unable to get them working. I'm going to try a little later tonight, but I know the DS1821 works fine.

 

Take a look at this:

http://milesburton.com/index.php?title= ... ol_Library

http://www.pjrc.com/teensy/td_libs_OneWire.html

http://www.phanderson.com/arduino/ds18b20_1.html

 

It really seems like for the DS1820's sensor we need to go about properly addressing it.

 

Anyways, I'll try to give it a try tonight, it would be nice to get high resolution working too.

Link to post
Share on other sites

@touch

I have a question, are you getting continuous readings when you put your

      OneWireReset(WIRE_PORT);
     OneWireOutByte(WIRE_PORT, 0xEE); // start temp conversion

outside of for loop?

 

I was under the impression that we only need to send 0xEE once, and then just do 0xAA, am I missing something here?

Link to post
Share on other sites
  • 3 weeks later...

I just wanted to tack on to this thread a vital piece of information about the ds1821 temp sensor.

 

If you have a 1-Wire bus filled with many devices (ie: ds18b20, ds18s20, ds1822) and you know you will have to search the 1-Wire bus for all the ROM ID's then don't put a ds1821 on that bus.

 

It will cause the search rom function to fail out prematurely.

 

The DS1821 does not have the ability to respond to the SEARCH ROM command (0xF0).

 

This becomes a non-issue if you never use the Search ROM function.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...