Avr Uart Sample Cover Letter

A microcontroller is a self-contained, but very limited computer — halfway between a computer and a component.

The top reasons to integrate a microcontroller into your projects are connectivity and interactivity, and one easy way to get your microcontroller talking with the outside world is standard asynchronous serial I/O. Many devices can communicate this way, from wi-fi routers to GPS units to your desktop or laptop computer. Getting comfortable with serial I/O makes debugging your AVR programs much easier because the AVR can finally talk to you, opening up a huge opportunity for awesome.

In this Skill Builder, we’ll set up two-way communication between an AVR microcontroller and your computer. Your computer will command the AVR to blink an LED, then the AVR will open a web page of your choice in a browser at the push of a breadboarded button using serial I/O.

You’ll need the following software:

Asynchronous Serial Communications — A Quick Technical Overview

Computers like to talk to each other in binary: ones and zeros. A simple way to send these binary bits between devices is to connect them together with a wire, and let a high or low voltage on the wire denote a one or zero. Sending bits one at a time like this is serial communication because the bits are sent in series, one after the other.

For asynchronous serial communication (above), there is no common clock signal between the two devices, so to interpret a stream of voltages, each device needs to know how fast the bits are being sent: the baud rate.

Atmel’s megaAVR family of AVRs (the ATmega series) have a built-in universal synchronous and asynchronous serial receiver/transmitter (USART for short) hardware peripheral that takes care of all of the hard bits — setting and reading voltages on the serial communication lines at just the right times. Using the USART is not hard: We configure the baud rate, turn the transmitter and receiver sections on, and then feed it data. The USART hardware takes care of the rest.

Configuration

The AVR chips set the baud rate by taking the CPU clock and dividing it down to the right speed. Your main job, in configuring the chip, is to figure out the correct division factor.

The AVR USART hardware samples each bit multiple times to make sure that it’s reading a consistent voltage level. In particular, it has two modes: one where it samples 16 times per bit (“normal” mode) and another where it samples 8 times per bit (“double speed” mode). So you’re going to divide the CPU speed by 16 and 8 times the baud rate respectively, and then use that result to set the USART timing clock divider.

There are two more catches, though. First, you need to subtract 1 from the result. This is because the AVR’s counter starts counting with 0 rather than 1. So if you want the AVR to divide by 4, select 3 for the counter value: 0, 1, 2, 3.

The second catch is tricky, and this is why I think it’s worth doing the math by hand as follows at least once. (The AVR standard library includes utilities that help you set up the baud rate automatically.) The AVR only deals in whole numbers, but unless you’ve chosen your CPU speed to be a multiple of the baud rate, the result of the division above is unlikely to be a round number. So when you round this result off to fit in the AVR, you’re introducing some error in the baud rate. A little error is fine, but too much makes the serial communications unreliable.

Baud Rate Example

Say I’m running the CPU at full speed off the internal CPU clock — at 8MHz — and sampling the default 16 times per bit. Let’s see which of the standard baud rates work well:

8,000,000 / 16 / 9,600 = 52.08   = 0.2%

8,000,000 / 16 / 14,400 = 34.72   = 0.8%

8,000,000 / 16 / 19,200 = 26.04   = 0.2%

8,000,000 / 16 / 28,800 = 17.36   = 2.1%

8,000,000 / 16 / 38,400 = 13.02   = 0.2%

8,000,000 / 16 / 57,600 = 8.68   = 3.7%

There are a few things to notice here. First, 9,600 baud, 19,200 baud, and 38,400 baud all look pretty good — with the same 0.2% error. The 14,400 baud rate isn’t horrible, but around 1% error is pushing it. Rates of 28,800 and 57,600 baud may not work at all with this CPU speed and multiplier combo.

Mini Project — Blinking Web-Page-Loader Button

Now you’ll breadboard an AVR, program it with an ISP, and connect it via USB-serial so it can communicate with your computer and launch a web page.

1. Breadboard the ISP and Test Power

TIP: The USBtinyISP must have the front jumper closed to provide power.

This example uses the USBtinyISP to provide 5V to the breadboard. If your ISP doesn’t provide power, you’ll have to add it.

2. Complete the Programming Circuit and Test Communications

Note: If you use a different ISP or AVR chip, you’ll need to adjust the Makefile.

Add the ATmega and the capacitor, resistor, and LEDs. Attempt to talk to the AVR via your terminal by typing . If you get an error, your wiring is incorrect or your chip is bad. Double-check the connections shown below.

NOTE: The USBtinyISP has two different connectors: a 6-pin and a 10-pin.

3. Flash the C Code to the AVR

In terminal, go to serialMiniproj, then compile and load the C program onto the AVR by typing . See hardware setup Step 1 and below.

The C Code Explained

At the top, we include some standard AVR libraries: defines the pins and port mnemonics, provides the command that we use to instruct the processor to run at full speed, and provides that we use to stall the AVR for a second.

Then we define some convenience macros and the pins that we’ve hooked up the LED and button to.

Skip down to the routine and look at the “Initialize serial” section. Calculate the baud rate clock divider as shown in the comments: using the AVR’s built-in 8MHz CPU clock at full speed, “normal” mode serial sampling 16 times per bit, and a target rate of 38,400 baud. Doing the division and rounding we get 12; set the USART baud-rate register accordingly. Then enable both the transmit and receive sides of the USART hardware.

The loop is the routine’s event loop, which runs forever. Inside it, we do two things: Check for data on the serial line, and check for a button press. Within the serial receive code, we directly compare the received byte in with the letter “L”. As soon as the USART data register is read, the AVR resets the receive-complete flag, , so that we’ll only execute this section of code once per incoming letter. Finally, if the AVR sees the button pressed, it waits until the USART is ready to send and then loads the data register , with the “X” we wish to transmit. It waits for a second before checking the button again and sending another command. If you leave this bit out, you end up opening multiple web pages before you can pull your finger off the button.

Serial with Python

Now that we’ve got the AVR speaking serial, it’s time to connect it to your desktop, and then on to the world. For the computer-side scripting, I’ll be using the Python language because it’s simple to learn and lets you do a tremendous amount with very little code.

4. Identify the USB-Serial Port

When using a USB-serial converter, you’ll need to figure out how your computer addresses it, and then replace the address in the Python code below. On Windows, the USB device will register as a COM port. You can find out which one by looking in Device Manager.

On Linux, the USB-serial device will show up as /dev/ttyUSB0 or /dev/ttyACM0. On Mac, open terminal and type ls /dev/tty.usb* to see the path. It will show up as /dev/cu.<something> or /dev/tty.usbserial-<something>.

We import the and the built-in libraries, and then open up a serial connection object. We specify the serial port (again, yours may be different) and the baud rate. I’ve also included the optional argument. This is important because otherwise the Python routine will just sit there waiting for data to come in over the serial line.

The other trick here is the line — depending on your operating system and what you’ve connected to the serial port in the past, there may already be data sitting around in your computer’s serial buffer. We want to clean that out first, so assures that we start with a clean slate.

The Python code is also structured as an infinitely repeating loop. Inside, we read a byte. If there is a byte available, the Python code immediately tests it for “X” and then opens a web page. If there is no byte available within the 2-second timeout, the blink-LED command (“L”) is sent.

5. Run the Python Code on Your Computer

Note: To finish up the project, connect the LED (through a 220-ohm current-limiting resistor) to the AVR’s PB0, and connect the pushbutton to the AVR’s PB1 and then to ground.

You’ll need to connect a USB-serial converter to your AVR circuit and add the LED and pushbutton, as shown in the diagram above. The FTDI cable plugs into your computer’s USB port. For two-way (full-duplex) communication, all that’s required are two signal wires and a common ground between the two devices to reference the communication-line voltages.

To run the Python program, open terminal, navigate to the serialMiniproj directory, and then type to run the program.

Then with the circuit powered and the USB-to-serial attached to your computer, push the breadboarded button and launch a web page.

That’s all there is to it! Two-way communication and control of your AVR and hardware through serial, from your desktop or laptop computer.

Expanding on this simple example is where it gets fun. What can you come up with?

AVR Studio


Create a C project in AVRStudio and make sure the AVR microcontroller is the one you want to use. WinAVR C is very fussy about the correct device and although the code will compile, it will not run properly unless the AVR microcontroller type is correct

To change AVR microcontroller, go to Project > Configuration Options and select correct AVR.
Note that only the C Compiler project changes, not main project device type. Also change
Optimization to -0s otherwise compiler has problems with delay routines.

Connect to PC via standard serial cable, not Nul-modem cable. Run Hyper Teminal (Programs > Accessories > Communications) and create New connection, with Connect Using set to COM1 (or other COM Port). In COM1 Properties set Baud Rate to 38400, Data bits to 8, no Parity, 1 stop bit
and no flow control.

#define F_CPU 8000000UL // 8 MHz /*Very Important - change F_CPU to match target clock Note: default AVR CLKSEL is 1MHz internal RC This program transmits continously on USART. Interrupt is used for Receive charactor, which is then transmitted instead. LEDs are used as a test. Normal RX routine is included but not used. Change USART_BAUDRATE constant to change Baud Rate */ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // Define baud rate #define USART_BAUDRATE 38400 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) volatile unsigned char value; /* This variable is volatile so both main and RX interrupt can use it. It could also be a uint8_t type */ /* Interrupt Service Routine for Receive Complete NOTE: vector name changes with different AVRs see AVRStudio - Help - AVR-Libc reference - Library Reference - <avr/interrupt.h>: Interrupts for vector names other than USART_RXC_vect for ATmega32 */ ISR(USART_RXC_vect){ value = UDR; //read UART register into value PORTB = ~value; // output inverted value on LEDs (0=on) } void USART_Init(void){ // Set baud rate UBRRL = BAUD_PRESCALE;// Load lower 8-bits into the low byte of the UBRR register UBRRH = (BAUD_PRESCALE >> 8); /* Load upper 8-bits into the high byte of the UBRR register Default frame format is 8 data bits, no parity, 1 stop bit to change use UCSRC, see AVR datasheet*/ // Enable receiver and transmitter and receive complete interrupt UCSRB = ((1<<TXEN)|(1<<RXEN) | (1<<RXCIE)); } void USART_SendByte(uint8_t u8Data){ // Wait until last byte has been transmitted while((UCSRA &(1<<UDRE)) == 0); // Transmit data UDR = u8Data; } // not being used but here for completeness // Wait until a byte has been received and return received data uint8_t USART_ReceiveByte(){ while((UCSRA &(1<<RXC)) == 0); return UDR; } void Led_init(void){ //outputs, all off DDRB =0xFF; PORTB = 0xFF; } int main(void){ USART_Init(); // Initialise USART sei(); // enable all interrupts Led_init(); // init LEDs for testing value = 'A'; //0x41; PORTB = ~value; // 0 = LED on for(;;){ // Repeat indefinitely USART_SendByte(value); // send value _delay_ms(250); // delay just to stop Hyperterminal screen cluttering up } }

If you found this information useful, please give us a mention or share it on Social media.










AVR Studio


Create a C project in AVRStudio and make sure the AVR microcontroller is the one you want to use. WinAVR C is very fussy about the correct device and although the code will compile, it will not run properly unless the AVR microcontroller type is correct

To change AVR microcontroller, go to Project > Configuration Options and select correct AVR.
Note that only the C Compiler project changes, not main project device type. Also change
Optimization to -0s otherwise compiler has problems with delay routines.

Connect to PC via standard serial cable, not Nul-modem cable. Run Hyper Teminal (Programs > Accessories > Communications) and create New connection, with Connect Using set to COM1 (or other COM Port). In COM1 Properties set Baud Rate to 38400, Data bits to 8, no Parity, 1 stop bit
and no flow control.

#define F_CPU 8000000UL // 8 MHz /*Very Important - change F_CPU to match target clock Note: default AVR CLKSEL is 1MHz internal RC This program transmits continously on USART. Interrupt is used for Receive charactor, which is then transmitted instead. LEDs are used as a test. Normal RX routine is included but not used. Change USART_BAUDRATE constant to change Baud Rate */ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // Define baud rate #define USART_BAUDRATE 38400 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) volatile unsigned char value; /* This variable is volatile so both main and RX interrupt can use it. It could also be a uint8_t type */ /* Interrupt Service Routine for Receive Complete NOTE: vector name changes with different AVRs see AVRStudio - Help - AVR-Libc reference - Library Reference - <avr/interrupt.h>: Interrupts for vector names other than USART_RXC_vect for ATmega32 */ ISR(USART_RXC_vect){ value = UDR; //read UART register into value PORTB = ~value; // output inverted value on LEDs (0=on) } void USART_Init(void){ // Set baud rate UBRRL = BAUD_PRESCALE;// Load lower 8-bits into the low byte of the UBRR register UBRRH = (BAUD_PRESCALE >> 8); /* Load upper 8-bits into the high byte of the UBRR register Default frame format is 8 data bits, no parity, 1 stop bit to change use UCSRC, see AVR datasheet*/ // Enable receiver and transmitter and receive complete interrupt UCSRB = ((1<<TXEN)|(1<<RXEN) | (1<<RXCIE)); } void USART_SendByte(uint8_t u8Data){ // Wait until last byte has been transmitted while((UCSRA &(1<<UDRE)) == 0); // Transmit data UDR = u8Data; } // not being used but here for completeness // Wait until a byte has been received and return received data uint8_t USART_ReceiveByte(){ while((UCSRA &(1<<RXC)) == 0); return UDR; } void Led_init(void){ //outputs, all off DDRB =0xFF; PORTB = 0xFF; } int main(void){ USART_Init(); // Initialise USART sei(); // enable all interrupts Led_init(); // init LEDs for testing value = 'A'; //0x41; PORTB = ~value; // 0 = LED on for(;;){ // Repeat indefinitely USART_SendByte(value); // send value _delay_ms(250); // delay just to stop Hyperterminal screen cluttering up } }

If you found this information useful, please give us a mention or share it on Social media.






0 thoughts on “Avr Uart Sample Cover Letter”

    -->

Leave a Comment

Your email address will not be published. Required fields are marked *