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.
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.
#Chip18F16Q41,64#OptionExplicit#ConfigCP=On'LCD connection settings#DefineLCD_IO4#DefineLCD_SPEEDFAST#DefineLCD_NO_RW'Port assignments#DefineLCD_RSPortA.0#DefineLCD_EnablePortA.1#DefineLCD_DB4PortA.2#DefineLCD_DB5PortC.0#DefineLCD_DB6PortC.1#DefineLCD_DB7PortC.2DimMyByteAsByteDimMyByteBitAsByteDimReferencedBitAsBitCLSLetMyByte=0DoLocate0,0PrintMyByte.7'These print as expectedPrintMyByte.6PrintMyByte.5PrintMyByte.4PrintMyByte.3PrintMyByte.2PrintMyByte.1PrintMyByte.0Locate0,13PrintMyByte'Print " "'With the above line commented out, prints "1" when MSB set'With the line used, prints "1" when LSB set?Locate1,0LetMyByteBit=7Repeat8PrintMyByte.MyByteBit'This does not print as expected.LetMyByteBit=MyByteBit-1EndRepeatLetMyByteBit=7Repeat8LetReferencedBit=MyByte.MyByteBitPrintReferencedBit'This prints as expectedLetMyByteBit=MyByteBit-1EndRepeatLetMyByte=MyByte+1IfMyByte<1ThenLetMyByte=1EndIfWait100mSLoop
Now I am aware of this, I'm using this in my program:
IfMyByte.MyByteBit=1ThenPrint"1"ElsePrint"0"EndIf
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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:
IfMyByte.MyByteBit=1ThenPrint"1"ElsePrint"0"EndIf
It works, it is logical, it is readable and it is consistent. That's all I need.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
SubHSerPrint(InSerPrintValBitAsBit,OptionalIncomport=comport)DimSerPrintValAsByteSerPrintVal=48IfSerPrintValBit=1ThenSerPrintVal=49HSerSend(SerPrintVal,comport)' Carriage Return#IfDefSerPrintCRHSerSend(13,comport)#EndIf' Line Feed#IfDefSerPrintLFHSerSend(10,comport)#EndIfEndSub
LCD Print Subroutine
SubPrint(InLCDValueBitAsBit)' Subroutine to print a bit variable on the LCDDimLCDValueTempAsByteSetLCD_RSOnLCDValueTemp=48IfLCDValueBit=1ThenLCDValueTemp=49LCDWriteByte(LCDValueTemp)EndSub
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 expectedCLRFLCDVALUE,ACCESSBTFSCMYBYTE,MYBYTEBIT,ACCESSINCFLCDVALUE,F,ACCESSRCALLPRINTxxx
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 expectedBCFSYSBITVAR0,2,ACCESSLFSR0,MYBYTEMOVLW7ANDWFMYBYTEBIT,W,ACCESSMOVWFSYSBYTETEMPX,ACCESSRCALLSYSREADBITBTFSSSTATUS,Z,ACCESSBSFSYSBITVAR0,2,ACCESSRCALLPRINTxxx
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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:
This does not work reliably:
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.
Test program used:
Now I am aware of this, I'm using this in my program:
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
Great insights.
Print MyByte.MyByteBit is working as expected. And your logic is a good approach.
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:
It works, it is logical, it is readable and it is consistent. That's all I need.
Sure. Not a problem.
Attach your source program to a post. I will compile to ensure I get the answer totally correct.
Here is the program I used to test the behaviour.
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:
Print
function because no bit typePrint
function existed. As a result, the bit referenceMyByte.MyByteBit
was incorrectly passed as a register-bit pair to the assembly code and then to the subroutine. This caused invalid assembly generation.The error occurs because
BTFSC MYBYTE,MYBYTEBIT,ACCESS
expects a constant bit number (0–7), butMYBYTEBIT
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.
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
LCD Print Subroutine
Old Assembly Code (Incorrect)
The original code attempted to print
MyByte.MyByteBit
but failed due to incorrect handling of the bit parameter:BTFSC MYBYTE,MYBYTEBIT,ACCESS
instruction is invalid becauseMYBYTEBIT
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:
SYSBITVAR0,2
).LFSR
to load the address ofMYBYTE
into File Select Register 0.MYBYTEBIT
with7
(ensuring the bit number is 0–7).SYSREADBIT
to read the specified bit fromMYBYTE
.STATUS,Z
) to determine the bit’s value.SYSBITVAR0,2
if the bit is 1.PRINT
( the specific bit supported function ) to output the bit value (as ASCII0
or1
).Outcome
Next Steps
HSerPrint
andPrint
subroutines to your GCBASIC program.Last edit: Anobium 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.
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.
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...
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.
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.
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.