Reading Usart to a Buffer

Discuss the Firewing language

Reading Usart to a Buffer

Postby bitfogav » Sun Aug 18, 2013 2:44 pm

Hi, I'm trying to read from Usart2 RX and store the data to a Buffer (as a long string) and then send the buffer out using Usart1, but I want to keep the buffer (string) do to some working with it at a later point. but for some reason i'm only seeing 1 byte out to Usart1.

I'm using the following code, I'm probably missing somthing simple or trying to do something thats not possible? :roll:

Serial comms:
Usart2 data = +CMT: "+xxxxxxxxxxxxx","xxxxxxxxxxxxx","15/08/13","15:38:02"+4",17\r\nTextMessage\r\n

Usart1 output = +


Code: Select all
      dim b as string(256)
      dim nxtStr as ushort = 0
      while Uart2.DataAvailable = true
         b(nxtStr) = Uart2.Readbyte()
         nxtStr += 1
      end while
     
      for i as ushort = 0 to nxtStr         
         Uart.Write(b(i),13,10)           
      next
User avatar
bitfogav
 
Posts: 75
Joined: Sat Nov 17, 2012 11:46 am
Location: UK

Re: Reading Usart to a Buffer

Postby David John Barker » Sun Aug 18, 2013 4:00 pm

The problem is in the way you have structured your program. You are assuming that:

Code: Select all
     while Uart2.DataAvailable = true
         b(nxtStr) = Uart2.Readbyte()
         nxtStr += 1
      end while

will read the whole string in. However, the loop is so fast that "DataAvailable" will return false (as the next character has not been received) - so it falls through to the uart output loop. In the meantime, more data is being received via uart2 but nothing is processing it, so you get a buffer overrun and uart2 will stop processing any further data until the overrun flag is cleared. You need to look for a line terminator before exiting the loop. For example:
Code: Select all
      dim b as string(256)
      dim nxtStr as ushort = 0
      dim data as byte = 0
      do
         data = Uart2.Readbyte()
         b(nxtStr) = data
         nxtStr += 1 
      loop until data = 13

I've checked this code and your routine now works as expected.

Personally, when reading data in from a uart (either 1 or 2), I prefer to use an interrupt that buffers data when it arrives. This way, you never miss a thing and your program can do other stuff without worrying about servicing the uart. There is an example included in the Firewing installation that does just this for uart1. It would be a very trivial task you make another module based around this code so it supported uart2 (the GPS module will also help in determining what flags to set as this module buffers data from uart2)
User avatar
David John Barker
 
Posts: 491
Joined: Thu Nov 08, 2012 12:21 pm

Re: Reading Usart to a Buffer

Postby bitfogav » Sun Aug 18, 2013 6:31 pm

Thank you so much David, that did fix the problem. And thank you for the tips on the GPS module, I will have a look at them :)
User avatar
bitfogav
 
Posts: 75
Joined: Sat Nov 17, 2012 11:46 am
Location: UK

Re: Reading Usart to a Buffer

Postby bitfogav » Tue Aug 20, 2013 6:27 pm

I've converted the Uart1 sample code and Interrupt buffer module for use with Uart2. If anyone interested in it then here it is..

Uart2Buffer.zip
Download the files here:
(2.23 KiB) Downloaded 1029 times


Sample Code
Code: Select all
imports RX2Bufffer
imports Uart2

' this event handler is triggered when data is received - it gives
' the program the opportunity to accept or reject the incoming byte
' or modify the data in some way - this example changes all space
' characters to underscore...
Sub OnData(ByRef Data As Byte, ByRef Accept As Boolean) Handles RX2.OnData
   Dim DataIn As Byte = Data
   If DataIn = cbyte(" ") Then
      Data = "_"
   End If
End Sub

' this event is fired if the RX buffer overruns...
Sub OnOverrun () Handles RX2.OnOverrun
   High(PORTB.15)
End Sub

Sub Main()
   UART2.SetBaudrate(UART2.Baudrate.Is38400) ' set baudrate
   RX2.Start()                               ' start buffering data
   PPS.EnableTx2()                           ' enable uart2 tx
   PPS.EnableRx2()                           ' enable uart2 rx
   While True
      If RX2.DataAvailable() Then      ' if data is available
         Console.Write(RX2.ReadByte()) ' then echo back
      End If
   End While
End Sub


Buffer Module
Code: Select all
Module RX2

imports Uart2

' size of the RX buffer using options - if no option is specified in the
' main program then the buffer size defaults to 64...
#if IsOption(RX_BUFFER_SIZE) And Not (RX_BUFFER_SIZE in (1 to 255))
   #error RX_BUFFER_SIZE, "Invalid option. Buffer size must be between 1 and 255 (bytes)."
#endif
#option RX_BUFFER_SIZE = 64     
private Const _bufferSize As Byte = RX_BUFFER_SIZE    ' bring the option into the program
private Const _allSystemVars As Byte = 0

' local variables...
Private _dataBuffer(_bufferSize) As Byte     ' the RX buffer
Private _indexIn As Byte                     ' data in pointer
Private _indexOut As Byte                    ' data out pointer

' event prototypes - see OnRX() for more information...
Public Event OnData(ByRef data As Byte, ByRef accept As Boolean)
Public Event OnOverrun()

'****************************************************************************
'* Name    : OnRX (Private)                                                 *
'* Purpose : Interrupt Service Routine (ISR) to buffer incoming data        *
'****************************************************************************
private Interrupt OnRX(Pic.U2RXInterrupt)   '<- change to Uart2
   
   ' read a data byte from the USART2...
   Dim byteRead As Byte = Uart2.RCREG
     
   ' this code is only linked in at compile time if an event handler has
   ' been assigned to OnData from within the main program...
   If OnData <> Nothing Then
      Dim accept As Boolean = True             ' by default, we accept the data
      RaiseEvent OnData(byteRead, accept)      ' call the event handler
      If accept Then                           ' if the accept flag is still true, buffer the data
         _dataBuffer(_indexIn) = byteRead           
         _indexIn += 1
         If _indexIn > UBound(_dataBuffer) Then _indexIn = 0
      End If     
     
   ' this code is only linked in at compile time if no event
   ' handler has been assigned to OnData from within the main program
   Else
      _dataBuffer(_indexIn) = byteRead
      _indexIn += 1
      If _indexIn > UBound(_dataBuffer) Then _indexIn = 0
   End If
     
   ' this code is only linked in at compile time if an event handler has
   ' been assigned to OnOverrun from within the main program
   If OnOverrun <> Nothing Then
      If _indexIn = _indexOut Then RaiseEvent OnOverrun()
   End If     

   ' clear interrupt flag   
   IFS1.14 = 0
End Interrupt

'****************************************************************************
'* Name    : Start                                                          *
'* Purpose : Start interrupt handling                                       *
'****************************************************************************
Public Sub Start()
   Enable(OnRX)
End Sub

'****************************************************************************
'* Name    : Stop                                                           *
'* Purpose : Stop interrupt handling                                        *
'****************************************************************************
Public Sub Halt()
   Disable(OnRX)
End Sub

'****************************************************************************
'* Name    : DataAvailable                                                  *
'* Purpose : Check to see if there is data in the buffer                    *
'****************************************************************************
Public Function DataAvailable() As Boolean
   Disable(OnRX)
   DataAvailable = _indexIn <> _indexOut
   Enable(OnRX)
End Function

'****************************************************************************
'* Name    : GetByte                                                        *
'* Purpose : Get a single byte from the buffer                              *
'****************************************************************************
private Function GetByte() As Byte
   GetByte = _dataBuffer(_indexOut)
   _indexOut += 1
   If _indexOut > UBound(_dataBuffer) Then
      _indexOut = 0
   End If   
End Function

'****************************************************************************
'* Name    : ReadByte                                                       *
'* Purpose : Read a single byte from the buffer                             *
'****************************************************************************
Public Function ReadByte() As Byte
   Disable(OnRX)
   ReadByte = GetByte()
   Enable(OnRX)
End Function

'****************************************************************************
'* Name    : ReadString                                                     *
'* Purpose : Read a String from the buffer. The function returns the number *
'*         : of characters read                                             *
'****************************************************************************
Public Function ReadString(ByRef text As String) As Byte
   Dim data As Char
   
   Disable(OnRX)
   a0 = AddressOf(text)
   ReadString = 0

   Do
      data = GetByte()
      If data <> CChar(0) Then
         ReadString += 1
         *(a0+) = data
      End If
   Loop Until data = CChar(0)
   *(a0) = 0
   Enable(OnRX)
End Function

'****************************************************************************
'* Name    : Reset                                                          *
'* Purpose : Reset the module. A call to Halt() should be made before       *
'*         : making a call to this routine                                  *
'****************************************************************************
Public Sub Reset() 
   ' data in and out pointers...
   _indexIn = 0 
   _indexOut = 0     
   
   IFS1.14 = 0               ' clear interrupt flag   
End Sub   

'****************************************************************************
'* Name    : Main                                                           *
'* Purpose : Initialize buffering                                           *
'****************************************************************************
private Inline Sub Main()
   Reset()
End Sub

End Module
User avatar
bitfogav
 
Posts: 75
Joined: Sat Nov 17, 2012 11:46 am
Location: UK

Re: Reading Usart to a Buffer

Postby skartalov » Tue Jan 06, 2015 12:58 pm

This is really very useful.
However if I declare another device to use, not FW, I get error while compiling saying:

------------------
a0 = AddressOf(text)
------------------
Identifier not declared A0



How to get over this?

I am using 24HJ128GP504

Thanks!
skartalov
 
Posts: 69
Joined: Sun Sep 15, 2013 1:12 pm

Re: Reading Usart to a Buffer

Postby David John Barker » Tue Jan 06, 2015 1:23 pm

The syntax was changed some time ago, there is a summary in this thread showing the correct way to use indirect addressing:

http://www.firewing.info/forum/viewtopic.php?f=7&t=39&p=190

so it should read...

Code: Select all
addr0 = AddressOf(text)
User avatar
David John Barker
 
Posts: 491
Joined: Thu Nov 08, 2012 12:21 pm


Return to Language

Who is online

Users browsing this forum: No registered users and 4 guests

x