Hello World - USART + Serial Comm with PC
Components:
- NTE7142 (same as MAX232) - to help convert from AVR logic levels (0-5v) and RS232 logic levels (15v to -15v or something like that). Integrated Circuit +5v powered, multichannel RS232 driver/receiver.
- Atmel ATtiny2313 Microcontroller
- 4 - 10uF capacitors
- 1 - .1uF capacitor
- D-sub9 female serial port connector
- PC with serial comm software (like Window's free hyperterminal)
- 5 Volt power supply (via 9volt battery, 7805, capacitors, diode, etc..)
- Ubuntu Linux Serial Port Terminal program set at 9600 baud, 8bits, No parity, 1 data stop bit, no other controls.
- LED was added to see blinks when it starts up (1 second blinks) to help check clock + to see when data sent.
- UBRR=(fclk / (16*BAUD)) - 1
- BAUD=fclk / 16(UBBR+1)
- "Magic" numbers for baud rate error of 0% is multiples of 1.8432mhz
- How to calculate error
- Calculate UBRR using desired baud
- UBRR must be whole number. Fill in that whole num to BAUD calc
- Error = Divide (calculated BAUD / desired BAUD-1) * 100 for the percent.
- Example:
- MCU clock = 8mhz, Desired BAUD=9600
- UBRR = (8000000/(16*9600)) - 1 = 51.0833 (round to whole # = 51)
- Calculated BAUD = 8000000 / 16(51+1) = 9615.3846 (round to whole # = 9615)
- Error = (9615 / 9600 - 1) * 100 = .15% error (this is less than +/- 2% so we are ok)
How to change MCU Clock frequency to 8mhz (instead of 1mhz) using internal Resistor/capacitor:
- To read -- uncomment this line in makefile. This will write out high and low fuse to text files in binary format (b)
- #AVRDUDE_WRITE_FLASH =-U hfuse:r:high.txt:b -U lfuse:r:low.txt:b #output values in high + low fuse bit
- To write -- uncomment this line in make file. It will set low fuse to 0xE4 = 1110 0100. This makes it 8mhz using internal resistor/capacitor clock. The 0100 at end is for 8mhz internal clock. the first 1 in 1110 unprograms the prescale (that is initially set to divide by 8)
- F_CPU = 8000000
- #AVRDUDE_WRITE_FLASH = -U lfuse:w:0xE4:m #run with 8 Mhz clock # jeff version to load 1110 0100
- Low byte MCU registers are: 7=CKDIV8, 6=CKout, 5=SUT1,4=SUT0, CKSEL3..0 (details in datasheet)
Wiring diagram:
- 5V power supply with 7805 -- See "how to use 7805 entry"
- MCU / NTE7142 / Serial port connections
Key Code:
Add real code used...
When you connect via Hyper terminal or some other serial comm program on PC you can type characters. The AVR will receive and echo it back so you see the response on the screen AND I added it to send back letter A also.
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
// Want baud as close to zero as possible for remainder
// At 1mhz.. /9600=104.16667, /4800=208.33333, /2400=416.6667,/1200=833.3333,/300=3333.33333,/110=9090.909090901
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
#define LEDOFF PORTB |= (1<<4)
#define LEDON PORTB &= ~(1<<4)
int main (void)
{
// Enable B4 for LED blink
DDRB |= 1<<DDB4;
// Blink at start
LEDON;
_delay_ms(1000);
LEDOFF;
_delay_ms(1000);
LEDON;
_delay_ms(1000);
LEDOFF;
// Start with light off
LEDOFF;
char ReceivedByte;
// Set baud rate
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
// Enable Receiver and transmitter
UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
/*
NOTE: Mega16 has a different shared bit than most AVRs so URSEL is used... Example:
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
AVR2313 UCSRC Registers:
7=unused, 6=UMSEL (0*=async, 1=sync operation mode), 5+4:UPM0+1 parity mode(00*=disabled,10=even, 11=odd parity)
3=USBS stop bit select (0*=1bit,1=2bit), 2/1=USCSZ2,USCSZ1,USSZ0 character size(USCSZ2 is actually in USCRB,
000=5bit, 001=6bit, 010=7bit, 011*=8bit, 111=9bit), 0=UCPOL Clock polarity(0=rising XCK edge, 1=falling. Used for sync only. In async write 0)
*/
// Set frame format: 8data (UCSZ2+1+0=011), no parity (UPM0+1=00 by default), 1 stop bit (USBS=0 default)
UCSRC |= (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
for (; ; ) // Loop forever
{
while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived"
/*// Blink for received
LEDON;
_delay_ms(1000);
LEDOFF;
_delay_ms(2000);
*/
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = 0b01000001; // Try to send letter A
// Blink for sent
LEDON;
_delay_ms(500);
LEDOFF;
/*
_delay_ms(1000);
LEDON;
_delay_ms(1000);
LEDOFF;
*/
}
}
Key Learnings:
- USART usage
- Changing fuse bits for clock speed
- Using PC Serial port terminal programs
- On the PC side you can use Window's Hyperterminal program
- Be sure to disable hardware flow control since the DTR/RTS pins are not used. My eyes kept missing that option in Hyperterm
- Determining "Magic" baud rate - System clocks for perfect USART communications should be multiples of 1.8432MHz which when used will give a 0.00% error. Other frequencies for the main AVR clock can be used, but as the frequency drifts from the "perfect" multiples of 1.8432MHz, the greater the percentage error will be (and thus the less reliable the serial communication will be). It is generally accepted that error percentages of less than +/- 2% are acceptable.
- The baud rate register is 16-bit, split into two 8-bit registers as is the case with all 16-bit registers in the AVR device family. To set our baud rate prescaler value, we first need to determine it. Note that the baud rate register value is NOT the same as the baud rate you wish to use - this is a common point of failure amongst those new to the serial subsystem. Instead, the value must be derived from the following formula:
- BaudValue = (((F_CPU / (USART_BAUDRATE * 16))) - 1)
- Good tutorial with c code - http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=45341
- Good tutorial with c code taking interrupt approach - http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=48188
- Decent example with c code - http://www.8051projects.net/serial-communication/
- Good tutorial with better connection diagram for MAX232 - http://www.avrbeginners.net/architecture/uart/setup_uart.html
- Fuses How to guide http://electrons.psychogenic.com/modules/arms/art/14/AVRFusesHOWTOGuide.php
- Another example -- http://homepage.hispeed.ch/peterfleury/avr-uart.html
- Good diagram -- http://sodoityourself.com/max232-serial-level-converter

Good post, but have you thought about USART + Serial Comm with PC before?
Reply to this
Thank you for this very useful information.
dissertation help | cheap research paper
Reply to this
I have found an invaluable resource in this blog
Reply to this
It's really difficult to find a good blog such as this one
Reply to this