Reading string from usart and storing in a char array

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

I am doing a project on sms controlled relay where a GSM module is connected to the microcontroller serially.
Once the message from the GSM module is stored in a char array I will be able to do further operations on that array. But i am stuck at this part.
I have tried many program on READING STRING FROM USART but didn't succeeded.

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

Show what you have - are you planning to do the reception of characters sitting in a loop (this is called "polled" or sometimes "synchronously") or are you planning to have the characters received by a UART interrupt (this is known as "asynchronously"). In either case you will ultimately have a single function that returns a character at a time. Maybe called getchar()?. To receive a string you keep processing getchar() until you see an end of line marker has arrived. That can be denoted by either carriage return (0x0D also '\r') or line feed (0z0A or '\n'). So something like:

char line[20];
index  i = 0;
while(1) {
  line[i] = getchar();
  if (line[i] == '\n') break;
  i++;
}
line[i] = 0;

When you exit this line[] contains the characters that were received with a 0 terminator at the end - so that str***() functions can be used such as:

if (strcmp(line, "relay off") == 0) { ...

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

How can it be implemented with the help of USART interrupt.
Does this work........

#include 
#include 


#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
int main (void)
{
UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UCSRB |= (1 << RXC); // Enable the USART Recieve Complete interrupt (USART_RXC)
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
DDRA = 0XFF;
while (1) // Loop forever
{
// Do nothing - echoing is handled by the ISR instead of in the main loop
char line[20];
if (strcmp(line, "on") == 0)
{
    PORTA = 0xFF;
}
}
}
ISR(USART_RXC_vect)
{
char line[20];
int  i = 0;
while(1) {
  line[i] = getchar();
  if (line[i] == '\n') break;
  i++;
}
line[i] = 0;
 // Echo back the received byte back to the computer
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Forget interrupts (which you clearly don't understand yet) and concentrate on a simple polling solution until you understand the basics. It may help to read some of the UART tutorials in the Tutorial Forum

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

I have read the tutorial of Dean

#include 
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
int main (void)
{
char line[20];
int i=0;
UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byteof the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
for (;;) // Loop forever
{

while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
while (line[i] != '\n')
{
    line[i] = getchar();
    i++;

}

}
}

I need to develop the code.

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

In the case what prompted you to define line[] within the ISR? It is a completely different line[] array to the one in main(). To share them it must be defined globally (outside a function body).

Also what prompted you to call a synchronous function such as getchar() from within an RXC ISR? Dean never did that. You cannot go into potentially infinite ISRs with while(1) loops and synchronous functions. The whole point of doing it with interrupts is each timer a character arrives the interrupt is triggered, it enters the ISR, you store that character as quick as possible then get back out of the ISR. You don't start looping within it. When the '\n' is received you then flag this fact to the main() loop somehow to tell it a complete string has now been received. That's where you do the strcmp() or whatever.

The index to the line[] array either needs to be global or at least function static so it's positioned is remembered from one ISR to the next.

The flag you use to signal that the whole string has arrived must be 'volatile' by the way. You also need to consider what happens if more characters arrive while you are still in the middle of processing the first string. (ultimately you will determine that a first-in-first-out(FIFO)/circular/ring buffer is the way to handle this).

But like I say, forget this complexity and get the synchronous polling version working first (which is what you were effectively trying to write in the ISR anyway).

One thing, you cann just call getchar() like that - you must setup a UAT receive routine to be used by the stdin file stream first (see FDEV_SETUP_STREAM). but I'd suggest that even that is a level of complexity beyond what you should be attempting at this point. For the time being write your own UART_receive_character() synchronous routine (blocking on the RXC bit) and use it.

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

I tried to correct the errors you said. This is the code without ISR

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

char line[20];
int i=0;
int main (void)
{

UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byteof the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
for (;;) // Loop forever
{

while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
while(1)
{
  line[i] = getchar();
  if (line[i] == '\n') break;
  i++;
}
line[i] = 0;
}
}

I didn't understand the last paragraph you said.

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

Remove this:

while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR 

Also how do you think getchar() operates? How does it know how to operate a UART?

Answer it does not. It's up to you to teach it. You write a uart_getchar() style routine then you use FDEV_SETUP_STREAM to associtae that routine with a file input stream. Finally you assign stdin=&name_of_your_stream to that when a routine tries to use character input on stdin (as getchar does) it gets redirected to the UART_getchar() routine you wrote.

The manual example explains this:

http://www.nongnu.org/avr-libc/u...

But like I said using getchar() and this mechanism is adding an extra level of complexity to your software that you don't need or want at this stage. Just write a simple:

uint8_t uart_gtechar(void) {
  while ((UCSRA & (1 << RXC)) == 0) {
  }
  return UDR;
}

and use this in place of the gtechar() call you have now.

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

I have made some modifications the code.....

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

char line[20];
int i=0;
int main (void)
{

UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byteof the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
while (1) // Loop forever
{

while(1)
{
  line = uart_getchar();
  if (line[i] == '\n') break;
  i++;
}
line[i] = 0;
}
}
uint8_t uart_getchar(void) {
  while ((UCSRA & (1 << RXC)) == 0) {
  }
  return UDR;
}

Can you write here the code for [i]teaching the uart_getchar() to operate the uart. I am not good on C.

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

I think i need more knowledge on C programming and GCC.

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

Is this correct...

#include

unsigned char receive_buffer[60];
unsigned int buffer_count=0;

/* Function Prototype */

void uart_init();

void uart_init()
{

UBRRH=0x00;
UBRRL=0x33;
UCSRB=(1<<RXEN)|(1<<TXEN);

}

int main()

{
unsigned int receive_buffer_count,data_count;
unsigned int delay_count;
uart_init();

DDRA=0XFF;
PORTA=0X00;

while(1)

{

while(buffer_count<56)

{

while(!(UCSRA & 0x80));
receive_buffer[buffer_count]=UDR;

buffer_count++;

}
buffer_count=0X00;
}

}