PDA

View Full Version : How come my DS18S20 code still works?



Wilson
- 12th September 2007, 13:14
I have been trying for 2 weeks to get my project working properly and now I am at my wits end.
Part of my project is to read a DS18S20 and display the correct termperature on a 2x16 lcd display. I have searched the forum and all the examples for reading the device are the same so I just used it and it worked great.
Problem is I cannot understand what the count_remain variable actually does. I am also confused about the count_per_c variable. So I did what any older person would do and just remarked them out of the code to see what would happen. But nothing did. Everything worked the same.

the code is as follows:

Hope someone can help

Wilson

@ DEVICE pic16F628a, INTRC_OSC_NOCLKOUT,LVP_OFF,WDT_OFF,MCLR_OFF,PROTEC T_OFF
@ DEVICE pic16F628a, CPD_OFF
trisa =%00100000
trisb =%00000000
cmcon =%00000111 'Comparators Off
Define LCD_BITS 4
Define LCD_DREG PORTB
Define LCD_DBIT 0
Define LCD_RWREG PORTA
Define LCD_RWBIT 4
Define LCD_RSREG PORTA
Define LCD_RSBIT 3
Define LCD_EREG PORTA
Define LCD_EBIT 2
Define LCD_COMMANDUS 5000
Define LCD_DATAUS 100
Define LCD_INITMS 2

pause 100

DQ VAR PORTB.5 ' One-wire data pin
temperature VAR WORD ' Temperature storage
'I removed the next two lines
'count_remain VAR BYTE ' Count remaining
'count_per_c VAR BYTE ' Count per degree C

loop:
LCDOUT $FE, 1
LCDOut $FE, $C0, "Temp ", dec(temperature / 100)," C "

OWOut DQ, 1, [$CC, $44] ' Start temperature conversion
pause 750 'NEEDED FOR TEMP STABILIZING

'and the following three lines
'waitloop:
'OWIn DQ, 4, [count_remain] ' Check for still busy converting
'IF count_remain = 0 Then waitloop

OWOut DQ, 1, [$CC, $BE] ' Read the temperature

'as well as the last bits of the next two lines
OWIn DQ, 0, [temperature.LOWBYTE, temperature.HIGHBYTE]', Skip 4, count_remain, count_per_c]

temperature = (((temperature >> 1) * 100) - 25)' + (((count_per_c - count_remain) * 100) / count_per_c)

goto loop

Wilson
- 13th September 2007, 11:35
I have studied (but not fully understood) the 18S20 data sheet and concluded that all that needs to happen is...

1: Initiate the device (start the conversion)
2: Wait until the conversion is complete (pause for at least 750ms)
3: Read what is in the register.

I have it running okay. The LCD displays the raw temp i.e. the register value in decimal as well as hex and whether bit 0 is set or not.

It seems that the value in the 18S20 register is actually 0.5 degrees centigrade units
so I figured out why not just divide it by 2 to get the temperature.




@ DEVICE pic16F628a, INTRC_OSC_NOCLKOUT,LVP_OFF,WDT_OFF,MCLR_OFF,PROTEC T_OFF
@ DEVICE pic16F628a, CPD_OFF
trisa =%00100000
trisb =%00000000
cmcon =%00000111 'Comparators Off
Define LCD_BITS 4
Define LCD_DREG PORTB
Define LCD_DBIT 0
Define LCD_RWREG PORTA
Define LCD_RWBIT 4
Define LCD_RSREG PORTA
Define LCD_RSBIT 3
Define LCD_EREG PORTA
Define LCD_EBIT 2
Define LCD_COMMANDUS 5000
Define LCD_DATAUS 100
Define LCD_INITMS 2

pause 100

DQ VAR PORTB.5 ' One-wire data pin
temperature VAR WORD ' Temperature storage
decimal var byte
loop:

OWOut DQ, 1, [$CC, $44] ' Start temperature conversion
pause 750 'Needed to complete conversion
OWOut DQ, 1, [$CC, $BE] ' Read the temperature
OWIn DQ, 0, [temperature.LOWBYTE, temperature.HIGHBYTE]

'just check if bit0 is set
decimal = temperature mod 2
if decimal = 1 then 'if set, it must be .5
decimal =5
else
decimal = 0
endif

' raw value is the register value
lcdout $FE,1, "Raw ", dec(temperature)," ", hex(temperature), " ", dec(decimal)

LCDOut $FE, $C0, "Temp ", dec(temperature /2), ".", dec(decimal), " C"

goto loop



My LCD displays
Raw 44 2C 0
Temp 22.0 C

When I touch the 18S20 for five seconds I get

Raw 55 37 5
Temp 27.5 C

I am not sure how accurate it is because I do not have a reference temperature.
I tried putting the 18S20 under my tongue but I got a shock.
It seems to work okay but I am not convinced it is the correct way to go about it.

Am I on the right track or just plain lucky that it works?

Wilson

Acetronics2
- 13th September 2007, 12:35
Hi,

At this time, there's another thread running about the 18S20 or 18B20 ...

just have a look to the methods used ...

http://www.picbasic.co.uk/forum/showthread.php?t=7079

Alain

Wilson
- 13th September 2007, 13:41
Thanks Alain

As I mentioned when I started the thread, I have already searched the forum read all the posts about the 18S20.
The only thing I learned was that someone wrote a piece of code a long time ago and it seems to be the defacto standard- everyone uses it. The samples are the same, comments and all. Thats okay. Cutting and pasting is easy but it doesn't help me learn.

Wilson

Acetronics2
- 13th September 2007, 17:16
Hi, Wilson

Learning is on your own whatever the book ...

so just trying to understand what happens is ... enough !!!

Why not cut and paste ... if you know what you're pasting ...

LOL ...

Following you, ... you also can make it work without Owin ansd Owout ... just toggling pins on the adequate moment ...

Alain

b1arrk5
- 14th September 2007, 18:44
Have you looked at Bruce's website? His Rentron Electronics site has some tutorials on using one wire devices, and explains it very well. He used the 18b20 in his examples, but I was able to get an 18s20 working after reading his explanations. I'm not where I can look it up, but I think the count remaining is a way of checking to see if the temperature conversion is completed or not, instead of just waiting a set amount of time like the 'pause' command does. So just pausing 750ms eliminates the need to check if the conversion is completed. Bruce also has an example that uses DIV32 to get better precision, but for my application anything within three degrees was close enough. Here is the link to the first example.

http://www.rentron.com/PicBasic/PBP1-wire.htm

Jerry.

Wilson
- 15th September 2007, 12:35
Thanks Jerry,

Been there and it helped a little bit but I still don't know what the count_remain is.
You could be right but I'm still not sure. To be honest, I don't think anybody knows exactly what it is. I'll just treat it as a Dallas magic number.

I monitored its value and it jumps around from 1 to 16 when the device temperature rises and falls, but when the temperature stabilises, it just sits around 8 to 9.
Anyhow I think I had a major breakthrough.

The temperature of my device right now reads 002AH
temperature2 = (temperature >> 1) effectively divides the value by 2 and gets rid of the radix point and now equals 0015h beacause of this move.

Because Dallas gave us this formula with the assumption everyone can follow it,
I just used it and hoped for the best.
first I moved 0015h left 8 bits so it becomes 1500h
then subtract 2.5 degree C (100h/4 = 40h =0.25C in Hex)
so 1500h minus 0040h = 14C0h

Dallas says count_per_C = 10h and I picked a number for count_remain - 9h
so 10h minus 9h = 7h then Dallas says to multiply this by 100h then divide 10h
okay, 7h * 100h = 0700h then divide by count_per_C (10h) = 0070h
now I have 14C0h + 70h = 1530h
so the 15h = 21C and the decimal part, 30h = 30h/100h = 48/256 = 0.1875 or 0.19
So my display now shows 21.19 C



DQ VAR PORTB.5 ' One-wire data pin
temperature VAR WORD ' Temperature storage
temperature2 VAR WORD
temperature3 VAR WORD
count_remain VAR BYTE ' Count remaining
count_per_c VAR BYTE ' Count per degree C
fractemp var word

loop:

OWOut DQ, 1, [$CC, $44] ' Start temperature conversion
pause 750 'NEEDED FOR TEMP STABILIZING

waitloop:
OWIn DQ, 4, [count_remain] ' Check for still busy converting
IF count_remain = 0 Then waitloop
OWOut DQ, 1, [$CC, $BE] ' Read the temperature
OWIn DQ, 0, [temperature.LOWBYTE, temperature.HIGHBYTE, Skip 4, count_remain, count_per_c]

temperature2 = (temperature >> 1)

temperature3= (temperature2 <<8 -64) + (((count_per_c - count_remain) * 100) / count_per_c)
fractemp = ((temperature3 <<8 >>8*64) >>8)

lcdout $FE,1, "Raw ", hex(temperature)," ", hex(temperature2), " ", dec(count_remain)
lcdout $FE, $C0, "Real ", dec(temperature2), ".", dec2(fractemp)

goto loop


I don't know how accurate the fraction part is but I reckon the whole number is okay

Bottom line is Jerry, I need someone willing to point out mistakes, offer sugestions or give constructive critisism.

Wilson

b1arrk5
- 15th September 2007, 15:31
Hi Wilson,

I am back where I can access better resources, and I think I can explain this satisfactorily now. The Dallas 18s20 offers a 9 bit thermometer that can measure from -55 degrees C. up to 125 degrees, a total range of 180 degrees C. Nine bit resolution allows for numbers from 0 to 511, so if the temperature is -55 degrees we would read a 0, and a reading of 511 would equate to 125 degrees. However, the ninth bit is used to provide a positive or negative reading, so our resolution now drops to 8 bits, from 0 to 255. Starting at -55 degrees C we should read 0, and +125 degrees will result in 255. Each step is roughly .7, but the device only measures in half degree steps, so as you guessed before, dividing by 2 will get you close. The Dallas 18B20 (a different chip!) offers user selectable resolution of 9 to 12 bits, consequently it can distinguish smaller changes in temperature, less than a half of a degree. The 18S20 uses the Count Remain byte to allow the user to calculate a little better resolution, so if you need to know the difference between say 20.5 degrees and 21.0 degrees you can calculate it if you need to. My guess is that internally the 9 bit chip really converts to higher resolution, and puts the extra bits in the Count Remain byte, but that is only my guess. The steps must be different, that would explain why the Count Per Degree C. is fixed at 10h in their formula.
Realistically most of us don't need that much precision, anything within two or three degrees will be close enough. Dallas/Maxim shows the accuracy as being 0.5 degrees C. in the middle range, and most other manufacturers give an accuracy of +/- 2.0 degrees C. in their high precision sensors.
In my earlier post I was mistaken (happens often!), you can perform time slot reads to see if the conversion is finished, or you can just pause 750ms like you did. Temperature doesn't usually change so fast that you can't waste a few milliseconds waiting for the conversion to finish, however if your application is doing other things as well then reading the time slot will be faster. If you were trying to service USB ports or something then you might not want to pause that long.
I have two identical LABX-USB boards, running identical programs, using two identical 18S20 chips, and they are always two degrees different, even sitting side by side on my bench. Part of this discrepancy is likely due to my conversion to Fahrenheit, but it is close enough for my application.

Jerry.

Wilson
- 15th September 2007, 23:36
Hello Jerry.

Excellent explanation. Now I understand it a lot better.

You are right, I really do not need that much accuracy but it was good to find out how it can be done.

Thanks very much.

Wilson

mystified
- 30th July 2011, 02:59
my code just gives me the same output, I'm trying to use 4 7 segment displays can you all help me I am useing a 18f452
clear
define osc 20
include "modedefs.bas"

trisa=%11111111 ' a as input
trisb=0 'port b as output
trisd=%00001111 'portd as output 7-4 & 0-3 as input
digit var byte
pattern var byte
digit1 var portd.7
digit2 var portd.6
digit3 var portd.5
digit4 var portd.4
'DS18S20_9bit con %00011111;93.75ms,0.5c
'DS18S20_10bit con %00111111;187.5ms,0.25c
'DS18S20_11bit con %01011111;375ms,0.125c
DS18S20_12bit con %01111111;750ms,0.0625c default

i var word
DQ var PORTA.4 ' one wire data pin

Temp_C var word
SignC var word
Busy var byte
Negative var word
Positive var word

Temper var word
count_remain var byte
count_per_c var word


digit4=0
digit3=0
digit2=0
digit1=0



Start:
temper.lowbyte=0
temper.highbyte=0
count_remain=0

owout DQ,1,[$CC,$B4] 'test for parasite power or external supplies
pause 10 'wait for power test

owout DQ,1,[$CC,$4E,0,0,DS18S20_12bit]


owout DQ,1,[$CC,$44] 'start conversion

Waitloop: ' check for still busy converting
owin DQ,4,[count_remain]
if Count_remain=0 then goto Waitloop

owout DQ,1,[$CC,$BE] 'read scratchpad

owin DQ,0,[temper.lowbyte,temper.highbyte,skip 4,count_remain,count_per_c]

'calculate temperature in c to 2 decimal
temp_C=((( Temper>>1)*100)-25)+(((count_per_c - count_remain)*100)/count_per_c)
' 7 segment 4 led display


digit=Temp_C dig 3 'get 1000s
gosub convert
portb=pattern
digit4=0
digit3=0
digit2=0
digit1=1

pause 5

digit=Temp_C dig 2 'get 100s
gosub convert
portb=pattern
digit4=0
digit3=0
digit2=1
digit1=0
portb.7=1

pause 5

digit=Temp_C dig 1 'get 10s
gosub convert
portb=pattern
digit4=0
digit3=1
digit2=0
digit1=0
portb.7=0
pause 5

digit=Temp_C dig 0 'get 1s
gosub convert
portb=pattern
digit4=1
digit3=0
digit2=0
digit1=0

pause 5
digit4=0


goto Start

end


convert:
lookup digit,[$3f,$06,$5b,$4f,$66,$6d,$7d,$07,$7f,$6f],pattern
portb=pattern
return