Serial/RS232 Buffer Ring

Explanation:

This program demonstrates how to create a serial input buffer ring.

The program receives a character into the buffer and sends it back. Try sending large volumes of characters.

This program uses an interrupt event to capture the incoming byte value and place it in the buffer ring. When a byte is received, the buffer ring is incremented to ensure the next byte is handled correctly.

Testing bkbhit will be True when a byte has been received. Reading the function bgetc will return the last byte received.

Demonstration program:

This demonstration program will support up to 256 bytes. For a larger buffer, change the variables to words.

    #chip 16F1937
    // #chip mega4809
    // #chip mega328p, 16


    // Add PPS if appropriate for your chip
    // [change to your config] This is the config for a serial terminal

    // assumes USART1 ( or USART0 on AVRDx ), if you select USART1/2/3/4 then you MUST add the comport parameter to all HSerxxxxx functions.
    // turn on the RS232 and terminal port.
    // Define the USART settings
    #DEFINE USART_BAUD_RATE 9600
    #DEFINE USART_BLOCKING  // Required, could use #define USART_TX_BLOCKING as the RX is interrupt driven.

    // This assumes you are using an ANSI compatible terminal.  Use PUTTY.EXE, it is very easy to use.

    //   Main program

    // Wait for terminal to settle
    wait 3 s

    // Create the supporting variables
    Dim next_in As Byte
    Dim next_out As Byte
    Dim syncbyte As Byte
    Dim temppnt As Byte

    // Constants etc required for Buffer Ring
    #DEFINE BUFFER_SIZE 8
    #DEFINE bkbhit (next_in <> next_out)

    // Define the Buffer
    Dim buffer( BUFFER_SIZE - 1 ) // we will use element 0 in the array as part of our buffer

    // Call init the buffer
    InitBufferRing

    HSerSend 10
    HSerSend 13
    HSerSend 10
    HSerSend 13
    HSerPrint "Started: Serial between two devices"
    HSerSend 10
    HSerSend 13


    // Get character(s) and send back
    Do

        //  Do we have data in the buffer?
        if bkbhit then

            // Send the next character in the buffer to the terminal, exposed via the function `bgetc`          ' <<< draining the buffer ring one character at a time
            HSerSend bgetc

        end if
    Loop


    // Supporting subroutines

    Sub readUSART

        buffer(next_in) = HSerReceive
        temppnt = next_in
        next_in = ( next_in + 1 ) % BUFFER_SIZE
        If ( next_in = next_out ) Then  // buffer is full!!
            next_in = temppnt
        End If

    End Sub

    Function bgetc
        Dim local_next_out as Byte    // maintain a local copy of the next_out variable to ensure it does not change when an Interrupt happens
        local_next_out = next_out
        bgetc = buffer(local_next_out)
        local_next_out=(local_next_out+1) % BUFFER_SIZE
        INTOFF
        next_out = local_next_out
        INTON
    End Function




    Sub InitBufferRing

        // Set the buffer to the first address
        next_in = 0
        next_out = 0
        // Interrupt Handler - some have RCIE and some have U1RXIE, so handle
        //
        // You would need to change the Interrupt if you use USART1,2,3, or 4
        //
        #IFDEF BIT( RCIE )
            On Interrupt UsartRX1Ready Call readUSART
        #ENDIF
        #IFDEF BIT( U1RXIE )
            On Interrupt UART1ReceiveInterrupt Call readUSART
        #ENDIF

        #IFDEF AVR
            #IFNDEF CHIPAVRDX
                //~ Support for legacy AVR
                On Interrupt UsartRX1Ready Call readUSART
            #ELSE
                //~ Support for AVRDx - AVRDx chips are USART0,USART1,USART2,USART3 and USART4 not USART.
                On Interrupt Usart0RXReady Call readUSART
            #ENDIF
        #ENDIF

    End Sub

Key line: HSerSend bgetc — calls the function bgetc, which pulls the oldest byte out of the ring buffer and advances the read pointer, then immediately transmits that byte back to the terminal; this only runs when bkbhit reports the buffer is non-empty.

See Also:

  • HSerReceive — receiving a byte directly, called from the interrupt handler above
  • HSerSend — sending a byte, used above to echo the buffered character