News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Interrupt driven DS18B20 solved

Started by LeonJ, May 08, 2021, 03:00 PM

Previous topic - Next topic

LeonJ

I need to read DS18B20 temperature continuously without the time delays required.
After studying Maxim's App note AN214 describing using a UART to transact with OneWire devices, I managed to achieve reading DS18B20 temperatures without wasting processor time.

UART TX & RX lines are switched to the same pin (with PPS) and the pin is configured as Open Drain and Pullup of 4K7.

The UART is set up with appropriate baudrate(s) and transmits appropriate byte(s) to generate the required Reset, Bit Read/Write time slots while
simultaneously, the UART receiver captures the resulting "return" byte and evaluates it to discover the OW device responses. The AppNote describes this thoroughly.

All that remained was to manage the UART transmissions and receptions in an Interrupt Service Routine. (triggered by a transmission completed which also means a reception has occurred).

The code is by no means mature but is functional for a single device that is Vcc powered (i.e. not parasitic power) and only demonstrates a rudimentary 9-bit temperature read. It also detects if no device is present or if the bus is short circuited. It is about 2kB which for the 18F27K42 is small enough.

The ISR seems to have a lot of code in it, but it executes only a few instructions at a time. All the required time delays happens automatically with the UART transmission duration and never is the processor occupied by any delay loops.

' One-Wire with UART and ISR
' --------------------------
(*

 Requirements: (one device on bus only)
1 UART
If we have PPS: 1 pin with open drain capability
If no PPS: 1 pin for UART TX
1 pin for UART RX (TX & RX connected together)
Pullup of 4k7 on bus
Power on DS18B29 Vcc pin
Notes: At present we can only do a single device that needs Vcc power
*)


(*

Revision History
================
OneWire-03.bas Initial creation
04 it works!!
05 1 degree C calculation works (negatives up to 127)
unpowered device works (using hi side drive FET to provide device power)
06 added bus drive on/off in bus idle times
it seems we can drive at least 1 device thru the 1k
it seems the diode makes no difference
so with busdrive plan and series 1K it works at least with one device
07
08 adding TXISR to manage a single sensor
09 using Symbol U1TXMTIF to cause TX ISR trigger
using U1TXMTIF to trigger ISR
NOTE!! U1EIE MUST be set to get U1TXMTIE interrupt!!!!!!!!!This is not clear in datasheet!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10
12 still has 1 1mS pre-poll delay
13 no more pre-poll delay - seems it works!!!
14 replaced pre poll delay - we might need it
14a shortening ISR
added short circuit detect and recovery
14b removing unneccessary code
added "no device" detect!
15 looks okay!!
(a 9-bit measurement completes in just under 8mS)


-------------------------------------------------------------------------------------------------------------
Based On Maxim Integrated Application Note AN214 "Using a UART to Implement a 1-Wire Bus Master"

Principle in summary (See AN214 For details)
--------------------
The UART can generate the proper waveform If configured correctly
If TX And RX are tied together, a transmit can act On the bus While simulataneously the RX
can determine the Slave(s) response.

The Pic can Disable the hi-side MOSFET On a Pin which means we can tie the TX And RX together
And still satisfy the bus requirements. We will have To Add a pullup resistor And we cannot
Do a short term hard pullup As some 1-wire bridge chips can Do.
Using PPS, the TX And RX can share the same Pin.

To Do OWReset: (1 Byte TX And echoed RX Byte needed)
--------------
Set UART To 9600,n,8,1
Transmit $F0
If the Rx is values $10 To $90, Device(s) are present On the bus
If RX is $F0, no devices are present

To Do OWRead: (8 bytes TX And 8 echoed RX bytes needed To read 8 bits from slave)
-------------
Set UART To 115200,n,8,1
Transmit $FF
RX $FE Or less will indicate a 0-Bit read
RX $FF will indicate a 1-Bit read

To Do OWWrite: (8 bytes TX needed To write 8 bits To slave)
--------------
Set UART To 115200,n,8,1
Transmit $FF For a 1-Bit write
Transmit $00 For a 0-Bit write
RX values here are meaningless except maybe To detect a short circuit On the bus
*******************************************************************************************************************************************************
1-wire transaction consists of three parts. OtherWise it wouldn't work.

    A 1-wire Line Reset;
    ROM command sequence;
    Function command sequence.

A Reset gives a start of new signaling.
ROM command enables To address slave devices.
There are several ROM commands with various purposes.
Like Search ROM (F0h), where the master identifies all slave devices connected To the 1-wire data Line.
Each slave is equipped with a unique 64-Bit address. So master during ROM search cycles through all slaves reads And stores all 64-Bit addresses.
Each cycle starts with Line Reset. If a single slave is connected, the master can use Read ROM (33h) command. When the master has all ROM codes Next time, it can address the slave by sending Match ROM (55h) command.

The third part of communication is the Command sequence.
This is where the master sends specific commands To slave(s) like start conversion If temperature sensors are used,
read temperature value from the scratchpad memory, And so On.

The first part of any communication involves the bus master issuing a "reset" which synchronizes the entire bus.
A slave Device is Then selected For subsequent communications.
This can be done by selecting all slaves, selecting a specific slave (using the serial number of the Device),
Or by discovering the Next slave On the bus using a binary search algorithm.
These commands are referred To collectively As "network" Or ROM (Read-Only-Memory) commands.
Once a specific Device has been selected, all other devices drop out And ignore subsequent communications Until the Next Reset is issued.

Once a Device is isolated For bus communication the master can issue device-specific commands To it, send data To it, Or read data from it.
Because each Device type performs different functions And serves a different purpose, each has a unique protocol once it has been selected.
Even though each Device type may have different protocols And features, they all have the same selection process
And follow the command flow As seen in Figure 1 (above).

*******************************************************************************************************************************************************
Signaling
---------
The master Device communicates with the slaves using controlled short pulses Or time slots.
A time slot is the time during which a logic zero Or a logic one is written Or read.

A Standard mode time slot is 60 µs duration And an Overdrive mode time slot is 8 µs.
1-Wire devices have an internal timebase that is synchronized To the falling edge of the master-generated timing.
Logic one is transmitted As a short, negative-going pulse At the beginning of the time slot,
While logic zero is transmitted As a longer negative-going pulse.
The receiving Device samples At a defined point in the time slot And so senses either a one Or a zero.

1-Wire protocol is a three-phase transaction,

'Reset - beginning with a master-initiated Reset
'Device SELECTION - which is followed by Device detection
'Device FUNCTION COMMAND - And Then by Device function commands

Reset
-----
In Standard mode the master issues a Reset command by holding the Line 1-Wire Line Low For more than 480 µs.
After Reset the bus master releases the Line, Then goes into receive mode And waits For a period of 15 µs To 60 µs,
during which time the 1-Wire Line goes into the High idle state.
After the Reset pulse, each And every connected slave Device acknowledges the master by pulling the Line Low For a period of 60 µs To 240 µs,
termed the presence pulse. By the End of the 240 µs presence pulse detection time all slave devices will have released the Line
And it will Return To idle High. At this point all slave devices On the 1-Wire Line are synchronized To a known state.

If multiple slave devices are connected they will all pull the Line Low simultaneously,
so the master knows only that At least one slave Device is connected.

1-Wire communications, standard mode with 60 µs time slots.
-----------------------------------------------------------
Once the slave devices are synchronized To a known state, the bus master can start communicating with the slave devices.

Each slave Device has a unique factory-programmed 64-Bit ROM ID, consisting of an 8-Bit family Code, 48-Bit serial number And 8-Bit CRC.
Resolution of the individual slave devices connected To the 1-Wire bus is done with a Device detection sequence.

The master selects a particular slave Device, based On its unique ID, with the ROM command sequence.

With a particular slave Device selected the remaining slave devices drop off the Line.
The master Then executes a Device function sequence command such As a write To, Or a read from, the slave memory.
*******************************************************************************************************************************************************


*)

'*******************************************************************************************************************************************************

Device = 18F27K42                               ' Set the device to a PIC18F27K42 type
Declare Xtal = 64                               ' Tell the compiler we are running at 16MHz


' COMPILER OPTIONS
' ================
On_Hardware_Interrupt GoTo ISR_Handler_hi
On_Low_Interrupt GoTo ISR_Handler_LO

'Declare All_Digital = True                          'Set all A\I to be D\I

Declare Keep_Hex_File = On      ' DONT ERASE OLD HEX FILE ON COMPILE FAILURE
Declare Optimiser_Level = 0 ' FOR R&D COMPILE TIME SPEEDUP
'Declare Reminders = Off

Declare Watchdog = OFF
Declare All_Digital = On
Declare Warnings OFF

' Setup UART2 for PC comms                                                                 
' ------------------------
Output PORTB.6 ' forgetting this, makes it not work!!!!
Input PORTB.7

Declare HRSOut2_Pin PORTB.6 ' or use PPS to do this
Declare HRSIn2_Pin PORTB.7 ' or use PPS to do this
Declare Hserial2_Baud 115200 ' or use PPS to do this
Declare HSerial2_Terminator = CRLF
     
' Port pins
' ---------
Symbol OWpin = PORTB.0
Symbol LED = PORTC.6

' Vars needed for OneWire stuff
' -----------------------------
Dim wStat As Byte ' The TxISR State
Dim wBitCtr As Byte ' counts 0-7 bits of a byte to be sent/received
Dim wTxByte As Byte ' the Timing byte to be transmitted
Dim wRxByte As Byte ' the resulting echo byte received
Dim wCommand As Word ' holds the command words to be transmitted  ($44CC and $BECC)
Dim wBit As Bit ' holds bit-value for bit tx/rx
Dim wTemperature As Word ' Holds the raw temperature value as read from device

' OneWire Bus Statuss (for both manual and ISR driven versions)
' -------------------
Dim wStatus As Byte ' after wReset(), this will contain the bus status as follows:
Symbol wIdle = $FF
Symbol wNoPresence = $FE
Symbol wShorted = $FD
Symbol wPresence = $FC
Symbol wError = $FB
Symbol wComplete = $FA

Symbol Drive = ODCONB.0 ' 1 for open drain, 0 for drive
Symbol DriveOn = 1 ' to disable bus drive during idle time, makes this also a "1"
Symbol DriveOf = 1
Dim Temp8Bit As SByte
Dim tbit As Bit

' Timer and other SFR BIT NAMES DEFINITIONS
' -----------------------------------------
Symbol TMR0IF = PIR3bits_TMR0IF ' so we can refer to bit names - great!!!
Symbol TMR0IE = PIE3.7 ' TIMER0 INTERRUPT ENABLE
Symbol T0EN = T0CON0.7 ' TIMER START/STOP BIT
Symbol GIE = INTCON0.7 ' INTERRUPT ENABLE
Symbol TMR1IF = PIR1.0 ' TIMER 1 ROLLOVER FLAG

Dim SaveGIE As Bit
Dim Ctr As Byte

' UART1 Module bits
' -----------------
Symbol U1ON = U1CON1.7 ' Uart circuitry on
Symbol U1IE = PIE3.6 ' interrput enable bit
Symbol U1IF = PIE3.6 ' interrput flag

' UART1 TX Bit Names
' ------------------
Symbol U1TXEN = U1CON0.5 ' transmitter enable bit - port pin state is active when disabled - UART drives pin when enabled
Symbol U1TXIE = PIE3.4 ' transmit interrupt enable
Symbol U1TXIF = PIR3.4 ' transmit buffer empty flag
Symbol U1TXMTIF= U1ERRIR.7 ' Transmit empty flag (sets at end of transmission)
Symbol U1TXMTIE= U1ERRIE.7 ' Transmit empty flag Interrupt enable
Symbol U1TXBE = U1FIFO.5 ' set this to clear the tx buffer

' UART1 RX Bit Names
' ------------------
Symbol U1RXEN = U1CON0.4 ' Receiver enable bit
Symbol U1RXIE = PIE3.3 ' receive interrupt enable
Symbol U1RXIF = PIR3.3 ' Receive interrupt flag
Symbol U1EIE = PIE3.5 ' framing error interrupt enable bit
Symbol U1EIF = PIR3.5 ' framing error int flag
Symbol U1PERIF = U1ERRIR.6 ' PERIF: Parity Error Interrupt Flag bit. Address mode: 1=byte received As address 0=byte received As data
Symbol U1RXBE = U1FIFO.1 ' RXBE: Receive Buffer Empty Status bit, 1=RX buffer is empty. Setting this bit will clear the RX buffer(1)
' 0 = Receive buffer is not empty. Software cannot clear this bit.
Dim U1Baud As U1BRGL.Word ' U1Baud now addresses U1BRGL and U1BRGH as a word

' UART2 Module bits and names
' ---------------------------
Symbol U2ON = U2CON1.7 ' Uart circuitry on
Symbol U2IE = PIE6.5 ' interrput enable bit
Symbol U2IF = PIR6.5 ' interrput flag
Symbol U2TXEN = U2CON0.5 ' transmitter enable bit - port pin state is active when disabled - UART drives pin when enabled
Symbol U2TXIE = PIE6.3 ' transmit interrupt enable
Symbol U2TXIF = PIR6.3 ' transmit buffer empty flag
Symbol U2TXMTIF= U2ERRIR.7 ' Transmit empty flag (sets at end of transmission)
Symbol U2TXMTIE= U2ERRIE.7 ' Transmit empty flag Interrupt enable
Symbol U2TXBE = U2FIFO.5 ' set this to clear the tx buffer
Symbol U2RXIF = PIR6.2 ' U2 Receive int flag
Symbol U2RXIE = PIE6.2 ' U2 receive int enable
Symbol U2RXEN = U2CON0.4 ' Receiver enable bit
Symbol U2EIE = PIE6.5 ' framing error interrupt enable bit
Symbol U2EIF = PIR6.5 ' framing error int flag
Symbol U2PERIF = U2ERRIR.6 ' PERIF: Parity Error Interrupt Flag bit. Address mode: 1=byte received As address 0=byte received As data
Symbol U2RXBE = U2FIFO.1 ' RXBE: Receive Buffer Empty Status bit, 1=RX buffer is empty. Setting this bit will clear the RX buffer(1)
' 0 = Receive buffer is not empty. Software cannot clear this bit.
Dim U2Baud As U2BRGL.Word ' U2Baud now addresses U2BRGL and U2BRGH as a word

'****************************************************************************************************************
GoTo Main ' jump over ISR's and Procs
'****************************************************************************************************************
' This where ISR's start
'****************************************************************************************************************
ISR_Handler_hi:

' Do context saving
' -----------------
Context Save ' Save any variables or SFRs used

' -------- TX ISR start ----------------------------------------------------------------------
TX_ISR:

If U1TXMTIF = 1 Then ' Transmit empty flag (sets at end of transmitted stop bit)

' Note: If we are done or if an errors exist (i.e no byte to be transmitted),
' then we MUST disable the TX interrupt else it will happen continuously!!

' check for possible bus short circuit
' ------------------------------------
If U1RXIF = 0 Then ' no byte was received - assume it's a shorted bus
wStat = wShorted
Clear U1TXMTIE ' we MUST disable the interrupt!
GoTo TXIFend ' and exit soonest

' grab received echo and clear all possible RX errors and flush RX buffers
' ------------------------------------------------------------------------
Else
wRxByte = U1RXB ' get the received echo byte (also clears the RX flag)
WREG = U1RXB ' read RCREG twice to clear Error and IF flags
EndIf

' determine the OneWire bus state and execute accordingly
' -------------------------------------------------------
Select wStat

' User initiated a Temperature read process by transmitting a ResetByte manually
' ------------------------------------------------------------------------------
Case 0 ' ResetByte complete

' check if device is present or not
' ---------------------------------
If wRxByte = $F0 Then ' no devices are present
wStat = wNoPresence
Clear U1TXMTIE ' we MUST disable the interrupt!
GoTo TXIFend

Else If wRxByte < $F0 Then  ' one or more OW devices are present

' Prep for and start CommandWord.0 ($44CC) TX
' -------------------------------------------
U1Baud = $008A ' baud=115200
wCommand = $44CC ' the "start conversion" command
Clear wBitCtr ' start with bit-0
wStat = 1 ' next state
GoTo TxCC44 ' and go Tx first bit-0
EndIf

' transmit wCommand.0-15
' ----------------------
Case 1
TxCC44: If wBitCtr < 16 Then           ' more bits to go
wBit = GetBit wCommand, wBitCtr ' and get next-bit
Clear wTxByte ' assume 0-bit
If wBit = 1 Then wTxByte = $FF ' no, it's a 1-bit
U1TXB = wTxByte ' Transmit the bit
Inc wBitCtr ' and point to next bit

' wCommand is  sent so begin pre-poll delay (might be neccessary later)
' -----------------------------------------
Else      ' all $44CC bits sent
U1Baud = $0682 ' Baud = 9600 (so we can get at least 1mS delay before polling begins)
U1TXB = $FF ' Transmit any byte - all we need is it's tx duration
wStat = 2 ' next state
EndIf

' pre-poll delay complete - start polling for conversion complete
' ---------------------------------------------------------------
Case 2
U1Baud = $008A ' baud=115200
U1TXB = $FF ' Transmit $FF to read a bit
  wStat = 3 ' next state

' polling for conversion complete
' -------------------------------
Case 3

' no response yet - keep polling (we must add a timeout here!!!)
' ------------------------------
If wRxByte = $00 Then ' device did not signal a 1-bit meaning conversion is still busy                                  '
U1TXB = $FF ' re-poll and remain in state3 unless we timeout

' we got response so send another ResetByte (to initiate the data read process)
' -----------------------------------------
Else ' device signalled a 1-bit meaning conversion is done
U1Baud = $0682 ' Baud = 9600
U1TXB = $F0 ' Transmit ResetByte
wStat = 4 ' next state
EndIf

' ResetByte complete - evaluate and send next command
' ---------------------------------------------------
Case 4 ' ResetByte complete

' check if device is present or not
' ---------------------------------
If wRxByte = $F0 Then ' echo received, but no devices are present
wStat = wNoPresence
Clear U1TXMTIE ' we MUST disable the interrupt!
GoTo TXIFend

Else If wRxByte < $F0 Then  ' echo received, one or more OW devices are present

' Transmit wCommand.0 ($BECC)
' -------------------
U1Baud = $008A ' baud=115200
wCommand = $BECC ' $CC and $BE
Clear wBitCtr ' start with bit-0
wStat = 5 ' next state
GoTo TxCCBE ' go Tx first bit
EndIf

' transmit wCommand.0-15
' ----------------------
Case 5
TxCCBE: If wBitCtr < 16 Then               ' more bits to go
wBit = GetBit wCommand, wBitCtr ' and get next-bit
Clear wTxByte ' assume 0-bit
If wBit = 1 Then Set wTxByte ' no, it's a 1-bit
U1TXB = wTxByte ' Transmit the next bit
Inc wBitCtr ' so point to next bit

' wCommand TX complete so start TemperatureWord.0 read
' ----------------------------------------------------
Else
Clear wBitCtr ' start with bit-0
U1TXB = $FF ' Transmit $FF to read bit-0
wStat = 6 ' next state
EndIf

' read Temperature Word.0-15
' --------------------------
Case 6
If wBitCtr < 16 Then ' more bits to receive

Clear wBit ' assume 0-bit received
If wRxByte = $FF Then wBit = 1 ' no, it's a 1-bit
LoadBit wTemperature, wBitCtr, wBit ' pack the bit
Inc wBitCtr ' next bit
U1TXB = $FF ' Transmit $FF to read bits1-15

' we're done ! Signal the fact
' ----------------------------
Else
wStat = wComplete ' the user must also know this now
Clear U1TXMTIE ' we MUST disable the interrupt!
EndIf

Case Else ' if we're lost,
wStat = wError ' indicate an error
Clear U1TXMTIE ' we MUST disable the interrupt!

EndSelect

TXIFend:

EndIf ' -------- TXISR HANDLER ENDIF
' -------- TXISR HANDLER END ----------------------------------------------------------------------

' Restore regs and exit isr_handler
' ---------------------------------
ISR_EXIT:

Context Restore ' Restore any variables or SFRs used and exit

'*******************************************************************************
ISR_Handler_LO:

'Context Save

'Context Restore

'*******************************************************************************
' THIS IS WHERE ISR'S END
'*******************************************************************************



'****************************************************************************************************************
' This where OneWire Procedures start
'****************************************************************************************************************
Proc wInitISR()

' Initialize the "background" i.e. ISR Bus pins, UART and interrupt
' -----------------------------------------------------------------

' setup the TX and RX pins
' ------------------------
PinMode OWpin, PullUp
PinMode OWpin, Output ' the RX can still read the pin even if it's an output
Set ODCONB.0 ' open drain

PPSopen() ' open PPS           
RB0PPS = $13 ' TX1 > RB0
U1RXPPS = $08 ' RB0 > RX1
PPSclose() ' close PPS

' setup the UART for ISR operations
' ---------------------------------
Clear U1ON ' UART switched off
Clear U1TXEN
Clear U1RXEN

    U1CON0 = %10000000 ' BRGS high speed; MODE Asynchronous 8-bit mode; RXEN disabled; TXEN disabled; ABDEN disabled;
    U1CON2 = %00000000 ' TXPOL not inverted; FLO off; C0EN Checksum Mode 0; RXPOL not inverted; RUNOVF RX input shifter stops all activity; STP Transmit 1Stop bit, receiver verifies first Stop bit;
    U1FIFO = 00 ' STPMD in middle of first Stop bit; TXWRE No error;
    U1UIR = 00 ' ABDIF Auto-baud not enabled or not complete; WUIF WUE not enabled by software; ABDIE disabled;
    U1ERRIR = 00 ' ABDOVF Not overflowed; TXCIF 0; RXBKIF No Break detected; RXFOIF not overflowed; CERIF No Checksum error;
    U1ERRIE = 00 ' TXCIE disabled; FERIE disabled; TXMTIE disabled; ABDOVE disabled; CERIE disabled; RXFOIE disabled; PERIE disabled; RXBKIE disabled;

' setup the transmitter first !
' -----------------------------
U1Baud = $008A ' baud=115200 to make it a snappy TX enable
Set U1TXBE ' flush the tx input buffer
U1ON = 1 ' UART switched on
Set U1TXEN         ' enable transmitter (it now asserts the pin)
Set U1EIE ' this MUST ALSO be set to get U1TXMTIE interrupt (no thanks to the data sheet!!)

' Wait for the TX enable to settle BEFORE setting up the receiver !!
' ------------------------------------------------------------------
DelayUS 200 ' we MUST wait for this to complete the resulting hi on the line that causes a reception before resetting the Receiver!!!!
WREG = U1RXB ' read RCREG twice to clear Error and IF flags
WREG = U1RXB ' also To flush the double-buffers
Set U1RXEN ' enable reception

wStat = wIdle ' waiting for user to start

' NOTES: Hereafter, the user must call wStartISR() to initiate the process

EndProc
'****************************************************************************************************************
Proc wStartISR()

' Kickstart the process by sending ResetByte & enable TX Interrupt
' ----------------------------------------------------------------
Clear wStat ' set transmitter status to 0, tasking the ISR to start with evaluating the wBusReset result
U1Baud = $0682 ' Baud = 9600 (needed for ResetByte)
U1TXB = $F0 ' Transmit ResetByte - this kickstarts the ISR process
Set U1TXMTIE ' Transmit empty flag Interrupt enable (caused by U1TXMTIF at end of transmission) U1EIE MUST ALSO BE SET!!
Set GIE

EndProc
'****************************************************************************************************************
Proc wMonitor() ' monitor the ISR progress and return the State

' monitor the OWbus progress
' --------------------------
wBusMonitor:
Select wStat

Case < 10
Nop ' do any other foreground tasks here
GoTo wBusMonitor ' the ISR is still busy getting a result

Case wComplete

' calculate an 8 bit temperature value and send to PC
' ---------------------------------------------------
tbit = GetBit wTemperature, 15 ' get the sign bit
Temp8Bit = (wTemperature & %0000011111110000) >> 4
LoadBit Temp8Bit, 7, tbit

Inc Ctr
HRSOut2 "T = ", SDec Temp8Bit, "  ", Dec3 Ctr, "  "
HRSOut2 13

Case wNoPresence
HRSOut2 "No device! ", 13

Case wShorted
HRSOut2 "Bus Shorted", 13

Case wError
HRSOut2 "Bus Error  ", 13

EndSelect

EndProc
'****************************************************************************************************************
Proc wInitNormal()

' Initialize the 1-Wire I/O hardware pin(s) and UART
' 1) Configure the Pins
' 2) Configure the designated UART (at 9600 baud because the first transaction WILL be a OneWireReset)
' 3) set the UART PPS correctly
' 4) enable the UART TX interrupt (we don't need the RX interrupt because the return excho will be captured by the TX ISR)

' setup the TX and RX pins
' ------------------------
PinMode OWpin, PullUp
PinMode OWpin, Output ' the RX can still read the pin even if it's an output
Set ODCONB.0 ' open drain

PPSopen() ' open PPS           
RB0PPS = $13 ' TX1 > RB0
U1RXPPS = $08 ' RB0 > RX1
PPSclose() ' close PPS
Drive = DriveOn

' Setup UART1 for OneWire communications
' --------------------------------------
    U1P1L = 0x00; // P1L 0;
    U1P1H = 0x00;    // P1H 0;
    U1P2L = 0x00;    // P2L 0;
    U1P2H = 0x00;    // P2H 0;
    U1P3L = 0x00;    // P3L 0;
    U1P3H = 0x00;    // P3H 0;

' U1 setup for 8-bit UART Standard mode
' -------------------------------------
    U1CON0 = %10010000;    // BRGS high speed; MODE Asynchronous 8-bit mode; RXEN disabled; TXEN disabled; ABDEN disabled;
'    U1CON0 = %10000100;    // BRGS high speed; MODE Asynchronous 9-Bit UART Address mode; RXEN disabled; TXEN disabled; ABDEN disabled;
    U1CON1 = %00000000;    // RXBIMD Set RXBKIF on rising RX input; BRKOVR disabled; WUE disabled; SENDB disabled; ON disabled (UART is off)
    U1CON2 = %00000000;    // TXPOL not inverted; FLO off; C0EN Checksum Mode 0; RXPOL not inverted; RUNOVF RX input shifter stops all activity; STP Transmit 1Stop bit, receiver verifies first Stop bit;


' U1Baud = $008A ' 115200 (138)
U1Baud = $0682 ' 9600

    U1FIFO = 0x00 ' STPMD in middle of first Stop bit; TXWRE No error;
    U1UIR = 0x00 ' ABDIF Auto-baud not enabled or not complete; WUIF WUE not enabled by software; ABDIE disabled;
    U1ERRIR = 0x00 ' ABDOVF Not overflowed; TXCIF 0; RXBKIF No Break detected; RXFOIF not overflowed; CERIF No Checksum error;
    U1ERRIE = 0x00 ' TXCIE disabled; FERIE disabled; TXMTIE disabled; ABDOVE disabled; CERIE disabled; RXFOIE disabled; PERIE disabled; RXBKIE disabled;

Clear U1RXEN ' first disable reception
WREG = U1RXB ' to clear IF flag It's better to read RCREG three times to completely flush the double-buffered F
WREG = U1RXB ' to clear IF flag It's better to read RCREG three times to completely flush the double-buffered F
WREG = U1RXB ' to clear IF flag It's better to read RCREG three times to completely flush the double-buffered F

' Set U1RXIE ' enable Rx interrupt
' Set U1TXIE ' enable TX interrupt

Set U1TXBE ' flush the tx input buffer
Set U1TXEN ' enable transmitter (it now asserts the pin as open drain)

Set U1RXEN ' enable reception
Set U1ON ' UART switched on

EndProc
'****************************************************************************************************************
Proc wReset(), Byte

' possible returns
' ----------------
'Symbol wNoPresence = 0
'Symbol wPresence = 1
'Symbol wShorted = 2

' Generate a 1-Wire Reset
' Return 0 if no slave(s) present
' Return 1 if Slave(s) present
' Return 2 if no reception (indicating possible shorted bus)

' Tasks:
' 1) change baud to 9600 required for the bus reset
' 2) do the reset and check for devise(s) present
' 3) change baud back to 115200 for the following bus transactions

'To Do OWReset: (1 Byte TX And echoed RX Byte needed)
'--------------
'Set UART To 9600,n,8,1
'Transmit $F0
'If the Rx is values $10 To $90, Device(s) are present On the bus
'If RX is $F0, no devices are present

' clear all possible errors and flush RX buffers
' ----------------------------------------------
Clear U1RXEN ' first disable reception
WREG = U1RXB ' read RCREG twice to clear Error and IF flags
WREG = U1RXB ' also To flush the double-buffers
' set U2RXBE ' RXBE: Receive Buffer Empty Status bit. Setting this bit will clear the RX buffer(1)
Set U1RXEN ' enable reception

Clear wStatus ' assume no presence
U1Baud = $0682 ' Baud = 9600

' U1TXB = $F0 ' Transmit $F0

Drive = DriveOf ' release the OneWireBus
HRSOut $F0 ' Transmit $F0

wRxByte = HRSIn, {1, Shorted} ' wait for the echo to arrive (should be almost immediately)
 
If wRxByte = $F0 Then ' no OW devices are present but bus seems okay
Result = wNoPresence
Else If wRxByte < $F0 Then  ' one or more OW devices are present
Result = wPresence
EndIf


wStatus = Result ' save the status
U1Baud = $008A ' set baud to 115200 (138) for bit read/write bus ops
DelayUS 10

Drive = DriveOn ' drive the OneWireBus hi
ExitProc ' we're done here

Shorted: ' if nothing received,
Result = wShorted ' the bus is possibly shorted
wStatus = Result ' save the status
Clear wRxByte ' and clear the contents of wRxByte to avoid confusion
' drive = driveon ' drive the OneWireBus

EndProc
'****************************************************************************************************************
Proc wBitWrite(onebit As Bit)

' write a bit contained in onebit
' -------------------------------

'To Do OWWrite: (8 bytes TX needed To write 8 bits To slave)
'--------------
'Set UART To 115200,n,8,1
'Transmit $FF For a 1-Bit write
'Transmit $00 For a 0-Bit write
'RX values here are meaningless except maybe To detect a short circuit On the bus

' Drive = DriveOf ' release the OneWireBus

If onebit = 1 Then ' for "1" bit,
HRSOut $FF ' Transmit $FF
Else
HRSOut $00 ' Transmit $00
EndIf

' Drive = DriveOn ' drive the OneWireBus

EndProc
'****************************************************************************************************************
Proc wBitRead(), Bit

' Read 1 bit and return it
' ------------------------
'To Do OWRead: (8 bytes TX And 8 echoed RX bytes needed To read 8 bits from slave)
'-------------
'Set UART To 115200,n,8,1
'Transmit $FF
'RX $FE Or less will indicate a 0-Bit read
'RX $FF will indicate a 1-Bit read

' clear all possible errors and flush RX buffers
' ----------------------------------------------
Clear U1RXEN ' first disable reception
WREG = U1RXB ' read RCREG twice to clear Error and IF flags
WREG = U1RXB ' also To flush the double-buffers
Set U1RXEN ' enable reception

Drive = DriveOf ' release the OneWireBus

Clear Result ' assume a 0 bit
HRSOut $FF ' Transmit $FF
wRxByte = HRSIn, {1, NoRx} ' wait for the echo to arrive (should be almost immediately)

If wRxByte = $FF Then Result = 1

NoRX:
Drive = DriveOn ' drive the OneWireBus

EndProc
'****************************************************************************************************************
Proc wByteWrite(onebyte As Byte)

' Write 1-Wire data Byte
' ----------------------\
Dim index As Byte
Dim bitsend As Bit

For index = 0 To 7
bitsend = GetBit onebyte, index
    wBitWrite(bitsend)
Next index

EndProc
'****************************************************************************************************************
Proc wByteRead(), Byte

Dim index As Byte
Dim bitget As Byte
Dim resultbyte As Byte

For index = 0 To 7
bitget = wBitRead()
LoadBit resultbyte, index, bitget
Next index

Result = resultbyte

EndProc
'****************************************************************************************************************
Proc wSetResolution(ress As Byte) ' Input: 9,10,11,12 bits resolution

(*
set the DS18B20 temperature conversion resolution (9,10,11,12 bits)
This is done by writing Bit-6 and Bit-5 of the configuration register (byte 4) in the Scratchpad as follows:

R1 R0 RESOLUTION(BITS) MAX CONVERSION TIME
-----------------------------------------------
0 0 9    93.75ms
0 1 10 187.5ms
1 0 11 375 ms
1 1 12 750 ms

WRITE SCRATCHPAD [4Eh]
This command allows the master to write 3 bytes of data to the DS18B20's scratchpad.
The first data byte is written into the TH register  (byte  2  of  the  scratchpad),
the  second  byte  is  written  into  the  TL register (byte  3),
and  the  third  byte  is  written  into  the  configuration  register  (byte  4).
All three bytes MUST be written before the master issues a reset, or the data may be corrupted.
*)

' Send "conversion request" command
' ---------------------------------
wReset() ' Do ResetBus for the write transactions to follow
wByteWrite($CC) ' skip ROM - meaning command all devices
wByteWrite($4E) ' Write Scratchpad Command

' Write the manadatory 3 bytes
' ----------------------------
wByteWrite($00) ' TH register (Alarm hi)
wByteWrite($00) ' TL register (Alarm lo)

Select ress
Case 10
wByteWrite(%00100000) ' 10-bits
Case 11
wByteWrite(%01000000) ' 11-bits
Case 12
wByteWrite(%01100000) ' 12-bits
Case Else ' 9 bits or any other value
wByteWrite(%00000000) ' 9-bits
EndSelect

wReset() ' All three bytes MUST be written before the master issues a Reset, Or the data may be corrupted.

EndProc
'****************************************************************************************************************
Proc wgetTemp()

' Enable the Transmitter and interrupt (at completion, ISR will disable transmitter)
' ------------------------------------
Clear wStat ' set transmitter status to 0, tasking the ISR to start with a wBusReset
Clear U1TXEN                 ' enable transmitter (it now asserts the pin)


Set U1TXBE ' flush the tx input buffer
Set U1TXEN                 ' enable transmitter (it now asserts the pin)
Set U1TXIE ' and enable interrupt. Because the U1TXB is empty, the interrupt now happens immediately.

U1ON = 1 ' UART switched on
' REMINDER: After transmission the ISR will disable UART1 which will tristate the pin again automatically
' but the pullup must remain on to stabilize the bus high


EndProc
'****************************************************************************************************************
' This is where general Procedures start
'****************************************************************************************************************

'****************************************************************************************************************
Proc PPSopen() ' UNLOCK PPS & PRESERVE INTCON0.7

SaveGIE = INTCON0.7
    INTCON0.7 = 0 ' DISABLE ALL INTERRUPTS
    PPSLOCK = 0x55
    PPSLOCK = 0xAA
    PPSLOCK.0 = 0 ' // unlock PPS
INTCON0.7 = SaveGIE 'INTS

EndProc
'*******************************************************************************
Proc PPSclose() ' LOCK PPS AND RE-INSTATE INTCON0.7

SaveGIE = INTCON0.7
INTCON0.7 = 0
    PPSLOCK = 0x55
    PPSLOCK = 0xAA
    PPSLOCK.0 = 1 ' lock PPS
INTCON0.7 = SaveGIE

EndProc
'*******************************************************************************

' Read a DS18B20 temperature device and transmit the temperature to a serial terminal
' -----------------------------------------------------------------------------------
Main:

' Print intro message
' -------------------
HRSOut2 13,10 ' mandatory! It seems it's needed to start the Uart ???
HRSOut2Ln "Onewire with UART V1.0",13,10 ' mandatory! It seems it's needed to start the Uart ???
HRSOut2 13,10 ' mandatory! It seems it's needed to start the Uart ???

Clear Ctr ' just a counter

' Init the "foreground" OneWire Bus stuff and set resolution
' ----------------------------------------------------------
wInitNormal() ' initialize the required elements for foreground use (pins, UART, etc)
wSetResolution(9) ' set conversion resolution (9,10,11,12 bits)

' initialize the OneWire ISR stuff
' --------------------------------
wInitISR() ' from here on we can use the autonomous ISR to read OW device

' Main loop
' ---------
Do

' Main foreground tasks to be done here
' -------------------------------------

' monitor the OWbus progress
' --------------------------
Select wStat

Case < wComplete ' ISR is busy (states 0 to 6), so do nothing

    Case wIdle ' OW bus is idle
wStartISR() ' so start a temperature measurement
   
Case wComplete ' we have a reading!
tbit = GetBit wTemperature, 15 ' get the sign bit
Temp8Bit = (wTemperature & %0000011111110000) >> 4 ' 7 bits only
LoadBit Temp8Bit, 7, tbit ' get the temperature sign
Inc Ctr ' just to show activity
HRSOut2 "T = ", SDec Temp8Bit, "  ", Dec3 Ctr, "  "
HRSOut2 13
wStat = wIdle ' so we start another reading

Case wShorted
HRSOut2 "Bus Shorted", 13
wStat = wIdle ' so we start another reading

Case wNoPresence
HRSOut2 "No device! ", 13
wStat = wIdle ' so we start another reading

Case wError
HRSOut2 "Bus Error  ", 13
wStat = wIdle ' so we start another reading

EndSelect

DelayMS 100 ' so as to not overwhelm the serial monitor on PC
Toggle LED

Loop

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

'Device = 18F27K42

Config_Start
  FEXTOSC = off ;off
  RSTOSC = HFINTOSC_64MHZ ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
  CLKOUTEN = OFF ;CLKOUT function is disabled
  PR1WAY = On ;PRLOCK bit can be cleared and set only once
  CSWEN = On ;Writing to NOSC and NDIV is allowed
  FCMEN = On ;Fail-Safe Clock Monitor enabled
  MCLRE = INTMCLR ;If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCLR
  PWRTS = PWRT_OFF ;PWRT is disabled
  MVECEN = OFF ;Interrupt contoller does not use vector table to prioritze interrupts
  IVT1WAY = On ;IVTLOCK bit can be cleared and set only once
  LPBOREN = OFF ;ULPBOR disabled
  BOREN = SBORDIS ;Brown-out Reset enabled , SBOREN bit is ignored
  BORV = VBOR_2P45 ;Brown-out Reset Voltage (VBOR) set to 2.45V
  ZCD = OFF ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
  PPS1WAY = OFF ;PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
  STVREN = On ;Stack full/underflow will cause Reset
  Debug = OFF ;Background debugger disabled
  XINST = OFF ;Extended Instruction Set and Indexed Addressing Mode disabled
  WDTCPS = WDTCPS_31 ;Divider ratio 1:65536; software control of WDTPS
  WDTE = OFF ;WDT Disabled; SWDTEN is ignored
  WDTCWS = WDTCWS_7 ;window always open (100%); software control; keyed access not required
  WDTCCS = SC ;Software Control
  BBSIZE = BBSIZE_512 ;Boot Block size is 512 words
  BBEN = OFF ;Boot block disabled
  SAFEN = OFF ;SAF disabled
  WRTAPP = OFF ;Application Block not write protected
  WRTB = OFF ;Configuration registers (300000-30000Bh) not write-protected
  WRTC = OFF ;Boot Block (000000-0007FFh) not write-protected
  WRTD = OFF ;Data EEPROM not write-protected
  WRTSAF = OFF ;SAF not Write Protected
  LVP = On ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored
  Cp = OFF ;PFM and Data EEPROM code protection disabled
Config_End

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------


John Drew

A terrific achievement Leon.
How about putting it in the WIKI so it is easier for users to find in future?
Cheers
John