Menu

Direct printing of 'bit' portion of byte fails if referenced by variable

2025-08-14
2025-08-25
  • c-conversion

    c-conversion - 2025-08-14

    I was struggling with a print statement in a program recently which wasn't working as I expected. I kept thinking I had my logic mixed up but eventually it turned out to be an oddity in the 'Print' statement.

    It may be 'expected' behaviour, if 'unexpected' for me.

    This works:

    Print MyByte.0
    
    Let MyByteBit = 0
    Let MyReferencedBit = MyByte.MyByteBit
    Print MyReferencedBit
    

    This does not work reliably:

    Print MyByte.MyByteBit
    

    It will print "1" only if the most significant bit of MyByte is set to 1.
    So if MyByte has a value > 127: Although this changed when I added an extra line to print spaces to the right of the decimal printed value? See the example program I used to test this.

    Let MyByte = 128
    Let MyByteBit = 0
    Print MyByte.MyByteBit 'Prints 1
    Let MyByteBit = 1
    Print MyByte.MyByteBit 'Prints 1
    ...
    Let MyByteBit = 7
    Print MyByte.MyByteBit 'Prints 1
    
    Let MyByte = 127
    Let MyByteBit = 0
    Print MyByte.MyByteBit 'Prints 0
    Let MyByteBit = 1
    Print MyByte.MyByteBit 'Prints 0
    ...
    Let MyByteBit = 7
    Print MyByte.MyByteBit 'Prints 0
    

    Test program used:

    #Chip 18F16Q41, 64
    
    #Option Explicit
    #Config CP=On
    
    'LCD connection settings
    #Define LCD_IO 4
    #Define LCD_SPEED FAST
    #Define LCD_NO_RW
    
    'Port assignments
    #Define LCD_RS        PortA.0
    #Define LCD_Enable    PortA.1
    
    #Define LCD_DB4       PortA.2
    #Define LCD_DB5       PortC.0
    #Define LCD_DB6       PortC.1
    #Define LCD_DB7       PortC.2
    
    Dim MyByte        As Byte
    Dim MyByteBit     As Byte
    Dim ReferencedBit As Bit
    CLS
    
    Let MyByte = 0
    
    Do
    
        Locate 0, 0
        Print MyByte.7 'These print as expected
        Print MyByte.6
        Print MyByte.5
        Print MyByte.4
        Print MyByte.3
        Print MyByte.2
        Print MyByte.1
        Print MyByte.0
    
        Locate 0, 13
        Print MyByte
        'Print "  "
        'With the above line commented out, prints "1" when MSB set
        'With the line used, prints "1" when LSB set?
    
        Locate 1,0
    
        Let MyByteBit = 7
        Repeat 8
            Print MyByte.MyByteBit 'This does not print as expected.
            Let MyByteBit = MyByteBit - 1
        End Repeat
    
        Let MyByteBit = 7
    
        Repeat 8
            Let ReferencedBit = MyByte.MyByteBit
            Print ReferencedBit    'This prints as expected
            Let MyByteBit = MyByteBit - 1
        End Repeat
    
        Let MyByte = MyByte + 1
    
        If MyByte < 1 Then
            Let MyByte = 1
        End If
        Wait 100 mS
    
    Loop
    

    Now I am aware of this, I'm using this in my program:

    If MyByte.MyByteBit = 1 Then
        Print "1"
    Else
        Print "0"
    End If
    

    Which is 100% reliable.
    At one point "Print MyByte.MyByteBit" printed nothing, not a "1", not a "0", nothing, as though the line was not even present. It was this behaviour that had me most confused.

    As I said, it may be that I was trying to do something that isn't possible and that is what actually should happen. I only report it as it gave me half a day of head scratching and confusion.

     

    Last edit: c-conversion 2025-08-14
  • Anobium

    Anobium - 2025-08-14

    Great insights.

    Print MyByte.MyByteBit is working as expected. And your logic is a good approach.

     
    • c-conversion

      c-conversion - 2025-08-15

      Would it be possible to clarify why "Print MyByte.MyByteBit" exhibits a change in behaviour when the program using it is modified please? {By adding the line 'Print " "}

      If the behaviour is expected to change when an additional line is added to a program, what is the rationale to this change?

      I don't mind that it is inconsistent, and I don't expect that there are (m)any people using "Print" to print a "bit" of a "byte" where that "bit" is referenced by a variable, but I am intrigued as to why it doesn't behave consistently.

      And please, I'm not trying to critique the operation, just attempting to get my head around it. I'm perfectly happy to use:

      If MyByte.MyByteBit = 1 Then
          Print "1"
      Else
          Print "0"
      End If
      

      It works, it is logical, it is readable and it is consistent. That's all I need.

       
  • Anobium

    Anobium - 2025-08-15

    Sure. Not a problem.

    Attach your source program to a post. I will compile to ensure I get the answer totally correct.

     
  • c-conversion

    c-conversion - 2025-08-15

    Here is the program I used to test the behaviour.

     
  • Anobium

    Anobium - 2025-08-16

    Thank you for the code. Really helps.


    Root Cause of the Compilation Issue

    The issue stemmed from a missing subroutine to handle a bit parameter passed to a subroutine in GCBASIC. After extensive debugging, the assembly (ASM) code has been corrected, ensuring the generated HEX file is accurate.

    Why Did One Print Function Work and Not the Other?

    The behavior is complex and relates to how GCBASIC matches function calls to subroutines:

    • Errant Case: In the original code, GCBASIC selected a subroutine expecting a byte type for the Print function because no bit type Print function existed. As a result, the bit reference MyByte.MyByteBit was incorrectly passed as a register-bit pair to the assembly code and then to the subroutine. This caused invalid assembly generation.
    • If compiled with PIC-AS, this would have triggered an error:
        Test_MyByte_MyByteBit.S:239:: error: (842) bad bit number
    

    The error occurs because BTFSC MYBYTE,MYBYTEBIT,ACCESS expects a constant bit number (0–7), but MYBYTEBIT is a register with a runtime value (e.g., 7).

    Interestingly, when targeting a chip supported by MPASM (e.g., a Q43), no error is reported, and the generated HEX matches GCBASIC’s output. This indicates GCBASIC’s behavior aligns with MPASM in this case, but the generated ASM is still incorrect.

    • Solution: To resolve this, two new subroutines were added to handle bit types explicitly—one for LCD output and one for serial output. These ensure GCBASIC finds a matching subroutine for bit variables, generating correct ASM code without errors in PIC-AS or MPASM.

    Added Subroutines

    The following subroutines were added to support printing bit variables. They convert a bit value (0 or 1) to an ASCII character (0 = 48, 1 = 49) for display or serial transmission.

    Serial Print Subroutine

    Sub HSerPrint (In SerPrintValBit As Bit, Optional In comport = comport)
        Dim SerPrintVal As Byte
        SerPrintVal = 48
        If SerPrintValBit = 1 Then SerPrintVal = 49
        HSerSend(SerPrintVal, comport)
        ' Carriage Return
        #IfDef SerPrintCR
            HSerSend(13, comport)
        #EndIf
        ' Line Feed
        #IfDef SerPrintLF
            HSerSend(10, comport)
        #EndIf
    End Sub
    

    LCD Print Subroutine

    Sub Print (In LCDValueBit As Bit)
        ' Subroutine to print a bit variable on the LCD
        Dim LCDValueTemp As Byte
        Set LCD_RS On
        LCDValueTemp = 48
        If LCDValueBit = 1 Then LCDValueTemp = 49
        LCDWriteByte(LCDValueTemp)
    End Sub
    

    Old Assembly Code (Incorrect)

    The original code attempted to print MyByte.MyByteBit but failed due to incorrect handling of the bit parameter:

    ; Print MyByte.MyByteBit ' This does not print as expected
    CLRF LCDVALUE,ACCESS
    BTFSC MYBYTE,MYBYTEBIT,ACCESS
    INCF LCDVALUE,F,ACCESS
    RCALL PRINTxxx
    
    • Issue: The BTFSC MYBYTE,MYBYTEBIT,ACCESS instruction is invalid because MYBYTEBIT is a register (not a constant). PIC-AS would flag this as a bad bit number error, as bit-oriented instructions require a literal bit number (0–7).

    New Assembly Code (Correct)

    With the new subroutines, GCBASIC generates correct ASM for bit handling:

    ; Print MyByte.MyByteBit ' This should print as expected
    BCF SYSBITVAR0,2,ACCESS
    LFSR 0,MYBYTE
    MOVLW 7
    ANDWF MYBYTEBIT,W,ACCESS
    MOVWF SYSBYTETEMPX,ACCESS
    RCALL SYSREADBIT
    BTFSS STATUS,Z,ACCESS
    BSF SYSBITVAR0,2,ACCESS
    RCALL PRINTxxx
    
    • Explanation:
    • Clears a system bit variable (SYSBITVAR0,2).
    • Uses LFSR to load the address of MYBYTE into File Select Register 0.
    • Masks MYBYTEBIT with 7 (ensuring the bit number is 0–7).
    • Calls SYSREADBIT to read the specified bit from MYBYTE.
    • Checks the Zero flag (STATUS,Z) to determine the bit’s value.
    • Sets SYSBITVAR0,2 if the bit is 1.
    • Calls PRINT( the specific bit supported function ) to output the bit value (as ASCII 0 or 1).

    Outcome

    • The new subroutines ensure GCBASIC correctly handles bit types, generating valid ASM code.
    • No errors are reported in PIC-AS, confirming the ASM and HEX are correct.
    • No need to switch to PIC-AS: I use PIC-AS to verify the generated ASM and HEX, but GCBASIC with the new subroutines works fine with MPASM or other assemblers.

    Next Steps

    • Add the provided HSerPrint and Print subroutines to your GCBASIC program.
    • Test if the issue is resolved for both serial and LCD output.
    • If successful, I will include these subroutines in the LCD and USART libraries for the next GCBASIC release.
     

    Last edit: Anobium 2025-08-16
  • c-conversion

    c-conversion - 2025-08-16

    Thanks for the update and the explanation.
    I'll be unable to test the HSerPrint routine as this is not something I've used and have no method of connecting a PIC device to any PC. I have something in the back of my mind that suggests a PicKit has this facility, but I no longer have one.

    The Print routine I should be able to add. I generally use an LCD display for my projects. All my prototyping is done with an LCD, possibly a serial LCD if I'm short of pins, but almost always have an LCD. If not an LCD then a serial 7 segment four digit LED.

     
    • Anobium

      Anobium - 2025-08-16

      Ok. I understand, thanks.
      Can you confirm that this resolves your PRINT issue. You can add both routines only the one you actually use will get included in your assembled hex.

      We have PICKIT2 for sale in my website. www.pickitplus.co.uk Get the hardware and software. I will do a special price so please contact me directly before you proceed.

       
  • c-conversion

    c-conversion - 2025-08-21

    I have added those to my program as requested and they work correctly. More in the manner I had expected.

    Print MyByte.MyByteBit prints the status of the individual bit rather than only when certain bits are set.

    I don't feel the need to upgrade to a PicKit, but thanks for the offer. I never really got on with it finding it quite frustrating to use, particularly when changing devices which caused it to require the firmware to be updated, then swapping back to another device required another (so called) update. It drove me mad. As soon as I figured out I could use something else, I did.

    I might see if I could make a simple serial terminal device though. It could be handy for debugging. When I get some time I might look into that. I made something similar using the old PicAxe serial protocol. Perhaps I could re-use that project? You've got me thinking now...

     
  • Anobium

    Anobium - 2025-08-21

    Great news of the fix. I will add to the next release .


    Re PICKit2. There is no firmware updates anymore. You can change chips with great ease. From GCBASIC there is zero configuration - it just works.


    A serial terminal is always useful! I use a terminal all the time.

     
  • Sleepwalker3

    Sleepwalker3 - 2025-08-25

    Just curious, does this 'fix' get updated in the 'Release' straight away, or does it get put in the line to come out with the next release? I don't have any need for it just now, just curious.

     
    • Anobium

      Anobium - 2025-08-25

      When a release is committed. So, many changes collated together. Any specific change gets included in the downloadable installed, plus, anyone using GCSTUDIO with updates turned on these changes, and only, these changes will be applied to a local installation.

      We are heading towards a release soon. I have to update the change log and make a few changes to the GCCode Helpers and it will be done.

       

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.