Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Receive continuous data on UART in PIC18

Status
Not open for further replies.

scorrpeio

Full Member level 5
Full Member level 5
Joined
Dec 26, 2006
Messages
286
Helped
10
Reputation
20
Reaction score
9
Trophy points
1,298
Activity points
3,496
hi...
I have interfaced the GSM modem with PIC18F4520 using UART interface.

I send the command "AT" to GSM modem. In response it sends reply "OK"

Now... RCREG in PIC18 is of 8bit. so it will only accept 'O' for the first RX interrupt. In the next RX interrupt RCREG will receive 'K'.

I want to store this whole response sent by the GSM modem into an array and display it onto the LCD screen.

Can anyone let me know, how to achieve it??

---------- Post added at 13:51 ---------- Previous post was at 13:47 ----------

I cant call the func WriteToLCD() inside the RX_isr routine as it will consume much time and the next received data might get lost.
Also, the reply sent by GSM modem varies like, OK, ERROR, 8078417. so, I wont know in advance, how many bytes has to be received in buffer.
 

STORE IT IN AN ARRAY.... then read the array in lcd display routing...

Dont call LCD functions in an ISR.. it will severly affect your ISR timing.... make it as a different function
 
The best solution for UART reception is a FIFO circular buffer - all data from the uP will be placed in this buffer.
 
Hi...
I tried to implement RingBuffer for 2 days but couldnt do. I have gone through the wikipedia for circular buffer and understood it.
However, dont know how will it fit in my prog. Can anybody put an example for it.
This is what I am doing...
Code:
const char 		MODEM_SEND[] = "AT";
char* 			cptrRingHead;
char* 			cptrRingTail;
static char 	ScRingStart	= 0;
static char 	ScRingEnd	= 9;
static char 	MODEM_RECV_INDEX = 0;
static unsigned char SucRingBuffer[10];


#pragma code low_vector = 0x18
void low_ISR (void)
{
_asm goto CHEK_isr _endasm
}
#pragma code

#pragma interruptlow CHEK_isr

void CHEK_isr(void)
{
	if( PIR1bits.TXIF == 1 )
	{
		TX_isr();
	}
	
	if( PIR1bits.RCIF == 1 )
	{
		RC_isr();
		EditRingBuffer();
	}

	if( INTCONbits.TMR0IF == 1 )
	{
		timer0_isr();
	}

}

void TX_isr(void)
{
	PORTB |= 0x0A;
	SendMessage(MODEM_SEND);
}

void RC_isr(void)
{
	PORTB |= 0x05;
	SucRingBuffer[MODEM_RECV_INDEX] = RCREG;
	MODEM_RECV_INDEX++;
		
}

void EditRingBuffer		(void)
{
	cptrRingHead = &MODEM_RECV_INDEX;
       //Check conditions for ring buffer full
      // display the message on to the lcd
	
}

I had a logic as...
1. RX interrupt indicating MODEM has sent message
2. GOTO RX_isr loop and receive the 1byte of the message and store it onto the RingBuffer
3. Wait for next interrupt(The data is of multiple bytes so RX intr would be in continuous fashion)
4. Again go to RX_isr loop and get the next byte of message to the RingBuffer.

After messge is collected completely, display it onto the LCD screen by passing ring buffer to the WriteDataToLCD function.

Is my logic right?
 

Take a look at this code. It's 100% working code, you just need to set the constants (buffer size, etc.). It has header, tail and counter of bytes

Code:
//===============================================================================
//
//
//             T O   H O S T    F I F O   R O U T I N E S
//
//
//===============================================================================

#define Waiting_ToHOST()  Buffer_ToHOST[BUFFER_HOST_SIZE-3]
//******************************************************************************
void FlushFIFO_ToHOST(void)      // clear FIFO structure (without resetting the data)
//******************************************************************************
{
 Buffer_ToHOST[BUFFER_HOST_SIZE-3] = 0;   // counter
 Buffer_ToHOST[BUFFER_HOST_SIZE-2] = 0;   // head
 Buffer_ToHOST[BUFFER_HOST_SIZE-1] = 0;   // tail

}

//******************************************************************************
void PushFIFO_ToHOST(unsigned char new_data)      // push into FIFO one byte
//******************************************************************************
{
 unsigned char var_head;     // we create temporary variable

 var_head = Buffer_ToHOST[BUFFER_HOST_SIZE-2];    // read the head
 Buffer_ToHOST[ var_head ] = new_data;       // save the data in FIFO head


 Buffer_ToHOST[BUFFER_HOST_SIZE-3]++;             // increment counter of waiting bytes
 if (Buffer_ToHOST[BUFFER_HOST_SIZE-3] > BUFFER_HOST_SIZE-5)
  {
    Buffer_ToHOST[BUFFER_HOST_SIZE-3] = BUFFER_HOST_SIZE-5;   // to avoid overflowing
    // when overflow we just don't increment the head
  }
 else
  {
     // ---- only when there is no overflow we increment the head
     var_head++;
     if (var_head > (BUFFER_HOST_SIZE-4))               // uups, overflow of the head, we have to wrap around the head
       var_head = 0;     // we wrap it around
  }

 Buffer_ToHOST[BUFFER_HOST_SIZE-2] = var_head;    // we return back the head in the array


} // end of PushFIFO routine


//******************************************************************************
unsigned char PopFIFO_ToHOST(void)      // pop from FIFO one byte
//******************************************************************************
{
 unsigned char var_tail, to_return;     // we create temporary variable

 var_tail = Buffer_ToHOST[BUFFER_HOST_SIZE-1];    // read the tail
 to_return = Buffer_ToHOST[ var_tail ];      // save the data in FIFO head

  if (Buffer_ToHOST[BUFFER_HOST_SIZE-3])
   {
     Buffer_ToHOST[BUFFER_HOST_SIZE-3]--;           // decrement by one the counter of waiting bytes

    var_tail++;
    if (var_tail > (BUFFER_HOST_SIZE-4))               // uups, overflow of the head, we have to wrap around the head
    var_tail = 0;     // we wrap it around

    Buffer_ToHOST[BUFFER_HOST_SIZE-1] = var_tail;   // we return back the tail in the array
   }


return to_return;


} // end of PopFIFO routine

If you call PushFIFO inside the ISR you need to protect access to the FIFO structures and routines from main level by disabling the Interrupt during the access
 
The fastes way of making a FIFO work is the following:

unsigned char inputpointer=0, outputpointer=0;
unsigned char array[16];

void interrupt(void)
{
array[inputpointer] = INPUT BYTE; // Store your byte in the FIFO !.
inputpointer++; // increment input pointer !.
inputpointer&=0x0F; // Auto reset input pointer !.
(SOME MORE PROCESSING)
}


//main function

unsigned char ByteOut;

if(inputpointer!=outputpointer)
{
ByteOut = array[outputpointer]; // Get your byte from the FIFO !.
outputpointer++; // increment output pointer !.
outputpointer&=0x0F; // Auto reset output pointer !.
}

This will generate mutch less code than the other examples and is hence faster. If you want to know how many bytes are stored inside the FIFO you can do the following: SIZE = abs(inputpointer-outputpointer);

The nice thing of the code is that you do not need to disable interrupts during access of the FIFO like in other examples.

regards, PaulHolland
 
yes, it's faster but there is no "free lunch" - in case of overflowing the queue you will get the FIFO totally unsinchronized.

In the example above which looks more complex you could also avoid disabling the interrupts if you remove the counter of the pending bytes. If you take in account that more uP have internal UART FIFO disabling the interrupts for several cysles should not be considered as critical, but overflowing the FIFO and then completly screwing up the functionality of the FIFO should be classified as dangerous.

So you can assume the more complex code pays more attentions to avoid FIFO nonsynchronization - one bad example is this:
1. You read 16 bytes without reading from the main code (overflow 1 byte)
2. Read and write poiners are equal so it looks like there are no bytes in the FIFO!!! Hence no reading will be made and all 16 bytes are lost!

Of course you can decide do you want shorter (and more risky) code depend on the case,
 
Last edited:
hi...
tnx for it.
I hve implemented it in my code and its working.
I cudnt hve done it without your invaluable guidance.
 

@luben111.

Your mistaken about lost of synchronization, the code is auto-synchronizing. If you have a FIFO overflow or if you are expecting one you will loose data anyway. There are two solutions depending on the type of application you can decide to do something about a possible overflow or let it happen. With the above code an overflow will result in a loss of 16 bytes unless you change the code as indicated below. Loss of data is then depending on how long it takes for your code to empty the FIFO. The whole purpose of a FIFO is to prevent overflows and loss of data from happening, so if you have a FIFO overflow increase the FIFO size. This will really solve your problem.
To prevent an overflow but you will still have loss of data, you can add one more line of code: This code you should only use if the inputpointer is ONE single unit on your processor platform. Like 1 Char on a 8 bits processor or a integer (16 bits) on a 16 bits platform. Normally this is not a problems since most FIFO's are mutch less than 256 bytes long on 8 bits microcontrollers and 65535 bytes on a 16 bits microcontroller/processor.

void interrupt(void)
{
if(abs(inputpointer-outputpointer)==15)
{
array[inputpointer] = INPUT BYTE; // Store your byte in the FIFO !.
inputpointer++; // increment input pointer !.
inputpointer&=0x0F; // Auto reset input pointer !.
}
else
{
SET A FLAG HERE TO INDICATE FIFO OVERFLOW IF NEEDED.
}
}

This code is not more risky than the other code example and is used by me in many applications. There is still no need to disable interrupts in the main code which is a very bad style of programming since it slows-down your code a lot.
 
Last edited:

The fastes way of making a FIFO work is the following:

Sir,
I have read your code but do not understand it.
Could you please explain to me how it works.

I don't understand how auto reset works in this statement: inputpointer&=0x0F; // Auto reset input pointer !. and how do you know it's the right time to reset


Your help will be greatly appreciated.

Daniel M.
Regards
 

Hi Daniel M,

No matter what people write (writing 16 bytes and than trying to read, means you FIFO is to small or you have to check more frequently) the code is very simple and fast AND Secure used in a proper way.

The inputpointer normally counts from 0,1,2,3....15,0,1,2,3 you see it is going from 15 to 0. The reset mask 0x0F is 15 (dec). Your FIFO size in this case is 15 bytes. If you always check if your FIFO pointer needs to be reset it will also take a lot of cycles better simply reset always. Most processors simply use ONE asm instruction for this compared to an instruction followed by a jump if you check which is mutch slower.

Hope you get the point.
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top