Begginer help please! [UART]

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

Hi, everybody
I'm new to this forum and to AVR too.
I'm having a problem with an exercise that i'm doing to learn start programming.
Could anyone help me? Or try to?

I have a code that was already corrected by a friend(teacher for me), but i don't know what is going wrong here.

My code is the this:

#define F_CPU 7372800UL
//#define F_CPU 8000000UL
#include
#include
#include
#include

#define USART_BAUDRATE 57600
#define MYUBRRN ((F_CPU/(USART_BAUDRATE<<4))-1)

void initUsart (uint16_t MY_UBBR);
void sendChar (uint8_t data);
void sendString ( char *data);

void initUsart(uint16_t MY_UBBR)
{

UBRR0H = (unsigned char )(MY_UBBR>>8);
UBRR0L = (unsigned char )MY_UBBR;

UCSR0B = (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0) |(1<<UDRIE0);
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}

//////////////////////////////////
//Function : send char to the usart
////////////////////////////////////

void sendChar(uint8_t data)
{
while ( !( UCSR0A & (1<<UDRE0)) );

UDR0 = data;
}

////////////////////////////////////
//Function : write string to the usart
////////////////////////////////////

void sendString(char *data)
{
int len, i;

len = strlen(data);
for (i=0; i if(data[i]=='\0')
{
return;
}
else
{
sendChar(*data+i);
}
}

// tambem podes ser ainda mais simples
//while(*data !=0x00){
// sendChar(*data);
// data++;
//}
}

////////////////////////////////////
//Function : main cicle
////////////////////////////////////

int main(void)
{
char nome[] ="Nelson Macieira";

DDRB |= (1<<PINB0);
CLKPR |= (1<<CLKPCE);
CLKPR |= (0);

OSCCAL=0xDD; //Do i really need this?

initUsart(MYUBRRN);
//sei(); //Enable allactivated interruptions
//PORTB = 0xff;
while(1)
{
sendChar('a');
//sendString (nome); //Escreve String
PORTB ^=(1<<PINB0);
_delay_ms(500);
}

}

Thanks for any help

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

Im trying to send just one char because i can´t get anything on terminal except strange characters when sending the string, so i commented out the string

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

Now i have put a delay after sendchar('a')
And i have a an "a" on terminal but string = strange characters same

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

Hopefully, a nice Moderator will move this to the correct Forum.

First off, you need to make the code readable:

#define F_CPU 7372800UL
//#define       F_CPU 8000000UL
#include 
#include 
#include 
#include 


#define USART_BAUDRATE 57600
#define MYUBRRN	((F_CPU/(USART_BAUDRATE<<4))-1)

void initUsart(uint16_t MY_UBBR);
void sendChar(uint8_t data);
void sendString(char *data);

void initUsart(uint16_t MY_UBBR)
{

    UBRR0H = (unsigned char) (MY_UBBR >> 8);
    UBRR0L = (unsigned char) MY_UBBR;

    UCSR0B = (1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0)|(1<<UDRIE0);
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}

//////////////////////////////////
//Function :  send char to the usart
////////////////////////////////////

void sendChar(uint8_t data)
{
    while (!(UCSR0A & (1<<UDRE0)));

    UDR0 = data;
}



////////////////////////////////////
//Function :  write string to the usart
////////////////////////////////////

void sendString(char *data)
{
    int len, i;

    len = strlen(data);
    for (i = 0; i < len; i++) {
        if (data[i] == '\0') {
            return;
        } else {
            sendChar(*data + i);
        }
    }

    // tambem podes ser ainda mais simples
    //while(*data !=0x00){
    //      sendChar(*data);
    //      data++;
    //}
}




////////////////////////////////////
//Function :  main cicle
////////////////////////////////////

int main(void)
{
    char nome[] = "Nelson Macieira";

    DDRB |= (1<<PINB0);
    CLKPR |= (1<<CLKPCE);
    CLKPR |= (0);

    OSCCAL = 0xDD;              //Do i really need this?

    initUsart(MYUBRRN);
    //sei(); //Enable allactivated interruptions
    //PORTB = 0xff;
    while (1) {

        PORTB ^= (1<<PINB0);
        _delay_ms(500);
    }

}

Then you can look to see what it is actually doing:

#define F_CPU 7372800UL
//#define       F_CPU 8000000UL
#include 
#include 
//Function :  main cicle

int main(void)
{
    DDRB |= (1<<PINB0);         // make PB0 an output
    CLKPR |= (1<<CLKPCE);       // set prescaler to DIV1
    CLKPR |= (0);

    OSCCAL = 0xDD;              // only alters internal 8MHz RC 
    while (1) {
        PORTB ^= (1<<PINB0);    // toggle PB0
        _delay_ms(500);
    }
}

I am assuming that you have a 7.37MHz crystal. So if you have an LED + resistor on PB0, it should blink.

If you want to see the USART:

#define F_CPU 7372800UL
//#define       F_CPU 8000000UL
#include 
#include 
#include 


#define USART_BAUDRATE 57600
#define MYUBRRN	((F_CPU/(USART_BAUDRATE<<4))-1)

void initUsart(uint16_t MY_UBBR);
void sendChar(uint8_t data);
void sendString(char *data);

void initUsart(uint16_t MY_UBBR)
{

    UBRR0H = (unsigned char) (MY_UBBR >> 8);
    UBRR0L = (unsigned char) MY_UBBR;
    // do NOT use interrupts:
    UCSR0B = (1<<TXEN0)|(1<<RXEN0)|(0<<RXCIE0)|(0<<UDRIE0);
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}

//////////////////////////////////
//Function :  send char to the usart
////////////////////////////////////

void sendChar(uint8_t data)
{
    while (!(UCSR0A & (1<<UDRE0)));

    UDR0 = data;
}

////////////////////////////////////
//Function :  write string to the usart
////////////////////////////////////

void sendString(char *data)
{
    int len, i;

    len = strlen(data);
    for (i = 0; i < len; i++) {
        if (data[i] == '\0') {
            return;
        } else {
            sendChar(*data + i);
        }
    }
}

////////////////////////////////////
//Function :  main cicle
////////////////////////////////////

int main(void)
{
    char nome[] = "Nelson Macieira";

    CLKPR = (1<<CLKPCE);        //set prescaler
    CLKPR = (0);                //to divide by 1

    OSCCAL = 0xDD;              //only for RC?

    initUsart(MYUBRRN);         // initialise UART

    while (1) {
        sendstring(nome);       // send something to UART
        sendstring("\r\n");     // and a new line
        _delay_ms(500);
    }
}

Untested.

David.

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

Welcome.

char nome[] ="Nelson Macieira";

Nelsonx, could you please format your code? You should edit your opening post.
urpzv

EDIT: David was faster..

No RSTDISBL, no fun!

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

You have turned on the receive and transmit interrupts in the uart. Don't do this until you get it to work with just regular old putchar and getchar subroutines. If you send and receive characters with the receive and transmit interrupts enabled, you need interrupt handlers for those interrupts.

Imagecraft compiler user

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

Thanks to everyone.
i'll try to correct it.

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

Does anyone knows how to generate a coff file to debug stepping on proteus?
I'm using avrstudio6
Thanks

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

You are using GCC which produces an ELF file.
CodeVision, ImageCraft, Bascom produce COFF file.

Proteus should work with both ELF and COFF.

Of course, if you have a problem with Proteus you should ask for help from your school or from LabCenter.

If you have a very old Proteus, you should ask your school to upgrade your licences.

David.

p.s. you can make GCC produce COFF files but this would be the wrong solution.

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

Here i come again with worst results.
Thanks all for your patience.

#define F_CPU 7372800UL //using internal osc @ multiple of 1843200
#include
#include
#include
#include

#define USART_BAUDRATE 57600
#define MYUBRRN ((F_CPU/(USART_BAUDRATE<<4))-1)

// prototipes

void initUsart (uint16_t MY_UBBR);
void sendChar (uint8_t data);
void sendString ( char *data);

//////////////////////////////////
//Function : Config the usart baudrate
////////////////////////////////////

void initUsart(uint16_t MY_UBBR)
{
cli(); //Clear global interrputs
UBRR0H =(unsigned char )(MY_UBBR>>8); //setting uart
UBRR0L =(unsigned char )MY_UBBR; //baudrate

UCSR0B =(1<<TXEN0) | (1<<RXEN0); // enable tx and rx
UCSR0C =(1<<UCSZ01)|(1<<UCSZ00);//setting 8 data
bits, no parity bit, 1 stop bit
}

//////////////////////////////////
//Function : send char to the usart
////////////////////////////////////

void sendChar(uint8_t data)
{
while ( !( UCSR0A & (1<<UDRE0)) );//wait until UDR be ready
UDR0 = data; //send data to UDR and TX
}

////////////////////////////////////
//Function : write string to the usart
////////////////////////////////////

void sendString(char *data)
{
int len, i;

len = strlen(data); //getting lenght from vec
//running all the vector till '\0'
for (i=0; i if(data[i]=='\0')
{
return;
}
else
//sending vec char by char using the func sendchar
{
sendChar(*(data+i));
}
}
}
////////////////////////////////////
//Function : main cicle
////////////////////////////////////

int main(void)
{
// string to send (trying to... )
char nome[] ="Nelson Macieira";

DDRB |= (1<<PINB0);//PORTB AS OUTPUT
//CLEARING CLKPCE TO EDIT PRESCALER
CLKPR = (1<<CLKPCE);
//SET PRESCALER TO DIV BY 1 (RUNNING @ 7372800)
CLKPR = (0);

initUsart(MYUBRRN); //CALLING INIT USART

while(1)
{
sendChar('x');//CALLING FUNC AND SEND 'x'
sendString(nome);//sending array "Nelson Macieira"
sendString("\r\n");//new line (which does nothing on terminal)
_delay_ms(500);// wait half a second
PORTB ^=(1<<PINB0);//TOGGLE PINB0 (led attached
_delay_ms(500); // delay again
}

}

And what i got is the same as the beggining.
Weird characters. Just buffer garbage i think

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

But the internal oscillator runs at 8MHz. You can attach an external crystal of 7.3728 MHz and set the fuses to use external crystal.

Imagecraft compiler user

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

The datasheet says that to minimze usart error should set the clock of multiples of 1843200. That is only for external osc?? There is no way to set it at a desired freq? Below 8MHz of course.

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

A nice person formatted code for you. Seriously, it is worth making the effort for yourself.

If you are using a modern AVR like mega328 or mega324, it has a 8MHz RC oscillator. So if you look in your data sheet, you can see what baud rates can be achieved @ 8MHz and U2X=0. e.g. 9600, 19200, 38400 baud.

57600 baud is an unusual baud rate. You either need to use a 7.37MHz crystal or calibrate the RC for 7.37MHz. (alter OSCCAL register)

Since most terminals default to 9600 baud, this would be the easiest solution. i.e. use 8MHz RC.

David.

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

I would humbly suggest spending $2 on a Real AVR and stick it in a plastic project board and write a program to flash an led on for 500ms and off for 1500ms. I'll bet you right here and now that it takes you at least a dozen edit-compile-burn-run cycles to get the led flashing, and one more cycle to get it right side up.

Imagecraft compiler user

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

It's working guys...
Thanks for all.
BobGardner had alerted my mind when you said

Quote:

But the internal oscillator runs at 8MHz. You can attach an external crystal of 7.3728 MHz and set the fuses to use external crystal.

And from here i was searching the datasheet for the correct registers and get correct baudrate for usart and to synchronize it with my terminal.
It's now working, thanks a LOT for everything.
And sorry, for my few knowledge. I'm growing on this environment.

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

hello, i am new about avr and i need help regarding my project on "gsm control of water pump and also detect dry run and reply to the owner's no." about its conditions i need code using atmega 32 and sim900 gsm module.
thanks in advance.

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

Please start your own thread instead of hijacking someone else's. And when you do, show that you have actually made some effort yourself to handle the problem. No one here is going to do the work for you unless you pay them.

Regards,
Steve A.

The Board helps those that help themselves.

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

Seems like a good project. Start simple. Write a program to turn an led on for 500ms and off for 1000 ms. Then write a program to init the uart at a standard baudrate and send UUUUU in a loop. Can you see it in a pc terminal program? Write a third program to read a char from the serial port and echo it out the serial port to the pc. At this point you can connect the gsm instead of the pc to send messages.

Imagecraft compiler user

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

Well, may be it would be even faster if gsm was first connected to the serial port (|usb adapter) of the PC, and terminal settings are kept... Then, once you withdraw the gsm ftrom the pc and plugs the avr, one just has to tune the avr to have the right baudrate/parity (if relevent) ...

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

I have, maybe, a stupid doubt.. abot setting the baud rate on UBRR.
Let's say my baud is 9600 = 0010 0101 1000 0000 , and UBRRH[11:8] takes the 4 MSB of 9600 which would be 0010, no? Then.. why I have to shift 8 positions instead of 4?
Like
UBRRH = 9600 >> 8 = 0000 0000 0010 0101 no? so, since UBRRH is 8 bits, it would be UBBRH = 0010 0101, so it will only take 0101 and no 0010 which is more significant.. I just don't understand... someone could hel please? thanks :D

Renan Margon

Computer Engineer

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

Load up the datasheet pdf. In the contents colum on the left, click USART0. Submenu appears. Click "Examples of baudrate setting". I see it says that 57600 baud is 7 when running at 7.3728. This is 0x00 in the hi byte and 0x07 in the lo byte. The baud rate divisor is 16 bits. Two bytes.

Imagecraft compiler user

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

Quote:
I just don't understand... someone could hel please?
Perhaps you could just read the datasheet where it explains how to calculate the baud rate multiplier used by UBRR from the desired baud rate

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks guys, I read how to calculate.. I just don't get why I have to shift 8 bits to the right on UBRRH..

Renan Margon

Computer Engineer

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

Quote:

Thanks guys, I read how to calculate.. I just don't get why I have to shift 8 bits to the right on UBRRH..


You seem to be missing something fundamental here even though two people have already told you what is wrong.

When you want to use 9600 baud you do NOT put 9600 into UBRR. Even if you did you would simply use:

UBRR = 9600;

There's no point using:

UBRRH = (9600 >> 8);
UBRRL = 9600 & 0xFF;

because the compiler already p0rovides a 16 bit "UBRR" to save you having to try and split a 16 bit value into two 8bit halves (which is all that >>8 and & 0xFF do).

The fact is that UBRR is a divider register. You don't put 9600 into it. You take the baud you want to use (9600) and the CPU speed (7.3728 MHz) and you follow the datasheet which says to calculate the UBRR value you use:

UBRR = (F_CPU / (BAUD * 16)) - 1

In your case this is:

UBRR = (7372800 / (9600 * 16)) - 1

That comes out as 47. So in your C code you just use:

UBRR = 47;

In reality most people put all this into code. So something like:

#define BAUD 9600
#define F_CPU 7372800UL
#define UBRRVAL ((F_CPU/(BAUD * 16)) - 1)

and finally

UBRR = UBRRVAL;

another way to do *16 is <<4 so you might write:

#define UBRRVAL ((F_CPU/(BAUD << 4)) - 1)

That actually looks remarkably similar to something in your code in fact!

So remind us again why it is you think you want to put 9600 directly into UBRR (or UBBRH/UBRRL if you want to make life difficult for yourself)?

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

Yes.. I spent all day studying UART and then I realize my mistake.. I was thinking that 9600 goes into the register, but then I realized that is not.. as you said.. It's okay now Thanks :D

Just one more question... How I define the exactly clock that my mcu is working.. by just putting F_CPU 80000000UL for example? or I have to do anything else? thanks

Renan Margon

Computer Engineer

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

I hate to say this, but its all in the datasheet. You can use internal oscillator, which is temperature sensitive and not reliable for serial comms. Or you can use an external crystal. Which is rock solid. Gives 0% error on serial comms.

Imagecraft compiler user

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

"Just one more question... How I define the exactly clock that my mcu is working.. by just putting F_CPU 80000000UL for example? "
First, you should be sure your mcu is working with the Xal (blinkink LEDs at 1 sec: verify it is 1 sec.).

Then as you defined F_CPU before using it , using Clawson bits of code should work..

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

The key thing is that the number you put in the #define of F_CPU is the speed the CPU is actually running at. Don't use 8000000 if you really attached a 7.3728MHz crystal, use 7372800 instead. Only you know what speed the CPU is really running at (because of your CKSEL selection and any crystal you attached) the F_CPU is your opportunity to tell the compiler and other library code (and your UART calculation) what speed you have chosen to use.

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

Ok.. I will study more this.. thanks guys :D

Renan Margon

Computer Engineer