3
\$\begingroup\$

I'm trying to get the atmega328 to communicate over serial port with my pc. I'm using hyperterminal to echo back the keyboard character entries. I'm using the max3232 chip to do the communicated with the computer.

When I try to compile it gives and error and says that the variables in this function are undeclared, but they aren't variables but data register assignments.

If I replace the 'n' char in the register assignments to a number it will compile and program but no info is displayed in hyperterminal.

What should the 'n' be set too?

My RX is on pin 2 and TX is on pin 3, if that helps. It is being programmed because I've done the blinky light programs.

unsigned char USARTReadChar( void )
{
   //Wait untill a data is available

   while(!(UCSRnA & (1<<RXCn)))
   {
      //Do nothing
   }

   //Now USART has got data from host
   //and is available is buffer

   return UDRn;
}

THE ENTIRE SOURCE CODE

#define FOSC 1843200 // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1

//This function is used to initialize the USART
//at a given UBRR value
void USARTInit(unsigned int ubrr)
{

   //Set Baud rate

    UBRR0H = (ubrr>>8);
    UBRR0L = ubrr;




   //Enable The receiver and transmitter
 UCSR0B = (1<<RXEN0)|(1<<TXEN0);
 // Set fram format: 8data 2stopBit
 UCSR0C = (1<<USBS0)|(3<<UCSZ00);


}


//This function is used to read the available data
//from USART. This function will wait untill data is
//available.
unsigned char USARTReadChar( void )
{
   //Wait untill a data is available

   while(!(UCSR0A & (1<<RXC0)))
   {
      //Do nothing
   }

   //Now USART has got data from host
   //and is available is buffer

   return UDR0;
}


//This fuction writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(unsigned char data)
{
   //Wait untill the transmitter is ready

   while(!(UCSR0A & (1<<UDRE0)))
   {
      //Do nothing
          PORTD ^= 1 << PINB2;

   }

   //Now write the data to USART buffer

   UDR0 = data;
}

int main(void)
{
DDRB |= 1 << PINB2;

   //Varriable Declaration
   char data;


   USARTInit(MYUBRR);   

  //Loop forever

   while(1)
   {
      //Read data
       data = USARTReadChar();

      /* Now send the same data but but surround it in
      square bracket. For example if user sent 'a' our
      system will echo back '[a]'.

      */

      USARTWriteChar('[');
      USARTWriteChar(data);
      USARTWriteChar(']');

  }
}
\$\endgroup\$
9
\$\begingroup\$

The 'n' is meant to be a placeholder for the actual UART peripheral that you want to use when discussing the set of registers associated with the UARTs.

So if you had two UARTs, you could read the status register from the first UART by replacing it with a '0' or the second UART with a '1' like: UCSR0A or UCSR1A - note that these two are #define'd for you in a register definition file. Since we only use the UCSRnA convention for when we refer to these registers in discussion, it will not be #define'd to a register and thus using it in code will throw an error. You can follow your #include statements to find where they are defined. The register definition file and datasheet are usually two things that I have handy when working.

The ATmega328 only has one UART peripheral, but follows the same naming convention. So you would replace it with a 0. Regarding being able to read/write to a serial port - assuming that you have hooked up your MAX232 correctly, have you set your baud rate correctly on both the ATmega and the PC? Post the rest of your UART initialization code if you want further help debugging that.

EDIT: Summary of follow-up comments.

  1. Check your clock frequency and make sure it's correct when calculating the baud register value
  2. Ensure that both uC and PC have same UART settings (baud, parity, stop bits)
  3. Try not to use random code samples that may or may not be valid for your hardware configuration.
\$\endgroup\$
  • 1
    \$\begingroup\$ @Cjueden, can I ask how you determined your clock frequency: #define FOSC 1843200 ? Also, have you tried to test USARTWriteChar() independently first? \$\endgroup\$ – Jon L Jul 3 '12 at 18:46
  • 1
    \$\begingroup\$ @Cjueden, that value may not correspond to what frequency you are running your chip at. Are you using an external oscillator? Internal oscillator? Are you using a board that you bought or your own design on a breadboard...? Also, what I meant by asking if you tested USARTWriteChar() independently is if you tried just looping and writing known, hard-coded characters out to the serial port and got them in-tact on the PC side without doing any reads. Probably irrelevant if your clock frequency in code is not correct. \$\endgroup\$ – Jon L Jul 3 '12 at 18:58
  • 2
    \$\begingroup\$ @Cjueden, if you are using the default internal oscillator setting, then try: #define FOSC 1000000 (1 MHz). See section 9.2.1 of the datasheet regarding "Default Clock Source" for an explanation \$\endgroup\$ – Jon L Jul 3 '12 at 19:06
  • 1
    \$\begingroup\$ @Cjueden // Set frame format: 8data 2stopBit - did you set this to be the same on the PC as well? Typical settings use 1 stop bit, either set your PC to 2 stop bits or change the uC to 1 stop bit. But be sure to verify that they are both set the same way. \$\endgroup\$ – Jon L Jul 3 '12 at 20:23
  • 1
    \$\begingroup\$ @Cjueden, as a side note, I would avoid using random code samples. Try to understand and set your registers according to what you want and how your hardware is configured. \$\endgroup\$ – Jon L Jul 3 '12 at 20:27
1
\$\begingroup\$

When I see the "variables in this function are undeclared" message, it often means that I haven't included or linked some library I'm trying to use -- in this case, I perhaps the library that defines TXEN0, RXEN0, UCSR0A, UBRR0H, etc.

There seem to be two popular ways to implement serial communication with the ATmega328: "Low-level control" using the gcc compiler, which generally requires the line a b c d

#include <avr/io.h>

somewhere in your code that implements the "send" and "recieve" functions out of individual register reads and writes.

"High-level control" (also using the gcc compiler) involves using libraries pre-written by someone else that implements the "send" and "receive" functions out of individual register reads and writes, such as the Arduino "Serial" library a b. (Its implementation a b already has "#include <avr/io.h>" so people who use it don't have to write that line again.)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.