View previous topic :: View next topic |
Author |
Message |
ELCouz
Joined: 18 Jul 2007 Posts: 427 Location: Montreal,Quebec
|
Non-blocking DS18B20 code... |
Posted: Fri Mar 25, 2016 7:00 pm |
|
|
I usually use TI TMP275 i2c temp sensor because it's faster and i2c bus is easy to control.
But I'm in a situation that the SOIC-8 package won't cut it for precise measurement (shape of the package fitment) vs the TO-92 offered with the DS18B20.
I skipped the DS18B20 because of the code when a sensor fail/1-wire line failure, it freeze the whole PIC on that line:
Code: |
while (busy == 0)
busy = onewire_read();
|
from the hansolo code post ---> https://www.ccsinfo.com/forum/viewtopic.php?t=28425
Any idea how to timeout the code properly?
Thanks! _________________ Regards,
Laurent
-----------
Here's my first visual theme for the CCS C Compiler. Enjoy! |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9253 Location: Greensville,Ontario
|
|
Posted: Fri Mar 25, 2016 8:04 pm |
|
|
instead of ...
while (busy == 0)
ADD a 'timeout' conditional to the while()
Have a look at the CCS manual regarding 'waiting for serial ' input yet needing to 'break' if nothing comes in after xx milliseconds.
Can't give you a specific link on wrong computer but I know it's in the manual somewhere!
Jay |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Sat Mar 26, 2016 8:14 am |
|
|
another option might be to pull out the part of the code that checks the busy and put it into another function similar to how uart provides the kbhit method. Then in your main code, you could check and see if it is busy by calling the new function before calling the read routine and if it is busy, then go do something else in your code. You could still implement a timeout that way, but it would be in the calling code rather than the driver (which I prefer when I have drivers honestly).
then your calling code might look like:
Code: |
while(timevalue < timeout){
if (!ds1820_busy()){
value = ds1820_read();
break;
}else{
//do something else here
}
}
|
or if you don't need to do anything else, then just simply
Code: |
while(timevalue < timeout){
if (!ds1820_busy()){
value = ds1820_read();
break;
}
}
|
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Mar 26, 2016 9:17 am |
|
|
Polling an uncommitted system timer could be your friend.
That way you decide when you've waited too long. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1911
|
|
Posted: Sat Mar 26, 2016 9:30 am |
|
|
I can't post the code I came up with, as it rightfully belongs to my employer, but I can give you some guidelines.
- Dedicate a timer to the task of interfacing with the DS18B20. That timer is used for nothing else.
- If you're using a processor with programmable interrupt priority, you may have to set the priority of this timer to the highest value (higher than any other interrupt you have) if you want completely accurate temperature measurements.
- My projects typically employ a dedicated timer/interrupt to give me a 10ms "system tick." I have a separate counter/flag mechanism as part of that system tick to trigger a temperature reading every 10 seconds.
- To trigger a reading, you first have to take the DS18B20's DQ line low for (I think) > 400 us. When my system tick determines that it's time to trigger a reading, the DQ line is set low and the dedicated timer is enabled and set to expire/fire ~ 500 us later.
- When the dedicated timer expires, it toggles the state of the DQ line, looks up (from a LUT) the next time the line should change state, and sets itself to expire/fire at that time. Writes to the DS18B20 proceed in this manner.
- Reads from the DS28B20 proceed similarly, except there is no advantage to using the timer to do the very timing specific reads of the DQ line. From memory, the general procedure is:
- set DQ line low, wait ~2us, then release the line. ~9us later, read the state of the DQ line (high = 1, low = 0). The process then waits several 10s of us before repeating the process to read the next bit. The underlined section is performed in my dedicated timer's interrupt using delay_us() statements. The reset/wait for the appropriate time to read the next bit is performed by using the dedicated timer.
- When you're done reading the DS18B20, the timer you've dedicated to that task is disabled.
This is a relatively straightforward way of reading a one wire temperature sensor whilst ensuring that your processor can still service other interrupts. This general process is in use on 4 different products. The only one that sometimes reads wonky temperatures is a communications bridge that has to handle very heavy high bit rate traffic. I was not able to set the priority of my temperature reading interrupt higher than everything else because then I'd have dropped packets, which I can't tolerate. An occasional weird temperature is okay though. |
|
|
|