touch 34 Posted February 2, 2011 Share Posted February 2, 2011 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. RobG and zeke 2 Quote Link to post Share on other sites
RobG 1,892 Posted February 2, 2011 Share Posted February 2, 2011 ...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.)... This is very nice! Will save me some work. Quote Link to post Share on other sites
zeke 693 Posted February 2, 2011 Share Posted February 2, 2011 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: Quote Link to post Share on other sites
RobG 1,892 Posted February 2, 2011 Share Posted February 2, 2011 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. Quote Link to post Share on other sites
zeke 693 Posted February 2, 2011 Share Posted February 2, 2011 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. Quote Link to post Share on other sites
zeke 693 Posted February 3, 2011 Share Posted February 3, 2011 While I'm working out my reading and writing time slots, I came across this AVR code that reinforces what I'm learning. In the end, I'm sure that I'll be emulating some things in this code. So I thought that someone else might like to check it out too. Quote Link to post Share on other sites
touch 34 Posted February 3, 2011 Author Share Posted February 3, 2011 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. zeke 1 Quote Link to post Share on other sites
RobG 1,892 Posted February 3, 2011 Share Posted February 3, 2011 @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? Quote Link to post Share on other sites
zeke 693 Posted February 22, 2011 Share Posted February 22, 2011 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. Quote Link to post Share on other sites
RobG 1,892 Posted February 23, 2011 Share Posted February 23, 2011 DS1821 spec sheet since the DS1821 is not addressable or multi-droppable, a single 1-Wire-mode DS1821 must be the only slave device on the bus. Quote Link to post Share on other sites
zeke 693 Posted February 23, 2011 Share Posted February 23, 2011 Where were you last Thursday?!? Why didn't you tell me earlier?!? Hindsight is 20-20. I should have read the datasheet before I plugged them in. I was just too eager. 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.