Shop OBEX P1 Docs P2 Docs Learn Events
Making a program more compact? — Parallax Forums

Making a program more compact?

patchespatches Posts: 15
edited 2009-10-21 13:24 in BASIC Stamp
So I've written a simple program to measure temperatures using DS18S20 chips. It works fine but I'm trying to compact the code.

Its pretty straightforward; each sensor is read 16 times and the results are averaged. This gives better accuracy at each sensor with a small cost in variable space (1 word, 1 nib, 1 bit) over non-averaged readings.

I'm not so hot at PBASIC, and it seems fairly ugly to have 4 almost-identical subroutines called ChekTemp1,CheckTemp2,CheckTemp3,CheckTemp4... but I can't figure out a way to put them into a loop since the 1-wire addresses would then (I think) have to be put into variables which would chew all my space up.


' -----[noparse][[/noparse] Directives ]-----------------------------------------
'
' {$STAMP BS2pe} 'specifies a BS2pe
' {$PBASIC 2.5}
'
' -----[noparse][[/noparse] Constants ]------------------------------------------
'
OWpin              CON 0 '1-wire device pin
OWFERst            CON %0001 'Front-End Reset
OWBERst            CON %0010 'Back-End reset
OWBitMode          CON %0100
SkipROM            CON $CC 'Skip ROM Command
ReadROM            CON $33 'Read one ID (if only one device on line)
MatchROM           CON $55   ' look for specific device
SearchROM          CON $F0 'Read all IDs
ReadScratch        CON $BE 'Read Scratch Pad
ConverT            CON $44 'Convert Temperature
MeasurementsToAverage CON 16
' -----[noparse][[/noparse] Variables ]------------------------------------------
'
TempRaw            VAR Word 'Stores either a raw temperature reading or a fractional adjustment
TempRawSign        VAR TempRaw.BIT15
TempFirst          VAR Word 'Stores the first temperature reading on a sensor for averaging with following readings
CRem               VAR Byte 'Counts remaining value
CPerC              VAR Byte 'Counts per degree C value

TempSensor1        VAR Word 'Temperature Value
TempSensor2        VAR Word 'Temperature Value
TempSensor3        VAR Word 'Temperature Value
TempSensor4        VAR Word 'Temperature Value

MeasurementCounter VAR Nib
Sign               VAR Bit


' ------------------[noparse][[/noparse] ID codes for connected sensors ]-----------------------
Sensor1A CON $10 'Sensor1 will be the reference standard sensor
Sensor1B CON $C5
Sensor1C CON $8F
Sensor1D CON $B8
Sensor1E CON $01
Sensor1F CON $08
Sensor1G CON $00
Sensor1H CON $7B

Sensor2A CON $10
Sensor2B CON $96
Sensor2C CON $C2
Sensor2D CON $B8
Sensor2E CON $01
Sensor2F CON $08
Sensor2G CON $00
Sensor2H CON $09

Sensor3A CON $10
Sensor3B CON $93
Sensor3C CON $50
Sensor3D CON $B8
Sensor3E CON $01
Sensor3F CON $08
Sensor3G CON $00
Sensor3H CON $D6

Sensor4A CON $10
Sensor4B CON $76
Sensor4C CON $96
Sensor4D CON $B8
Sensor4E CON $01
Sensor4F CON $08
Sensor4G CON $00
Sensor4H CON $AA




' -----[noparse][[/noparse] Initialization ]-------------------------------------
'
Setup:
PAUSE 1000 'open debug window

Main:

  GOSUB CheckTemp1
  GOSUB CheckTemp2
  GOSUB CheckTemp3
  GOSUB CheckTemp4
  DEBUG CR, "1: ", DEC TempSensor1/10, ".", DEC1 TempSensor1-(TempSensor1/10*100), "F"
  DEBUG "  2: ", DEC TempSensor2/10, ".", DEC1 TempSensor2-(TempSensor2/10*100), "F"
  DEBUG "  3: ", DEC TempSensor3/10, ".", DEC1 TempSensor3-(TempSensor3/10*100), "F"
  DEBUG "  4: ", DEC TempSensor4/10, ".", DEC1 TempSensor4-(TempSensor4/10*100), "F"
  GOTO Main
  END


CheckTemp1:
  FOR MeasurementCounter = 0 TO (MeasurementsToAverage-1) STEP 1
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor1A,Sensor1B,Sensor1C,Sensor1D,Sensor1E,Sensor1F,Sensor1G,Sensor1H,ConverT]
    GOSUB PauseToConverT
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor1A,Sensor1B,Sensor1C,Sensor1D,Sensor1E,Sensor1F,Sensor1G,Sensor1H,ReadScratch]
    GOSUB GetFullTemp
    IF  MeasurementCounter =0 THEN
      TempSensor1 = TempRaw
      TempFirst = TempRaw
    ELSE
      GOSUB CalculateTempAdjustment
      TempSensor1 = TempSensor1 + TempRaw
    ENDIF
  NEXT
  RETURN

CheckTemp2:
  FOR MeasurementCounter = 0 TO (MeasurementsToAverage-1) STEP 1
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor2A,Sensor2B,Sensor2C,Sensor2D,Sensor2E,Sensor2F,Sensor2G,Sensor2H,ConverT]
    GOSUB PauseToConverT
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor2A,Sensor2B,Sensor2C,Sensor2D,Sensor2E,Sensor2F,Sensor2G,Sensor2H,ReadScratch]
    GOSUB GetFullTemp
    IF  MeasurementCounter =0 THEN
      TempSensor2 = TempRaw
      TempFirst = TempRaw
    ELSE
      GOSUB CalculateTempAdjustment
      TempSensor2 = TempSensor2 + TempRaw
    ENDIF
  NEXT
  RETURN

CheckTemp3:
  FOR MeasurementCounter = 0 TO (MeasurementsToAverage-1) STEP 1
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor3A,Sensor3B,Sensor3C,Sensor3D,Sensor3E,Sensor3F,Sensor3G,Sensor3H,ConverT]
    GOSUB PauseToConverT
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor3A,Sensor3B,Sensor3C,Sensor3D,Sensor3E,Sensor3F,Sensor3G,Sensor3H,ReadScratch]
    GOSUB GetFullTemp
    IF  MeasurementCounter =0 THEN
      TempSensor3 = TempRaw
      TempFirst = TempRaw
    ELSE
      GOSUB CalculateTempAdjustment
      TempSensor3 = TempSensor3 + TempRaw
    ENDIF
  NEXT
  RETURN

CheckTemp4:
  FOR MeasurementCounter = 0 TO (MeasurementsToAverage-1) STEP 1
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor4A,Sensor4B,Sensor4C,Sensor4D,Sensor4E,Sensor4F,Sensor4G,Sensor4H,ConverT]
    GOSUB PauseToConverT
    OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,Sensor4A,Sensor4B,Sensor4C,Sensor4D,Sensor4E,Sensor4F,Sensor4G,Sensor4H,ReadScratch]
    GOSUB GetFullTemp
    IF  MeasurementCounter =0 THEN
      TempSensor4 = TempRaw
      TempFirst = TempRaw
    ELSE
      GOSUB CalculateTempAdjustment
      TempSensor4 = TempSensor4 + TempRaw
    ENDIF

  NEXT
  RETURN

CalculateTempAdjustment:
  'Its OK to use TempRaw as a place to store a small adjustment now, since we stored the initial reading.
  Sign = TempRawSign
  TempRaw = (ABS(TempFirst-TempRaw)/ MeasurementsToAverage)
  IF (Sign=1) THEN TempRaw = -TempRaw
  RETURN

PauseToConverT:
  PAUSE 750
  RETURN

GetFullTemp:
  OWIN OWpin, OWBERst, [noparse][[/noparse]TempRaw.LOWBYTE,TempRaw.HIGHBYTE,CRem,CRem,CRem,CRem,CRem,CPerC]
  TempRaw = (TempRaw>>1*100-25+((CPerC*100-(CRem*100))/CPerC))* 9 / 50 + 320
  RETURN


Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2009-03-21 15:37
    Why not use a variable for the 1-Wire pin? You can use the same variable for something else in another part of your program. With "aliases" you can even give the same variable two or more names for convenience and understandability. Your 1-Wire address statement could use variables temporarily that are set from DATA statements in EEPROM given a sensor index. You'd use a series of READ statements to fetch the values, then use them for the rest of your sensor processing. You'd need 8 bytes for the 1-Wire address and one byte (or a nibble) for the pin #.
  • patchespatches Posts: 15
    edited 2009-03-21 16:38
    Excellent! I moved the sensor addresses to EEPROM, and the results to Scratch PadRAM (they will be updated to often to put in EEPROM).

    Program size is cut by 50%, and the number of sensors I can monitor goes way way up.

    Thank you Mike, if you have any other suggestions let me know.

    ' -----[noparse][[/noparse] Directives ]-----------------------------------------
    '
    ' {$STAMP BS2pe} 'specifies a BS2pe
    ' {$PBASIC 2.5}
    '
    ' -----[noparse][[/noparse] Constants ]------------------------------------------
    '
    OWpin              CON 0 '1-wire device pin
    OWFERst            CON %0001 'Front-End Reset
    OWBERst            CON %0010 'Back-End reset
    OWBitMode          CON %0100
    SkipROM            CON $CC 'Skip ROM Command
    ReadROM            CON $33 'Read one ID (if only one device on line)
    MatchROM           CON $55   ' look for specific device
    SearchROM          CON $F0 'Read all IDs
    ReadScratch        CON $BE 'Read Scratch Pad
    ConverT            CON $44 'Convert Temperature
    MeasurementsToAverage CON 16
    ' -----[noparse][[/noparse] Variables ]------------------------------------------
    '
    TempRaw            VAR Word 'Stores either a raw temperature reading or a fractional adjustment
    TempRawSign        VAR TempRaw.BIT15
    TempFirst          VAR Word 'Stores the first temperature reading on a sensor for averaging with following readings
    Temp1              VAR Word 'Used to store result of temperature reading, or, later, to compare with Temp2
    Temp2              VAR Word 'For comparing with Temp1
    CRem               VAR Byte 'Counts remaining value
    CPerC              VAR Byte 'Counts per degree C value
    
    SensorAddress0     VAR Byte
    SensorAddress1     VAR Byte
    SensorAddress2     VAR Byte
    SensorAddress3     VAR Byte
    SensorAddress4     VAR Byte
    SensorAddress5     VAR Byte
    SensorAddress6     VAR Byte
    SensorAddress7     VAR Byte
    
    
    SensorCounter      VAR Nib
    MeasurementCounter VAR Nib
    Sign               VAR Bit
    
    
    
    ' -----[noparse][[/noparse] Initialization ]-------------------------------------
    '
    DATA $10,$C5,$8F,$B8,$01,$08,$00,$7B 'Sensor0 Address, starts at 0
    DATA $10,$96,$C2,$B8,$01,$08,$00,$09 'Sensor1 Address, starts at 8
    DATA $10,$93,$50,$B8,$01,$08,$00,$D6 'Sensor2 Address, starts at 16
    DATA $10,$76,$96,$B8,$01,$08,$00,$AA 'Sensor3 Address, starts at 24
    
    
    Setup:
    PAUSE 1000 'open debug window
    
    Main:
      FOR SensorCounter = 0 TO 3 STEP 1
        READ (SensorCounter*8)  , SensorAddress0
        READ (SensorCounter*8)+1, SensorAddress1
        READ (SensorCounter*8)+2, SensorAddress2
        READ (SensorCounter*8)+3, SensorAddress3
        READ (SensorCounter*8)+4, SensorAddress4
        READ (SensorCounter*8)+5, SensorAddress5
        READ (SensorCounter*8)+6, SensorAddress6
        READ (SensorCounter*8)+7, SensorAddress7
        GOSUB CheckTemp
        PUT (SensorCounter*2), Word Temp1
      NEXT
      DEBUG CR
      FOR SensorCounter = 0 TO 3 STEP 1
        GET (SensorCounter*2), Word Temp1
        DEBUG  DEC sensorcounter, ": ", DEC Temp1/10, ".", DEC1 Temp1-(Temp1/10*100), "F "
      NEXT
      GOTO Main
      END
    
    CheckTemp:
      FOR MeasurementCounter = 0 TO (MeasurementsToAverage-1) STEP 1
        OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,SensorAddress0,SensorAddress1,SensorAddress2,SensorAddress3,SensorAddress4,SensorAddress5,SensorAddress6,SensorAddress7,ConverT]
        PAUSE 750
        OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,SensorAddress0,SensorAddress1,SensorAddress2,SensorAddress3,SensorAddress4,SensorAddress5,SensorAddress6,SensorAddress7,ReadScratch]
        OWIN OWpin, OWBERst, [noparse][[/noparse]TempRaw.LOWBYTE,TempRaw.HIGHBYTE,CRem,CRem,CRem,CRem,CRem,CPerC]
        TempRaw = (TempRaw>>1*100-25+((CPerC*100-(CRem*100))/CPerC))* 9 / 50 + 320
        IF  MeasurementCounter =0 THEN
          Temp1 = TempRaw
          TempFirst = TempRaw
        ELSE
          'Its OK to use TempRaw as a place to store a small adjustment now, since we stored the initial reading.
          Sign = TempRawSign
          TempRaw = (ABS(TempFirst-TempRaw)/ MeasurementsToAverage)
          IF (Sign=1) THEN TempRaw = -TempRaw
          Temp1 = Temp1 + TempRaw
        ENDIF
      NEXT
      RETURN
    
    
  • Mike GreenMike Green Posts: 23,101
    edited 2009-03-21 18:34
    Small point ... you don't need "STEP 1" since that's the default.

    You could use a byte array for the sensor address. This would let you read the bytes of the sensor address from EEPROM using a loop rather than 8 READ statements. You'd declare "SensorAddress VAR Byte(8)", then do

    FOR i = 0 to 7
    READ (SensorCounter*8)+i, SensorAddress(i)
    NEXT

    In your OWOUT statements, you would put

    OWOUT OWpin,OWFERst,[noparse][[/noparse] MatchROM, SensorAddress\8, ConverT ]

    There are ways to compress your sensor address table. For example, all of your sensor addresses have what seem to be fixed bytes like $10, $xx, $xx, $B8, $01, $08, $00, $xx. The only bytes you really need to store in your table are the $xx ones.

    Post Edited (Mike Green) : 3/21/2009 6:41:37 PM GMT
  • patchespatches Posts: 15
    edited 2009-03-21 19:06
    Even better... Question though, I was able to load the SensorAddress array no problem, but was not able to access it using:
    SensorAddress\8
    


    but instead had to use
    SensorAddress(0),SensorAddress(1),SensorAddress(2),SensorAddress(3),SensorAddress(4),SensorAddress(5),SensorAddress(6),SensorAddress(7)
    


    When I tried to use the \8, the editor told me it was expecting an ]. Must have something to do with it being inside the brackets of the OWOUT statement. Is there a workaround for this?

    Thanks for the advice Mike, I've never bothered to learn how to use EEPROM, ScratchPad, or arrays so this has opened up tons of new doors for me.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-03-21 19:11
    My typing mistake. It needs to be "STR SensorAddress\8"
  • patchespatches Posts: 15
    edited 2009-03-21 19:17
    Bingo, thanks Mike!
  • patchespatches Posts: 15
    edited 2009-03-21 19:20
    Oh, for posterity here's where I am now. Functionality is the same, but its much smaller and I've de-confused the code by using variable aliases (another first for me):

    
    ' -----[noparse][[/noparse] Directives ]-----------------------------------------
    '
    ' {$STAMP BS2pe} 'specifies a BS2pe
    ' {$PBASIC 2.5}
    '
    ' -----[noparse][[/noparse] Constants ]------------------------------------------
    '
    OWpin              CON 0 '1-wire device pin
    OWFERst            CON %0001 'Front-End Reset
    OWBERst            CON %0010 'Back-End reset
    OWBitMode          CON %0100
    SkipROM            CON $CC 'Skip ROM Command
    ReadROM            CON $33 'Read one ID (if only one device on line)
    MatchROM           CON $55   ' look for specific device
    SearchROM          CON $F0 'Read all IDs
    ReadScratch        CON $BE 'Read Scratch Pad
    ConverT            CON $44 'Convert Temperature
    NumMeasurements    CON 16
    NumberOfSensors    CON 4
    ' -----[noparse][[/noparse] Variables ]------------------------------------------
    '
    Temp1              VAR Word
      TempThisReading   VAR Temp1 'Stores a raw temperature reading
      TempAdjustment    VAR Temp1 'Stores a temperature adjustment
      TempAdjSign       VAR TempAdjustment.BIT15
    Temp2              VAR Word
      TempFirstReading  VAR Temp2
    Temp3              VAR Word
      TempFinalResult   VAR Temp3
    CRem               VAR Byte 'Counts remaining value
    CPerC              VAR Byte 'Counts per degree C value
    
    SensorAddress      VAR Byte(8)
    
    Counter1               VAR Nib
      SensorCounter          VAR Counter1
    Counter2               VAR Nib
      SensorAddressCounter   VAR Counter2
    Counter3               VAR Nib
      MeasurementCounter     VAR Counter3
    
    Sign                   VAR Bit
    
    
    
    ' -----[noparse][[/noparse] Initialization ]-------------------------------------
    '
    DATA $10,$C5,$8F,$B8,$01,$08,$00,$7B 'Sensor0 Address, starts at 0
    DATA $10,$96,$C2,$B8,$01,$08,$00,$09 'Sensor1 Address, starts at 8
    DATA $10,$93,$50,$B8,$01,$08,$00,$D6 'Sensor2 Address, starts at 16
    DATA $10,$76,$96,$B8,$01,$08,$00,$AA 'Sensor3 Address, starts at 24
    'Temperature readings stored in Scratch PadRAM:
    'Sensor0 at location 0 (size is Word)
    'Sensor1 at location 2 (size is Word)
    'Sensor2 at location 4 (size is Word)
    'Sensor3 at location 6 (size is Word)
    
    
    Setup:
    PAUSE 1000 'open debug window
    
    Main:
      FOR SensorCounter = 0 TO (NumberOfSensors-1)
        FOR SensorAddressCounter = 0 TO 7
          READ (SensorCounter*8)+SensorAddressCounter, SensorAddress(SensorAddressCounter)
        NEXT
        GOSUB CheckTemp
        PUT (SensorCounter*2), Word TempFinalResult
      NEXT
      DEBUG CR
      FOR SensorCounter = 0 TO 3
        GET (SensorCounter*2), Word Temp1
        DEBUG  DEC sensorcounter, ": ", DEC Temp1/10, ".", DEC2 Temp1-(Temp1/10*100), "F "
      NEXT
      PAUSE 15000
      GOTO Main
      END
    
    CheckTemp:
      FOR MeasurementCounter = 0 TO (NumMeasurements-1)
        OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,STR SensorAddress\8,ConverT]
        PAUSE 750
        OWOUT OWpin,OWFERst,[noparse][[/noparse]MatchROM,STR SensorAddress\8,ReadScratch]
        OWIN OWpin, OWBERst, [noparse][[/noparse]TempThisReading.LOWBYTE,TempThisReading.HIGHBYTE,CRem,CRem,CRem,CRem,CRem,CPerC]
        TempThisReading = (TempThisReading>>1*100-25+((CPerC*100-(CRem*100))/CPerC))* 9 / 50 + 320
        IF  MeasurementCounter =0 THEN
          TempFinalResult = TempThisReading
          TempFirstReading = TempThisReading
        ELSE
          Sign = TempAdjSign
          TempAdjustment = (ABS(TempFirstReading-TempThisReading)/ NumMeasurements)
          IF (Sign=1) THEN TempAdjustment = -TempAdjustment
          TempFinalResult = TempFinalResult + TempAdjustment
        ENDIF
      NEXT
      RETURN
    
    
  • patchespatches Posts: 15
    edited 2009-03-21 19:30
    One more thing... if anyone comes across this post in the future doing a search on DS18s20 chips, search my post history for more recent posts, I expect this project will be updated in the months to come.
  • GeekgirlGeekgirl Posts: 50
    edited 2009-10-21 13:24
    patches said...
    One more thing... if anyone comes across this post in the future doing a search on DS18s20 chips, search my post history for more recent posts, I expect this project will be updated in the months to come.


    Hi All,

    I know, I'm dragging up a pretty old thread, but it's the only one I could find where the code actually worked for the poster, as opposed to not working and they're·asking for·help.

    I've never used a OW device yet, so I'm just starting to understand the protocol.

    I've been looking at a DS18x20 project myself, and wondered if you've made any further tweaks to this program.

    Also, did you write a seperate program to retrieve the ROM code for each 1820?

    If anyone has a sample code to do that, I'd be most appreciative.


    Thanks in advance,

    Darlene
Sign In or Register to comment.