MikroBasic en de DS18B20

Bavelt

Golden Member

Ik heb een programma in MikroBasic om een temperatuur sensor uit te lezen.
Processor: PIC16F1847.
Daarbij maak ik gebruik van de HELP-functie in MikroBasic, maar het resultaat is dat er geen temperatuur wordt weergegeven. De display zelf werkt correct en geeft de literals weer.

Ergens maak ik een fout (Ik twijfel zelf over de LATA of PORTA.
Ik heb begrepen / geleerd dat je PORT voor input en LAT voor output gebruikt (voor zover dat wordt ondersteund door de uC).
Maar er kan ook iets anders zijn.

pic basic code:

program DS18B20_1847
'==============================================================================

dim LCD_RS as sbit at LATB6_bit
    LCD_EN as sbit at LATB7_bit
    LCD_D4 as sbit at LATA0_bit
    LCD_D5 as sbit at LATA1_bit
    LCD_D6 as sbit at LATA2_bit
    LCD_D7 as sbit at LATA3_bit

dim LCD_RS_Direction as sbit at TRISB6_bit
    LCD_EN_Direction as sbit at TRISB7_bit
    LCD_D4_Direction as sbit at TRISA0_bit
    LCD_D5_Direction as sbit at TRISA1_bit
    LCD_D6_Direction as sbit at TRISA2_bit
    LCD_D7_Direction as sbit at TRISA3_bit

Dim  Str as String[16]

const TEMP_RESOLUTION as byte = 12
Const RES_SHIFT = TEMP_RESOLUTION - 8

dim text as char[9]
    temp as word

sub procedure Display_Temperature( dim temp2write as word )
dim temp_whole as byte
    temp_fraction as word

    text = "000.0000"
    ' Check if temperature is negative
    if (temp2write and 0x8000) then
        text[0] = "-"
        temp2write = not temp2write + 1
    end if

    ' Extract temp_whole
    temp_whole = word(temp2write >> RES_SHIFT)

    ' Convert temp_whole to characters
    if ( temp_whole div 100 ) then
      text[0] = temp_whole div 100  + 48
    else
      text[0] = "0"
    end if

    text[1] = (temp_whole div 10)mod 10 + 48               ' Extract tens digit
    text[2] =  temp_whole mod 10        + 48               ' Extract ones digit

    ' Extract temp_fraction and convert it to unsigned int
    temp_fraction  =  word(temp2write << (4-RES_SHIFT))
    temp_fraction  = temp_fraction and 0x000F
    temp_fraction  = temp_fraction * 625

    ' Convert temp_fraction to characters
    text[4] = word(temp_fraction div 1000)    + 48         ' Extract thousands digit
    text[5] = word((temp_fraction div 100)mod 10 + 48)     ' Extract hundreds digit
    text[6] = word((temp_fraction div 10)mod 10  + 48)     ' Extract tens digit
    text[7] = word(temp_fraction mod 10)      + 48         ' Extract ones digit

    ' Print temperature on Lcd
    Lcd_Out(2, 5, text)
end sub

'==============================================================================
main:

'==============================================================================
 '  Set TEMP_RESOLUTION to the corresponding resolution of used DS18x20 sensor:
'  18S20: 9  (default setting can be 9,10,11,or 12)
'  18B20: 12

  ANSELA.4  = 1                                            ' Configure AN pins as digital I/O

  text = "000.0000"
  Lcd_Init()                                               ' Initialize Lcd
  Lcd_Cmd(_LCD_CLEAR)                                      ' Clear Lcd
  Lcd_Cmd(_LCD_CURSOR_OFF)                                 ' Turn cursor off
  Lcd_Out(1, 1, " Temperature:   ")

  Lcd_Chr(2,13,223)                                        ' Print degree character, "C" for Centigrades
                                                           ' Different Lcd displays have different char code for degree
  Lcd_Chr(2,14,"C")                                        ' If you see greek alpha letter try typing 178 instead of 223

  '--- Main loop
  while (TRUE)
    '--- Perform temperature reading
    Ow_Reset(LATA, 4)                                     ' Onewire reset signal
    Ow_Write(LATA, 4, 0xCC)                               ' Issue command SKIP_ROM
    Ow_Write(LATA, 4, 0x44)                               ' Issue command CONVERT_T
    Delay_us(120)

    Ow_Reset(LATA, 4)
    Ow_Write(LATA, 4, 0xCC)                               ' Issue command SKIP_ROM
    Ow_Write(LATA, 4, 0xBE)                               ' Issue command READ_SCRATCHPAD

    temp =  Ow_Read(PORTA, 4)
    temp = (Ow_Read(PORTA, 4) << 8) + temp

    '--- Format and display result on Lcd
    Display_Temperature(temp)
    Delay_ms(520)
  wend
end.

End. 
Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Met OneWire doe ik helaas (gelukkig ;) ) niks...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

@Bavelt,
Waar heb je dit programma gevonden?
Ik zie nergens iets van adressering van de DS18B20 en de teruglezing van de geadresseerde DS18B20.
In het originele programma zal dat vast wel opgenomen zijn, maar dat is hier zoek geraakt.

Bavelt

Golden Member

De basis komt van de HELP funktie van MikroBasic. Ik heb het omgezet van een PIC16f887 naar een PIC 16F1847.

Het adresseren doet men met

pic basic code:

 Ow_Reset(PORTE, 2)                                     ' Onewire reset signal
    Ow_Write(PORTE, 2, 0xCC)                               ' Issue command SKIP_ROM
    Ow_Write(PORTE, 2, 0x44)                               ' Issue command CONVERT_T
    Delay_us(120)

    Ow_Reset(PORTE, 2)
    Ow_Write(PORTE, 2, 0xCC)                               ' Issue command SKIP_ROM
    Ow_Write(PORTE, 2, 0xBE)                               ' Issue command READ_SCRATCHPAD

 

Het lezen zou moeten gebeuren met

pic basic code:

temp =  Ow_Read(PORTA, 4)
    temp = (Ow_Read(PORTA, 4) << 8) + temp  

.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Met OneWire doe ik helaas (gelukkig ;) ) niks...

Geen 'fan' dus van OW_read begrijp ik. :/

Maar hoe dan anders de OneWire uitlezing van een sensor als de DS18B20?

Fouten zijn het bewijs dat je het probeert..

Ik zie nu hoe je de DS18B20 aanstuurt.
Je schrijft naar LATA met de instructie 'Ow_Write(LATA, 4, 0xCC)'
Kennelijk is LATA of LATA, 4 het pennetje waar je de DS18B20 aangesloten hebt.
Je leest van hetzelfde pennetje in.
Je code zou dus temp = Ow_Read(LATA, 4) moeten zijn ipv temp = Ow_Read(PORTA, 4)
Kijk verder in de HELP-file van MikroBasic hoe je LATA moet definiëren.
Is dat altijd als uitgang of ingang of vlak voor de schrijfactie als uitgang definiëren en vlak voor de leesactie als ingang definiëren.

Arco

Special Member

code:


Geen 'fan' dus van OW_read begrijp ik. :/
Maar hoe dan anders de OneWire uitlezing van een sensor als de DS18B20?

Ik neem gewoon een 'echte' sensor als de MCP9801... ;)

't Is me trouwens niet duidelijk hoe die code om zou moeten schakelen van output naar input, als je dat nergens op moet geven???
(de voorbeelden in de helpfile moet je met een korreltje zout nemen, er staan helaas bar veel fouten in)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

(de voorbeelden in de helpfile moet je met een korreltje zout nemen, er staan helaas bar veel fouten in)

Dat is een aardig 'wetenswaardigheidje'. Grappig, Ik ging er vanuit dat wat er in de manual van de Compiler staat de 'waarheid' was.
Niet dus.

Ik zou een proefje kunnen nemen door het exact zo te doen als ze schrijven, dus met een 887.
Die gebruiken dan PORTE.2 voor het schrijven/uitlezen.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik heb ook even een voorbeeld programmaatje erbij gepakt met een PIC16F628A in PICBASIC:

pic basic code:

OWrite PORTA.4, 1, [$CC, $44]    ' Zend 'Convert' opdracht (temperatuur meten)
While ORead PORTA.4,4 = 0 : Wend ' Wacht tot conversie is voltooid...
OWrite PORTA.4, 1, [$CC, $BE]    ' Zend 'Read ScratchPad' opdracht
ORead  PORTA.4, 2, [Temperatuur.LowByte, Temperatuur.HighByte] ;Lees temperatuur en plaats dit in de variabele 
 

Ik zie hier ook niet hoe de omschakeling input-output wordt geregeld.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik heb het inmiddels aan de praat: Ik heb Poort B1 gebruikt.
(PORT, want LAT werkt hier niet)

pic basic code:

while (TRUE)
    '--- Perform temperature reading
                                                           ' Onewire reset signal

    Ow_Reset(PORTB, 1)                                     ' Onewire reset signal
    Ow_Write(PORTB, 1, 0xCC)                               ' Issue command SKIP_ROM
    Ow_Write(PORTB, 1, 0x44)                               ' Issue command CONVERT_T
    Delay_us(120)

    Ow_Reset(PORTB, 1)
    Ow_Write(PORTB, 1, 0xCC)                               ' Issue command SKIP_ROM
    Ow_Write(PORTB, 1, 0xBE)                               ' Issue command READ_SCRATCHPAD

    temp =  Ow_Read(PORTB, 1)
    temp = (Ow_Read(PORTB, 1) << 8) + temp

    '--- Format and display result on Lcd

    Display_Temperature(temp)

    Delay_ms(520)

  wend 
Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Ik denk dat die OneWire library vrij oud is, toen waren er nog geen LATx registers... ;)
Ik denk dat voor het omschakelen van input naar output gewoon 0x80 bij het PORTx wordt geteld om het adres van het TRISx register te krijgen.
Die zaten altijd 0x80 uit elkaar: bijv PORTE op 0x09, TRISE op 0x89...

Eeen 'quick and dirty' methode, omdat die niet hoeft te kloppen met nieuwere pics, en zeker niet klopt met LATx registers...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Dit is inderdaad iets waar ik tegen aanloop. Na zoveel jaren, toen TTL 'recent' was, weer de hobby elektronica opgepakt.
Van nieuwere IC's al snel naar de microcontrollers.

Maar terwijl ik nu dingen zie "goh, wat leuk" en "kan dat ook? tjee..." maak ik nu regelmatig mee dat deze voor mij nieuwe dingen alweer vele jaren oud zijn.
Cursussen die redelijk achterhaald zijn, Oude library's, PIC's die niet meer courant zijn en er betere, snellere en meer uitgebreide microprocessoren tegen veelal nog lagere prijzen ook, Compilers die een help bieden met 'zo ongeveer'.
Tja.

Maar gewoon doorgaan denk ik, en kijken hoe snel de 'inhaalslag' zich manifesteert.
Met dank aan de forumleden! En al helemaal aan Arco.
Waarvan akte...

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik neem gewoon een 'echte' sensor als de MCP9801... ;)

Die heb ik dus ook maar even besteld om mee te oefenen. Hij heeft een I2C protocol zie ik.

Ik heb hem niet in een DIL uitvoering gezien, wordt dus even solderen op een printje en dan headerpins toevoegen om het in een breadboard te kunnen prikken.

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Routines voor de MCP980x:

pic basic code:


      MCP9800_TEMP     = 0x00                                       'MCP9800 registers
      MCP9800_CONFIG   = 0x01                                       '  "
      MCP9800_HYST     = 0x02                                       '  "
      MCP9800_ALERT    = 0x03                                       '  "

'========================================================================================
Sub Function MCP9800_Read(Dim pReg As Byte) As Word                 'Read
'========================================================================================
  I2C1_Start()                                                      'Start
  I2C1_Write(0x90)                                                  'MCP write address
  I2C1_Write(pReg)                                                  '
  I2C1_Restart()                                                    'Bus restart
  I2C1_Write(0x91)                                                  'MCP read address
  If pReg = MCP9800_CONFIG Then                                     'Config reg. only
    Result = I2C1_Read(1)                                           '1 byte long; rest
  Else                                                              'is 2 bytes
    Hi(Result) = I2C1_Read(0)                                       '
    Lo(Result) = I2C1_Read(1)                                       '
  End If                                                            '
  I2C1_Stop()                                                       'Stop
  delay_ms(5)                                                       'Wait to complete
End Sub                                                             '

'========================================================================================
Sub Procedure MCP9800_Write(Dim pReg As Byte, dim lData As Word)    'Write
'========================================================================================
  I2C1_Start()                                                      'Start
  I2C1_Write(0x90)                                                  'MCP write address
  I2C1_Write(pReg)                                                  '
  If pReg = MCP9800_CONFIG Then                                     'Config re. only
    I2C1_Write(lData)                                               '1 byte long; rest
  Else                                                              'is 2 bytes
    I2C1_Write(Hi(lData))                                           '
    I2C1_Write(Lo(lData))                                           '
  End If                                                            '
  I2C1_Stop()                                                       'Stop
  delay_ms(5)                                                       'Wait to complete
End Sub                                                             '

'========================================================================================
Sub Procedure MCP9800_SetAlert(Dim pMin, pMax As Byte)
'========================================================================================
  MCP9800_Write(MCP9800_HYST, pMin<<8)                              'Sets min/max temp
  MCP9800_Write(MCP9800_ALERT, pMax<<8)                             '
End Sub                                                             '

'========================================================================================
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Op 20 december 2019 15:54:44 schreef Bavelt:
[...]

Die heb ik dus ook maar even besteld om mee te oefenen. Hij heeft een I2C protocol zie ik.

Ik heb hem niet in een DIL uitvoering gezien, wordt dus even solderen op een printje en dan headerpins toevoegen om het in een breadboard te kunnen prikken.

Het solderen is jammerlijk mislukt; het is echt priegelwerk. 2 van de pootjes braken al af bij de behuizing wanneer je ze 2 keer buigt.
Hoe kan je deze dingen überhaupt solderen behoudens machinaal?

Deze zijn vast niet verkrijgbaar in een grotere behuizing, waardoor je het kan testen op een breadboard of printplaat met 0,1" gaatjes afstand?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

SOIC-8 is (voor mij) al een vrij lompe behuizing... ;)
(pitch is 1.27mm, meeste 24F pics zijn 0.4 of 0.5mm...)

Pootjes moet je ook niet buigen, daar zijn ze niet voor. Gewoon op de print leggen en vastsolderen)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Tja, Dan moet je dus een op maat gemaakte print hebben.
(en een héél fijn soldeerboutje)

Ik wilde er eerst mee oefenen op een breadboard of printboard.
maar die zijn allemaal 0,1 inch.

Ik neem niet aan dat er 'voetjes' of zo verkrijgbaar zijn waar je ze in kan stoppen.

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
buckfast_beekeeper

Golden Member

Op 25 december 2019 00:08:30 schreef Bavelt:
Tja, Dan moet je dus een op maat gemaakte print hebben.
(en een héél fijn soldeerboutje)

Ik wilde er eerst mee oefenen op een breadboard of printboard.
maar die zijn allemaal 0,1 inch.

Ik neem niet aan dat er 'voetjes' of zo verkrijgbaar zijn waar je ze in kan stoppen.

SOIC is best wel te solderen met de hand. Ik doe dat met een punt van 0,8mm breed. Eerst 1 eilandje vertinnen. Daar het correcte pootje van het IC vast maken en zo goed mogelijk uitlijnen. Daarna het diagonaal zittende pootje. Als dat correct is en goed uitgelijnd kan je de rest vast solderen.

Als soldeer geen loodgieter spul van 5mm dik. Goede Sn60/Pb40 of Sn63/Pb37 (Kester is wat duurder maar heel goed) van 0,4 of 0,5mm dik is perfect. Neem dan ook nog een no clean flux en je bent vertrokken.

Van Lambiek wordt goede geuze gemaakt.

Je krijgt een SOIC best in een dip voetje, niet dat ik het adviseer, een adapterprintje is beter.

It's the rule that you live by and die for It's the one thing you can't deny Even though you don't know what the price is. It is justified.
buckfast_beekeeper

Golden Member

Ik heb ze wel eens omgekeerd op een gaatjesprint geplakt en dan met kleine stukjes draad naar printpennetjes gebracht. Werkt ook wel. Zet ik er meestal ook direct een c-tje bij.

Van Lambiek wordt goede geuze gemaakt.
Bavelt

Golden Member

Op 20 december 2019 16:12:12 schreef Arco:
Routines voor de MCP980x:

pic basic code:


      MCP9800_TEMP     = 0x00                                       'MCP9800 registers
      MCP9800_CONFIG   = 0x01                                       '  "
      MCP9800_HYST     = 0x02                                       '  "
      MCP9800_ALERT    = 0x03                                       '  "

'========================================================================================
Sub Function MCP9800_Read(Dim pReg As Byte) As Word                 'Read
'========================================================================================
  I2C1_Start()                                                      'Start
  I2C1_Write(0x90)                                                  'MCP write address
  I2C1_Write(pReg)                                                  '
  I2C1_Restart()                                                    'Bus restart
  I2C1_Write(0x91)                                                  'MCP read address
  If pReg = MCP9800_CONFIG Then                                     'Config reg. only
    Result = I2C1_Read(1)                                           '1 byte long; rest
  Else                                                              'is 2 bytes
    Hi(Result) = I2C1_Read(0)                                       '
    Lo(Result) = I2C1_Read(1)                                       '
  End If                                                            '
  I2C1_Stop()                                                       'Stop
  delay_ms(5)                                                       'Wait to complete
End Sub                                                             '

'========================================================================================
Sub Procedure MCP9800_Write(Dim pReg As Byte, dim lData As Word)    'Write
'========================================================================================
  I2C1_Start()                                                      'Start
  I2C1_Write(0x90)                                                  'MCP write address
  I2C1_Write(pReg)                                                  '
  If pReg = MCP9800_CONFIG Then                                     'Config re. only
    I2C1_Write(lData)                                               '1 byte long; rest
  Else                                                              'is 2 bytes
    I2C1_Write(Hi(lData))                                           '
    I2C1_Write(Lo(lData))                                           '
  End If                                                            '
  I2C1_Stop()                                                       'Stop
  delay_ms(5)                                                       'Wait to complete
End Sub                                                             '

'========================================================================================
Sub Procedure MCP9800_SetAlert(Dim pMin, pMax As Byte)
'========================================================================================
  MCP9800_Write(MCP9800_HYST, pMin<<8)                              'Sets min/max temp
  MCP9800_Write(MCP9800_ALERT, pMax<<8)                             '
End Sub                                                             '

'========================================================================================

Ik heb het pinnetje met veel gepruts alsnog aan het chipje kunnen solderen (en nu vooral niet meer aanraken... :))

Welke waarde gebruik ik nu voor pReg voor het lezen van de temperatuur?

Ik gebruik een PIC16F1847, die heeft een tweede I2C.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Op 25 december 2019 09:58:33 schreef Roland van Leusden:
Je krijgt een SOIC best in een dip voetje, niet dat ik het adviseer, een adapterprintje is beter.

[/quote]

Wat een grappige voetjes met die rondjes, al mijn voetjes zijn als deze:

De contactjes liggen dieper, dan kun je ze amper solderen.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Welke waarde gebruik ik nu voor pReg voor het lezen van de temperatuur?

MC9800_TEMP.
Met Set_Alert (28,32) kun je de alarmtemperatuur instellen. Bij 32° wordt de alarmuitgang hoog, bij 28° weer laag (hysteresis)

[Bericht gewijzigd door Arco op woensdag 25 december 2019 12:40:36 (41%)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com