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.

[SOLVED] Missing Uart characters?

Status
Not open for further replies.

kgavionics

Full Member level 3
Full Member level 3
Joined
Jun 12, 2012
Messages
167
Helped
7
Reputation
14
Reaction score
11
Trophy points
1,298
Location
Alberta.Canada
Activity points
2,482
Hello guys
I'm trying to send a string of characters from my Pc to an Atmega328, and It works if I send a character at a time, but not a string (I get missing characters)!
I know that the problem is due to LCD routine that takes too much time and the UDR0 gets overwritten several times!
Can someone give me a heads-up how can I store the UDR0 register into the string, so I can send it once it's completely received to the LCD?
This is my code:

C:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

unsigned char rc,i;


#define FOSC 16000000                       // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD -1
int  main(void)
 {

    /*Set baud rate */
    UBRR0H = (MYUBRR >> 8);
    UBRR0L = MYUBRR;

    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);      // Enable receiver and transmitter
    UCSR0B |= (1 << RXCIE0);                    // Enable reciever interrupt
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);    // Set frame: 8data, 1 stp


    LCDinit();//init LCD bit, dual line, cursor right
    LCDclr();//clears LCD
    LCDcursorOFF();
while(1)
{
while (! (UCSR0A & (1<<RXC0)));
rc=UDR0;

LCDsendChar(rc);
}
retrun (0);

}

Thank you in advance!
 

Solution
Hterm can't send a null character at the end of the line, it has no way to tell where the end of the line is!
Better to use a pre-determined delimiter, maybe a carriage return or line feed character.

Brian.
Hi,

I guess sendChar is a blocking function.
So it is busy for more more than a byte time.

Klaus
 

The solution is so obvious, but I was tired! After some rest, I fixed it ! Here's the code!

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <avr/io.h>
#include <avr/interrupt.h>
 
 
unsigned char rc,i;
unsigned char table[16]={};
 
#define FOSC 16000000                       // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD -1
int main(void)
 {
 
    /*Set baud rate */
    UBRR0H = (MYUBRR >> 8);
    UBRR0L = MYUBRR;
 
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);      // Enable receiver and transmitter
    UCSR0B |= (1 << RXCIE0);                    // Enable reciever interrupt
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);    // Set frame: 8data, 1 stp
 
 
    LCDinit();//init LCD bit, dual line, cursor right
    LCDclr();//clears LCD
    LCDcursorOFF();
     while(1)
     {
for (i=0;i<16;i++)
{
while (! (UCSR0A & (1<<RXC0)));
rc=UDR0;
table[i]=rc;
 
}
LCDstring(table,16);
 
}
 
return (0);
 
}

 

That is one solution but it makes the UART the blocking device instead of the the LCD. If less than 16 characters arrive, the program waits forever.

The better solution is to prioritize the UART over the LCD rather than waiting for each to finish then switching from one to the other. If you change the UART routine so it interrupts the program when a character arrives you overcome that problem and it can still display each character as it arrives.

Brian.
 

Hi,

I avoid blocking functions where possible. For me blocking functions are a waste of processing power.

In this case I´d
* make the UART interrupt driven and
* make the display either interrupt driven or timing driven in main loop context.

In the above code I don´t understand this: There is an interrupt library included, USART interrupt is enabled, but not used.

I also don´t understand why many members are afraid of using interrupts. It takes an hour maybe two to get familiar with the interrupt concept. There are many great tutorials and videos.
Once you know how it works you will use it. The great benefit is: Write an interrupt function, test it and forget it. With "forget" I mean: You may add code in your main loop - maybe 100 times the code before, but you don´t need to take care about the interrupt function - it will work .. without being influenced by the main loop.

But if you try to do the same in main loop .. every time you add code you have to check whether this code does not have bad influence on the already existing main loop functions (timing).

Klaus
 

Actually, the interrupt library was there, because the first version of the code that I wrote was using interrupts, and it's working fine to receive one char at a time, but not a string (see the code below) and by the way I use interrupt almost all the time either in Assembly or C.
I tried the bellow code to receive a string, but I get this repeating patterns, which I'm trying to fix right now!

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <avr/io.h>
#include <avr/interrupt.h>
 
 
unsigned char rc,i=0,table[16]={};
 
#define FOSC 16000000                       // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD -1
int  main(void)
{
 
    /*Set baud rate */
    UBRR0H = (MYUBRR >> 8);
    UBRR0L = MYUBRR;
 
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);      // Enable receiver and transmitter
    UCSR0B |= (1 << RXCIE0);                    // Enable reciever interrupt
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);    // Set frame: 8data, 1 stp
 
 
    LCDinit();//init LCD bit, dual line, cursor right
    LCDclr();//clears LCD
    LCDcursorOFF();
 
    sei();
while(1)
{
 
    if( rc =='\0')
    {
LCDstring(table,16);
        rc=0;
    }
}
return 0;
 
 
}
 
 
 
ISR(USART_RX_vect)
{
    rc=UDR0;
    table[i]=rc;
    i++;
 
}
 
This is the output of the above code:

 

Attachments

  • helloworld.jpg
    helloworld.jpg
    109.8 KB · Views: 131

Hi,

You defined
i= 0 (char)
table[16]

then you write:
table=rc;
i++;

but what happens after you receive more than 16 characters?

****
with
if( rc =='\0')
you wait for an ASCII = 0 = string_delimiter. I don´t know how your sending function behaves, but usually when sending a string the delimiter is not sent via UART ... unless you force it to.

****
Generally we don´t see what data you send, thus it´s just guessing what your display should show.

Klaus
 

There is no "Hello world!" on your code.
Are you sure you're actually updating the firmware on device ?
 

Hi,

so .. 11 characters?

but usually a terminal program adds some delimiters like Cr...

So what do you send exactly?
or 11 + 1? ("Hello world" + 0)
or 11 + 1? ("Hello world" + Cr)
or 11 + 1? ("Hello world" + Lf) --> (most UNIX)
or 11 + 2? ("Hello world" + Cr + Lf) --> (most Windows)
or 11 + 2? ("Hello world" + Cr + 0)
or 11 + 2? ("Hello world" + Lf + 0)
or 11 + 3? ("Hello world" + Cr + Lf + 0)
(.... without taking care of the order of Cr, Lf and \0)

from my experience it is not likely that it sends a \0 at all.

Klaus
 
Hi,

so .. 11 characters?

but usually a terminal program adds some delimiters like Cr...

So what do you send exactly?
or 11 + 1? ("Hello world" + 0)
or 11 + 1? ("Hello world" + Cr)
or 11 + 1? ("Hello world" + Lf) --> (most UNIX)
or 11 + 2? ("Hello world" + Cr + Lf) --> (most Windows)
or 11 + 2? ("Hello world" + Cr + 0)
or 11 + 2? ("Hello world" + Lf + 0)
or 11 + 3? ("Hello world" + Cr + Lf + 0)
(.... without taking care of the order of Cr, Lf and \0)

from my experience it is not likely that it sends a \0 at all.

Klaus
I think that Hterm doesn't send any \0 at all, that's the problem!
 

Hterm can't send a null character at the end of the line, it has no way to tell where the end of the line is!
Better to use a pre-determined delimiter, maybe a carriage return or line feed character.

Brian.
 
Solution
Hterm can't send a null character at the end of the line, it has no way to tell where the end of the line is!
Better to use a pre-determined delimiter, maybe a carriage return or line feed character.

Brian.
Thank you guys for your help. I used the Carriage return, and it's working fine!


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <avr/io.h>
#include <avr/interrupt.h>
 
 
unsigned char rc,i=0,table[16]={};
 
#define FOSC 16000000                       // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD -1
int  main(void)
 { 
 
    /*Set baud rate */
    UBRR0H = (MYUBRR >> 8);
    UBRR0L = MYUBRR;
 
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);      // Enable receiver and transmitter
    UCSR0B |= (1 << RXCIE0);                    // Enable reciever interrupt
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);    // Set frame: 8data, 1 stp
 
 
    lcd_init();//init LCD bit, dual line, cursor right
    lcd_clrscr();//clears LCD
    
 
    sei();
while(1)
{
 
    if( rc !='\r')
    {
 
lcd_goto(0x40);
lcd_puts(table);
//        rc=0;
    }
}
return 0;
 
 
}
 
 
 
ISR(USART_RX_vect)
{
    rc=UDR0;
    table[i]=rc;
    i++;
 
}

 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top