I'm just getting back to this project. I've tried to use the hardware usart routines from Steve as they are before I made any changes for midi, but I can't get them to compile.
I replaced the existing usart.h with that portion of his post and fixed the setup serial portion. I copy the program part into GCBIDE and compile and get the following error message:
midi-serial.gcb (30): Error: Syntax Error
Any ideas?
Thanks,
...Dave
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The hardware USART library in the contributors section will handle the 31.25kbaud rate. You will need to set the values in the setup sub, like the Rx, Tx pins, and the SPBRG, BRGH bits. Checking the UART/USART section of the device data sheet, table values are given for the SPBRG and BRGH bits. Use those bits which will give the least amount of error for your speed and osc.
The header file will need to be copied/pasted into a blank "xxxx.h" file in the include folder.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
'Filename: test_usart.txt
'A program to test serial communications
'Chip model
#chip 16F690, 8
#config INTRC_OSC_NOCLKOUT, WDT_OFF
#include "usart.h"
'Hardware USART constants
'Main routine
ADOFF
dir PORTC.7 out
SetupSerial '9600 baud, 8/N/1 no flow control
Main:
SET PORTC.7 ON
TransmitSerial_Print("Please type in a character ")
Transmitserial(13)
Transmitserial(10)
Loopx:
Character = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx
TransmitSerial_Print("Message received, you entered a: ")
TransmitSerial(Character)
Transmitserial(13)
Transmitserial(10)
Set flags.gotnewdata OFF
SET PORTC.7 OFF
wait 25 ms
goto Main
Line 30 is the "wait 25 ms"
Here;s the usart.h:
' Filename: usart.h
' Hardware USART routines for Great Cow BASIC
' Steve Bell
' February 3, 2007
'Subs
' sub SetupSerial Setup serial port with baudrate 9600 for 8Mhz clock
' sub ReceiveSerial(data) Receive data from serial port into byte data
' sub TransmitSerial(data) Transmit data to serial port
' sub TransmitSerial_Print(PrintData$) Transmit a string to the serial port
'Hardware USART constants
#define GOTNEWDATA 0 'bit that indicates new data received
sub SetupSerial
ADOff 'make port digital
DIR PORTB.7 OUT
DIR PORTB.5 IN
SPBRG = 12 ' this value is for 9600 baud with brgh bit = 0 P16F690
TXSTA = b'00100000' '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
' CalcParity(TXDATA) 'calculate parity
' rotate ParityByte RIGHT 'get parity bit into status.c
' SET TXSTA.TX9D OFF 'set parity bit to zero
' IF STATUS.C = 1 THEN SET TXSTA.TX9D ON 'if status.c is one, set parity bit
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 CalcParity(Temp) 'calculate even parity bit, data starts in paritybyte
'result is in Lsb of ParityByte
Paritybyte = Temp 'get data for parity calculation
rrf Paritybyte,W 'rotate
xorwf Paritybyte,W 'compare all bits against neighbor
movwf Paritybyte 'save
rrf ParityByte,F 'rotate
rrf ParityByte,F 'rotate
xorwf ParityByte,F 'compare every 2nd bit and save
swapf ParityByte,W 'rotate 4
xorwf ParityByte,F 'compare every 4th bit and save
end sub
function ReceiveSerial 'check if data received, and if so, return data
IF PIR1.RCIF OFF THEN GOTO endreceiveserial
IF RCSTA.OERR ON THEN ErrSerialOverr 'if overrun error occured, handle error
IF RCSTA.FERR ON THEN ErrSerialFrame 'if framing error occurred, handle error
' for non-parity just use this below
ReceiveSerial = RCREG
SET FLAGS.GOTNEWDATA ON
GOTO successreceiveserial
' for parity checking use this
' ParityBit = RCSTA.0 get received parity bit and save
' RxData = RCREG get received data
' CalcParity(RxData)
' rotate ParityByte RIGHT get parity bit into status.c
' IF STATUS.C = ParityBit THEN
' SET FLAGS.GOTNEWDATA ON indicate got new data
' ReceiveSerial = RxData
' GOTO successreceiveserial
' END IF
' ErrSerlParity then parity is different, error
endreceiveserial:
ReceiveSerial = 0
successreceiveserial:
end function
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If I change the include statement as you indicate, I now get these errors:
midi-serial.gcb (14): Error: Syntax Error
midi-serial.gcb (18): Error: Array/Function TRANSMITSERIAL_PRINT has not been declared
midi-serial.gcb (18): Error: Syntax Error
midi-serial.gcb (19): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (19): Error: Syntax Error
midi-serial.gcb (20): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (20): Error: Syntax Error
midi-serial.gcb (24): Error: Array/Function TRANSMITSERIAL_PRINT has not been declared
midi-serial.gcb (24): Error: Syntax Error
midi-serial.gcb (25): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (25): Error: Syntax Error
midi-serial.gcb (26): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (26): Error: Syntax Error
midi-serial.gcb (27): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (27): Error: Syntax Error
I've installed GCBasic on 2 PC's this week and I get the same result on both, so perhaps I've missed something. I used the installer then copied the files from the update.zip into the GCBasic folder.
...Dave
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have that problem sorted out. I had my suart.h file in the include/lowlevel folder where the original was. Moving it to the include folder solved the compile problem.
Now I'll modify it to work for 31250 baud.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I made the following changes to usart.h to work with a 20MHz 16F877A:
sub SetupSerial
ADOff 'make port digital
DIR PORTC.7 IN
DIR PORTC.6 OUT
SPBRG = 9 ' this value is for 31250 baud with brgh bit = 0 P16F877A 20MHz
TXSTA = b'00100000' 'note, bit 2 is BRGH
RCSTA = b'10010000' 'enable serial port and reception
SET FLAGS.GOTNEWDATA OFF
end sub
Using the following code, I'm able to display data coming from a midi controller keyboard:
'Filename: test_usart.txt
'A program to MIDI communications
'Chip model
#chip 16F877A, 20
#config OSC =HS
#config WDT = OFF
Loopx:
Character = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx
If Character <> 254 then
LCDHex(Character)
Print ","
end if
clearflag:
Set flags.gotnewdata OFF
goto Main
It seems to regularly send a byte value of 254, which I'm ignoring.
Now I'm working on checking for Note On/ Note Off commands and getting the next two data bytes to process and toggle a port bit to control an LED based on the note pressed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Loopx:
Character = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx
locate 0,0
Print(Character)
If Character > 143 and Character < 160 then 'if Keyon, get rest of data
locate 1,0
Print(" ")
locate 1,0
Print(Character)
Print ","
Set flags.gotnewdata OFF
Loopx1:
Character2 = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx1
Print(Character2)
Print ","
Set flags.gotnewdata OFF
Loopx2:
Character3 = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx2
Print(Character3)
end if
clearflag:
Set flags.gotnewdata OFF
goto Main
Now I need to turn a port bit on or off depending on the values. As soon as I add another if statement before the Endi If, I get compile errors for lines that compile fine before I add another if statement.
Is there a limit to the number of if statements? It also only wants a single End If no matter how many If's there are.
Any input on how to streamline the reception of the 3 data bytes and then be able to test and toggle data port bits would be appreciated.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Can anyone help me with routines to send/receive 31.25kbaud midi serial data with a 20MHz 16F877A? I have a project to make for my son.
Thanks,
...Dave
I would like to know it also. would like to know the routines for 31.25kbaud serial comunication
I'm just getting back to this project. I've tried to use the hardware usart routines from Steve as they are before I made any changes for midi, but I can't get them to compile.
I replaced the existing usart.h with that portion of his post and fixed the setup serial portion. I copy the program part into GCBIDE and compile and get the following error message:
midi-serial.gcb (30): Error: Syntax Error
Any ideas?
Thanks,
...Dave
The hardware USART library in the contributors section will handle the 31.25kbaud rate. You will need to set the values in the setup sub, like the Rx, Tx pins, and the SPBRG, BRGH bits. Checking the UART/USART section of the device data sheet, table values are given for the SPBRG and BRGH bits. Use those bits which will give the least amount of error for your speed and osc.
The header file will need to be copied/pasted into a blank "xxxx.h" file in the include folder.
What is in your program in line 30?
It's right out of the posting for the usart:
'Filename: test_usart.txt
'A program to test serial communications
'Chip model
#chip 16F690, 8
#config INTRC_OSC_NOCLKOUT, WDT_OFF
#include "usart.h"
'Hardware USART constants
'Main routine
ADOFF
dir PORTC.7 out
SetupSerial '9600 baud, 8/N/1 no flow control
Main:
SET PORTC.7 ON
TransmitSerial_Print("Please type in a character ")
Transmitserial(13)
Transmitserial(10)
Loopx:
Character = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx
TransmitSerial_Print("Message received, you entered a: ")
TransmitSerial(Character)
Transmitserial(13)
Transmitserial(10)
Set flags.gotnewdata OFF
SET PORTC.7 OFF
wait 25 ms
goto Main
Line 30 is the "wait 25 ms"
Here;s the usart.h:
' Filename: usart.h
' Hardware USART routines for Great Cow BASIC
' Steve Bell
' February 3, 2007
'Subs
' sub SetupSerial Setup serial port with baudrate 9600 for 8Mhz clock
' sub ReceiveSerial(data) Receive data from serial port into byte data
' sub TransmitSerial(data) Transmit data to serial port
' sub TransmitSerial_Print(PrintData$) Transmit a string to the serial port
'Hardware USART constants
#define GOTNEWDATA 0 'bit that indicates new data received
sub SetupSerial
ADOff 'make port digital
DIR PORTB.7 OUT
DIR PORTB.5 IN
SPBRG = 12 ' this value is for 9600 baud with brgh bit = 0 P16F690
TXSTA = b'00100000' '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
' CalcParity(TXDATA) 'calculate parity
' rotate ParityByte RIGHT 'get parity bit into status.c
' SET TXSTA.TX9D OFF 'set parity bit to zero
' IF STATUS.C = 1 THEN SET TXSTA.TX9D ON 'if status.c is one, set parity bit
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 CalcParity(Temp) 'calculate even parity bit, data starts in paritybyte
'result is in Lsb of ParityByte
Paritybyte = Temp 'get data for parity calculation
rrf Paritybyte,W 'rotate
xorwf Paritybyte,W 'compare all bits against neighbor
movwf Paritybyte 'save
rrf ParityByte,F 'rotate
rrf ParityByte,F 'rotate
xorwf ParityByte,F 'compare every 2nd bit and save
swapf ParityByte,W 'rotate 4
xorwf ParityByte,F 'compare every 4th bit and save
end sub
function ReceiveSerial 'check if data received, and if so, return data
IF PIR1.RCIF OFF THEN GOTO endreceiveserial
IF RCSTA.OERR ON THEN ErrSerialOverr 'if overrun error occured, handle error
IF RCSTA.FERR ON THEN ErrSerialFrame 'if framing error occurred, handle error
' for non-parity just use this below
ReceiveSerial = RCREG
SET FLAGS.GOTNEWDATA ON
GOTO successreceiveserial
' for parity checking use this
' ParityBit = RCSTA.0 get received parity bit and save
' RxData = RCREG get received data
' CalcParity(RxData)
' rotate ParityByte RIGHT get parity bit into status.c
' IF STATUS.C = ParityBit THEN
' SET FLAGS.GOTNEWDATA ON indicate got new data
' ReceiveSerial = RxData
' GOTO successreceiveserial
' END IF
' ErrSerlParity then parity is different, error
endreceiveserial:
ReceiveSerial = 0
successreceiveserial:
end function
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
I have no erros compiling your code, just copy usart.h to GCBASIC/include folder and used the #include this way:
#include <usart.h>
I don't know if the library or the code works, but it compiles Ok for me. Hope it's just the #include issue.
If I change the include statement as you indicate, I now get these errors:
midi-serial.gcb (14): Error: Syntax Error
midi-serial.gcb (18): Error: Array/Function TRANSMITSERIAL_PRINT has not been declared
midi-serial.gcb (18): Error: Syntax Error
midi-serial.gcb (19): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (19): Error: Syntax Error
midi-serial.gcb (20): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (20): Error: Syntax Error
midi-serial.gcb (24): Error: Array/Function TRANSMITSERIAL_PRINT has not been declared
midi-serial.gcb (24): Error: Syntax Error
midi-serial.gcb (25): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (25): Error: Syntax Error
midi-serial.gcb (26): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (26): Error: Syntax Error
midi-serial.gcb (27): Error: Array/Function TRANSMITSERIAL has not been declared
midi-serial.gcb (27): Error: Syntax Error
I've installed GCBasic on 2 PC's this week and I get the same result on both, so perhaps I've missed something. I used the installer then copied the files from the update.zip into the GCBasic folder.
...Dave
I have that problem sorted out. I had my suart.h file in the include/lowlevel folder where the original was. Moving it to the include folder solved the compile problem.
Now I'll modify it to work for 31250 baud.
I made the following changes to usart.h to work with a 20MHz 16F877A:
sub SetupSerial
ADOff 'make port digital
DIR PORTC.7 IN
DIR PORTC.6 OUT
SPBRG = 9 ' this value is for 31250 baud with brgh bit = 0 P16F877A 20MHz
TXSTA = b'00100000' 'note, bit 2 is BRGH
RCSTA = b'10010000' 'enable serial port and reception
SET FLAGS.GOTNEWDATA OFF
end sub
Using the following code, I'm able to display data coming from a midi controller keyboard:
'Filename: test_usart.txt
'A program to MIDI communications
'Chip model
#chip 16F877A, 20
#config OSC =HS
#config WDT = OFF
#include <usart.h>
'Hardware USART constants
'Main routine
SetupSerial '31250 baud, 8/N/1 no flow control
'LCD connection settings
#define LCD_IO 4
#define LCD_DB4 PORTB.4
#define LCD_DB5 PORTB.5
#define LCD_DB6 PORTB.6
#define LCD_DB7 PORTB.7
#define LCD_RS PORTB.0
#define LCD_RW PORTB.1
#define LCD_Enable PORTB.2
'Show opening message
CLS
PRINT "MIDI Light"
locate 1,0
PRINT "Controller"
Wait 5 s
CLS
Main:
Loopx:
Character = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx
If Character <> 254 then
LCDHex(Character)
Print ","
end if
clearflag:
Set flags.gotnewdata OFF
goto Main
It seems to regularly send a byte value of 254, which I'm ignoring.
Now I'm working on checking for Note On/ Note Off commands and getting the next two data bytes to process and toggle a port bit to control an LED based on the note pressed.
I'm making progress.....
I can capture the Note On commands and display it and the next 2 data bytes that go with it:
'Filename: test_usart.txt
'A program to MIDI communications
'Chip model
#chip 16F877A, 20
#config OSC = HS, WDT = OFF, LVP = OFF, CP = OFF
#config BODEN = OFF
#include <usart.h>
'Hardware USART constants
'Set up Key map
#define C1 PORTD.1
DIR C1 Out
Set C1 Off
'Main routine
SetupSerial '31250 baud, 8/N/1 no flow control
'LCD connection settings
#define LCD_IO 4
#define LCD_DB4 PORTB.4
#define LCD_DB5 PORTB.5
#define LCD_DB6 PORTB.6
#define LCD_DB7 PORTB.7
#define LCD_RS PORTB.0
#define LCD_RW PORTB.1
#define LCD_Enable PORTB.2
'Show opening message
CLS
PRINT "MIDI Light"
locate 1,0
PRINT "Controller"
Wait 5 s
CLS
CLS
Main:
Loopx:
Character = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx
locate 0,0
Print(Character)
If Character > 143 and Character < 160 then 'if Keyon, get rest of data
locate 1,0
Print(" ")
locate 1,0
Print(Character)
Print ","
Set flags.gotnewdata OFF
Loopx1:
Character2 = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx1
Print(Character2)
Print ","
Set flags.gotnewdata OFF
Loopx2:
Character3 = ReceiveSerial
If flags.gotnewdata OFF then GOTO Loopx2
Print(Character3)
end if
clearflag:
Set flags.gotnewdata OFF
goto Main
Now I need to turn a port bit on or off depending on the values. As soon as I add another if statement before the Endi If, I get compile errors for lines that compile fine before I add another if statement.
Is there a limit to the number of if statements? It also only wants a single End If no matter how many If's there are.
Any input on how to streamline the reception of the 3 data bytes and then be able to test and toggle data port bits would be appreciated.
I've been able to get it to work using Case statements and have it working for decoding 8 keys for now.