Avr Tutorial
Avr Tutorial
Introduction Application and programmer boards WinAVR Basic I/O ADC, timers USART, LCD
Mehul Tikekar Chiraag Juvekar Electronics Club May 26, 2010
What is a microcontroller?
It is essentially a small computer Compare a typical microcontroller (uC) with a typical desktop
ATmega16 Typical desktop
AVR microcontroller
http://www.instructables.com/id/How-to-choosea-MicroController/ AVR: Cheap, easy to use, fast and lots of features ATmega16:
o 16KB flash memory o 1KB SRAM o Up to 16MHz clock o Four 8-bit I/O ports o ADC, timers, serial interface, etc. o 40 pin DIP, VDD = 5V
4
Port B
Port A
Reset Power
Crystal Oscillator
Power
Port D
Port C
Interrupts Timer 1
WinAVR
Hardware
Programmer board Application board
WinAVR
A complete package for Windows
Programmers Notepad (user interface) avr-gcc (C/C++ compiler) Mfile (makefile generator) avrdude (programmer software)
10
USBasp
11
On a bread-board
IC1
14
USBasp
15
The ATmega16 datasheet a 358 page bible Tutorials and sample codes:
1. 2. 3. http://www.avrtutor.com http://winavr.scienceprog.com http://kartikmohta.com/tech/avr/tutorial
17
Hello world
4.
5. 6.
Relevant registers : DDR set pin data direction PORT set pin output PIN read pin input
18
blink.c
#include <avr/io.h> // contains definitions for DDRB, PORTB #include <util/delay.h> // contains the function _delay_ms()
int main(void) { DDRB = 0b11111111; // set all pins on PortB to output while(1) { PORTB = 0b00000001; // Set PortB0 output high, others low _delay_ms(250); // Do nothing for 250 ms PORTB = 0b00000000; // Set all of them low _delay_ms(250); // Do nothing for 250 ms } return 0; }
/* DDRB is a 8-bit register which sets direction for each pin in PortB PORTB decides output for output pins 0b prefix for binary numbers, 0x hex, no prefix - decimal Thus, 15 = 0xf = 0b1111
*/
19
Save the code as blink.c in a separate folder (not strictly necessary, just a good practice) Create a makefile using Mfile and save in the same folder Open it in Programmers Notepad and change:
Line 44: MCU = atmega16 Line 65: F_CPU = 1000000 Line 73: TARGET = blink, Line 83: SRC = $(TARGET).c Alternatively, TARGET = anything_you_want and SRC = blink.c Line 278: AVRDUDE_PROGRAMMER = usbasp Line 281: AVRDUDE_PORT = usb
In Programmers Notepad, Tools > Make All to compile Connect USBasp to computer and ATmega16 Tools > Program to program ATmega16
20
A better code
#include <avr/io.h> #include <util/delay.h> int main(void) { DDRB = DDRB | 0b00000001; // Set PortB0 as output, leave other pin directions unchanged while(1) { PORTB = PORTB | 0b00000001; // Set output high without affecting others _delay_ms(250); PORTB = PORTB & 0b11111110; // Set output low without affecting others _delay_ms(250);
}
return 0; }
Try this out : Toggle the pin instead of set and clear
21
_delay_ms(250);
} return 0; }
22
{
DDRB |= _BV(PB1); while(1) { // x |= y; is same as x = x|y;
Try these out: Blink LED on PortB1 if PortB0 is high, else turn LED off. What happens when an input pin if left floating?
23
8 8 16 16
32 64 32
1. Since AVR is an 8-bit uC, char and unsigned char are natural data types 2. int should be used only when the range of char is not sufficient 3. Replace floating point operations by int or char operations wherever possible. e.g. Instead of y = x*0.8, use y = (x*4)/5 4. Take care of overflow. Stay within the range of the data-type used 5. Beware of integer round-off
24
Converts an analog voltage VIN to a digital number ADC_Data 10-bit conversion result Conversion time = 13.5 * ADC clock period Up to 15k conversions per sec 8 inputs (Port A)
ADC_Data
1023 4 3 2 1 0 0 VREF
ADC _ Data
VIN
25
Setting up the ADC Select reference voltage : REFS1:0 Select prescaler : ADPS2:0 Select output format (left adjust/right adjust) : ADLAR Enable the ADC : ADEN
26
adcroutines.c
#include <avr/io.h> void adc_init(void) { DDRA = 0x00; // Set all PortA pins to input PORTA = 0x00; // Disable pull-ups ADMUX = _BV(REFS0) | _BV(ADLAR); ADCSRA = _BV(ADEN) |_BV(ADPS2)|_BV(ADPS1); /* Use AVcc as reference, Left adjust the result Enable the ADC, use prescaler = 64 for ADC clock */ }
unsigned char adc_read (unsigned char channel) // valid options for channel : 0 to 7. See datasheet { ADMUX = (ADMUX&0xe0) + channel; // Set channel bits in ADMUX without affecting other bits ADCSRA |= _BV(ADSC); // Start conversion while((ADCSRA & _BV(ADSC)) != 0) {}; // Do nothing until conversion is done return(ADCH); // Return upper 8 bits }
Try these out : Control the blinking speed using potentiometer Try the other ADC options : Free running, Auto-trigger, different channels, prescalers, etc.
27
Alpha-numeric display with backlight 16 columns x 2 rows (larger sizes available too) 8-bit data interface, 3 control signals For pin-starved applications : 4-bit data interface +5V supply, separate power for backlight Readymade libraries available Working with multiple files
1. main.c the main code
2.
3.
29
On the bread-board
30
lcdroutines.h
// Connections between uC and LCD #define DATA_DDR DDRC #define DATA_PORT PORTC #define #define #define #define CONTROL_DDR CONTROL_PORT RS E DDRD PORTD PD6 PD7
/* Function prototypes for interfacing to a 16x2 LCD Actual functions in lcdroutines.c */ void lcd_init(void); // Initialize the LCD void lcd_clear(void); // Clear LCD and send cursor to first char void lcd_home(void); // Send cursor to first character void lcd_command(unsigned char command); // Send command to LCD void display_char(unsigned char data); void display_byte(unsigned char num); void display_int(unsigned int num); // Display ASCII character // Display number 0 - 255 // Display number 0 - 65535 // Move cursor
31
Codes:
1.
2. 3. 4. 5.
lcd1.c
#include <avr/io.h> #include "lcdroutines.h" int main(void) { unsigned char a[] = {"Hello World!"}; lcd_init(); for(unsigned char i =0;i<sizeof(a)-1;i++) display_char(a[i]); while(1); return 0; }
32
Interrupts
Suppose you are making an obstacle avoiding robot. Drive motors continuously, and stop immediately when obstacle is detected.
while(1) { drive_motors();
if(obstacle_detected()) stop_motors();
}
No obstacle detection when driving motors. Might miss the obstacle and crash!
while(1) { drive_motors();
while(!obstacle_detected()) {};
stop_motors(); }
33
Run motor-driving routine in the main loop. Interrupt it when obstacle is detected.
ISR(vector_name) {
stop_motors();
} int main(void)
{
initialize_interrupt(); while(1) {
drive_motors();
} }
34
Interrupts explained
Interrupt is a special function which gets called when a specific hardware condition is met. When condition is met, an interrupt flag is set in a specific register. If interrupt is enabled, the interrupt flag signals the muC to stop executing main program and jump to an interrupt service routine (ISR). After ISR is done, CPU resumes main program from where it left. Possible conditions that can cause interrupts Voltage change on pins INT0, INT1 and INT2. (External interrupt) ADC conversion complete, Timer, UART, etc. (Internal interrupt)
In ISR(vector name), vector name depends on which interrupt condition is being used. Get the vector name from avr-libc manual : WinAVR_installation_path/doc/avr-libc/avr-libc-usermanual/group__avr__interrupts.html
35
#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> volatile unsigned char i=0; /* Declare variables being used in ISR as global and voltatile */ ISR(INT0_vect) { PORTC |= _BV(PC6); PORTC &= ~(_BV(PC0)); i++; } int main(void) { DDRD = ~(_BV(PD2)); PORTD = _BV(PD2); // Set PortD2 (INT0) as input // Enable pullup on INT0 // Need to include this for interrupts
36
Timer clock
Compare value
Counter register
37
Timer/counters in ATmega16
ATmega16 has 3 timer/counters : 0, 1 and 2 0 and 2 are 8-bit counters, 1 is a 16-bit counter Each T/C has different modes of operation : normal, CTC and PWM Special waveform generation options : variable frequency pulses using CTC, variable duty-cycle pulses using PWM
38
Select mode of operation : Normal Select prescaler Select the event which causes the interrupt Set the time delay to interrupt every 250ms Relevant registers for Timer 1:
TCNT1 : 16-bit count register TCCR1A : Mode of operation and other settings
39
timer1blink.c
#include <avr/io.h> #include <avr/interrupt.h>
void timer1_init(void) { TCCR1B = _BV(CS11); TIMSK = _BV(OCIE1A); } ISR(TIMER1_COMPA_vect) { PORTB ^= _BV(PB0); OCR1A += 31250; return; // Initialize timer
// ISR for T/C1 Compare Match A interrupt // Toggle pin /* Increment Compare Match register by 250ms*1MHz/8 = 31250 */ // return to main code
}
int main(void) { DDRB = _BV(PB0); timer1_init(); sei(); while(1) {}; return 0; }
// // // //
Set pin to output Initialize timer Enable global interrupts Do anything you want here
40
CTC mode
OCR1A TCNT1
Try these out: Use CTC instead of Normal mode to blink LED Now control the blinking speed using potentiometer
41
Apply a variable duty-cycle high frequency clock to the LED Duty-cycle decides the brightness of the LED Timer 1 in PWM mode Special output pins OC1A (PD5) and OC1B (PD4) Function of output pins depends on the compare output mode : COM1A and COM1B bits in TCCR1A No interrupt is needed
TOP OCR1A TCNT1 Overflow interrupt flag is set t OC1A pin Compare match interrupt flag is set
5V 0V
42
43
ledbrightness.c
#include <avr/io.h> void timer1_init(void) { TCCR1A = _BV(WGM10) | _BV(COM1A1); // Fast 8-bit non-inverting TCCR1B = _BV(WGM12) | _BV(CS11); OCR1AH = 0; } int main(void) { DDRD |= _BV(PD5); timer1_init(); // Necessary to set DDR value for PD5 // PWM with prescaler = 8
adc_init();
return 0; }
Try this out: Use CTC mode instead of PWM mode and change blinking speed instead of brightness without using interrupts
44
USART
Universal Synchronous and Asynchronous serial Receiver and Transmitter Serial communication : one bit at a time. Communication speed : baud rate (number of bits per sec) Master
RxD TxD
Slave
TxD RxD XCK
Master and slave can be microcontrollers, computers or any electronic device with a USART interface Computer serial port uses UART protocol. Connection between uC and computer can be used for data-logging, sending commands, etc. Programs like HyperTerminal, Tera Term, Brays terminal are available for using serial port in Windows
45
uC to computer
MAX232
R1OUT T1IN R1IN T1OUT -13V +13V
46
serial port
MAX232
47
Relevant registers
Control and status registers UCSRA, UCSRB, UCSRC Baud rate registers UBRRH, UBRRL Data register UDR (2 registers by the same name)
Initialize UART
Enable transmitter and receiver Set baud rate typically 2400 bps Frame length 8bits Other settings 1 stop bit, no parity bits
Transmit data
Check if data register is empty (UDRE bit in UCSRA) Write data to data register UDR
Receive data
Check if receive is complete (RXC bit in UCSRA) Read UDR
48
UART functions
#include <avr/io.h> void uart_init( unsigned int ubrrval ) // ubrrval depends on uC clock frequency and required baudrate { UBRRH = (unsigned char) (ubrrval>>8); // set baud rate UBRRL = (unsigned char) ubrrval; // set baud rate UCSRB = _BV(RXEN) | _BV(TXEN); /* Enable UART receiver and transmitter, 8-bit data length, 1 stop bit, no parity bits */ } unsigned char uart_rx( void ) { while ( !(UCSRA & _BV(RXC)) ); return UDR; } void uart_tx( unsigned char data ) { while ( !(UCSRA & _BV(UDRE)) ); UDR = data; }
49
2.
3. 4. 1. 2. 3.
Some pins on PortC arent working properly: Disable JTAG using fusebits.
50
4. Check if there is too much noise on the input and reference. 5. Keep pull-ups disabled (PORTA = 0)
Mathematical operations give incorrect results:
for(int i= 0;i<50000;i++) is an infinite loop since the maximum value of an int is 32767. Read the Atmel application note on Efficient C Coding for AVR. Important precautions:
1.
Be extra careful when using USB power for powering the uC. Shorting the supply may damage the USB port. Use external 5V regulated power to be safe. Connect power, programmer and other connectors in the correct location and correct polarity. Use matching male-female connectors as far as possible as they do not allow reverse connection. Do not short output pins to any supply or other outputs. AVRs have some amount of ESD (electrostatic discharge) protection. But, still, do not touch them if you are charged, say by wearing a woolen sweater.
2.
3. 4.
52
1.
2. 3.
http://www.avrtutor.com
http://winavr.scienceprog.com http://kartikmohta.com/tech/avr/tutorial