Menu

MIDI

Help
2008-09-05
2013-05-30
  • Dave Burniston

    Dave Burniston - 2008-09-05

    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

     
    • Ricardo Lameiro

      Ricardo Lameiro - 2008-09-09

      I would like to know it also. would  like to know the routines for 31.25kbaud serial comunication

       
      • Nobody/Anonymous

        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

         
    • kent_twt4

      kent_twt4 - 2008-09-09

      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.

       
    • Nobody/Anonymous

      What is in your program in line 30?

       
    • Nobody/Anonymous

      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

       
    • Nobody/Anonymous

      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.

       
    • Nobody/Anonymous

      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

       
    • Dave Burniston

      Dave Burniston - 2009-07-10

      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.

       
    • Dave Burniston

      Dave Burniston - 2009-07-11

      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.

       
    • Dave Burniston

      Dave Burniston - 2009-07-11

      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.

       
    • Dave Burniston

      Dave Burniston - 2009-07-16

      I've been able to get it to work using Case statements and have it working for decoding 8 keys for now.

       

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.