News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

DS18B20 Problem

Started by Giuseppe MPO, Apr 14, 2021, 10:58 PM

Previous topic - Next topic

towlerg

Silly question. but you do realize that 18F27K42 has PPS?

Giuseppe MPO

Now, Mr Les,
since it just didn't work, I changed the PIC but tonight I can try your code with the K42 and I'll be able to tell you.
If it helps, I can also make you a screenshot of the oscilloscope or logic analyzer.
Sorry my bad english but i am using google translate.

Giuseppe MPO

I am using the latest version of the compiler (3.7.5.5)
but the PIC is not the PIC18F27K42 but the PIC18F25K42

top204

The PIC18F25K42 sould be the same as the PIC18F27K42, but has less RAM and flash memory etc...

The program's code does not use any peripherals, other than the Ports, and the TRIS_Offset value is the same as a PIC18F27K42, so it will be OK.

The TRIS_Offset is what the compiler calculates to indirectly point to a TRIS SFR when given a PORT SFRs address. It subtracts the difference betweem PORTA and TRISA address', and that is the offset, because Microchip keep moving them around on devices.

In the Asm code listing, you will see the TRIS_Offset value that the compiler calculates for its library routines on different devices:

#define _TRIS_offset -8



top204

#24
I made a mistake in the previous ORead and OWrite replacement library routines (now removed from the forum), where I loaded system variables PP1 and PP1H with the reverse values in Oread. That's what I get for doing things in a hurry. :-)

Here is a modified version of the code:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Experimental replacement for the One-Wire compiler commands for the PIC18FxxK42 family of devices
' Experimental, because I cannot find a One-Wire device anywhere to test it
'
    Device = 18F27K42                               ' Set the device to a PIC18F27K42 type
    Declare Xtal = 16                               ' Tell the compiler we are running at 16MHz
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                    ' Setup the Baud rate of USART1
    Declare HRSOut1_Pin = PORTB.6                   ' Setup the pin used for USART1 TX

    #Disable ORead, OWrite, OWReset                 ' Disable the compiler's ORead and OWrite library routines
       
    Symbol DQ_Pin = PORTB.0                         ' Set the pin to use for the One-Wire interface
'
' Create some compiler system variables for the replacement Oread and OWrite routines
'
    Dim GPR  As Byte System
    Dim GEN  As Byte System
    Dim GENH As Byte System
    Dim PP1  As Byte System
    Dim PP1H As Byte System
'
' Create some aliases to compiler system variables
'   
    Dim Port_Addr  As GEN
    Dim Pin_Mask   As GENH
    Dim Mode_Type  As GPR
'
' Create some variables for the demo
'   
    Dim wTemperature As Word                        ' Holds the temperature value
    Dim bCounts As Byte                             ' Holds the counts remaining value
    Dim bCPerD As Byte                              ' Holds the counts per degree C value
 
'---------------------------------------------------------------------------------
' Read a DS18B20 temperature device and transmit the temperature to a serial terminal
'
Main:
    Do
        OWrite DQ_Pin, 1, [$CC, $44]                ' Send the read Temperature command
        Repeat                                      ' \
            DelayMS 25                              ' |
            ORead DQ_Pin, 4, [bCounts]              ' | Keep reading low pulses until the DS1820 is finished
        Until bCounts <> 0                          ' /
        OWrite DQ_Pin, 1, [$CC, $BE]                ' Send Read ScratchPad command
        ORead DQ_Pin, 2, [wTemperature.LowByte, wTemperature.HighByte,_
                          bCounts, bCounts, bCounts, bCounts, bCounts, bCPerD]
        '
        ' Calculate the temperature in degrees Centigrade
        '
        wTemperature = (((wTemperature >> 1) * 100) - 25) + (((bCPerD - bCounts) * 100) / bCPerD)
        '
        ' Transmit the temperature value to a serial terminal
        '
        HRSOutLn Dec wTemperature / 100, ".", Dec2 wTemperature, " C"
        DelayMS 512
    Loop
 
'---------------------------------------------------------------------------------
' Read a byte from a one-wire interface for the PIC18FxxK42 device family
' Input     : Port_Addr holds the Port address
'           : Pin_Mask holds the pin bitmask
'           : Mode_Type holds the mode
' Output    : WREG holds the value read from the device
' Notes     : Replacement for the compiler's ORead command library routine
'
__oread_:
    WREG = 8                            ' 8 bits to a byte
    If Mode_Type.2 = 1 Then             ' Read the loop size required
        WREG = 1                        ' 1 bit to a write
    EndIf
    PP1H = WREG                         ' Load the amount of bits into the bit counter
    PP1 = 0                             ' Clear the result before entering the loop   
    Movlw High(PORTA)                   ' \ Load FSR0H with the high address of the Ports
    FSR0H = WREG                        ' /
    FSR0L = Port_Addr                   ' Load FSR0L with the port's address used for the DQ pin
_ReadLoop:
    WREG = ~Pin_Mask                    ' Invert the pin bit mask into WREG
    INDF0 = INDF0 & WREG                ' Set the DQ pin low
    Btg FSR0L.3                         ' \
    Clear FSR0L.4                       ' / Point to the correct TRIS SFR
    INDF0 = INDF0 & WREG                ' Make the DQ pin an output low
    DelayUS 7                           ' Wait 7 microseconds
    WREG = Pin_Mask                     ' Load the pin bitmask into WREG
    INDF0 = INDF0 | WREG                ' Make the DQ pin an input
    DelayUS 7                           ' Wait 7 microseconds
    Movffl Port_Addr,FSR0L              ' Load FSR0L with the PORT SFR
    WREG = Pin_Mask                     ' Load the DQ pin bitmask back into WREG
    WREG = INDF0 & WREG                 ' Read the DQ pin condition into WREG
    Addlw 255                           ' Move the bit condition into the Carry flag
    Btfss Mode_Type.2                   ' Is the loop for 8-bits?
    Ror PP1                             ' Yes. So move the bit
    Btfsc Mode_Type.2                   ' Is the loop for a single bit?
    Rol PP1                             ' Yes. So move the single bit
    DelayUS 60                          ' Wait 60 microseconds
    Decfsz PP1H,f                       ' \ Close the loop
    Bra _ReadLoop                       ' /
    WREG = PP1                          ' Place the byte read into WREG
    Set STATUSbits_C                    ' Set the carry flag before exiting
    Return                              ' Exit the routine

'---------------------------------------------------------------------------------
' Write a byte to a one-wire interface for the PIC18FxxK42 device family
' Input     : Port_Addr holds the Port address
'           : Pin_Mask holds the pin bitmask
'           : Mode_Type holds the mode
'           : WREG holds the byte to write
' Output    : None
' Notes     : Replacement for the compiler's OWrite command library routine
'
__owrite_:
    PP1 = WREG                          ' Load the byte to write into PP1
    WREG = 8                            ' 8-bit loop?
    If Mode_Type.2 = 1 Then             ' Read the loop size required
        WREG = 1                        ' 1-bit to a write
    EndIf
    PP1H = WREG                         ' Load the amount of bits into the bit counter
    Movlw High(PORTA)                   ' \ Load FSR0H with the high address of the Ports
    FSR0H = WREG                        ' /
_WriteLoop:
    FSR0L = Port_Addr                   ' Load FSR0L with the port's address used for the DQ pin
    WREG = ~Pin_Mask                    ' Invert the pin bit mask into WREG
    INDF0 = INDF0 & WREG                ' Set the DQ pin low
    Btg FSR0L.3                         ' \
    Clear FSR0L.4                       ' / Point to the correct TRIS SFR
    INDF0 = INDF0 & WREG                ' Make the DQ pin an output low
    DelayUS 7                           ' Wait 7 microseconds
    WREG = Pin_Mask                     ' Load the DQ pin bitmask into WREG
    Ror PP1                             ' Get the next bit into the carry flag
    Btfsc STATUSbits_C                  ' Should the bit be a 0 or a 1?
    INDF0 = INDF0 | WREG                ' One. So set the DQ pin to an input
    DelayUS 55                          ' Wait 55 microseconds
    WREG = Pin_Mask                     ' Get the DQ pin mask back into WREG
    INDF0 = INDF0 | WREG                ' Make sure the DQ pin finishes as an input
    DelayUS 10                          ' Wait for 10 microseconds
    Decfsz PP1H,f                       ' \ Close the loop
    Bra _WriteLoop                      ' /
    Set STATUSbits_C                    ' Set the carry flag before exiting
    Return                              ' Exit the routine
 
'---------------------------------------------------------------------------------
' One-wire reset mechanism for the PIC18FxxK42 device family
' Input     : Port_Addr holds the Port address
'           : Pin_Mask holds the pin bitmask
'           : Mode_Type holds the mode type for the reset, before or after data
' Output    : None
' Notes     : Part of the compiler's ORead and OWrite library routines

__owreset1_:
    If Mode_Type.1 = 0 Then             ' Is a reset required after data
        Return                          ' No reset required, so exit the routine
    EndIf
    Bra __owreset_                      ' Otherwise... Send the reset

__owreset2_:
    Mode_Type = WREG                    ' Save the mode value
    If Mode_Type.0 = 0 Then             ' Is a reset required before data
        Return                          ' No reset required, so exit the routine
    EndIf
   
__owreset_:
    Movlw High(PORTA)                   ' \ Load FSR0H with the high address of the Ports
    FSR0H = WREG                        ' /
    WREG = Port_Addr                    ' Load WREG with the Port's low address
    Addlw (_TRIS_offset)                ' Add the value to point to the TRIS SFRs
    FSR0L = WREG                        ' FSR0L now points to the TRIS SFRs
    WREG = Pin_Mask                     ' Load WREG with the DQ pin mask value
    INDF0 = INDF0 | WREG                ' Set the DQ pin an input (high because of the pullup resistor)
    FSR0L = Port_Addr                   ' Load FSR0L with the Port's low address
    WREG = ~Pin_Mask                    ' Load WREG with the inverted pin mask
    INDF0 = INDF0 & WREG                ' Pull the DQ pin low for reset
    Btg FSR0L.3                         ' \
    Clear FSR0L.4                       ' / Point to the correct TRIS SFR
    INDF0 = INDF0 & WREG                ' Make the DQ pin an output low
    DelayUS 480                         ' Wait 480 microseconds
    WREG = Pin_Mask                     ' Get the DQ pin mask into WREG
    INDF0 = INDF0 | WREG                ' Set the DQ pin to an input
    DelayUS 480                         ' Wait 480 microseconds
    Return                              ' Exit the routine

Giuseppe MPO

I have tested the program.
The programming of the PIC is successful but the PIC shows no signs of life, it is dead.
I tried to insert my include file and set the oscillator registers and this way it starts working.

    OSCCON1 = 0x60
    OSCCON3 = 0x00
    OSCEN = 0x00
    OSCFRQ = 0x05
    OSCTUNE = 0x00

Config_Start

FEXTOSC = OFF         ; External Oscillator Selection->Oscillator not enabled
RSTOSC = HFINTOSC_1MHZ ; Reset Oscillator Selection->HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
CLKOUTEN = OFF         ; Clock out Enable bit->CLKOUT function is disabled
PR1WAY = On ; PRLOCKED One-Way Set Enable bit->PRLOCK bit can be cleared and set only once
CSWEN = On ; Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
FCMEN = On ; Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor enabled
MCLRE = EXTMCLR         ; MCLR Enable bit->If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR
PWRTS = PWRT_OFF ; Power-up timer selection bits->PWRT is disabled
MVECEN = OFF         ; Multi-vector enable bit->Interrupt contoller does not use vector table to prioritze interrupts
IVT1WAY = On         ; IVTLOCK bit One-way set enable bit->IVTLOCK bit can be cleared and set only once
LPBOREN = OFF         ; Low Power BOR Enable bit->ULPBOR disabled
BOREN = SBORDIS         ; Brown-out Reset Enable bits->Brown-out Reset enabled , SBOREN bit is ignored
BORV = VBOR_2P45 ; Brown-out Reset Voltage Selection bits->Brown-out Reset Voltage (VBOR) set to 2.45V
ZCD = OFF ; ZCD Disable bit->ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
PPS1WAY = On         ; PPSLOCK bit One-Way Set Enable bit->PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
STVREN = On ; Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset
Debug = OFF ; Debugger Enable bit->Background debugger disabled
XINST = OFF ; Extended Instruction Set Enable bit->Extended Instruction Set and Indexed Addressing Mode disabled
WDTCPS = WDTCPS_31 ; WDT Period selection bits->Divider ratio 1:65536; software control of WDTPS
WDTE = OFF ; WDT operating mode->WDT Disabled; SWDTEN is ignored
WDTCWS = WDTCWS_7 ; WDT Window Select bits->window always open (100%); software control; keyed access not required
WDTCCS = SC ; WDT input clock selector->Software Control
BBSIZE = BBSIZE_512 ; Boot Block Size selection bits->Boot Block size is 512 words
BBEN = OFF ; Boot Block enable bit->Boot block disabled
SAFEN = OFF ; Storage Area Flash enable bit->SAF disabled
WRTAPP = OFF         ; Application Block write protection bit->Application Block not write protected
WRTB = OFF ; Configuration Register Write Protection bit->Configuration registers (300000-30000Bh) not write-protected
WRTC = OFF ; Boot Block Write Protection bit->Boot Block (000000-0007FFh) not write-protected
WRTD = OFF ; Data EEPROM Write Protection bit->Data EEPROM not write-protected
WRTSAF = OFF         ; SAF Write protection bit->SAF not Write Protected
LVP = On ; Low Voltage Programming Enable bit->Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored
Cp = OFF ; PFM and Data EEPROM Code Protection bit->PFM and Data EEPROM code protection disabled

Config_End

in this way it starts to work even if it decodes the temperature incorrectly, the decimal point position is wrong.
On the serial monitor it indicates:
208.00 þ‡C
instead of 20.8°C

That's it, I'm available for any other test

Giuseppe MPO

On the serial monitor it indicates in HEX:

32 30 38 2E 30 30 20 FE 87 43 0D

LeonJ

I tested Les' code (second version) with a DS18B20 and 18F27K42 @ 64MHz.
After adding Fuse Configuration, it works correctly except for showing 10 times the temperature and does not display negative temperatures.

So I changed the following 3 lines:

    Dim wTemperature As SWord                        ' Holds the temperature value
    wTemperature = (((wTemperature >> 1) * 10) - 25) + (((bCPerD - bCounts) * 10) / bCPerD)
    HRSOutln SDec wTemperature / 100, ".", Dec2 wTemperature, " degC    "

It now displays temps as low as -35 up to +102.14 degrees C correctly.

Thanks Les, much appreciated!




LeonJ

Oops sorry my "fix" in the previous post is incorrect.
Perhaps Les can help?

However, the replacement ORead, OWrite and OWReset for K42 seems to work.

Ideally I'd like to implement these with interrupts in order not to waste the OneWire required delay times in the mainloop.   

top204

#29
Thanks Leon. I'll make it as a library include file until I get the upgrade ready. It will also allow users to change the code if required.

I originally created the code for a DS1820 device, not a DS18B20 type, and it has been about 18 years since I created the demo code. :-)

The standard One-Wire interface will not work well in an interrupt because it is soooooooo slow. It is now a "very" outdated interface and you would be better off with one of the analoque, SPI or I2C temperature devices because they are a lot faster. Or a tiny PIC microcontroller with a temperature device attached to it, so a single wire will still perform the task via a serial interface, but a lot faster.

towlerg

Obviously I agree with Les re. limitations of 18B20 but it is damn convenient. There is an version with a waterproof stainless steel probe and the parasitic ability could be very helpful in the right circumstances.

LeonJ

Les, totally agreed. 

I'm considering the DS2482S-100 I2C to OneWire bridge (RS PN 189-8914). "Cheap enough" and still offers the conveniences as mentioned by Towlerg.

With an interrupt managed I2C Module, the OW timing overheads can be significantly reduced.

top204

#32
To set the PIC18FxxK42 devices to operate at 64MHz with their internal oscillator, just use the configs below:

'---------------------------------------------------------------------------------------
' Setup for internal oscillator operating at 64MHz. With the OSC pins as general purpose I/O pins
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ     ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    FEXTOSC = Off               ' HS off
    WDTE = Off                  ' WDT Disabled. SWDTEN is ignored
    CLKOUTEN = Off              ' CLKOUT function is disabled
    PR1WAY = Off                ' PRLOCK bit can be set and cleared repeatedly
    CSWEN = On                  ' Writing to NOSC and NDIV is allowed
    Debug = Off                 ' Background debugger disabled
    FCMEN = Off                 ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR             ' MCLR pin as VPP and reset
    PWRTS = PWRT_Off            ' PWRT is disabled
    MVECEN = Off                ' Interrupt contoller does not use vector table
    IVT1WAY = Off               ' IVTLOCK bit can be cleared and set repeatedly
    LPBOREN = Off               ' ULPBOR disabled
    BOREN = Off                 ' Brown-out Reset disabled
    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 = Off                ' Stack full/underflow will not cause Reset
    XINST = Off                 ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_2           ' Divider ratio 1:128
    WDTCWS = WDTCWS_0           ' Window delay = 87.5. no software control. Keyed access required
    WDTCCS = LFINTOSC           ' WDT reference clock is the 31.0 kHz LFINTOSC
    BBSIZE = BBSIZE_1024        ' Boot Block size is 1024 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 = Off                   ' HV on MCLR/VPP must be used for programming
    Cp = Off                    ' PFM and Data EEPROM code protection disabled
Config_End

With the above configs, there is no need to set any oscillator SFRs.