Receiving a String from Hyperterminal

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, My question is how do you receive a string, that ends with a carriage return and or line feed, from the Hyperterminal, standard 8-N-1? In this code the InitUART, SendByte, and SendString functions are confirmed working, but the ReceiveByte function has not been working reliably and ReceiveString function has not been working at all. Is there a probelm with ReceiveByte, or with the way I wrote ReceiveString, timing, or all of it?!?!?!?!?!?

Please help me out!?

#include 
#include 

#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)



char ReceivedString[50];

void InitUART(void);
void SendByte(char send);
void SendString(char string[50]);
char ReceiveByte(void);
int ReceiveString(void);


int main(void)
{
	InitUART();
	
	while(1)
	{
		ReceiveString();
		SendString(ReceivedString);
	}
}

void InitUART(void)
{
	UBRR0L = BAUD_PRESCALE;
	UBRR0H = (BAUD_PRESCALE >> 8);
	
	UCSR0B |= (1 << RXEN0) | (1 << TXEN0); 
	UCSR0C |= (1 << UCSZ00);
}

void SendByte(char send)
{
	while ((UCSR0A & (1 << UDRE0)) == 0); 
	UDR0 = send;
}

void SendString(char string[50])
{
	int i;
	for( i = 0; i < strlen(string) ; i++)
	{
		SendByte(string[i]);
	}
}

char ReceiveByte(void)
{
	while(UCSR0A & (1 << RXC0));
	return UDR0;
}

int ReceiveString(void)
{
	char RX_char;
	int i = 0;
	while(1)
	{
		RX_char = ReceiveByte();
		if(RX_char == 13) break;
		ReceivedString[i] = RX_char;
		i++;
	}
	return 1;
}

Life Is Like A Bucket Of Chicken.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You normally append a terminating NUL character.

int ReceiveString(void)
{
   char RX_char;
   int i = 0;
   while(1)
   {
      RX_char = ReceiveByte();
      if(RX_char == 13 || RX_char == 10) break;
      ReceivedString[i] = RX_char;
      i++;
   }
   ReceivedString[i] = '\0';
   return 1;
}

But if you "attach" the USART to the functions, then you would use:

     gets(ReceivedString, 50);

which will place the line in your buffer AND make sure that a very long line does not crash your program.

There is a lot to be said for using fully debugged standard library routines rather than re-inventing wheels. And of course your high level code could move to a 8051, ARM or even a Pentium.

David.
Edit. I have only just noticed your KBHIT() is wrong:

char ReceiveByte(void)
{
   while ((UCSR0A & (1 << RXC0)) == 0)
       ;                      // wait for KBHIT()
   return UDR0;
}
Last Edited: Mon. Aug 10, 2009 - 08:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Most likely you have harware handshaking enabled in Hyperterminal and it will not send anything out. Turn off handshaking (Flow control = none) and see if it works then.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

There is a lot to be said for using fully debugged standard library routines rather than re-inventing wheels.

Totally agree. If you just provide the single character send and receive routines the rest of the support is provided by the C library so reading a string becomes nothing more than the gets() (possibly fgets() ) that David mentioned. Here's some code that works on a mega128:

#include 
#include 
#include 

uint8_t uart_rx_buffer[32];
volatile uint8_t rx_wr_ptr, rx_rd_ptr;

int uart_put(char c, FILE *unused) {
	while (!(UCSR0A & (1<<UDRE)));
	UDR0 = c;
	return 0;
}

ISR(USART0_RX_vect) {
	if (UCSR0A & _BV(FE))
	  return;
	if (UCSR0A & _BV(DOR))
	  return;
	uart_rx_buffer[ rx_wr_ptr ] = UDR0;
	++rx_wr_ptr;
	rx_wr_ptr = rx_wr_ptr % 32;
}

int uart_get(FILE * unused) {
	uint8_t c;

	while (rx_wr_ptr == rx_rd_ptr) { // wait until character(s) in buffer
		// this is where the program will be mainly waiting during gets()
	}
	c = uart_rx_buffer[ rx_rd_ptr ];
	++rx_rd_ptr;
	rx_rd_ptr = rx_rd_ptr % 32;
	return c;
}

uint8_t uart_test(void) {
	return (rx_wr_ptr != rx_rd_ptr);
}

FILE uart_str = FDEV_SETUP_STREAM(uart_put, uart_get, _FDEV_SETUP_RW);

void uart_init(void) {
	UBRR0L = 51; // 9600 @ 8MHz
	UCSR0B = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE); // only using it as output debug channel
	stdout = stdin = &uart_str;
}

#if 0
int uart_example(void) {
	uint8_t n = 0, c, string[20], str_ptr=0;

	string[0] = 0;
	uart_init();
	sei();

	while(1) {
		if (uart_test()) {
			c = getchar();
			if (c == '\r') {
				str_ptr = 0;
				string[0] = 0;
			}
			else if (str_ptr <= 18) {
				string[str_ptr++] = c;
				string[str_ptr] = 0;
			}
		}
		if (string[0]) {
			printf("Hello, world n=#u, s=#s\r\n", n++, string);
		}
		else {
			printf("Hello, world n=#u\r\n", n++);
		}
	}
}
#endif

The #if 0 test stuff just shows one way of using it - making use of uart_test() so it doesn't block inside a system call but only calls getchar() when there is at least one character in the buffer.

A small main() to use the above but with gets/fgets might be:

int main(void) {
  char buffer[40];

  uart_init();

  gets(buffer);
  // if "hello\r\n" were typed, buffer[] holds "hello\r"
  // that is the '\n' does not get put in the buffer

  fgets(buffer, sizeof(buffer), stdin);
  // if "hello\r\n" were typed, buffer[] holds "hello\r\n"
  // that is the '\n' DOES get put in the buffer
}