Hello World - USART + Serial Comm with PC

Purpose: Create simple Hello world example of serial comm to a PC using microcontroller USART.

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.
How to calculate Baud Rate + error:
  • 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
Other code items / usage to watch:
  • 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)
Web References:
 
Trackbacks
  • No trackbacks exist for this post.
Comments

Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name (required)

 Email (will not be published) (required)

 Website

Your comment is 0 characters limited to 3000 characters.