Menu

Serial Transmit Number not Ascii code

Help
2007-05-26
2013-05-30
  • Nobody/Anonymous

    Hello!

    I am trying to use the code below to send an actual number to Hyperterminal not the Ascii Code.
    The small number (25) works, but the large number (2500) does not.
    In Hyperterminal I receive 25 - 0196.
    I have no idea what is wrong with this code.

    Thanks!

    Alex

    ' ------------- CODE
    #chip P16F876, 20
    #config HS_OSC, WDT_OFF

    #define GOTNEWDATA 0    'bit that indicates new data received

    ' LED's
    #define Green   PORTB.6   'Green LED
    dir Green out

    Dim temp as word
    Dim temp2 as word

    ProgStart:
    'Inititalize the serial connection
    SetupSerial

    'Send a test message
    TransmitSerial_Print("Ready to Work!")
    Transmitserial(13)
    Transmitserial(10)

    Mainloop:
      SET Green ON
     
      temp = 25
      temp2 = 2500

      ascii(temp)               'Send actual number instead of Ascii code
      TransmitSerial_Print(" - ")
      ascii(temp2)              'Send actual number instead of Ascii code

      Transmitserial(13)
      Transmitserial(10)
     
      Wait 60 10ms
      SET Green OFF
      Wait 60 10ms
     
    Goto Mainloop

    Sub ascii(LCDValue as Word)#NR

    SERDECMIL = 0
    SERMIL = 0
    SERCEN = 0 
    SERDEC = 0 
    SERUN = 0 
    LCDValueTemp = 0 

    IF LCDValue >= 10000 then
      LCDValueTemp = LCDValue / 10000
      SERDECMIL = LCDValueTemp + 48
      TransmitSerial(SERDECMIL)
      LCDValue = LCDValue - LCDValueTemp * 10000
    End if

    If LCDValue >= 1000 Then
      LCDValueTemp = LCDValue / 1000 
      SERMIL = LCDValueTemp + 48
      TransmitSerial(SERMIL)
      LCDValue = LCDValue - LCDValueTemp * 1000 
    End if

    If LCDValue >= 100 Then
      LCDValueTemp = LCDValue / 100 
      SERCEN = LCDValueTemp + 48
      TransmitSerial(SERCEN)
      LCDValue = LCDValue - LCDValueTemp * 100 
    End if

    If LCDValue >= 10 Then
      LCDValueTemp = LCDValue / 10
      SERDEC = LCDValueTemp + 48
      TransmitSerial(SERDEC)
      LCDValue = LCDValue - LCDValueTemp * 10
    End if

      SERUN = LCDValue + 48 
      TransmitSerial(SERUN)

    End Sub

    Sub SetupSerial
    ADOff 'make port digital
    DIR PORTC.6 OUT
    DIR PORTC.7 IN
    SPBRG = 129                    ' this value is for 9600 baud with brgh bit = 0 P16F876
    TXSTA = b'00100100'         'note, bit 2 is BRGH
    RCSTA = b'10010000'         'enable serial port and reception
    SET FLAGS.GOTNEWDATA OFF
    end sub

    Sub TransmitSerial(xmitdata)
    LoopTransmit:
    IF PIR1.TXIF OFF THEN goto LoopTransmit 'check if transmitter is busy
      TXDATA = xmitdata
      TXREG = TXDATA 'transmit data
    End sub

    Sub TransmitSerial_Print(PrintData$)
    PrintLen = PrintData(0)
    if PrintLen = 0 then exit sub
    'Write Data
    for SysPrintTemp = 1 to PrintLen
    TransmitSerial(PrintData(SysPrintTemp))
    next
    End Sub

    sub ErrSerialOverr 'error because OERR overrun errr bit is set
    'this code simply clears and continues
    SET RCSTA.CREN OFF
    SET RCSTA.CREN ON
    end sub

    sub ErrSerialFrame 'error because FERR framing error bit is set
    movf RCREG,W 'discard received data that has error
    movf RCREG,W
    movf RCREG,W
    end sub

    sub ErrSerlParity 'error because parity bit is not correct
    end sub

     
    • Tam Do

      Tam Do - 2007-05-26

      It looks like when you use LCDValue / 1000 you are dividing a word by an integer. Try adding [Word] after 1000 to explicitly state that the value you are dividing by is also a Word.

       
    • Hugh Considine

      Hugh Considine - 2007-05-26

      There are two problems here:

      The first is that there is a bug in GCBASIC that was causing the IF statements in your program to be treated as though the LCDValue variable is a byte. This is fixed now - http://gcbasic.sourceforge.net/newfiles/update.zip

      Second, as Tam said, you need to add [word] to the ends of the lines where you set LCDValueTemp to LCDValue / (some number over 255). This is really only a temporary arrangement, and will be changed before the next major release.

       
    • Nobody/Anonymous

      Hello!

      Thanks for the input Tam and Hugh.
      I added the [Word] qualifier at the appropriate places.
      Also, I added provisions for the case that the remainder of a division = 0.
      For example value 500, the equation:
        LCDValue = LCDValue - LCDValueTemp * 100
      will result in 0.
        0 = 500 - 5 * 100
      So added a line of code to check for a value of 0 and put out the appropriate
      number of 0's.
      E.g. If LCDValue = 0 then TransmitSerial_Print("0")

      I have included the complete code below. The code also includes an additional
      Sub to output the value with one decimal (Ascii1Dec).

      Thanks again!

      ------------------------------------------------------

      #chip P16F876, 20
      #config HS_OSC, WDT_OFF

      #define GOTNEWDATA 0    'bit that indicates new data received

      ' LED's
      #define Green   PORTB.6   'Green LED
      dir Green out

      Dim temp1
      Dim temp2 as word
      Dim temp3 as word
      Dim temp4 as word
      Dim temp5 as word
      Dim temp6 as word

      ProgStart:
      'Inititalize the serial connection
      SetupSerial

      'Send a test message
      TransmitSerial_Print("Ready to Work!")
      Transmitserial(13)
      Transmitserial(10)

      Mainloop:
        SET Green ON
       
        temp1 = 25
        temp2 = temp1 * 18 + 320  'Convert to Fahrenheit * 10
        temp3 = 789
        temp4 = 2345
        temp5 = 2500
        temp6 = 56789

        ascii(temp1)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(25)- ")
        ascii(temp2)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(770) - ")
        ascii(temp3)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(789) - ")
        ascii(temp4)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(2345)- ")
        ascii(temp5)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(2500)- ")
        ascii(temp6)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(56789)- ")

        Transmitserial(13)
        Transmitserial(10)
       
        ascii1Dec(temp1)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(2.5)- ")
        ascii1Dec(temp2)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(77.0) - ")
        ascii1Dec(temp3)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(78.9) - ")
        ascii1Dec(temp4)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(234.5)- ")
        ascii1Dec(temp5)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(250.0)- ")
        ascii1Dec(temp6)              'Send actual number instead of Ascii code
        TransmitSerial_Print("(5678.9)- ")

        Transmitserial(13)
        Transmitserial(10)

        Wait 60 10ms
        SET Green OFF
        Wait 60 10ms
       
      Goto Mainloop

      Sub Ascii(LCDValue as Word)#NR

      SERDECMIL = 0
      SERMIL = 0
      SERCEN = 0 
      SERDEC = 0 
      SERUN = 0 
      LCDValueTemp = 0 

      IF LCDValue >= 10000 then
        LCDValueTemp = LCDValue / 10000 [WORD]
        SERDECMIL = LCDValueTemp + 48
        TransmitSerial(SERDECMIL)
        LCDValue = LCDValue - LCDValueTemp * 10000
        If LCDValue = 0 then TransmitSerial_Print("000")
      End if

      If LCDValue >= 1000 Then
        LCDValueTemp = LCDValue / 1000 [WORD]
        SERMIL = LCDValueTemp + 48
        TransmitSerial(SERMIL)
        LCDValue = LCDValue - LCDValueTemp * 1000 
        If LCDValue = 0 then TransmitSerial_Print("00")
      End if

      If LCDValue >= 100 Then
        LCDValueTemp = LCDValue / 100 [Word]
        SERCEN = LCDValueTemp + 48
        TransmitSerial(SERCEN)
        LCDValue = LCDValue - LCDValueTemp * 100
        If LCDValue = 0 then TransmitSerial_Print("0")
      End if

      If LCDValue >= 10 Then
        LCDValueTemp = LCDValue / 10
        SERDEC = LCDValueTemp + 48
        TransmitSerial(SERDEC)
        LCDValue = LCDValue - LCDValueTemp * 10
      End if

        SERUN = LCDValue + 48
        TransmitSerial(SERUN)

      End Sub

      Sub Ascii1Dec(LCDValue as Word)#NR

      SERDECMIL = 0
      SERMIL = 0
      SERCEN = 0 
      SERDEC = 0 
      SERUN = 0 
      LCDValueTemp = 0 

      IF LCDValue >= 10000 then
        LCDValueTemp = LCDValue / 10000 [WORD]
        SERDECMIL = LCDValueTemp + 48
        TransmitSerial(SERDECMIL)
        LCDValue = LCDValue - LCDValueTemp * 10000
        If LCDValue = 0 then TransmitSerial_Print("00.0")
      End if

      If LCDValue >= 1000 Then
        LCDValueTemp = LCDValue / 1000 [WORD]
        SERMIL = LCDValueTemp + 48
        TransmitSerial(SERMIL)
        LCDValue = LCDValue - LCDValueTemp * 1000 
        If LCDValue = 0 then TransmitSerial_Print("00.")
      End if

      If LCDValue >= 100 Then
        LCDValueTemp = LCDValue / 100 [Word]
        SERCEN = LCDValueTemp + 48
        TransmitSerial(SERCEN)
        LCDValue = LCDValue - LCDValueTemp * 100
        If LCDValue = 0 then TransmitSerial_Print("0.")
      End if

      If LCDValue >= 10 Then
        LCDValueTemp = LCDValue / 10
        SERDEC = LCDValueTemp + 48
        TransmitSerial(SERDEC)
        LCDValue = LCDValue - LCDValueTemp * 10
        TransmitSerial_Print(".")
      End if

        SERUN = LCDValue + 48
        TransmitSerial(SERUN)

      End Sub

      Sub SetupSerial
      ADOff 'make port digital
      DIR PORTC.6 OUT
      DIR PORTC.7 IN
      SPBRG = 129                    ' this value is for 9600 baud with brgh bit = 1 P16F876
      'SPBRG = 20                      ' this value is for 57600 baud with brgh bit = 1 P16F876
      TXSTA = b'00100100'         'note, bit 2 is BRGH
      RCSTA = b'10010000'         'enable serial port and reception
      SET FLAGS.GOTNEWDATA OFF
      end sub

      Sub TransmitSerial(xmitdata)
      LoopTransmit:
      IF PIR1.TXIF OFF THEN goto LoopTransmit 'check if transmitter is busy
        TXDATA = xmitdata
        TXREG = TXDATA 'transmit data
      End sub

      Sub TransmitSerial_Print(PrintData$)
      PrintLen = PrintData(0)
      if PrintLen = 0 then exit sub
      'Write Data
      for SysPrintTemp = 1 to PrintLen
      TransmitSerial(PrintData(SysPrintTemp))
      next
      End Sub

      sub ErrSerialOverr 'error because OERR overrun errr bit is set
      'this code simply clears and continues
      SET RCSTA.CREN OFF
      SET RCSTA.CREN ON
      end sub

      sub ErrSerialFrame 'error because FERR framing error bit is set
      movf RCREG,W 'discard received data that has error
      movf RCREG,W
      movf RCREG,W
      end sub

      sub ErrSerlParity 'error because parity bit is not correct
      end sub

       
    • Tam Do

      Tam Do - 2007-05-27

      You're welcome. I looked at your code and it seems great, however I went ahead and made some improvements of my own to your code. I followed the latest lcd.h code for LCDInt for integers and LCDWord for word. I also wrote a routine for printing words with N decimal places. Its not thoroughly tested yet, and i'm sure it can be improved upon. Also Hugh, I found that the code for the repeat function doesn't work the same as the equivalent for loop.

      Example:

      In my code I wrote

      NRepeat = DECPlace - PrintLen
      repeat NRepeat
      TransmitSerial(48)
      end repeat

      What I ended up is this:

      0.000000000000000000000000000000000000000000000000000000000000000000000000000000
      00000000000000000000000000000000000000000000000000000000000000000000000000000000
      00000000000000000000000000000000000000000000000000000000000000000000000000000000
      00000000000000000000

      Which I believe is the result of an endless loop of about 255 or 256 zeros. So I think theres a problem there...

      Okay and for the code:

      'Transmit Byte as Decimal Value
      sub SERIALTXInt(DECValue) #NR
      DECValueTemp = 0
      IF DECValue >=100 then
        DECValueTemp = DECValue / 100
        DECValue = SysCalcTempX
        TransmitSerial(DECValueTemp + 48)
      end if

      IF DECValueTemp > 0 or DECValue >=10 then
        DECValueTemp = DECValue / 10
        DECValue = SysCalcTempX
        TransmitSerial(DECValueTemp + 48)
      end if

      TransmitSerial(DECValue + 48)
      end sub

      'Transmit Word as Decimal Value
      sub SERIALTXWord(WORDValue as word) #NR
      Dim SysCalcTempX as word
      WORDValueTemp = 0
      SerialShowChar = 0

      IF WORDValue >= 10000 then
        wait 5 s
        WORDValueTemp = WORDValue / 10000 [word]
        WORDValue = SysCalcTempX
        TransmitSerial(WORDValueTemp + 48)
        SerialShowChar = TRUE
      end if

      IF SerialShowChar > 0 or WORDValue >= 1000 then
        WORDValueTemp = WORDValue / 1000 [word]
        WORDValue = SysCalcTempX
        TransmitSerial(WORDValueTemp + 48)
        SerialShowChar = TRUE
      end if

      IF SerialShowChar > 0 or WORDValue >= 100 then
        WORDValueTemp = WORDValue / 100 [word]
        WORDValue = SysCalcTempX
        TransmitSerial(WORDValueTemp + 48)
        SerialShowChar = TRUE
      end if

      IF SerialShowChar > 0 or WORDValue >= 10 then
        WORDValueTemp = WORDValue / 10 [word]
        WORDValue = SysCalcTempX
        TransmitSerial(WORDValueTemp + 48)
      end if

      TransmitSerial(WORDValue + 48)
      end sub

      'Transmit Word as Decimal Value with N Decimal Places
      'Basically creates a string of the output without decimals
      'and then inserts the decimal and leading zeros at the right place
      sub SerialTXNDec(WORDValue as word, DECLen) #NR
      Dim SysCalcTempX as word
      Dim PrintString(7)

      WORDValueTemp = 0
      PrintLen = 0
      ShowChar = 0
      DecPlace = 0

      IF WORDVALUE >= 10000 then
        WORDValueTemp = WORDValue / 10000 [word]
        WORDValue = SysCalcTempX
        PrintLen = PrintLen + 1
        PrintString(PrintLen) = WordValueTemp + 48
        ShowChar = TRUE
      end if

      IF ShowChar > 0 or WORDValue >=1000 then
        WORDValueTemp = WORDValue / 1000 [word]
        WORDValue = SysCalcTempX
        PrintLen = PrintLen + 1
        PrintString(PrintLen) = WordValueTemp + 48
        ShowChar = TRUE
      end if

      IF ShowChar > 0 or WORDValue >= 100 then
        WORDValueTemp = WORDValue / 100 [word]
        WORDValue = SysCalcTempX
        PrintLen = PrintLen + 1
        PrintString(PrintLen) = WordValueTemp + 48
        ShowChar = TRUE
      end if

      IF ShowChar > 0 or WORDValue >= 10 then
        WORDValueTemp = WORDValue / 10 [word]
        WORDValue = SysCalcTempX
        PrintLen = PrintLen + 1
        PrintString(PrintLen) = WordValueTemp + 48
      end if

      PrintLen = PrintLen + 1
      PrintString(PrintLen) = WordValue + 48

      IF PrintLen < DECLen Then
        TransmitSerial_Print("0.")
        NRepeat = DECLen - PrintLen
       
        for Index = 1 to NRepeat
        TransmitSerial(48)
        next
       
        IF PrintLen = 1 Then
         TransmitSerial(PrintString(1))
         exit sub
        end if
       
        FOR Index = 1 to PrintLen
         TransmitSerial(PrintString(Index))
        next
       
        exit sub
      end if

      DECPlace = PrintLen - DECLen

      FOR Index = 1 to DECPlace
        TransmitSerial(PrintString(Index))
      NEXT

      TransmitSerial(46)

      DECPlace = DECPlace + 1

      FOR Index = DECPlace to PrintLen
      TransmitSerial(PrintString(Index))
      NEXT

      end sub

       
    • Tam Do

      Tam Do - 2007-05-27

      Error in code above.

      Remove this piece of code in SerialTXNDec, it was just there to test if everything was working as it should.

      IF PrintLen = 1 Then
      TransmitSerial(PrintString(1))
      exit sub
      end if

       
    • Nobody/Anonymous

      To my recollection when both the LCDValue and LCDValueTemp were defined as words, the [word] qualifiers were not required on word size operations.  Not sure which way is most effecient code wise.

      I think if the ascii subroutine were to become a header file, then define LCDValue and LCDValueTemp as words there?  Or passing another variable as a switch (could be a little awkward?), when setting up the ascii syntax for its use.  For example, ascii(DecimalNum, IntegerSize), IntegerSize = Byte(default) or Word?  Again, not sure which is most efficient way.

      Kent

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.