Have written a simple program using SerReceive to capture output from my PC keyboard. It works with digits 0-9, but only captures the first digit with 10 or larger. I have dimensioned the captured variable as a byte, and have tried using two different terminal programs with the same result. I'm thinking I'm missing something simple; any help appreciated.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for responding to this query. Below is the code, and attached is a picture of what I see on my terminal following several responses.
There are actually 2 things I don’t understand; first why the “Type number to convert “ always shows up twice when I first run the program, and second, why SerReceive appears to only capture the first digit of my keyboard response.
~~~~~
;This program takes num <=255, "converts" it to binary
;by showing result via serial transmission.
#define SendAHigh Set SerOutPort on
#define SendALow Set SerOutPort off
#define RecAHigh SerInPort on
#define RecALow SerInPort off
#define cr 13
#define lf 10
;Variables
Dim num, divby, bid, rm As byte
dir GPIO out
dir SerInPort in
InitSer 1, r4800, 1+WaitForStart, 8, 1, none, invert
do
divby = 128
SerPrint 1, "Type number to convert (<= 255) "
SerSend 1, cr :SerSend 1, lf
SerReceive 1, num
SerPrint 1, "You typed " : SerSend 1, num : SerSend 1, cr :SerSend 1, lf
num = num - 48
Repeat 8
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
SerPrint 1, bid
num = rm
divby = divby/2
End Repeat
SerSend 1, cr :SerSend 1, lf
loop
NB: Edit by Anobium only to sorted the layout.... Please use indents and 5 tilders before posting code.
This is not something I have come across. I can build your setup at the weekend.
Try this.
- Remove the REPEAT and change to a FOR/NEXT as there is a known issue with REPEAT.
- Check your circuit. Is the chip resetting to cause the two lines to be serialised?
Last edit: Anobium 2014-01-29
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm not sure I understand your setup.
You say you are getting values from your keyboard but it looks like you are receiving data from a serial port.
When you type a value and the PC sends it out the serial port it is broken into ASCII bytes.
So 37 is broken into a byte containing 3 and a second containing 7.
Your program only is receiving one byte so it gets the first digit only and misses the second.
Add a second SerReceive to get the second byte.
Add a third for the third byte(255).
I don't know the SerReceive command well enough but according to the manual I don't see a timeout option so you may need to put the SerReceive lines in a timed loop otherwise a single byte could hang it up. Or just always send three bytes i.e. 002 or 010.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I really appreciate the efforts in helping me figure this out.
To clarify my setup, I have a serial cable connecting my PC and the 12F683, I am running Free Serial Port Terminal (although the results are the same with
other terminal programs I have tried), and I am typing decimal number to be processed on my PC keyboard. Serial input is onto pin 4, and Serial output from pin 2 of the PIC.
• I changed Repeat to a For/Next loop, but that did not change anything.
• If a chip reset is occurring to cause the first SerPrint command to execute twice, I don’t know how to check for that. I did recheck my wiring and found nothing loose or otherwise iffy. Could that problem be related to the contents of my gbasic.ini file?
• Thank you for helping me understand that even a “single digit” being received on the serial port is a byte; I changed my code to reflect that, and except for the double line at the beginning, it works now.
• There is one more wrinkle to this; after the double line is seen on the terminal, the program halts until I check and then uncheck the /MCLR box under VDD target on the PICkit2 software software. Is this a clue?
Below find my revised code:
~~~~
;This program takes num <=255, "converts" it to binary
;by showing result via serial transmission.
#define SendAHigh Set SerOutPort on
#define SendALow Set SerOutPort off
#define RecAHigh SerInPort on
#define RecALow SerInPort off
#define cr 13
#define lf 10
;Variables
Dim numhunds, numtens, numones, count, divby, bid, rm As byte
dir GPIO out
dir SerInPort in
InitSer 1, r4800, 1+WaitForStart, 8, 1, none, invert
do
divby = 128
SerPrint 1, "Type 3 digit number"
SerPrint 1, " to convert (<= 255) "
SerSend 1, cr : SerSend 1, lf
SerReceive 1, numhunds : SerReceive 1, numtens : SerReceive 1, numones
SerPrint 1, "You typed "
SerSend 1, numhunds : SerSend 1, numtens : SerSend 1, numones
SerSend 1, cr : SerSend 1, lf
numhunds = numhunds - 48
numtens = numtens - 48
numones = numones - 48
num = (numhunds * 100) + (numtens * 10) + numones
SerPrint 1, num
SerSend 1, cr : SerSend 1, lf
For count = 0 to 7
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
SerPrint 1, bid
num = rm
divby = divby/2
Next
SerSend 1, cr :SerSend 1, lf
loop
Anobium, please please use five tilders before posting your code. Edited to revise formatting only.
Last edit: Anobium 2014-02-01
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I just discovered that if I use a different pin (not the MCLR pin) for SerInPort, no double line, but still have to check and uncheck /MCLR for the program to run.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
;Defines (Constants)
' [todo] This is the config for a serial terminal
' turn on the RS232 and terminal port.
' Define the USART port
#define USART_BAUD_RATE 9600
#define USART_BLOCKING
' [todo] Ensure these port addresses are correct
#define SerInPort PORTc.7
#define SerOutPort PORTc.6
'Set pin directions
Dir SerOutPort Out
Dir SerInPort In
' [todo] This assumes you are using an ANSI compatible terminal. Use PUTTY.EXE it is very easy.
wait 1 s
ANSIERASECREEN
ANSI ( 0, 2)
HSerPrint "Started: "
ANSI ( 0, 6)
#define cr 13
#define lf 10
;Variables
Dim numhunds, numtens, numones, count, divby, bid, rm As byte
For count = 0 to 7
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
HserPrint bid
num = rm
divby = divby/2
Next
HSerSend cr :hSerSend lf
loop
' get the serial character, create a string of up to 3 chars, then take the value of that string and return a numeric value.
Sub GetNum ( Out InputVal ) as byte
dim inputstring as string * 3
Dim inputstringpointer as byte
inputstringpointer = 1
' init SNum of you will create an endless on the second call this this sub.
SNum = 255
' stay in loop Until CR is pressed or 3 chars entered
Do while SNum <> 13 and inputstringpointer < 4
HSerReceive SNum
' limit string handlers to NUMBERS only
IF SNum > 0x2f AND SNum < 0x3A Then
HSerSend SNum
' add the char to the string
inputstring ( inputstringpointer ) = SNum
inputstring ( 0) = inputstringpointer
inputstringpointer++
END IF
'the delete Key
IF SNum = 0x7f then
HSerSend SNum
' remove the last char from the string
if inputstringpointer > 1 then
inputstringpointer--
inputstring ( 0) = inputstringpointer
end if
End iF
Loop
' get the value
InputVal = val ( inputstring )
End Sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
;Defines (Constants)
#define CLEARCARRY set STATUS.C OFF
#define CARRYOVERFLOW STATUS.C
' [todo] This is the config for a serial terminal
' turn on the RS232 and terminal port.
' Define the USART port
#define USART_BAUD_RATE 9600
#define USART_BLOCKING
' [todo] Ensure these port addresses are correct
#define SerInPort PORTc.7
#define SerOutPort PORTc.6
'Set pin directions
Dir SerOutPort Out
Dir SerInPort In
' [todo] This assumes you are using an ANSI compatible terminal. Use PUTTY.EXE it is very easy.
wait 1 s
ANSIERASECREEN
ANSI ( 0, 2)
HSerPrint "Started: "
ANSI ( 0, 6)
#define cr 13
#define lf 10
;Variables
Dim numhunds, numtens, numones, count, divby, bid, rm As byte
dim num as word
do
HserPrint "Type 3 digit number"
HserPrint " to convert (<= 255) "
HSerSend cr : hSerSend lf
num = 0
GetNum ( num )
HSerSend cr : hSerSend lf
if num > 255 then
HserPrint "Error! Number larger than 255"
HSerSend cr : hSerSend lf
ELSE
divby = 128
For lcount = 0 to 7
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
HserPrint bid
num = rm
divby = divby/2
Next
HSerSend cr :hSerSend lf
END IF
loop
' get the serial character, create a string of up to 3 chars, then take the value of that string and return a numeric value.
Sub GetNum ( Out InputVal as word )
dim inputstring as string * 3
Dim inputstringpointer as byte
inputstringpointer = 1
' init SNum of you will create an endless on the second call this this sub.
SNum = 255
' stay in loop Until CR is pressed or 3 chars entered
Do while SNum <> 13 and inputstringpointer < 4
HSerReceive SNum
' limit string handlers to NUMBERS only
IF SNum > 0x2f AND SNum < 0x3A Then
HSerSend SNum
' add the char to the string
inputstring ( inputstringpointer ) = SNum
inputstring ( 0) = inputstringpointer
inputstringpointer++
END IF
'the delete Key
IF SNum = 0x7f then
HSerSend SNum
' remove the last char from the string
if inputstringpointer > 1 then
inputstringpointer--
inputstring ( 0) = inputstringpointer
end if
End iF
Loop
' get the value
InputVal = val ( inputstring )
End Sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Use of string array to capture the input, then, using VAL to change to a WORD variable.
Addressing the string as an array (which is fully supported).
Use of a WORD variable to capture numbers bigger then 255.
I did try to use STATUS.C... ignore that! :-)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Have written a simple program using SerReceive to capture output from my PC keyboard. It works with digits 0-9, but only captures the first digit with 10 or larger. I have dimensioned the captured variable as a byte, and have tried using two different terminal programs with the same result. I'm thinking I'm missing something simple; any help appreciated.
Post your code, or a subset of your code, to help understanding.
Thank you.
Thank you for responding to this query. Below is the code, and attached is a picture of what I see on my terminal following several responses.
There are actually 2 things I don’t understand; first why the “Type number to convert “ always shows up twice when I first run the program, and second, why SerReceive appears to only capture the first digit of my keyboard response.
~~~~~
;This program takes num <=255, "converts" it to binary
;by showing result via serial transmission.
;Chip Settings
#chip 12F683,8
#config OSC=INT
;Defines (Constants)
#define SerInPort GPIO.3
#define SerOutPort GPIO.5
#define SendAHigh Set SerOutPort on
#define SendALow Set SerOutPort off
#define RecAHigh SerInPort on
#define RecALow SerInPort off
#define cr 13
#define lf 10
;Variables
Dim num, divby, bid, rm As byte
dir GPIO out
dir SerInPort in
InitSer 1, r4800, 1+WaitForStart, 8, 1, none, invert
do
divby = 128
SerPrint 1, "Type number to convert (<= 255) "
SerSend 1, cr :SerSend 1, lf
SerReceive 1, num
SerPrint 1, "You typed " : SerSend 1, num : SerSend 1, cr :SerSend 1, lf
num = num - 48
Repeat 8
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
SerPrint 1, bid
num = rm
divby = divby/2
End Repeat
SerSend 1, cr :SerSend 1, lf
loop
NB: Edit by Anobium only to sorted the layout.... Please use indents and 5 tilders before posting code.
Last edit: Anobium 2014-01-29
This is not something I have come across. I can build your setup at the weekend.
Try this.
- Remove the REPEAT and change to a FOR/NEXT as there is a known issue with REPEAT.
- Check your circuit. Is the chip resetting to cause the two lines to be serialised?
Last edit: Anobium 2014-01-29
I'm not sure I understand your setup.
You say you are getting values from your keyboard but it looks like you are receiving data from a serial port.
When you type a value and the PC sends it out the serial port it is broken into ASCII bytes.
So 37 is broken into a byte containing 3 and a second containing 7.
Your program only is receiving one byte so it gets the first digit only and misses the second.
Add a second SerReceive to get the second byte.
Add a third for the third byte(255).
I don't know the SerReceive command well enough but according to the manual I don't see a timeout option so you may need to put the SerReceive lines in a timed loop otherwise a single byte could hang it up. Or just always send three bytes i.e. 002 or 010.
I really appreciate the efforts in helping me figure this out.
To clarify my setup, I have a serial cable connecting my PC and the 12F683, I am running Free Serial Port Terminal (although the results are the same with
other terminal programs I have tried), and I am typing decimal number to be processed on my PC keyboard. Serial input is onto pin 4, and Serial output from pin 2 of the PIC.
• I changed Repeat to a For/Next loop, but that did not change anything.
• If a chip reset is occurring to cause the first SerPrint command to execute twice, I don’t know how to check for that. I did recheck my wiring and found nothing loose or otherwise iffy. Could that problem be related to the contents of my gbasic.ini file?
• Thank you for helping me understand that even a “single digit” being received on the serial port is a byte; I changed my code to reflect that, and except for the double line at the beginning, it works now.
• There is one more wrinkle to this; after the double line is seen on the terminal, the program halts until I check and then uncheck the /MCLR box under VDD target on the PICkit2 software software. Is this a clue?
Below find my revised code:
~~~~
;This program takes num <=255, "converts" it to binary
;by showing result via serial transmission.
;Chip Settings
#chip 12F683,8
#config OSC=INT
;Defines (Constants)
#define SerInPort GPIO.3
#define SerOutPort GPIO.5
#define SendAHigh Set SerOutPort on
#define SendALow Set SerOutPort off
#define RecAHigh SerInPort on
#define RecALow SerInPort off
#define cr 13
#define lf 10
;Variables
Dim numhunds, numtens, numones, count, divby, bid, rm As byte
dir GPIO out
dir SerInPort in
InitSer 1, r4800, 1+WaitForStart, 8, 1, none, invert
do
divby = 128
SerPrint 1, "Type 3 digit number"
SerPrint 1, " to convert (<= 255) "
SerSend 1, cr : SerSend 1, lf
SerReceive 1, numhunds : SerReceive 1, numtens : SerReceive 1, numones
SerPrint 1, "You typed "
SerSend 1, numhunds : SerSend 1, numtens : SerSend 1, numones
SerSend 1, cr : SerSend 1, lf
numhunds = numhunds - 48
numtens = numtens - 48
numones = numones - 48
num = (numhunds * 100) + (numtens * 10) + numones
SerPrint 1, num
SerSend 1, cr : SerSend 1, lf
For count = 0 to 7
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
SerPrint 1, bid
num = rm
divby = divby/2
Next
SerSend 1, cr :SerSend 1, lf
loop
Anobium, please please use five tilders before posting your code. Edited to revise formatting only.
Last edit: Anobium 2014-02-01
I just discovered that if I use a different pin (not the MCLR pin) for SerInPort, no double line, but still have to check and uncheck /MCLR for the program to run.
Are you sending 3 digit numbers?
If not, the program will sit and wait for the third byte that will never come.
Clicking Mclr on and off just resets the pic and it starts working again.
Try this. I changed the method but it works for me. You will to revert the chip, serial etc. etc.
I essentially create and manage a string, when 3 numbers or the return key is pressed the numeric value is returned.
You can add handlers to key the number below 256 by changing the sub to a WORD and then handle in your main code. You have lots of options. :-)
Post your working code when you have got it all working, please.
~~~~
;This program takes num <=255, "converts" it to binary
;by showing result via serial transmission.
;Chip Settings
#chip 16F1937,32
#config Osc = intOSC, MCLRE_OFF, PLLEN_ON, VCAPEN_OFF
;Defines (Constants)
' [todo] This is the config for a serial terminal
' turn on the RS232 and terminal port.
' Define the USART port
#define USART_BAUD_RATE 9600
#define USART_BLOCKING
' [todo] Ensure these port addresses are correct
#define SerInPort PORTc.7
#define SerOutPort PORTc.6
'Set pin directions
Dir SerOutPort Out
Dir SerInPort In
#define cr 13
#define lf 10
;Variables
Dim numhunds, numtens, numones, count, divby, bid, rm As byte
' InitSer 1, r4800, 1+WaitForStart, 8, 1, none, invert
do
divby = 128
HserPrint "Type 3 digit number"
HserPrint " to convert (<= 255) "
HSerSend cr : hSerSend lf
GetNum ( num )
HSerSend cr : hSerSend lf
For count = 0 to 7
If divby > num Then
bid = 0
rm = num
Else
bid = 1
rm = num % divby
End If
HserPrint bid
num = rm
divby = divby/2
Next
HSerSend cr :hSerSend lf
loop
' get the serial character, create a string of up to 3 chars, then take the value of that string and return a numeric value.
Sub GetNum ( Out InputVal ) as byte
dim inputstring as string * 3
Dim inputstringpointer as byte
inputstringpointer = 1
End Sub
A revised version. This version works. :-)
~~~~
;This program takes num <=255, "converts" it to binary
;by showing result via serial transmission.
;Chip Settings
#chip 16F1937,32
#config Osc = intOSC, MCLRE_OFF, PLLEN_ON, VCAPEN_OFF
;Defines (Constants)
#define CLEARCARRY set STATUS.C OFF
#define CARRYOVERFLOW STATUS.C
#define cr 13
#define lf 10
;Variables
Dim numhunds, numtens, numones, count, divby, bid, rm As byte
dim num as word
' InitSer 1, r4800, 1+WaitForStart, 8, 1, none, invert
do
HserPrint "Type 3 digit number"
HserPrint " to convert (<= 255) "
HSerSend cr : hSerSend lf
num = 0
GetNum ( num )
HSerSend cr : hSerSend lf
loop
' get the serial character, create a string of up to 3 chars, then take the value of that string and return a numeric value.
Sub GetNum ( Out InputVal as word )
dim inputstring as string * 3
Dim inputstringpointer as byte
inputstringpointer = 1
' init SNum of you will create an endless on the second call this this sub.
SNum = 255
End Sub
Thanks so much for your interest in this; I'm sure I'll learn much from studying your code.
Pleasure.
A few interesting pieces in this code.
Use of string array to capture the input, then, using VAL to change to a WORD variable.
Addressing the string as an array (which is fully supported).
Use of a WORD variable to capture numbers bigger then 255.
I did try to use STATUS.C... ignore that! :-)