Shop OBEX P1 Docs P2 Docs Learn Events
Code optimization help if you have some spare time :) — Parallax Forums

Code optimization help if you have some spare time :)

eagletalontimeagletalontim Posts: 1,399
edited 2009-03-02 04:26 in General Discussion
I have created a sub and need help trimming it down a bit.

The sub takes a byte and splits it up to show on an LCD. I don't want leading 0's so I had to add more code into it which took up alot of programming space. If you have some spare time, could you help optimize this code a bit please [noparse]:)[/noparse]

store:
  temp1 = __PARAM1
  temp3 = __PARAM2
  temp4 = __PARAM3
  cmd = __PARAM4
  temp5 = 0
digit1:
  temp1 = temp1 / 100
  temp2 = __REMAINDER
  IF temp1 = 0 THEN
    temp5 = 0
    GOTO digit2
  ELSE
    temp5 = 1
  ENDIF
  temp1 = temp1 + "0"
  IF temp4 = 2 THEN
    PUT line2(temp3), temp1
  ELSE
    PUT line1(temp3), temp1
  ENDIF
  INC temp3
digit2:
  temp1 = temp2 / 10
  temp2 = __REMAINDER
  IF temp5 = 0 THEN
    IF temp1 = 0 THEN
      temp5 = 0
      GOTO digit3
    ELSE
      temp5 = 1
    ENDIF
  ENDIF
  temp1 = temp1 + "0"
  IF temp4 = 2 THEN
    PUT line2(temp3), temp1
  ELSE
    PUT line1(temp3), temp1
  ENDIF
  INC temp3
digit3:
  temp1 = temp2 + "0"
  IF temp4 = 2 THEN
    PUT line2(temp3), temp1
  ELSE
    PUT line1(temp3), temp1
  ENDIF
  IF cmd <> 0 THEN
    FOR idx = 1 to cmd
      INC temp3
      IF temp4 = 2 THEN
        PUT line2(temp3), "0"
      ELSE
        PUT line1(temp3), "0"
      ENDIF
    NEXT
  ENDIF
  RETURN



Thanks!
«1

Comments

  • ZootZoot Posts: 2,227
    edited 2009-01-17 16:50
    First best thing -- wrap DIVISION into a subroutine. If you look at the list output for something like

    temp1 = temp2 / 10

    You will find a LOT of code is generated for division. In fact, if you are using division, multiplication or modulo anywhere in your application, wrap 'em into a subroutine and you will find huge amounts of code space freed up, e.g.

    ' Use -- result = MATH_DIV word|byte, word|byte
    ' when mixing word and byte, the WORD comes first...
    ' tmpW1 and 2 are word vars
    
    FUNC MATH_DIV
    
       IF __PARAMCNT = 2 THEN
          tmpW1 = __PARAM1
          tmpW2 = __PARAM2
       ELSEIF __PARAMCNT = 3 THEN
          tmpW1 = __WPARAM12
          tmpW2 = __PARAM3
       ELSE
          tmpW1 = __WPARAM12
          tmpW2 = __WPARAM34
        ENDIF
        tmpW1 = tmpW1 / tmpW2     
        RETURN tmpW1
    
        ENDFUNC
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-22 16:21
    I know this is an old thread, but I need help returning 2 variables if possible with the Math_Div function. Just returning the whole number and not the remainder is not working for me [noparse]:([/noparse] Is there any way to use the same function but also return the __REMAINDER?
  • ZootZoot Posts: 2,227
    edited 2009-02-22 17:27
    The remainder should already be there and loaded (SX/B 2.x). It's built-in to the division operation. You don't return it; just use it immediately after the function call, e.g.

    
    result = MATH_DIV someWord1, someWord2
    myRemain = __REMAINDER
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-22 17:31
    I was able to do:

    result = MATH_DIV 255, 100
    rrem = __PARAM2

    But....now my display is putting strange characters in place of what used to be numbers if I did it the old fashion way. The reason I need to get this working is because I cannot fit anything else on the chip and I need more room. There are only 2 divide functions through the entire code but any little bit will help.
  • ZootZoot Posts: 2,227
    edited 2009-02-22 17:37
    The remainder is not __PARAM2, though. Use __REMAINDER (*if* I remember properly, and I'm not sure I do, it is __PARAM5, but use __REMAINDER).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php


    Post Edited (Zoot) : 2/22/2009 5:57:35 PM GMT
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-22 17:43
    does that still work in v3.2.92? I have not downloaded the new version yet because I am not sure if the code will work correctly. I have spent months on this project and don't want it to get messed up tongue.gif Over 1000 lines of code on 2 chips 0.o
  • ZootZoot Posts: 2,227
    edited 2009-02-22 17:53
    Don't confuse your version of the IDE (SX editor, assembler, programmer) with the SX/B compiler (1.51.x or 2.x).

    In any case, __REMAINDER is available in both 1.51.x and 2.x of SX/B -- I just don't recall which param is actually assigned, SO DON'T USE __PARAMx, use __REMAINDER as this will keep your code compatible down the road.
    sxb documentation said...


    The only requirement for using __REMAINDER (or __WREMAINDER for word values) is that the assignment to
    another variable must be the first instruction following the division or modulus operation.


    Oh, and until I refreshed myself I forgot about __WREMAINDER (which will have an automatically assigned _LSB and _MSB). But I don't think you need that here as you have byte division going on?

    To wit:

    ' without sub/func for clarity 
    tmpW1 VAR Word
    tmpW2 VAR Word
    tmpB1 VAR Byte
    
    WATCH tmpW1
    WATCH tmpB1
    
    tmpW1 = 200
    tmpW2 = 11
    
    tmpW1 = tmpW1 / tmpW2
    tmpB1 = __REMAINDER
    
    BREAK
    
    DO
    LOOP
    
    
    



    Even if you have it wrapped in a sub/func, it will be fine, as long as you save/use the __REMAINDER immediately upon return from the sub/func (because subsequent SX/B intructions may clobber that param variable).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • ZootZoot Posts: 2,227
    edited 2009-02-22 18:00
    P.S. -- this is closer to the div func I usually use... includes rounding for more accurate division (the purists will note that 1 should be added to __WPARAM34 before the divide by 2, for even *more* accurate rounding, but I generally don't like to take up the code space).

    FUNC MATH_DIV
    
       IF __PARAMCNT < 4 THEN
          __PARAM4 = 0
          IF  __PARAMCNT < 3 THEN
             __PARAM3 = __PARAM2
             __PARAM2 = 0
          ENDIF
       ENDIF
       \CLC
       \RR __PARAM4
       \RR __PARAM3
       tmpW1 = tmpW1 + __WPARAM34
       tmpW1 = tmpW1 / tmpW2     
       RETURN tmpW1
    
       ENDFUNC
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-24 02:44
    well, even with changing it to a function, I still have run out of room on the chip [noparse]:([/noparse] The function is only supposed to split down a Byte to display on an LCD. Is there an easier way to convert the byte to simply show on the LCD without all the complex chopping and splitting?
  • ZootZoot Posts: 2,227
    edited 2009-02-24 02:51
    See attached. This has some of JonnyMac's compact subs/funcs for dumping output to an LCD.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-24 03:15
    thanks [noparse]:)[/noparse] Can you help explain the code a bit if you don't mind. The hex stuff confuses me tongue.gif

    SUB LCD_HEX2
      hHigh        VAR    tmpB3            ' for high nib
      hLow        VAR    tmpB4            ' for low nib
    
      hHigh = __PARAM1 & $F0   ' >>>>>>>>>>> What happens here? <<<<<<<<<<
      hLow = __PARAM1 & $0F
    
      SWAP hHigh                    ' flip nibs
      READ Hex_Digits + hHigh, hHigh        ' convert to ASCII
      LCD_OUT hHigh
      READ Hex_Digits + hLow, hLow
      LCD_OUT hLow
      ENDSUB
    



    Will this code work with numbers higher than 99? I would also need to leave out leading 0's so I guess this would be a simple IF statement. The way my function is designed, it splits the Byte down, number by number, removes leading 0's, then it stores the individual numbers into an array. Later in the code, the Array is sent to another sub to display on the LCD. Would storing hex in place of the array mess it up?

    Here is an example of how it works now :
    PUT Line1, "This is Line 1 "
    PUT Line2, "Var : "
    MyVar = 220
    store MyVar, 6, 2, 1
    UPDATE_L1
    UPDATE_L2

    The LCD would then show :
    This is Line 1
    Var : 2200
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-24 03:42
    That routine is designed for HEX or packed BCD -- if you're wanting to display decimal it will not work.

    SX/B 2.0 has a new feature called STR that will do the "splitting" of numbers for you.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-24 03:51
    No decimals [noparse]:)[/noparse] Just 0 through 255. If I want to send 15 to the LCD, I need it to be stored into the Line# array the corresponds with what line i need it to be on and what character space to start from.
  • ZootZoot Posts: 2,227
    edited 2009-02-24 04:12
    SUB LCD_HEX2
      hHigh        VAR    tmpB3            ' for high nib
      hLow        VAR    tmpB4            ' for low nib
    
      hHigh = __PARAM1 & $F0   ' mask off the low nibble, leaving just the upper 4 bits "as they were" 
      hLow = __PARAM1 & $0F   ' ditto but with the low nibble
    
      SWAP hHigh                    ' but we want this in the low nibble also
    
    ' now, if you had the BCD "number" $89 to start with,
    ' you now have $9 in the hLow byte's lower nibble and
    ' and $8 in hHigh's lower nibble, in other words
    ' __PARAM1 (value passed to sub) was $89
    ' then hHigh = $80
    ' then hLow = $09
    ' then hHigh = $08
    
    'That's very helpful because then you can add the nib's value 
    'to the start of a table to convert to ASCII characters to 
    ' send to LCD, i.e. if the value of hLow is $9, then add $9 to "0" (that's ASCII character "0" not value 0)
    
      READ Hex_Digits + hHigh, hHigh        ' convert to ASCII -- I.E., a lookup in the hex chars
      LCD_OUT hHigh                                ' send it
      READ Hex_Digits + hLow, hLow          ' ditto
      LCD_OUT hLow
      ENDSUB
    
    



    And no, it only does two digits, but just call it twice. Second, if you are dumping conversion to LCD, I see no reason to "store" the values; just convert on the fly and dump them and move on. Array code will consume a lot of space quickly. Here is a simple, pseudo-codish version of using above to send a 4 digit HEX "value" to LCD....

    
    myWord VAR Word
    
    myWord = $1234
    
    LCD_CMD xxx ' set character position
    LCD_HEX2 myword_MSB ' send MSB, two "digits"
    LCD_CMD xxx+2 ' set character postion two to the right
    LCD_HEX2 myWord_LSB ' send lower two "digits"
    
    



    So, what about decimal numbers? Well, divide and dump as you go.
    myWord VAR Word
    myByte1  VAR Byte ' a work byte -- can be resused endlessly in your program
    myByte2  VAR Byte ' ditto
    
    myWord = 1234 ' pure value
    
    LCD_CMD  LcdLine1   ' first character's position
    
    myByte1 = MATH_DIV myWord, 1000  ' divide by 1000 for most sig. digit
    myByte2 = MATH_DIV __REMAINDER, 100 ' divide remainder by 100s
    SWAP myByte1
    myByte1 = myByte1 | myByte2
    myByte2 = __REMAINDER ' save for next round of 10s and units
    LCD_HEX2 myByte1
    
    LCD_CMD LcdLine1+2   ' third and fourth character's position
    
    myByte1 = MATH_DIV myByte2, 10  ' divide by 10; remainder from 100 was saved from last time
    myByte2 = __REMAINDER  ' save it; you can prob. just use __REMAINDER from here on out, as it won't get clobbered
    SWAP myByte1
    myByte1 = myByte1 | myByte2
    LCD_HEX2 myByte1
    
    



    If you want to suppress leading zeros, you can parse that as you get each byte and decide what to do (move the cursor over a postion, etc). You can also rewrite LCD_HEX2 do to one character at a time and automatically advance the display char position (which is what I would prob. do, but it depends on what kind of stuff you might send). You also don't need to do a read; you can just use the "add to zero" method....

    myNumber VAR Byte
    myChar VAR Byte
    myNumber = 9 ' pure value
    myChar = "0" + myNumber ' will equal ASCII "9"
    LCD_OUT mychar ' dump ascii char
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-24 04:19
    I've attached an updated version of my Stopwatch program that includes an LCD_DEC3 subroutine -- it prints directly to the display so it may not work for you as-is.

    What you'll find is that it uses the new STR instruction which you can use and simply copy characters from the nStr() array to your line array. Note that the 100s digit (or a space) ends up in nStr(0), the 10s (or space) in nStr(1), and the 1s in nStr(2). If you want to print without the spaces you'll have the test the value and advance the index into the nStr() array to skip past the spaces.

    Post Edited (JonnyMac) : 2/24/2009 4:26:06 AM GMT
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-28 00:44
    I tried using the LCD_DEC3 sub and could not get it to work at all. I kept getting Unknown Command on line : STR nStr, dcWork

    Am I using the wrong editor? I have version 3.2.92h Beta
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-28 00:53
    You need to download version 2.xx of the SX/B compiler (_not_ the IDE) from a sticky post at the top of this forum. Unzip the compiler files into the SXB folder; on my system that folder is:
    -- C:\Program Files\Parallax Inc\SX-Key v3.2.3\Compilers\SXB
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-28 04:12
    ok, thanks [noparse]:)[/noparse] I will be testing it tomorrow.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-28 17:36
    Well since version 2.0 had conflicts with some of my other code, I am not going to be able to go that route. I do have a few other spots that need to be optimized as well. Since I only use BYTES in most of my code, I need to convert a few other functions that I have used from other code found on this forum to use only Bytes.

    Here is some that are used for EEprom access :
    PUT_EE:
      IF __PARAMCNT = 3 THEN                        ' write one byte
        tmpW1 = __WPARAM12
        temp1 = __PARAM3
        i2cMulti = 0
      ELSE
        tmpW1 = __WPARAM12
        temp1 = __PARAM3
        temp2 = __PARAM4
        i2cMulti = 1
      ENDIF
    
      I2C_START
      I2C_OUT SlaveWr                               ' send slave ID
      I2C_OUT tmpW1_MSB                             ' send address, high byte
      I2C_OUT tmpW1_LSB                             ' send address, low byte
      I2C_OUT temp1                                 ' send data byte
      IF i2cMulti = 1 THEN
        I2C_OUT temp2                ' send second data byte
      ENDIF
      I2C_STOP                                      ' finish
    
      DO                                            ' let write cycle finish
        I2C_START
        I2C_OUT SlaveWr
      LOOP UNTIL ackNak = Ack
      RETURN
    
    FUNC Div
      temp1 = __PARAM1
      temp2 = __PARAM2
      temp1 = temp1 / temp2
      temp2 = __REMAINDER
      RETURN temp1, temp2
    ENDFUNC
    
    FUNC PUT_DIGIT
      temp1 = __PARAM1                 ' copy value
      LOOKUP temp1, $3F,$06,$5B,$4F,$66,$5E,$79, temp1
      RETURN temp1
    ENDFUNC
    
    FUNC GET_EE
      tmpW1 = __WPARAM12
    
      I2C_START
      I2C_OUT SlaveWr                               ' send slave ID
      I2C_OUT tmpW1_MSB                             ' send address, high byte
      I2C_OUT tmpW1_LSB                             ' send address, low byte
      I2C_START
      I2C_OUT SlaveRd
      temp1 = I2C_IN Nak
      I2C_STOP
      RETURN temp1
      ENDFUNC
    
    SUB I2C_START
      I2CSTART SDA
      ENDSUB
    
    SUB I2C_STOP
      I2CSTOP SDA
      ENDSUB
    
    SUB I2C_OUT
      I2CSEND SDA, __PARAM1, ackNak
      ENDSUB
    
    FUNC I2C_IN
      ackNak = __PARAM1.0
      I2CRECV SDA, __PARAM1, ackNak
      ENDFUNC
    
    FUNC RX_BYTE
      SERIN RX, Baud, temp1
      RETURN temp1
      ENDFUNC
    
    FUNC load_eprom
      eeAddr = __PARAM1
      eeIn = GET_EE eeAddr
      wait 50
      RETURN eeIn
      ENDFUNC
    



    eeAddr will never be higher than 255 and the value to be stored will never be higher than 255. I have tried to convert it to use Bytes, but once completed, no values are ever returned or saved [noparse]:([/noparse]
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-28 20:15
    ' Low-level I2C routines
    
    I2C_START       SUB     0                       ' generate I2C Start
    I2C_STOP        SUB     0                       ' generate I2C Stop
    I2C_OUT         FUNC    1, 1                    ' write byte to SDA
    I2C_IN          FUNC    1, 1                    ' read byte from SDA
    
    ' High-level I2C routines
    
    WRITE_EE        SUB     2, 3
    READ_EE         FUNC    1, 1, 2
    


    ' Use: I2C_START
    ' -- generates I2C start condition on SDA/SCL pins
    
    SUB I2C_START
      I2CSTART SDA
      ENDSUB
    
    ' -------------------------------------------------------------------------
    
    ' Use: I2C_STOP
    ' -- generates I2C stop condition on SDA/SCL pins
    
    SUB I2C_STOP
      I2CSTOP SDA
      ENDSUB
    
    ' -------------------------------------------------------------------------
    
    ' Use: { ackResult = } I2C_OUT byteVal
    ' -- writes "byteVal" to SDA pin
    ' -- affects global var "ackNak"
    ' -- may be used like a subroutine
    
    FUNC I2C_OUT
      I2CSEND SDA, __PARAM1, ackNak
      __PARAM1 = ackNak
      ENDFUNC
    
    ' -------------------------------------------------------------------------
    
    ' Use: byteVal = I2C_IN AckBit
    ' -- reads "byteVal" from SDA pin
    
    FUNC I2C_IN
      ackNak = __PARAM1.0
      I2CRECV SDA, __PARAM1, ackNak
      ENDFUNC
    
    ' -------------------------------------------------------------------------
    
    ' Use: WRITE_EE address, value
    ' -- "address" is a word (compiler promoted if necessary)
    ' -- "value" is a byte
    
    SUB WRITE_EE
      wrAddr        VAR     tmpW1
      wrValue       VAR     tmpB1
    
      IF __PARAMCNT = 2 THEN
        wrAddr = __PARAM1
        wrValue = __PARAM2
      ELSE
        wrAddr = __WPARAM12
        wrValue = __PARAM3
      ENDIF
    
      I2C_START
      I2C_OUT SlaveWr
      I2C_OUT wrAddr_MSB                            ' send address, high byte
      I2C_OUT wrAddr_LSB                            ' send address, low byte
      I2C_OUT wrValue                               ' send data byte
      I2C_STOP                                      ' finish
    
      '{$IFDEF EEWAIT}
      DO                                            ' let write cycle finish
        I2C_START
        I2C_OUT SlaveWr
      LOOP UNTIL ackNak = Ack
      '{$ENDIF}
    
      ENDSUB
    
    ' -------------------------------------------------------------------------
    
    ' Use: value = READ_EE address
    ' -- reads "value" from EEPROM location "address"
    
    FUNC READ_EE
      rdAddr        VAR     tmpW1
      rdResult      VAR     tmpB1
    
      IF __PARAMCNT = 1 THEN
        rdAddr = __PARAM1
      ELSE
        rdAddr = __WPARAM12
      ENDIF
    
      I2C_START
      I2C_OUT SlaveWr
      I2C_OUT rdAddr_MSB                            ' send address, high byte
      I2C_OUT rdAddr_LSB                            ' send address, low byte
      I2C_START                                     ' restart for read
      I2C_OUT SlaveRd
      rdResult = I2C_IN Nak
      I2C_STOP
      RETURN rdResult
      ENDFUNC
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-28 21:48
    I noticed that the Write and Read functions still use WORD values. Is that a must when using EEproms even though I will never have a number higher than 255?
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-28 21:58
    Which EEPROM are you using?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-28 22:17
    the 4K from Parallax. I have built everything to use as little space as possible and use WORD values ONLY when there is no work around. If I could free up the eeAddr as a WORD, that would save some space. I would also not have to use the __PARAMCNT statement either which would free up some code space.
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-28 22:28
    Please, just give us the part # and don't make us search the Parallax site to help you.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-02-28 22:37
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-02-28 23:02
    You know, I think you're making this stuff harder than it is. tongue.gif Here's how to limit the 24LC32 to 256 addresses:

    ' Use: WRITE_EE address, value
    ' -- "address" is a byte
    ' -- "value" is a byte
    
    SUB WRITE_EE
      wrAddr        VAR     tmpB1
      wrValue       VAR     tmpB2
    
      wrAddr = __PARAM1
      wrValue = __PARAM2
    
      I2C_START
      I2C_OUT SlaveWr
      I2C_OUT $00
      I2C_OUT wrAddr
      I2C_OUT wrValue
      I2C_STOP 
    
      '{$IFDEF EEWAIT}
      DO 
        I2C_START
        I2C_OUT SlaveWr
      LOOP UNTIL ackNak = Ack
      '{$ENDIF}
    
      ENDSUB
    
    ' -------------------------------------------------------------------------
    
    ' Use: value = READ_EE address
    ' -- reads "value" from EEPROM location "address"
    ' -- "address" is a byte
    
    FUNC READ_EE
      rdAddr        VAR     tmpB1
      rdResult      VAR     tmpB2
    
      rdAddr = __PARAM1
    
      I2C_START
      I2C_OUT SlaveWr
      I2C_OUT $00
      I2C_OUT rdAddr
      I2C_START 
      I2C_OUT SlaveRd
      rdResult = I2C_IN Nak
      I2C_STOP
      RETURN rdResult
      ENDFUNC
    
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-03-01 01:00
    You have mentioned many times that you're trying to keep to bytes -- does that include RPM? One would assume a practical value is RPM/100 -- if that's the case see the attached program. It simply counts the 0->1 transitions on the TachIn pin for 0.6 seconds and then updates a program variable called rpm. This happens in the ISR which means you don't have to do anything. Use the ISR means you can have background serial, too.
    RPM.SXB 16.7K
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-03-01 21:43
    I added the interrupt to the chip and now it boots up like normal and instantly goes to menu option 1 and locks up. Since I am only running the chip at 5mhz, I figured it may conflict with other things. If I can stay away from interrupts for the time being, that would be perfect [noparse]:)[/noparse]
  • eagletalontimeagletalontim Posts: 1,399
    edited 2009-03-01 21:58
    ok, COUNT 310 gives the correct RPM, but it is at a slow pace. If I rev quickly, it cannot keep up. I am confused on the math formula to convert PULSIN to RPM's. If anyone can clue me in on this, I would greatly appreciate it!
  • JonnyMacJonnyMac Posts: 9,214
    edited 2009-03-01 23:33
    Conceptually, it's a no-brainer: RPM is revolutions per minute; by using PULSIN for the high and low side of the cycles you've measured the time of a single revolution in units of 10 microseconds (1/100,000th of a second). There are 6,000,000 10us units in a minute, so by dividing the period in to 6,000,000 you get the number of revolutions in a minute.

    You never did say what resolution you need and how often you need it. The ISR code I posted was, essentially, a background version of the COUNT command (by using the ISR we could send and receive serial at the same time).

    You might try this to get RPM in units of 100:

    COUNT TachIn, 600, rpm100
    


    The downside is that this holds the program for 0.6 seconds and this might be a problem.

    It would be really helpful if you would post your program -- doing this piecemeal is really difficult. What the heck, you're asking for free consulting, anyway, you might as well go all the way and end up with a better product to sell. tongue.gif
Sign In or Register to comment.