I bought a digital thermometer DS18B20 and I wanted to connect it to my LaunchPad. DS18B20 communicates via 1-Wire protocol. I used a bit banging to emulate the protocol. CPU speed should be over 1 MHz since the protocol requires timing almost on a microsecond level.
If you are not very familiar with 1-Wire protocol I suggest to check out an excellent analysis and illustrated guide by Ishan.
I used only two wires connection where the DS’s VDD is connected to the ground. DS’s datasheet requires an external pull up 4.7 kohm resistor on the data line but I successfully used the MSP’s internal pull up resistor.
Download
Example of communication with DS18B20
Lets connect the thermometer e.g. to pin P1.7.
#include <msp430.h>
#include "onewire.h"
#include "delay.h"
int main()
{
onewire_t ow;
int i;
uint8_t scratchpad[9];
WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
BCSCTL1 = CALBC1_8MHZ;
DCOCTL = CALDCO_8MHZ;
ow.port_out = &P1OUT;
ow.port_in = &P1IN;
ow.port_ren = &P1REN;
ow.port_dir = &P1DIR;
ow.pin = BIT7;
onewire_reset(&ow);
onewire_write_byte(&ow, 0xcc); // skip ROM command
onewire_write_byte(&ow, 0x44); // convert T command
onewire_line_high(&ow);
DELAY_MS(800); // at least 750 ms for the default 12-bit resolution
onewire_reset(&ow);
onewire_write_byte(&ow, 0xcc); // skip ROM command
onewire_write_byte(&ow, 0xbe); // read scratchpad command
for (i = 0; i < 9; i++) scratchpad[i] = onewire_read_byte(&ow);
_BIS_SR(LPM0_bits + GIE);
return 0;
}
Search ROM command
Materials for inspiration:
- DS18B20 datasheet contains a flowchart but it doesn’t show very well the recursive nature of the algorithm
- 1-Wire Search Algorithm from Maxim
Following example shows usage of search ROM command (0xF0). I used printf() and UART for debugging.
#include <msp430.h>
#include <stdio.h>
#include <stdint.h>
#include "onewire.h"
#include "delay.h"
/***************************************************************/
int putchar(int c)
{
if (c == '\n') putchar('\r');
while (!(IFG2&UCA0TXIFG));
UCA0TXBUF = c;
return 0;
}
/***************************************************************/
void uart_setup()
{
P1SEL = BIT1 + BIT2;
P1SEL2 = BIT1 + BIT2;
P1DIR &= ~ BIT1;
P1DIR |= BIT2;
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 8MHz 9600
UCA0BR1 = 0x03; // 8MHz 9600
UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1
UCA0CTL1 &= ~UCSWRST;
}
/***************************************************************/
void search(onewire_t *ow, uint8_t *id, int depth, int reset)
{
int i, b1, b2;
if (depth == 64)
{
// we have all 64 bit in this search branch
printf("found: ");
for (i = 0; i < 8; i++) printf("%02x", id[i]);
printf("\n");
return;
}
if (reset)
{
if (onewire_reset(ow) != 0) { printf("reset failed\n"); return; }
onewire_write_byte(ow, 0xF0); // search ROM command
// send currently recognized bits
for (i = 0; i < depth; i++)
{
b1 = onewire_read_bit(ow);
b2 = onewire_read_bit(ow);
onewire_write_bit(ow, id[i / 8] & (1 << (i % 8)));
}
}
// check another bit
b1 = onewire_read_bit(ow);
b2 = onewire_read_bit(ow);
if (b1 && b2) return; // no response to search
if (!b1 && !b2) // two devices with different bits on this position
{
// check devices with this bit = 0
onewire_write_bit(ow, 0);
id[depth / 8] &= ~(1 << (depth % 8));
search(ow, id, depth + 1, 0);
// check devices with this bit = 1
id[depth / 8] |= 1 << (depth % 8);
search(ow, id, depth + 1, 1); // different branch, reset must be issued
} else if (b1) {
// devices have 1 on this position
onewire_write_bit(ow, 1);
id[depth / 8] |= 1 << (depth % 8);
search(ow, id, depth + 1, 0);
} else if (b2) {
// devices have 0 on this position
onewire_write_bit(ow, 0);
id[depth / 8] &= ~(1 << (depth % 8));
search(ow, id, depth + 1, 0);
}
}
/***************************************************************/
int main()
{
onewire_t ow;
uint8_t id[8]; // 64 bits
WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
BCSCTL1 = CALBC1_8MHZ;
DCOCTL = CALDCO_8MHZ;
uart_setup();
ow.port_out = &P1OUT;
ow.port_in = &P1IN;
ow.port_ren = &P1REN;
ow.port_dir = &P1DIR;
ow.pin = BIT7;
printf("start\n");
search(&ow, id, 0, 1);
printf("done\n");
_BIS_SR(LPM0_bits + GIE);
return 0;
}
hi
can you elaborate a bit more on the code.
like how do you select a thermometer when you have multiple connected on the line?
the code does not compile as is, most likely
onewire_…_(ow)
should be
onewire_…_(&ow)?
i’m a newbie with the msp430, i just received a launchpad in the mail and was testing it out.
cheers,
kf
Comment by kristfin — 2012-05-08 @ 02:22
kristfin: Hi! Thanks for pointing out the uncompilable code. I copied fragments of my code here and I didn’t test this example. Now it should work.
About the ROM searching – I have those thermometers each on individual line so I only issue “skip ROM”. I’ll try ROM searching and I’ll post the result.
Comment by admin — 2012-05-08 @ 09:39
I tried the “Example of communication with DS18B20” code and I constantly get:
scratchpad[2] = 0x4B
scratchpad[3] = 0x46
the others are 0
which is 52 celsius, in room temp. (doesn’t even change)
18B20 has stable power.
What could be the problem?
Thanks,
Comment by Zoli — 2012-07-25 @ 22:28
Zoli: Hi! This is strange because at least scratchpad[5…7] must be 0xFF, 0x0C, 0x10. Did you try it with more DS18B20 samples? It might be broken. Also try only reading the scratchpad without previous temperature command sequence.
Comment by admin — 2012-07-26 @ 07:22
Using recursion might be not such a good idea taking into account small amount of memory available.
Take a look at this http://www.pjrc.com/teensy/td_libs_OneWire.html library – it uses simple iteration.
Comment by ss — 2013-01-09 @ 10:49
Hello!
Why are you not using function ewire_write_b()?
Maybe function newire_write_bit() must have this body:
void onewire_write_bit(onewire_t *ow, int bit)
{
DELAY_US(2); // recovery, min 1us
onewire_line_hight(ow); //this changes
if (bit)
DELAY_US(6); // max 15us
else
DELAY_US(64); // min 60us
onewire_line_release(ow);
// rest of the write slot
if (bit)
DELAY_US(64);
else
DELAY_US(6);
}
Comment by Oleg — 2013-01-16 @ 23:46
…. or maybe that:
void onewire_write_bit(onewire_t *ow, int bit)
{
DELAY_US(2); // recovery, min 1us
onewire_line_low(ow); //this changes
if (bit)
{
DELAY_US(6); // max 15us
onewire_line_high(ow); //!this changes
}
else
DELAY_US(64); // min 60us
onewire_line_release(ow);
// rest of the write slot
if (bit)
DELAY_US(64);
else
DELAY_US(6);
}
Comment by Oleg — 2013-01-16 @ 23:55
Oleg: What do you mean “not using function ewire_write_b()”? Where?
OneWire protocol is time/delay based so the bit value is determined by a delay length and not the line state.
Comment by admin — 2013-01-17 @ 15:05
I learned the protocol. I used your code:
ow.port_out = &P1OUT;
ow.port_in = &P1IN;
ow.port_ren = &P1REN;
ow.port_dir = &P1DIR;
ow.pin = BIT7;
onewire_reset(&ow);
onewire_write_byte(&ow, 0xcc); // skip ROM command
onewire_write_byte(&ow, 0x44); // convert T command
onewire_line_high(&ow);
DELAY_MS(800); // at least 750 ms for the default 12-bit resolution
onewire_reset(&ow);
onewire_write_byte(&ow, 0xcc); // skip ROM command
onewire_write_byte(&ow, 0xbe); // read scratchpad command
for (i = 0; i < 9; i++) scratchpad[i] = onewire_read_byte(&ow);
…
but ALL scratchpad[i] = 0xFF;(scratchpad[0] = 0xFF, scratchpad[1] = 0xFF …)
Why this code does not work?
I also replaced the code on the other:
int id[8];
onewire_reset(&ow);
onewire_write_byte(&ow, 0x33); // skip ROM command
for (i = 0; i < 9; i++) id[i] = onewire_read_byte(&ow);
all id's also equals '0xFF'. Whats wrong?!
Comment by Elvin — 2013-01-18 @ 21:58
Elvin: Hi! There might be many places where it should go wrong – wrong delay function (depends on CPU speed), wrong thermometer connection, … What MCU do you have? What frequency?
Comment by admin — 2013-01-19 @ 13:56
Hi! My project:http://www.shelezyakin.ru/?p=104
It’s work!
Comment by Eugene — 2013-03-19 @ 12:41
hi,
did anyone got the problem when using the inline function to change the status of the corresponding port?
could the inline function failed?When the function failed, and it never change the status that I hope!
Comment by lzyun — 2013-09-13 @ 11:19
lzyun: Hi! What exact problem do you experience? What MCU and port do you use? Can you post your setup code e.g. on https://gist.github.com/?
Comment by admin — 2013-09-13 @ 11:30