Jump to content
Sign in to follow this  
Danny Higgins

Another Rs232 Problem

Recommended Posts

I have a problem sending ASCII characters via my hardware UART routine. I am using an 18F4525 at 16.384MHz sending 7 bit ASCII with EVEN parity at 9600 Baud.

 

I need to put a delay in the putChar routine to get it to work. With no delay only a NULL is sent. With 250uS delay only the first few characters are sent and with a 1mS delay all the characters are sent. Can someone tell me why I need the delay? The sendString routine puts all of the characters into txBuffer but they are not all sent. If I stop after sending a truncated string, the txIn pointer is correct, but the txOut pointer and the txBtyeCount show that there are still characters in the buffer waiting to be sent.

 

Apologies for code indents - I can't seem to find how to post code.

 

Code:

 

// My_UART.c

// Hardware UART routines

//

// Danny Higgins, G3XVR

// 22/03/2008

 

 

void serialInit()

 

// Initialise the UART variables and registers

 

{

txByteCount = 0; // Number of bytes waiting to be sent in Buffer

txIn = 0; // Point to beginning of TX_In Buffer

txOut = 0; // Point to beginning of TX_Out Buffer

 

rxByteCount = 0; // Number of bytes waiting in RX Buffer

rxIn = 0; // Point to beginning of RX_In Buffer

rxOut = 0; // Point to beginning of RX_Out Buffer

 

txsta = 0x24; // dc, 8 bit, TX enabled, Async, 0, HighSpeed, trmt, tx9d

spbrg = BAUD;

rcsta = 0x90; // serial port enable, receive enable

set_bit(pie1, TXIE); // Enable TX interrupt

set_bit(pie1, RCIE); // Enable RX interrupt

}

 

 

void interruptRx()

 

// Interrupt when a character is received in the UART

 

{

if (pir1&0x20 && pie1&0x20)

{

if (rcsta&0x02) // Clear overrun error

{

rcsta &= 0xEF;

rcsta |= 0x10;

}

else if (rcsta&0x04) // Clear framing error

{

rxBuffer[rxIn] = rcreg;

}

else

{

rxBuffer[rxIn++] = rcreg & 0x7F; // Get byte from UART, ignore parity bit and put in RX Buffer

if (rxIn >= RX_BUFFER_SIZE) // Check to see if reached end of RX Buffer

{

rxIn = 0; // If YES, point to start of RX Buffer

}

if (rxByteCount < RX_BUFFER_SIZE) // If RX Buffer not full ...

{

rxByteCount++; // ... increment number of bytes

}

else // keep only the last {RX_BUFFER_SIZE} bytes

{

rxOut++; // Increment the RX_Out Buffer pointer (loses a byte that has not been read)

if (rxOut >= RX_BUFFER_SIZE) // Check to see if reached end of RX Buffer

{

rxOut = 0; // If YES, point to start of RX Buffer

}

}

}

}

}

 

void interruptTx()

 

// Interrupt when txreg in UART is empty

 

{

if (pie1&0x10 && pir1&0x10)

{

clear_bit(pie1,TXIE); // Disable interrupt

txreg = txBuffer[txOut++]; // Send byte from TX Buffer to UART and increment TX_Out Buffer pointer

if (txOut >= TX_BUFFER_SIZE) // Check to see if reached end of TX Buffer

{

txOut = 0; // If YES, then point to start of TX Buffer

}

if (txByteCount > 1) // If there were bytes waiting to be sent ...

{

txByteCount--; // ... decrement the number of bytes in the queue

}

else

{

txByteCount = 0; // If this was the last byte in the TX queue, set the queue length to zero

clear_bit(pie1,TXIE); // Disable interrupt

}

}

}

 

char getRxByteCount()

 

// Returns the number of bytes in RX Buffer waiting to be read

 

{

return rxByteCount;

}

 

char getChar(void)

 

// Reads the next character from the RX Buffer

 

{

char temp = 0;

if (rxByteCount > 0) // Return if nothing in the RX Buffer

{

temp = rxBuffer[rxOut]; // Save the character in the UART register

clear_bit(pie1, RCIE); // Disable Rx interrupt

rxOut++; // Point to next character in RX Buffer

if (rxOut >= RX_BUFFER_SIZE) // If pointer is at the end of the buffer ...

{

rxOut = 0; // Put pointer back to start of buffer

}

rxByteCount--; // Decrement the number of bytes waiting to be read

set_bit(pie1, RCIE); // Enable Rx interrupt

}

return temp; // Return the next character in the RX buffer

}

 

char getTxByteCount()

 

// Returns the number of bytes in TX Buffer waiting to be sent

 

{

return txByteCount;

}

 

void putChar(char character)

 

// Sets 7 bit EVEN Parity, puts a character in the TX Buffer and adjusts the pointers

 

{

delay_ms(1); // WHY ???

 

clear_bit(pie1,TXIE); // Disable Tx interrupt

txBuffer[txIn] = Set_Parity(character); // set 7 bit EVEN parity and put in TX_In Buffer queue

txIn++; // Increment pointer to TX_In Buffer

if (txIn >= TX_BUFFER_SIZE) // Check to see if end of TX_In Buffer has been reached

{

txIn = 0; // If end of TX_In Buffer, then point to start of TX_In Buffer again

}

if (txByteCount < TX_BUFFER_SIZE) // If the TX_In Buffer isn't full ...

{

txByteCount++; // ... add 1 to the number of bytes in the queue

}

else // keep only the last {TX_BUFFER_SIZE} bytes

{

txOut++; // Increment the TX_Out Buffer pointer (overwrites a byte that has not been sent)

if (txOut >= TX_BUFFER_SIZE) // If the pointer is at the end of the buffer ...

{

txOut = 0; // ... set it back to the beginning

}

}

set_bit(pie1,TXIE); // Enable Tx interrupt

}

 

void sendString(const char * string)

 

{

char i = 0; // Point to first character in String

while(string != 0x00) // Put all of String (except final 0x00) ...

{

putChar(string[i++]); // ... into TX_Out Buffer

}

}

 

char Set_Parity(char character)

 

// sets 7 bit EVEN parity

 

// Parity bit (character.7) = 1 if there are an ODD number of 1s in the byte

 

{

character.7 = 0; // reset parity (8th) bit

if (character.0) character ^= 0x80; // toggle parity bit

if (character.1) character ^= 0x80; // toggle parity bit

if (character.2) character ^= 0x80; // toggle parity bit

if (character.3) character ^= 0x80; // toggle parity bit

if (character.4) character ^= 0x80; // toggle parity bit

if (character.5) character ^= 0x80; // toggle parity bit

if (character.6) character ^= 0x80; // toggle parity bit

 

return character;

}

Share this post


Link to post
Share on other sites

The secret of how to do this:

 

what{
   indent
}

 

 

is to use

  followed by your code and then ending with the same thing except end with /code in brackets.

 

As far as your problem is concerned, how big is your transmit buffer and how long of a string are you sending. 9600 baud is pretty slow, about 100 characters/second. Also, Why are you calculating parity. I thought the UART did this for you while you are sleeping? The data sheet will have the secrets. I'm not sure what device you are using but I wrote ASM code for the 16F628 to do the buffered RS-232 receive for a little LCD terminal project. (http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html#LCD%20Terminal or http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html if the previous link is messed).

 

If your buffer is 10 characters and you shove a string longer than 10 characters at it, you will most likely overrun your buffer and have your string chopped off. The delay you add plus all the code you execute may be enough to slow the buffer fill rate down low enough to get longer strings out. At least, you should try using a buffer of 10 bytes and see if it is rock solid sending strings of 9 characters with a wait of 100ms between each string sent. You should not need the 1ms wait for each character.

Share this post


Link to post
Share on other sites

Hi trossin.

 

Thanks for the reply. The transmit buffer is 40 characters long and I don't send new messages until there is less than 5 characters in the txBuffer waiting to be sent. The maximum message length is only about 20 characters long, so the txBuffer does not overflow. I am testing it at the moment by sending a short string to an empty buffer and putting a breakpoint in MPLAB after the message has been sent. All of the message goes into the txBuffer but it is not all sent, depending on the delay I put in. 1ms delay is about the length of time it takes to send each character at 9600 baud, so I think this figure may be significant. This is the maximum data rate that the device can manage and it expects 7 bit data with EVEN parity. This is not an option with the hardware UART in the 18F4525 so I have to calculate the parity myself. Parity on receive is ignored.

 

One other point I have noticed this afternoon. When a complete message has been sent the txout pointer is 1 in front of the txin pointer, so the second message may be truncated by 1 character at the start. I think that the issue is something to do with enabling/disabling the interrupts, but I can't find it.

 

I'll have another go at posting the updated code:

 

// My_UART.c
// Hardware UART routines
//
// Danny Higgins, G3XVR
// 24/03/2008
//
// The UART is set for 7 bit operation with EVEN parity running at 9600 baud with a 16.384MHz clock frequency
// Two circular buffers (rxBuffer and txBuffer) are used to receive and transmit characters.  The buffer sizes
// are determined by RX_BUFFER_SIZE and TX_BUFFER_SIZE which are currently set to 40 bytes each.  EVEN parity
// is set on transmitted characters and parity is ignored on received characters.  txByteCount and rxByteCount
// keep a track of the number of characters in each buffer waiting to be sent or read.  If the buffers overflow
// the oldest characters in the buffers get overwritten.  There is no flow control or handshaking between the
// the control unit and the receiver.
//
// The routines that send data to the receivers will only put data in the TX buffer when there are less than 5
// characters waiting to be sent.  The longest command sent to the receivers is less than 20 characters.
//
// Known issues:
//
// This routine only works when there is a delay at the beginning of the putChar routine that puts characters
// from commands into the txBuffer.  With zero delay, only a NULL gets sent.  With 250uS delay only a few characters
// are transmitted.  With a 1mS delay, all the characters seem to get sent.  1ms is about the time it takes to send
// each character.
// 
// When the delay is short enough to cause characters not to be sent, the characters are actually in the txBuffer
// and the number of bytes waiting to be sent shows that there are characters waiting to be sent.  When the delay
// is long enough to send all the characters, the txout pointer to the next character to be transmitted is 1 ahead
// of the txin pointer which puts the next message into the txBuffer.

void serialInit()

// Initialise the UART variables and registers

{
txByteCount = 0;											  // Number of bytes waiting to be sent in Buffer
txIn = 0;																		// Point to beginning of TX_In Buffer
txOut = 0;																		// Point to beginning of TX_Out Buffer

rxByteCount = 0;											  // Number of bytes waiting in RX Buffer
rxIn = 0;																		// Point to beginning of RX_In Buffer
rxOut = 0;																		// Point to beginning of RX_Out Buffer

txsta = 0x24;																	// dc, 8 bit, TX enabled, Async, 0, HighSpeed, trmt, tx9d
spbrg = BAUD;
rcsta = 0x90;																	// serial port enable, receive enable 
set_bit(pie1, TXIE);														// Enable TX interrupt 
set_bit(pie1, RCIE);														// Enable RX interrupt
}


void interruptRx()

// Interrupt when a character is received in the UART

{
if (pir1&0x20 && pie1&0x20)
{
	if (rcsta&0x02)															// Clear overrun error
	{
		rcsta &= 0xEF;
		rcsta |= 0x10;
	}
	else if (rcsta&0x04)													// Clear framing error
	{
		rxBuffer[rxIn] = rcreg;
	}
	else
	{
		rxBuffer[rxIn++] = rcreg & 0x7F;		   					// Get byte from UART, ignore parity bit and put in RX Buffer
		if (rxIn >= RX_BUFFER_SIZE)									// Check to see if reached end of RX Buffer
		{
			rxIn = 0;										 // If YES, point to start of RX Buffer
		}
		if (rxByteCount < RX_BUFFER_SIZE)					 // If RX Buffer not full ...
		{
			rxByteCount++;									// ... increment number of bytes 
		}
		else																	// keep only the last {RX_BUFFER_SIZE} bytes
		{
			rxOut++;										  // Increment the RX_Out Buffer pointer (loses a byte that has not been read)
			if (rxOut >= RX_BUFFER_SIZE)								// Check to see if reached end of RX Buffer
			{
				rxOut = 0;									// If YES, point to start of RX Buffer
			}
		}
	}
}
}

void interruptTx()

// Interrupt when txreg in UART is empty

{
if (pie1&0x10 && pir1&0x10)
{
//		 clear_bit(pie1,TXIE);													// Disable interrupt
	txreg = txBuffer[txOut++];											// Send byte from TX Buffer to UART and increment TX_Out Buffer pointer
	if (txOut >= TX_BUFFER_SIZE)										// Check to see if reached end of TX Buffer
	{
		txOut = 0;															// If YES, then point to start of TX Buffer
	}
	if (txByteCount > 1)													// If there were bytes waiting to be sent ...
	{
		txByteCount--;														// ... decrement the number of bytes in the queue
	}
	else
	{
		 txByteCount = 0;													// If this was the last byte in the TX queue, set the queue length to zero
		 clear_bit(pie1,TXIE);	   									// Disable interrupt
	}
}
}

char getRxByteCount()

// Returns the number of bytes in RX Buffer waiting to be read

{
return rxByteCount;
}

char getChar(void)

// Reads the next character from the RX Buffer

{
char temp = 0;
if (rxByteCount > 0)										  // Return if nothing in the RX Buffer
{
	temp = rxBuffer[rxOut];								   // Save the character in the UART register
	clear_bit(pie1, RCIE);												// Disable Rx interrupt
	rxOut++;												  // Point to next character in RX Buffer
	if (rxOut >= RX_BUFFER_SIZE)							  // If pointer is at the end of the buffer ...
	{
		rxOut = 0;											// Put pointer back to start of buffer
	}
	rxByteCount--;											// Decrement the number of bytes waiting to be read
	set_bit(pie1, RCIE);													// Enable Rx interrupt
}
return temp;												  // Return the next character in the RX buffer
}

char getTxByteCount()

// Returns the number of bytes in TX Buffer waiting to be sent

{
return txByteCount;
}

void putChar(char character)

// Sets 7 bit EVEN Parity, puts a character in the TX Buffer and adjusts the pointers

{
 delay_ms(1);												  // WHY ???

clear_bit(pie1,TXIE);														// Disable Tx interrupt 
txBuffer[txIn] = Set_Parity(character);								// set 7 bit EVEN parity and put in TX_In Buffer queue
txIn++;																			// Increment pointer to TX_In Buffer
if (txIn >= TX_BUFFER_SIZE)												// Check to see if end of TX_In Buffer has been reached
{
	txIn = 0;																	// If end of TX_In Buffer, then point to start of TX_In Buffer again
}
if (txByteCount < TX_BUFFER_SIZE)										// If the TX_In Buffer isn't full ...
{
	txByteCount++;															// ... add 1 to the number of bytes in the queue
}
else																				// keep only the last {TX_BUFFER_SIZE} bytes
{
	txOut++;												  // Increment the TX_Out Buffer pointer (overwrites a byte that has not been sent)
	if (txOut >= TX_BUFFER_SIZE)							  // If the pointer is at the end of the buffer ...
	{
		txOut = 0;											// ... set it back to the beginning
	}
}
set_bit(pie1,TXIE);															// Enable Tx interrupt	
}

void sendString(const char * string)

{
char i = 0;												   // Point to first character in String
while(string[i] != 0x00)									  // Put all of String (except final 0x00) ...
{
	putChar(string[i++]);									 // ... into TX_Out Buffer
}
}

char Set_Parity(char character)

// sets 7 bit EVEN parity

// Parity bit (character.7) = 1 if there are an ODD number of 1s in the byte

{
  character.7 = 0;																// reset parity (8th) bit
  if (character.0) character ^= 0x80;										// toggle parity bit
  if (character.1) character ^= 0x80;										// toggle parity bit
  if (character.2) character ^= 0x80;										// toggle parity bit
  if (character.3) character ^= 0x80;										// toggle parity bit
  if (character.4) character ^= 0x80;										// toggle parity bit
  if (character.5) character ^= 0x80;										// toggle parity bit
  if (character.6) character ^= 0x80;										// toggle parity bit

  return character;
}

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...