PDA

View Full Version : DS18B20 interfers with Timer 2 interrupts



John_Mac
- 19th February 2009, 23:58
I'm still chasing this down, but maybe someone has some insight into this problem...(using PICBASIC PRO)

I am using 16F88 Timer2 interrupts to update seconds and minutes variables. I output the results every second on a LCD as MM:SS.

I am running 4MHz int clock, prescale of 1:1 and postscale of 1:16 with a loop in the Interrupt Service Routine to scale the number of ticks to get one second.

This all works fine with the LCD ticking off the seconds at the right rate.

I then added code to read out a DS18B20 temp sensor with the OWIN and OWOUT commands. Again the temp is output to the LCD and gives the right temps.

The problem is that when I'm reading out the DS18B20 the clock runs about 50% FASTER.

I code the ISR in pbp not asy. Have a DISABLE before the ISR code and ENABLE after it. I don't believe I have any other interrupts enabled (other than TIMER2) and check PIR1.1 at the start of the ISR to be sure I'm only servicing a Timer 2 interrupt.

Does OWIN or OWOUT mess with Timer2 or generate any interrupts?

Thanks

Acetronics2
- 20th February 2009, 08:22
Hi, John

Could we have a piece of code :

just DS 1820 and ISR parts ...

Thanks

Did you remember DS needs a certain amount of time for its conversion AND OnInterrupt waits for the current command to be completed ???

Alain

John_Mac
- 20th February 2009, 16:41
Hi, John

Could we have a piece of code :

just DS 1820 and ISR parts ...

Thanks

Did you remember DS needs a certain amount of time for its conversion AND OnInterrupt waits for the current command to be completed ???

Alain

Alain...Thanks for the reply. Below is the code for the ISR ande DS. Again both work fine, but running together, timer runs faster. Throughout the code I have tried to keep the instructions as short as possible since pbp has to finish with the instruction line before it can service the interrupt. for instance, instead of PAUSE 2000, I loop 2000 times on a PAUSE 1. But the DEBUG, OWIN and OWOUT may take a long time to execute and could be missing interrupts. But I would think this would make the clock run slower.

I calculate that I should get a Timer2 interrupt every 4 msec (prescale 1:1, postscale 1:16, 4 MHz and PR2=255). this means I would loop about 250 interrupts to get 1 sec. I find I have to loop about 1960 times. So this tells me I am missing interrupts. My guess is that some of these I/O statements may be taking longer than 4 msec and I miss an interrupt. But why I get more with the DS readout is a mystery right now. I will try to time some of the statements.

Anyway here are the code snippets for the ISR and DS:

DISABLE
Self_Test_Counter:

' Interupt Service Routine for Self Test timer interupt
' want to do a diagnostic every hour, but do it every minute
' for debugging prposes
' SecLoop is a constant defined earlier as 1960. when I calculate
' what it should be, I get a number more like 245. So this could be a clue!

' check that this was a Timer2 interupt
if PIR1.1=0 then ExitInterrupt

Ticks = Ticks + 1 ' Count pieces of seconds
If Ticks < SecLoop Then ExitInterrupt

' One second elasped - update time
Ticks = 0
Second = Second + 1
If Second >= 60 Then
Second = 0
' temp set flag every minute for testing
DoSelfTest = 1 ' Set update flag
Minute = Minute + 1
If Minute >= 60 Then
Minute = 0
DoSelfTest = 1 ' Set update flag
endif
Endif
PIR1.1 = 0 ' Reset timer2 interrupt flag

ExitInterrupt:
Resume

ENABLE


DS readout....

' One-wire temperature for DS18B20
Get_Temp:
OWOut Temp_DQ, 1, [$CC, $44] ' Start temperature conversion

waitloop:
OWIn Temp_DQ, 4, [Busy] ' Check for still busy converting
If Busy = 0 Then waitloop
OWOut Temp_DQ, 1, [$CC, $BE] ' Read the temperature
OWIn Temp_DQ, 2, [temperature.LOWBYTE, temperature.HIGHBYTE]
gosub Convert_Temp

return

Convert_Temp:
Sign = "+"
IF Sign_Bit = 1 THEN Sign="-"

' must disable interupts between dummy multiply and DIV32
DISABLE

Dummy = 625 * temperature ' Multiply to load internal registers with 32-bit value
TempC = DIV32 10 ' Use Div32 value to calculate precise deg C
Dummy = 1125 * temperature
TempF = DIV32 100

ENABLE

IF TempF >6795 THEN ' Over 99.5 deg F..?
TempF = TempF + 3200

debug "F = ",Sign,DEC TempF DIG 4,DEC TempF DIG 3,DEC TempF DIG 2,".",DEC2 TempF, 13
ELSE
TempF = TempF + 3200
debug "F = ",Sign,DEC TempF DIG 3,DEC TempF DIG 2,".",DEC2 TempF,13
ENDIF
TempC = (temperature & $0FF0) >> 4 ' Mask middle 8-bits, shift into lower byte
Float = ((temperature.Lowbyte & $0F) * 625) ' Lower 4-bits of result * 625
debug "C = ",Sign,DEC TempC,".",DEC Float,13

RETURN

Bruce
- 21st February 2009, 18:01
Heavy math, DEBUG with a lot of outgoing characters + conversions like DEC, DIG, etc, are probably eating up a lot more time than 4mS, so you'll need to increase the time period between each interrupt. You want as much time as possible before the int flag gets set.

The 18B20 can take up to, or more than, 750mS just to convert the temp. A better way might be to 1. tell it to convert temp, 2. do something else for 1 second or more, 3. then read the temp from the scratchpad without using the waitloop.

Timer1 would be better if it's available. Something like this http://www.picbasic.co.uk/forum/showthread.php?t=6957&highlight=O_FLOWS should work - even without interrupts. But you still wouldn't want to wait after issuing the convert temp. It takes way too long for the 18B20 to convert if it's in 12-bit mode.

200,000 single-cycle instructions should be plenty of time for the math, DEBUG, etc..

If you prefer to use an interrupt, set Timer1 up with a 1:4 prescale. Load CCPR1H:CCPR1L with 50,000, set CCP1CON for COMPARE mode with reset Timer1, and CCP1 interrupt enabled. You'll get an interrupt every 200mS. That would give you a lot more time in between interupts.

Acetronics2
- 21st February 2009, 20:04
Hi,

I do agree with Bruce ... and do not see how to avoid Timer 1 use.

a 1 sec interrupt interval would be the best for 12 bits ... Interrupt can ask for conversion launching ... and you do what you want in between ...

500 ms interval ( easy w/Timer 1 ...) is perfect for 11 bits ...

In fact, the clock tick would be perfect to initiate each full cycle ...

As I smell, this could be a Datalogger ( so, why use a clock ??? ) ... 30 or 40 ms mini NOT INTERRUPTED for EEPROM writing is to consider too ...

Alain

Bruce
- 21st February 2009, 20:31
If you need even more time, load CCPR1H:CCPR1L with 62,500, and set Timer1 prescale to 1:8 for 500mS interrupts. You have around 500,000 single-cycle instructions before each interrupt.

John_Mac
- 22nd February 2009, 01:44
Great minds.... I was just in the process of longer times between interrupts given all the math and I/O and conversion. I will look into Timer1 and the other tricks. But I still find it a mystery why the clock runs FASTER with the DS. If I'm missing interrupts without it, adding the DS should make it worse.

Thanks for all the pointers and I will update when i actually figure it out (if not sooner).

John

John_Mac
- 23rd February 2009, 23:52
ok what i did was to use Timer 1 (16 bit) with a prescale of 1:8 at 4 MHz. This gives me 1usec*65K*8 or about 0.5sec interrupt period.

Now with or without DS readout I get the same clock speed, and get the calculated interrupt period. So looks like this will work. Trick is to also be sure all lengthy PAUSE statements are broken into DO loops of 1msec PAUSEs and no other "WAIT" options. The readout of the DS doesn't seem to be a problem since I issue a convert command, then test for BUSY bit in a loop, so it can be interrupted.

If I had a 32 KHz xrystal I would run an external clock, but don't right now. Can get een longer interrupts that way (including a realtime clock).

The biggest reason in going to Timer 1 from 2 was the 16 bit count registers for 1 vs 8 bit for 2 (even though you can adjust the clock)...win some and loose some.

So this fixes my problems. Thanks for the good suggestions.