[TUT] [SOFT] Using the USART - Interrupt driven serial comms

Go To Last Post
341 posts / 0 new

Pages

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

Hi everyone. I encounter some problems when using USART. This is the senario: I need to transmit a string of characters through USART to a PC. Hyperterminal is the terminal emulator that I use at the PC end. I know this terminal is not good. But I have to use it. I tried to run the code posted over here and it worked perfectly. I can see every characters that I pressed. But when I change

UDR = ReceivedByte;

to

UDR = 'J';

or some other characters, something else will turn up on the terminal window. I don't have any idea how that happen. Do I need to set anything other than the baud rate and flow control? I normally use 2400, 8-N-1, Auto detect emulation.

Also, I am using ATmega8, at 8Mhz using calibrated internal RC oscillator.

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

Calibrated against what?

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

clawson wrote:
Calibrated against what?

I am not quite sure. I just load the calibration bytes into OSCCAL register

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

Well as long as you operate at normal room temperature and from a 5V supply the Atmel factory profiled valued should be OK and the 207 you load into UBRRL should be giving you just 0.2% error but to check maybe use a scope to measure the bit widths on transmitted characters (repeatedly sending 'U' is good for this!). For 2400 baud you are looking for 416.6us

Cliff

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

clawson wrote:
Well as long as you operate at normal room temperature and from a 5V supply the Atmel factory profiled valued should be OK and the 207 you load into UBRRL should be giving you just 0.2% error but to check maybe use a scope to measure the bit widths on transmitted characters (repeatedly sending 'U' is good for this!). For 2400 baud you are looking for 416.6us

Cliff


I know what you mean. I am aware of the 0.2% error too. I just don't understand why the Hyperterminal can recognize the echoed characters, but not the characters that are coded in the program. I am suspecting that Hyperterminal is not configure properly to recognize char that is sent by USART.

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

hello everyone, i am facing some problem when using the code below

ISR(USART_RXC_vect)
{ // USART RX interrupt
unsigned char c;
c = UDR;
}
the compile result get this
warning: 'USART_RXC_vect' appears to be a misspelled signal handler

i have no idea wat happening, :?

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

what AVR are you using, maybe it has more than one USART and needs to be USART0 or USART1?

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

i am using ATmega8535
because this interrupt is very simple to use..
1 more problem dunno anyone can help..
i am trying to set the
F_CPU = 11059200
baudrate = 2400
MYUBRR = 287
using the pony prog, and set the CKOPT at the configuration and security bit
the programmer circuit also putting 12MHz oscillator + 22pf capacitor..
and trying with hyperterminal, using IR communication
but unlucky that cant show the result when transmit from AVR to the hyperterminal..
can anyone help?
thanks :( :(

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

From iom8535.h:

/* USART, RX Complete */
#define USART_RX_vect			_VECTOR(11)

So try making it:

ISR(USART_RX_vect) {
  ...

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

Hi,

I seemed to have a problem with interrupt driven Usart so I tried to follow the example given in this tutorial. I have a AtMega128 at 16 MHz and I'm using USART1 on the device. Usart communication with polling is working on the same exact cirtuitry but interrupt based communication isn't.

My source code is as follows:

#include 
#include 
#include 

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

#include 

void delay(uint8_t);

int main (void)
{
   //char ReceivedByte;

    UCSR1B |= (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);   // 10011000 UCSRnB
    UCSR1C |= (1 << UCSZ0) | (1 << UCSZ1); // 00000110 UCSRnC

    UBRR1L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
    UBRR1H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
	DDRA |= 1<<PA6; // Port A pin 6 as output
	sei(); // enable interrupts
	
   for (;;)
   {
   	delay(250);
   	PORTA ^= 1<<PA6; // Toggle led on and off
   }   
}

int SRI(USART1_RX_vect){
	char ReceivedByte;
   ReceivedByte = UDR1; // Fetch the recieved byte value into the variable "ByteReceived"
   UDR1 = ReceivedByte; // Echo back the received byte to the computer
   return 0; back 
}

When I run the code, led toggles happily. The time when I try to connect Usart with MiniCom it seems that the program hangs inside of the interrupt handler. I am using Linux and as there where proposals earlier in this thread that older versions of AVRLibC and AVR-GCC might be the problem, I compiled version 4.2.2 GCC as target AVR and I also compiled AVRLibC 1.4.6. Oh and of course binutils 2.18.

Any idea what might be wrong? Am I forgetting something or is my AVR broken or Is the fault in my toolchain?

I configured the source for toolchain like this:

binutils 2.18

configure --target=avr --program-prefix="avr-"

(avr-)gcc 4.2.2

configure --target=avr --program-prefix="avr-" --enable-languages=c --disable-libssp

AVRLibC 1.4.6

configure --host=avr

When I compile the code I showed earlier it compiles without warnings (with -Wall). Should I use some other flags when compiling the gcc? Or any other idea what might be wrong? I would need help with this problem urgently. I really hope that someone could help.

thanks
Mikko

"I have made this letter longer than usual, because I lack the time to make it short." - Blaise Pascal

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

Obvious things first. Have you disabled the M103 compatibility fuse? That'll certainly cause the interrupt vectors to mis-behave if it's still set.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

abcminiuser wrote:
Obvious things first. Have you disabled the M103 compatibility fuse? That'll certainly cause the interrupt vectors to mis-behave if it's still set.

- Dean :twisted:

After reading your reply I thought that it must be that fuse.. But output from avrdude is:

&>avrdude -c stk200 -p m128 -P /dev/parport0 -v

***clip***

avrdude: Device signature = 0x1e9702
avrdude: safemode: lfuse reads as CF
avrdude: safemode: hfuse reads as 9
avrdude: safemode: efuse reads as FF

***clip***

Regarding that efuse seems to be 11111111.
In M103 compatibility mode it should be 11111101, right?

-Mikko

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int SRI(USART1_RX_vect){ 

Is this a typo (but I guess you did not type all that in)?

ISR(USART1_RX_vect){ 

would be correct.
/Lars

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

Lajon wrote:

int SRI(USART1_RX_vect){ 

Is this a typo (but I guess you did not type all that in)?

ISR(USART1_RX_vect){ 

would be correct.
/Lars

Yes, I would think so too but my compiler doesn't:

../uart.c:39: warning: return type defaults to ‘int’
../uart.c: In function ‘SRI’:
../uart.c:44: warning: control reaches end of non-void function

No idea where that comes from but changing that wont do any good either. I tried also to echo a single character by typing "echo "U" > /dev/ttyS0". It also hangs the whole avr. I also tried compiling (WinAVR 2007-05-25) in windows and avrdude did a good job with messing LFUSE bits even if I did not ask it to do so... For example a few second delay that I use in main changed to maybe 200 milliseconds etc.. I didn't bother to find out what caused it but I changed fuse bits to original and went back to Linux later on. Compiled with WinAVR's avr-gcc sending a char for usart still hung the AVR.

thanks anyway
Mikko

edit: And yes, I had misspelled ISR to SRI at some point... but still no go. Could it be that USART1_RX_vect is wrong interrupt vector afterall?

Last Edited: Wed. Oct 10, 2007 - 10:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you're getting those warnings, it means that you *are* trying to make the ISR with the code:

int SRI(...)

Your ISRs should be defined verbatim as:

ISR(...)

As the "ISR" is a macro which is defined in avr/interrupt.h and expanded out at compile time to all the right compiler hints. Try changing your code's "int SRI" to plain "ISR" and see if it will recompile. Remember to do a "make clean" between builds to ensure a fresh compile!

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

ok, now code looks like this:

int main (void)
{
   UCSR1B |= (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
   UCSR1C |= (1 << UCSZ0) | (1 << UCSZ1);

   UBRR1L = BAUD_PRESCALE;
   UBRR1H = (BAUD_PRESCALE >> 8); 
   DDRA |= 1<<PA6;
   sei();

   for (;;) // Loop forever
   {
   	delay(100);
   	PORTA ^= 1<<PA6;
   }
   return 0;
}

ISR(USART1_RX_vect){
	char ReceivedByte;
   ReceivedByte = UDR1;
   UDR1 = ReceivedByte;
}

Compiles without warnings. But it is not still working. There should not be bits and pieces of old code since using make clean.

- Mikko

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

So, it works if you do not enable the interrupts?

Does it work OK if you leave out the ISR()?

Can we see your delay()?

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

davef wrote:
So, it works if you do not enable the interrupts?

It wont of course echo back anything then. If I poll RXC bit in UCSR1A I can read from USART and send characters back.

davef wrote:

Does it work OK if you leave out the ISR()?

Does the same

davef wrote:

Can we see your delay()?

void delay(uint8_t t){
uint8_t foo;
for (foo = 0; foo < t; foo++) _delay_ms(20);
}

This should not be causing it because even if there is an empty for loop in the main (without delay or led blinking), there is still no echo.

-Mikko

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

Sorry, by "not working" I thought you meant the LEDs didn't blink anymore!

Moving right along . . .

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

davef wrote:
Sorry, by "not working" I thought you meant the LEDs didn't blink anymore!

Moving right along . . .

Well actually I said before that led stops blinking at the moment I send the byte to the Usart (when interrupt is enabled). I just tried with another mega128 but same problem exists, so I quess that I have to try some other compiler/version.

- Mikko

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

Hi,

Got it working in WinAVR without changing the source code. But I have still check into what the toolchain does wrong in Linux by disassembling the object files. Just in case someone else runs into same problem. Maybe I'll just change back to older versions on Linux.

Thanks for help

- Mikko

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

Hy all,

let me start by thanking everyone for the great tutorials and comments ! I'm a newbie to avr and this is the motherload for me :)

I'm trying to parse files line by line via USART, I've managed to get a CRLF terminated textfile bounce line by line in minicom when catting to /dev/modem... But I want to parse file line by line. I think I should parse 'm inside ISR(USART_RX_vect) but how to fill UDR line by line in stead of filling SRAM/FLASH (file sizes unknown)

I've also tried the "static FILE mystdio = FDEV_SETUP_STREAM(usart_putchar,usart_getchar,_FDEV_SETUP_RW);"
routines, but I'm not sure how to implement them with interrupt driven UART and I also loose chars when catting a file to /dev/modem ...

I hope this makes some sense :)

bye,
gert

#include 
#include 
#include 

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

// Global variables
unsigned short int ports, leds ;

// A delay routine
void delay(uint8_t t){
uint8_t foo;
for (foo = 0; foo < t; foo++) _delay_ms(10);
} 

int main (void)
{
   UCSRB |= (1 << RXEN) | (1 << TXEN);   
   UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); 

   UBRRL = BAUD_PRESCALE;
   UBRRH = (BAUD_PRESCALE >> 8);
   UCSRB |= (1 << RXCIE); 
   sei();

for (ports=0;ports<=7;ports++)
  {
  DDRD&=~_BV(ports);//set PORTD (button) pin{ports} to zero as input
  PORTD|=_BV(ports);//Enable pull up
  PORTB|=_BV(ports);//led {ports} OFF
  DDRB|=_BV(ports);//set PORTB (leds) led to zero as output
  }

   for (;;) // Loop forever
   {
         // RS232 communication is now handled by the ISR instead of in the main loop
	 // This frees up MCU to do other stuff in stead of waiting around for RX

     if (bit_is_clear(PIND, 0))//if button is pressed
	{
		PORTB&=~_BV(0);//led 0 ON
		loop_until_bit_is_set(PIND, 0);//LED ON while Button is pressd
		PORTB|=_BV(0);//led 0 OFF
	} else if (bit_is_clear(PIND, 7))
		{ PORTB&=~_BV(7);//led 7 ON
	          loop_until_bit_is_set(PIND, 7);//LED ON while Button is pressd
		  PORTB|=_BV(7);//led 7 OFF
		}
     else { 
             // blink blink
	     for (leds=0;leds<=7;leds++)
	    	{ delay(2) ;
		  PORTB&=~_BV(leds) ;
		  delay(2) ;
  		  PORTB|=_BV(leds) ;
		}		  
	  }
    }
  return 0 ;
}

ISR(USART_RX_vect)
{
   char DaTa;
   DaTa = UDR; 

   // Must find way to read line by line ...
   
   // pseudo code
   if (DaTa=='\0') { myline = DaTa_from_ringBufffer? ;
                     parse_myline();
                   }
   UDR = DaTa; 
}

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

What you need to do, is set up some buffers that are larger than the longest line you want to read in. You'd probably need two of them, one for reading in from the USART and one for processing (you'd "ping-pong" between them, to ensure you never lose bytes).

Your ISR would read in the UDR bytes and stuff them into the current write buffer, until a \n is reached. When the newline character is sent, you need to set a flag to indicate to the main program that the buffer is ready to be parsed, and start writing to the other buffer.

Your main program then has to wait for the "ready to be parsed" flag to be set on each buffer, whereupon it clears the flag and does the parsing.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

i am working with atmega 8..what i have seen is the registers are the same as in case of atmega 16

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

Hey Dean,

thnx for the reply, I think I worked something out ...

abcminiuser wrote:
What you need to do, is set up some buffers that are larger than the longest line you want to read in. You'd probably need two of them, one for reading in from the USART and one for processing (you'd "ping-pong" between them, to ensure you never lose bytes).

Indeed, I think I'm not losing any ...

Quote:
Your ISR would read in the UDR bytes and stuff them into the current write buffer, until a \n is reached. When the newline character is sent, you need to set a flag to indicate to the main program that the buffer is ready to be parsed, and start writing to the other buffer.

Here's the ISR part now ...

// Read in USART and place in buffer for later usage ...
ISR(USART_RX_vect)
{
	uint8_t c ;
	c = UDR ;

	if (bit_is_clear(UCSRA, RXC))
	{ 
		rxbuff = c ;
		intflags.rx_int = 1 ;
	}
}

Quote:
Your main program then has to wait for the "ready to be parsed" flag to be set on each buffer, whereupon it clears the flag and does the parsing.

and here's the part that parses untill "\n" ... catting works fine

   for (;;) // Loop forever
   {
      if (intflags.rx_int)
        {
          intflags.rx_int = 0;
	  
	  p=string_buffer ;
	  
          if (rxbuff == '\r')
            {
	      *p=0; // terminate string
            }
	  else { 
		  if (i<10) // charbuffer size
			{ *p++=rxbuff ;
				i+=1 ;
			}
		  UDR = rxbuff ; // bounce

	  }
      }
  }   

Now I can read in line by line (if file is CRLF terminated at least); that leaves me with the part of parsing the strings, but while this parsing is going on, won't I risk loosing input from USART this way ? I'll figure this out when my parsing code is there I guess ...

bye,
Gert

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

Quote:

but while this parsing is going on, won't I risk loosing input from USART this way ?

Which is why I suggested two large buffers. You fill one in the ISR, then null-terminate it when you receive the newline character, and set a flag. Your main code then parses the line while the ISR switches to filling the other buffer while the parser runs on the first buffer. When the next line is ready you set another flag to tell the parser to work on the second buffer while you start filling the first again.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Hya Dean,

I understood what you meant the first time, but I don't to see how 2 buffers (or even 3 of 4 for what that matters) will be sufficient for ISR RX throttling.

The usart will receive approx. 200Kb (or more) data, which needs to be parsed and will trigger delays and high/low on several pins - if I use interrupts for these, will this temporarly block ISR UART, and will a "cat file > /dev/ttyS0" be able to handle this ? -

Won't a 2nd (or 3d, 4th etc.) buffer also loose chars if the parsing and following delays() & pin changes take quite long to finish ? Maybe I should call cli() when parsing a string ? Or use uart polling ?

I've also thought about storing entire usart input in PROGMEM and read from there, but that means restriction on file size. I've read many excellent docs about U(S)ART but implementation in these docs are focused on bouncing, uart<->uart or cmdline-interface... These I've got sorted 8)

However, I've only been doin' C and AVR for 1 month, so maybe I'm missing the point entirely :oops:

Thnx for yer time :)

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

I wouldn't have thought you'd have time to wait for the SPM operation of writing PROGMEM data to complete anyway. Wouldn't it be easier to add some buffer RAM to the AVR - maybe an SPI or I2C/TWI connected SRAM devices or, if it needs to be non-volatil, FRAM

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

Well, as long as your operations on a single line (buffer) are shorter than the time it takes to read in another line, you won't loose any characters - the ISR fills the opposite line buffer to the one being operated on.

A better way to do this would be to use a large ringbuffer (see the "AVR Experiments" page of my site for a code example) to store the characters. You'd also keep a counter for the number of *complete* lines stored in the buffer. The system would work like this:

volatile uint8_t TotalRecLines;
volatile RingBuffer_t RingBuff;

ISR(Byte Recieved)
{
   uint8_t RecByte = UDR;

   if (RecByte == '\n')
   {
      TotalRecLines++;
      RecByte = '\0';
   }

   StoreByte(&RingBuff, RecByte);
}

int main (void)
{
 // Usual setup code

 for (;;)
 {
    if (TotalRecLines) // Line waiting to be processed
    {
        // Process line, read in bytes from ringbuffer until \0 is reached
        TotalRecLines--;
    }
 }
}

That way, the ISR just has to keep feeding in bytes into the ringbuffer. When a complete line is read it increments the counter to tell the main program to start reading it back out of the buffer again and process it. While the processing is being done, the ISR can still add bytes to the ringbuffer, so no information is lost as long as the buffer is large enough.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Hy,

I'm not sure I quite understand how to use AdvRingBuffer, I understand what it does, but I struggle to get the data back out of the buffer. Should I read chars until '\0' and then strcpy to a string ?

// RingBuffer stuff
#include "RingBuff.h"
volatile uint8_t TotalRecLines;
volatile RingBuff_t RingBuff;

ISR(USART_RX_vect)
{
    uint8_t c ;
    c = UDR;
    if (c == '\r') {
	TotalRecLines++ ;
	c = '\0'; // Null terminate
    }
  Buffer_StoreElement(&RingBuff, c); // store in RingBuffer
}


void check_RS232(void)
{
    if (TotalRecLines) {
	uart_rxbuf[uart_rx_pos] = Buffer_GetElement(&RingBuff); // read chars from ringbuffer
	if (Buffer_GetElement(&RingBuff) == '\0' ) { // till '\0' encountered
		strcpy(buffer, uart_rxbuf);
		uart_rx_pos=0;
	} else {
		uart_rx_pos++;
		}
	TotalRecLines-- ;
	}
}

bye
djeez

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

Here's a quick example of what I was getting at:

// RingBuffer stuff
#include "RingBuff.h"
volatile uint8_t TotalRecLines;
volatile RingBuff_t RingBuff;

ISR(USART_RX_vect)
{
    char c = UDR;

	if (c != '\r')    // Ignore the \r in the standard \r\n sequence
		return;

	if (c == '\n')    // Reached the \n in the \r\n sequence
	{
		TotalRecLines++; // Indicate that an entire line is ready
		c = '\0'; // Null terminate
    }

	Buffer_StoreElement(&RingBuff, c); // Store next byte in RingBuffer
}


void check_RS232(void)
{
	char LineBuffer[100]; // Max line length is 100 bytes
	
    if (TotalRecLines) // Wait for a whole line to be buffered before reading it out
	{
		char c;
		uint8_t LineSize = 0;
	
		do
			LineBuffer[LineSize++] = Buffer_GetElement(&RingBuff);
		while ((c != '\0') && (LineSize != sizeof(LineBuffer)))
		
		if (LineSize == LineBuffer) // Line too long for buffer
			LineBuffer[sizeof(LineBuffer) - 1] = '\0'; // Terminate string
		
		TotalRecLines--;

		// LineBuffer now contains the next line from the USART - process it here
   }
}

Haven't even tried to compile it, but you should get the basic idea of what it's trying to do.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Hello, i was trying this Tutorial-code with ATmega32 and it wont work. I tried the code suggested in the datasheet and got some strange results:

if i am just sending stuff via:

void USART_transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) )
;
/* Put data into buffer, sends the data */
UDR = data;
}

i get all the chars on HyperTerminal, but my Problem is, i cant recieve any Characters. I use the same Init as given in the tutorial. Could i've missed something or maybe its a Problem with a RX part of the cable?

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

I'd wager it's a hardware problem. If you've tried the datasheet code also, and others have tested my code then your failure to receive characters is most likely an issue with your RX pin connection.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Yea, i tried another cable and its working now. Thanks for the great Tutorial, Dean.

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@infibit

Everything in this tutorial + everything in the ADC tutorial plus the use of the itoa() function in the C library.

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you using the internal RC oscillator? If so, is it calibrated? At the very least you should load the calibration value for 8Mhz in the OSCCAL register. The calibration for 1Mhz is loaded at reset so you could try running at 1Mhz also (lower the baud rate to 4800 or lower if you do). You can ignore all this if you have an external 8Mhz crystal.

The ADC questions are off-topic here but anyway:

Quote:
dint even connect anything to the ADC port and numbers just kept flowing in randomly.

What do you expect if you have nothing connected? The input will be floating and you will get some random values. Start with grounding the input and verify you get 0. Then try some voltage near the reference and verify you get a value close to 1023.
Have you connected a reference voltage at AREF btw? AREF is what you have selected as the reference by having the bits REFS1 and REFS0 both 0 in ADMUX.
/Lars

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi

Last Edited: Sun. Mar 2, 2008 - 03:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi

Last Edited: Sun. Mar 2, 2008 - 03:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I have configured the atmega8 now to 1mhz

Crystal or internal RC oscillator? If latter how are you calibrating it?

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But you haven't told us how you are calibrating it?

(to cut a long story short, if you want to use the UART get a crystal)

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I dint even connect any device.
Again, I suggest you connect some known voltage to the ADC input.

Calibration or not depends, if you are using a reasonable baud rate and are just experimenting you may not need it. But this is still good advice for long term reliable communication:

Quote:
(to cut a long story short, if you want to use the UART get a crystal)
And since you already have a crystal why not just enable it.
/Lars

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

First of all, I really found this guide useful. Thanks!

I am using an ATMEGA8L AVR. I have switches connected to my PIND2 and PIND3, which are used for INT0 and INT1 respectively. With this interrupt-driven UART code enabled, I can get INT1 to work, but not INT0. However, if I comment out all the UART code, both INT0 and INT1 work fine. Is there something about this code that alters the functionality of INT0? If so, can someone explain it to me? I can post my code if needed, but I figured my question is probably general enough not to require the posting of my code (not that I mind posting it; I just want to avoid the clutter here).

Thanks. Just getting back into the AVR after a hiatus due to the completion of an I2C-accelerometer project :)

-Eric

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

Eric,

That is not a general issue so I think we need to see your code but it'd probably be most appropriate to start a new thread about it in AVR Forum.

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

Hello,

I want to share this code in order to help out Stefan and anyone else who wants to to UART transmit using interrupts. This code uses the TXC interrupt, not UDRE. I don't know much about the latter. Maybe it would be better? But this code works, and it has a nice wrap-around buffer for very efficient use of processor time.

- Sage Radachowsky
Boston, USA

// SendWithInterrupt - main.c
//
// by Sage Radachowsky, Feb-Mar 2008 ("sager" at "mit" dot "edu")
//
//
// Program to test sending data to the serial output (UART / RS232) using interrupts
// instead of actively polling to check if the last byte was written.
//
// This has two advantages -- the CPU is using its built-in hardware signals rather than
// burning CPU instructions so it consumes less power, and (2) the CPU is freed
// to do other things rather than wait for some 9600 baud output or even 57k baud output,
// which is a heck of a long time in a multi-MHz world.
//
// This is written for the AT90CAN128 microcontroller, which has 2 UART lines. To rewrite
// it for any Atmel AVR micro that has just one serial line, you would have to change the
// names of all the UART registers to remove the "0".
//
// Note that interrupts must be globally enabled for this stuff to work - of course!
//
// This code sets up the interrupts to interface with stdout, so that "printf()" sends
// by interrupt! Easy and Sweet!
//
// NOTE: Be sure to change your CPU speed if it's not 1.8432 MHz !
//




//**********************************************
//                DEFINITIONS
//**********************************************



// CPU frequency
#define F_CPU 1843200L   // 1.8432 MHz

// UART baud rate
#define UART_BAUD  9600 

// UART buffer size
#define UART_BUFFER_SIZE 256


//**********************************************
//               HEADER FILES
//**********************************************


#include 
#include 
#include 
#include 

#include 
#include 
#include 

#include 




//**********************************************
//            FUNCTION DECLARATIONS
//**********************************************

void         USART0_Init(void);
static int   UART0_Putchar(char c, FILE *stream);
void         DelayAwhile(void);


//**********************************************
//               GLOBAL VARIABLES
//**********************************************

char UartBuffer[UART_BUFFER_SIZE]; // this is a wrap-around buffer
int  UartBufferNextByteToSend; // position of next byte to be sent
int  UartBufferNextFree; // position of next free byte of buffer
int  UartSendingInProgress; // 1 = sending is in progress


/* This is the pointer to the serial interface */
/* Defines the stream interface for write only */

FILE uart_str = FDEV_SETUP_STREAM (UART0_Putchar, NULL, _FDEV_SETUP_WRITE);




// ################## here we GO! ####################

int main()

{

	// initialize the UART and enable interrupts
	USART0_Init(); sei();

	printf ("Hello from SendWithInterrupt.\n");
	DelayAwhile();


	// loop forever
	while (1)
	{

		printf ("This is test output. How's the weather?\n");
		DelayAwhile();

	}


}


//===============================================================================
  void DelayAwhile()

//
// Delays a while, to slow down to a human level.
//


{
	_delay_ms(200);
	_delay_ms(200);
	_delay_ms(200);
}





//****************************************************
//                 UART functions
//****************************************************




//===============================================================================
  void USART0_Init() 

// This routine initializes the UART0 port of the AT90CAN128 and clears the
// write buffer.
//
// This routine does NOT enable the transmit-complete interrupt (TXCIE0).
// That is left up to the UART0_PutChar() routine, after it puts something in
// the buffer for the first time.
//
// This routine also does NOT enable general interrupts. That is left to the
// main() initializing code, and it MUST be done for this stuff to work.
//
// Also sets standard out to the uart interface, so printf() works sweetly.
//

{ 

	// init buffer data structures
	UartBuffer[0] = '\0'; // clear the first byte of buffer
	UartBufferNextByteToSend = 0; // set "next byte to send" to beginning
	UartBufferNextFree = 0; // next free byte is also beginning of buffer
	UartSendingInProgress = 0; // clear "sending in progress" flag

	// set baud rate
	UBRR0H = (unsigned char) (((F_CPU/(16L*UART_BAUD))-1) >> 8); 
	UBRR0L = (unsigned char) ((F_CPU/(16L*UART_BAUD))-1); 

	// Set frame format: 8data, no parity & 1 stop bits
	UCSR0C = (0<<UMSEL0) | (0<<UPM0) | (0<<USBS0) | (3<<UCSZ00); 


	// Enable transmit
	UCSR0B = (1<<TXEN0); //Enable the transmitter only

 	// set standard output stream to our UART interface
	stdout = &uart_str;

} 


//===============================================================================
  static int UART0_Putchar(char c, FILE *stream)

// If transmit is in progress, adds a character to the UART output buffer.
// If transmit is not in progress, kicks off a transmit.
//
// The send buffer is a wrap-around buffer.
//
// If the buffer is full, then this routine returns EOF.
// A successful completion returns 0.
//
// This routine disables the UART Tx interrupt temporarily, because
// things would get funky if the interrupt signal routine were called during
// execution of this routione.
//
// If the buffer was empty to start with, then this routine "primes the pump"
// sending the character directly to the UART.
//
// This routine also adds carriage returns to newlines.
//

{
	register int ReturnStatus = 0; // return 0 for success
	register int UartBufferNextFree_last; // space to save last UartBufferNextFree

	// if character is a "newline" then add a "carriage return" before it.
	if (c == '\n')
		UART0_Putchar('\r', stream);


	// if no send is already in progress, then "prime the pump" by sending directly to UART
	if (UartSendingInProgress == 0)
	{
		// set "sending in progress" flag
		UartSendingInProgress = 1;
		// send the first byte!
		UDR0 = c;
	}
	else
	{
		// disable the Tx Complete interrupt
		UCSR0B &= ~( 1 << TXCIE0 );

		UartBuffer[UartBufferNextFree] = c;

		// increment the next free byte index, while saving last value
		UartBufferNextFree_last = UartBufferNextFree++;

	 	// check for wrap-around
		if (UartBufferNextFree == UART_BUFFER_SIZE) // if we reached the end of the buffer -
	  		UartBufferNextFree = 0; // start back at the beginning

		if (UartBufferNextFree == UartBufferNextByteToSend) // if buffer is full -
		{
			// bump back the index so transmit routine doesn't think buffer's empty
			UartBufferNextFree = UartBufferNextFree_last;
			// return with error code	
			ReturnStatus = EOF; 
		}
		
		// enable the Tx Complete interrupt
		UCSR0B |= ( 1 << TXCIE0 );
	}


	// return with status code
	return ReturnStatus;
}









//********************************
//       INTERRUPT HANDLERS
//********************************


//===============================================================================
   ISR (USART0_TX_vect)


// This interrupt service routine is called when a byte has been sent through the
// UART0 port, and it's ready to receive the next byte for transmission.
//
// If there are more bytes to send, then send the next one and increment the index.
// If the index reached the end of the buffer, then wrap around to the beginning.
//
// If there is not another byte to write, then clear the "UartSendingInProgress"
// flag, otherwise set it if a byte has just been sent.
//

{
	if (UartBufferNextByteToSend == UartBufferNextFree)  // if nothing to send -
	{
	  	UartSendingInProgress = 0;	// clear "sending in progress" flag
	    return; // then we have nothing to do, so return
	}

	// set "sending in progress" flag
	UartSendingInProgress = 1;

	// send the next byte on UART0 port
	UDR0 = UartBuffer[UartBufferNextByteToSend];

	// increment index and check for wrap-around
	UartBufferNextByteToSend++;
	if (UartBufferNextByteToSend == UART_BUFFER_SIZE) // if we reached the end of the buffer -
		UartBufferNextByteToSend = 0; // then start back at the beginning

}

Have fun!

Why choose? Be there *and* be square!

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

nice tutorial

Pages