Author Topic: UART read string question  (Read 1696 times)

0 Members and 1 Guest are viewing this topic.

Offline DuncanSteel

  • Contributor
  • Posts: 39
  • Country: ee
UART read string question
« on: March 17, 2017, 11:35:09 pm »
Hi

I would like to understand how can I retrieve a string from UART receiver of the UDR1 register (Atmega32u4). I`am able to do it 1 character at the time, but I cant figure out how to get a whole string.

I mean how is the data stored in the UDR1? Does it always contain only 1 char?

For example lets say i send 1x3n, what is inside UDR1 ?

Code: [Select]
char INPUT[5];

ISR(USART1_RX_vect){

for(int8_t i=0;i>=2;i++){
char ch = UDR1;
INPUT[i] = ch;
}

UCSR1B = (0 <<RXCIE1)|(0 <<RXEN1)|(1<<TXEN1);  // disable reciever
UART_SendString(INPUT);

}

 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 6547
  • Country: us
Re: UART read string question
« Reply #1 on: March 17, 2017, 11:49:46 pm »
Right, the UART only stores the most recent char.  It is your responsibility to store it in an array (string) and terminate the string with a '\0'.

There are two ways of doing this that don't block the program:  First, use a superloop that calls all the external functions, one at a time.  One of those will handle the UART.  None of the external functions can take a lot of time.  If they  do, change them into a state machine and do one small part on each pass (switch statement and remember where you are).

Second, and the right way to do it, is to have the UART interrupt on received char.  The interrupt handler will put the char in a circular buffer and possibly increment a counter.  If the counter is above 0 in the superloop test, grab one char (or more) and decrement the counter.  You MUST disable interrupts before you manipulate the counter and enable after.

There are other ways to implement a circular buffer, you can Google for them.
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: UART read string question
« Reply #2 on: March 18, 2017, 12:45:01 am »
"Normally" one has an interrupt routine where the character is
stored into a string variable in memory using a ptr. ptr is used
to minimize latency in the ISR. Declare any variables used in ISR
externally as volatile. Usually a flag is set and serviced external to
ISR to service the string memory. eg detection of end of string, overflow,
clear, ptr reset......

http://www.barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword    Volatile

http://www.embedded.com/design/programming-languages-and-tools/4397803/Interrupts-short-and-simple--Part-1---Good-programming-practices

As an aside many high performance processors have DMA capabilities, which
can automate handling of UART buffer and ancillary string buffer for use. Like
Cypress PSOC 3 or 5LP families. Even detection of special characters and acting
on their receipt. All done in HW. Or mixed code + HW.


Regards, Dana.




« Last Edit: March 18, 2017, 12:48:51 am by danadak »
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline FreddyVictor

  • Regular Contributor
  • *
  • Posts: 164
  • Country: gb
Re: UART read string question
« Reply #3 on: March 18, 2017, 08:57:59 am »
as mentioned by earlier posters, your best approach is to use an interrupt handler
which you have:

Code: [Select]
ISR(USART1_RX_vect)
{
    // some code
   char c = UDR1;
}

if setup correctly, the above function will get called each time a character is received - but note this is when 1 character is received
therefore, you will need to buffer/store these into an array for later processing.

How do you know when you have received this string ?
Well, strings are usually null-terminated, but, the null character is not usually sent - most put-string functions only send up until the null-character is found but then stop.
The sender must append a 'string-end' character, typically a 0x0A (LineFeed) is used.
So, you'll need to look for this character to trigger processing of the string held in your array

You need to make some decisions, how long is the string you expect (size of the array) to receive and make sure that it cannot overflow.
when you receive the complete string, you'll need to decide what you want to do:
whether you want to process the string immediately - ok if this is very short
copy this string somewhere else for later processing
or simply turn-off the Rx interrupt until you have processed the string - at risk of losing new data tho'

HTH
 

Offline DuncanSteel

  • Contributor
  • Posts: 39
  • Country: ee
Re: UART read string question
« Reply #4 on: March 18, 2017, 10:09:32 am »
Code: [Select]
ISR(USART1_RX_vect)
{
    // some code
   char c = UDR1;
   DDRC = (1<<DDC6);   
   PORTC = (1<<PORTC6);
   _delay_ms(1000);
   PORTC = (0<<PORTC6);

}

Oh ok I get it, it generates interrupt every time a char is received. So if I send 1n3x5 it will generate 5 interrupts & UDR1 value will always be only 1 char. I was looking for this answer.

Thank you for clarification.

That code by the way gets stuck in an infinite loop for some reason.
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: UART read string question
« Reply #5 on: March 18, 2017, 11:26:41 am »
Sounds like you did not clear UART isr flag or bit
after reading the character, so upon exit it re-interrupts. Most
UARTS clear the flag upon byte read for you.

Usually you disable the ISR when first entering the routine as well.
Depends on part you are using. Vendor usually has example code
you can look at to see how ISR UART is handled vs polled operation.

http://www.avrfreaks.net/forum/tut-soft-using-usart-interrupt-driven-serial-comms?page=all



Regards, Dana.
« Last Edit: March 18, 2017, 11:38:47 am by danadak »
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline FreddyVictor

  • Regular Contributor
  • *
  • Posts: 164
  • Country: gb
Re: UART read string question
« Reply #6 on: March 18, 2017, 02:06:29 pm »
Code: [Select]
ISR(USART1_RX_vect)
{
    // some code
   char c = UDR1;
   DDRC = (1<<DDC6);   
   PORTC = (1<<PORTC6);
   _delay_ms(1000);
   PORTC = (0<<PORTC6);

}

Oh ok I get it, it generates interrupt every time a char is received. So if I send 1n3x5 it will generate 5 interrupts & UDR1 value will always be only 1 char. I was looking for this answer.

Thank you for clarification.

That code by the way gets stuck in an infinite loop for some reason.

Ok 1st rule of coding wrt interrupts is: don't put any processing into an interrupt handler that takes any appreciable time ! especially  delays !
by doing the delay, you will miss all other interrupts !

best technique is to have a volatile flag which you set inside the ISR and then back in main function code check the status of

another point:
Code: [Select]
   PORTC = (1<<PORTC6); // this works
   PORTC = (0<<PORTC6); // strangely this doesn't !!

to clear a flag, you need to do this:
PORTC &= ~(1<<PORTC6); // nb: this clears pin6 but leaves the rest as they were

regarding danadak's point "you did not clear UART isr flag or bit", this is not necessary for this particular chip, but it is a relevant point for other chips.
The process of reading the UDR1 variable re-sets the flag.
« Last Edit: March 18, 2017, 02:09:05 pm by FreddyVictor »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf