Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

RS232 Simple linear Buffer (OshonSoft Basic).

DogFlu66

Member
Hello; on this occasion I leave a simple linear buffer.
Specially applied for the RS232 port.
To avoid losing data, what is done is to add another software buffer to the hardware buffer of the pic (2 bytes). The length of the latter will depend on the user's needs and the amount of memory available. This is for those who are interested in learning how a simple buffer works and how it is complemented by the asynchronous pic module, in this case the usat module.
The input data blocking check has been implemented, since apparently those who start working with this type of port are not clear that if the pic buffer is overloaded it is blocked and stops working, and to activate it again you have to reset the control bits of the internal buffer of the pic.
If anyone sees that improvements can be made or another better algorithm can be presented, they can share it.

I leave the main program and the functions necessary for it to work as attachments.

Main program:

'Example of buffer for RS232 port
'Pic12F1840, 08/12/2023
Define CONFIG1 = 0x0f84
Define CONFIG2 = 0x1dff
Include "_FuncionesPic12F1840.bas"
Include "_Funciones_Buffer_RS232.Bas"
Define CLOCK_FREQUENCY = 32 '32Mhz system oscillator
'constants (ASCII control codes).
Const FF = 0x0c 'FF, page advance
Const Bell = 0x07 'Bell, sound signal
Const Sp = 0x20 'Sp, space
Const Bksp = 0x08 'Bksp, go back
'Const Cr = 0x0d 'Cr, car return
'Const Lf = 0x0a 'Lf, line break
Const Ctrlz = 0x1a 'Ctrl - Z
Const Esc = 0x1b 'Escape
main:
'Call _setup_oscillator_mode(_oscillator_by_fosc) 'Select by configuration word.
Call _setup_oscillator(_osc_32mhz_hf) 'Interno 8Mhz x 4(PLL) = 32Mhz
AllDigital
TRISA = 0xff

UART_Init 9600 'Initialize port pin (default: A0 = Tx, RA1 = Rx)
Call _uart_pin_tx_ra4(True) 'Pin Tx = RA4
Call _uart_pin_rx_ra5(True) 'Pin Rx = RA5
WaitMs 10

Call _setup_buffer_rs232() 'Initialize buffer by software
Call _enable_interrupts(_int_rda) 'Enables uart interrupts
Call _enable_interrupts(_global) 'Enables peripheral and global interrupts.

Dim data As Byte

UART_Write "Ready", CrLf

While True

If _buffer() = True Then 'If there is data in the buffer.
'data = _read_buffer_rs232()'Reads byte fron buffer and assigns it to a variable.
'UART1_Write data'Write the byte to the serial port.
UART_Write _read_buffer_rs232() 'Reads byte fron buffer and write to the serial port.
Endif
Wend
End
On Interrupt
Save System
If _uartif = True Then 'If there is data in the uart hardware buffer.
Call _get_rs232() 'Moves a byte from the hardware buffer to the software buffer.
Endif
Resume
 

Attachments

  • _FuncionesPic12F1840.bas
    31.6 KB · Views: 112
  • _Funciones_Buffer_RS232.Bas
    3.5 KB · Views: 90
Last edited:
just some of the more obvious ones...

In the file _Funciones_Buffer_RS232.Bas you have
Code:
Dim Long_Buffer As Byte
You can get rid of Long_Buffer entirely... it's a const value based on the buffer size, so it'll never change.
You can define it and the buffer size definition in 'dim Rx_Data(20)' as const.

In the routines _Setup_Buffer_RS232() and _Get_RS232() you assign '_buffer = 0'.
Does that "variable" even exist? _buffer is the return value of the Function _buffer(), so there's no reason to try and set it outside the function.

The variable 'Tx_Buffer' is poorly named. It's the index used to read buffer elements and has nothing to do with transmitting, which is what the name implies.

If the buffer ever fills data is just discarded with no way for the user to know that's happened.
Same with OERR.
 
just some of the more obvious ones...

In the file _Funciones_Buffer_RS232.Bas you have
Code:
Dim Long_Buffer As Byte
You can get rid of Long_Buffer entirely... it's a const value based on the buffer size, so it'll never change.
You can define it and the buffer size definition in 'dim Rx_Data(20)' as const.

In the routines _Setup_Buffer_RS232() and _Get_RS232() you assign '_buffer = 0'.
Does that "variable" even exist? _buffer is the return value of the Function _buffer(), so there's no reason to try and set it outside the function.

The variable 'Tx_Buffer' is poorly named. It's the index used to read buffer elements and has nothing to do with transmitting, which is what the name implies.

If the buffer ever fills data is just discarded with no way for the user to know that's happened.
Same with OERR.
My intention was to declare the length of the buffer in the following way as I do in C:
Const Long_Buffer = 20 -1
Dim _Buffer(Long_Buffer + 1)
But these two statements are the only ones that do not allow it, they only allow numerical argument without mathematical operations.
I have already reported it, I hope that they include it in the next version, because it is more comfortable to work with arrays.

You're right making _buffer = 0 is redundant, I've already removed it.

On the other hand, _buffer is declared, because every function name is automatically declared as a global variable, it is a form more or less equivalent to C "return _buffer".

I use Tx_buffer because it refers to the output buffer, I don't know what other more appropriate name I could call it.

This is a form of simple buffer, I did not put a full buffer indicator, it is indicated with a simple overflow bit.

If there are no more suggestions I will add all the modifications.
 
So leave the variables related to the buffer functions.

'**********************************************************
Const Long_Buffer = 19 'Buffer elements -1
Dim _Buffer_Data(20) As Byte '0 al 19 store bytes Buffer
Dim _Buffer_Hardware_Index As Byte 'Input data index
Dim _Buffer_Software_Index As Byte 'Output data index
Dim _Buffer_Overflow_Bit As Bit 'Overflow bit
'**********************************************************
Added the buffer overflow bit, if activated the user will be responsible for clearing it.
 
Last edited:
A linear buffer is a suboptimal choice. What you want is a circular buffer. They work marvelously for both TX and RX.
 
A linear buffer is a suboptimal choice. What you want is a circular buffer. They work marvelously for both TX and RX.
I have been using a ring buffer for years, in this link I leave the Basic version that I translated from C (CCS) that I usually use.

 
Hi D,
I am having a blocking problems with a project I'm working on, and I'm trying to trace them.

I use 4 PICS in the project, which is in other threads, and would be too complicated to post here.

The project uses UARTs plus other peripherals, so if I address the possible UART blocking problems that can occur, this would be a good start.

I will read this thread and link more carefully, but it is a bit advanced for me, so it will take me some time.
Cheers, Camerart.
 
I advise you to use a ringbuffer better, I attach the library, try it separately and when you understand how it works, incorporate it into your program.
_BUFFER > 0: There is data in the buffer.
_Receive(10): Sometimes, when we anticipate the arrival of a frame, advancing ahead of its bytes can lead to reading errors. The '10' parameter is used to introduce a delay if the frame's entry is slower than usual, waiting 10 milliseconds to adapt to the frame byte input speed. This adjustment is unrelated to the baud rate.

The issue is complex and not straightforward to implement, as each code has its unique characteristics.

Include "_FuncionesUartRingBuffer.bas"
Call _Interrupts_Mode(_DISABLE_PRIORITY)
UART1_Init 115200
Call _SetUpRBF() 'Initialize buffer by software
Call _Enable_Interrupts(_INT_RDA) 'Enables uart interrupts
Call _Enable_Interrupts(_GLOBAL_HIGH) 'Enables peripheral and global interrupts.
'Main
While True
If _BUFFER > 0 Then 'If there is data in the buffer.
UART1_Write _Receive(10) 'Reads byte fron buffer and write to the serial port.
Endif
Wend
End
On High Interrupt
Save System
If _UAR1IF = True Then 'If there is data in the uart hardware buffer.
Call _RingBuffer() 'Moves a byte from the hardware buffer to the software buffer.
Endif
Resume
 

Attachments

  • _FuncionesUartRingBuffer.bas
    4.5 KB · Views: 19
Last edited:
Hi D,
Thank you!
I made CODE with #11 CODE, and the INCLUDE, but it doesn't compile.
I will be able to work through why this isn't compiling, but I can see that the compile errors, may be because I missed some CODE from earlier in this thread.

Am I correct that as #11 is it needs altering for my system?
C
 
This belongs to my own library, which I will attach later, and I use it to avoid having to configure the registers involved, but I think it is understood that you have to replace them with the bits of the appropriate registers.

Call _Interrupts_Mode(_DISABLE_PRIORITY)
Call _Enable_Interrupts(_INT_RDA) 'Enables uart interrupts
Call _Enable_Interrupts(_GLOBAL_HIGH) 'Enables peripheral and global interrupts.
If _UAR1IF = True Then 'If there is data in the uart hardware buffer.
 
This belongs to my own library, which I will attach later, and I use it to avoid having to configure the registers involved, but I think it is understood that you have to replace them with the bits of the appropriate registers.

Call _Interrupts_Mode(_DISABLE_PRIORITY)
Call _Enable_Interrupts(_INT_RDA) 'Enables uart interrupts
Call _Enable_Interrupts(_GLOBAL_HIGH) 'Enables peripheral and global interrupts.
If _UAR1IF = True Then 'If there is data in the uart hardware buffer.
Hi D,
Yes, I mostly understand, so will add your CODE into a short working/set-up vesion of my CODE, and see what happens, so I shouldn't need your set-up.
Thanks.
C.
 
Hi,
I notice that I have an earlier thread about buffers and ring buffers, which I did and still find difficult.
I spoke to my mate today, who will help me adopt them into my programs.

One question I have is: When a peripheral's data is placed into it's memory location, and 1/2 way along loading them, clocks over, e,g, 1.00 to 0.99 to 1.00 how does this get corrected?
C
 
When the data from a peripheral is placed in its memory location and the system clock changes halfway through the transfer, it can be corrected by:

Implementing double buffering.
Using error control and synchronization techniques.
Properly handling interrupts.
Correcting and verifying data after the transfer.

Implementing an interrupt-driven ring buffer should eliminate the problems. Additionally, having some form of checksum in place also helps.
 
When the data from a peripheral is placed in its memory location and the system clock changes halfway through the transfer, it can be corrected by:

Implementing double buffering.
Using error control and synchronization techniques.
Properly handling interrupts.
Correcting and verifying data after the transfer.

Implementing an interrupt-driven ring buffer should eliminate the problems. Additionally, having some form of checksum in place also helps.
Hi D,
I'm using linear buffers at the moment, and how I control the change, is: Search for the start of the sentence [ $ ] then load the whole sentence and mark BUFF_FULL then is BUFF_FULL parse, and once parsed, then look for another $ while processing the sentence.

Having looked a bit into 'ring buffers' I can see that this is a constant process, where writing and reading are done at the same time as long as READ doesn't catch up with WRITE, I'm at early stages of understanding so far.
C.
 
Last edited:
Using one buffer or another isn't the most important thing; what matters is that you can't stop receiving input data while you're doing something else. The reception of input data cannot be interrupted, or you will have problems. In the buffer, each time a byte is read, it is destroyed, making room for a new incoming byte. The input process never stops. You can either process the read byte in real-time or store it in a variable to process once the variable is full. Be mindful of the header byte and the end byte; in your case, the header byte is "$".
 
Using one buffer or another isn't the most important thing; what matters is that you can't stop receiving input data while you're doing something else. The reception of input data cannot be interrupted, or you will have problems. In the buffer, each time a byte is read, it is destroyed, making room for a new incoming byte. The input process never stops. You can either process the read byte in real-time or store it in a variable to process once the variable is full. Be mindful of the header byte and the end byte; in your case, the header byte is "$".
Hi D,
This seems to be a busier way, than the existing one, but if that's what will work better, then ok.

There are a number of peripherals to be read: UART, ALTIMETER, COMPASS, all of these have BUFFER STRINGS, do they all run at the same time, or in turn as they do now? The last 2x are CHIP SELECTED, within the MAIN LOOP.
C.
 

Latest threads

New Articles From Microcontroller Tips

Back
Top