Buscar

Tutorial AVR - ATmega 8

Prévia do material em texto

Tutorial – Microcontroladores AVR – Atmega8 
Instrumentação – UnBall 
Engenharia Mecatrônica – Universidade de Brasília 
 
 
 
Integrantes: José Oniram Limaverde 
 João Vitor Vilela 
 David Bevilaqua 
 Heyder Araújo 
 Tiago Silva 
 
12 de Abril de 2010 
 
 
Sumário 
1. Introdução 
2. Microcontrolador Atmel AVR ATmega8 
2.1 Arquitetura AVR RISC 
2.2 Memória EEPROM 
2.3 Memória Flash 
2.4 Memória SRAM 
2.5 Registradores do Avr 
3. Tipos de Variáveis 
4. Arquitetura de um Programa 
4.1 Estrutura Fundamental de um Programa 
4.2 Códigos Exemplos 
5. Registradores e Comandos I/O 
5.1 Registradores I/O 
5.2 Acesso às portas 
6. Interrupções 
6.1Funcionamento Básico 
6.2 Registradores de Controle 
6.3 Códigos Exemplos 
7. Timers/Counters 
7.1Características dos Temporizadores 
7.2 Códigos Exemplos 
8. USART 
8.1 Registradores de Controle 
8.2 Códigos Exemplos 
9. Conclusões 
10. Bibliografia 
 
1. Introdução 
Na área de Controle e Automação, a necessidade de alguma unidade de processamento se tornou 
algum imprescindível nas mais diversas aplicações. Dentre essas, os microcontroladores se destacam 
como uma alternativa de menor custo, confiabilidade satisfatória, simplicidade, menor consumo de 
energia, no entanto, com limitada capacidade de memória e processamento. 
Um microcontrolador contém um processador, acesso a memória e periféricos de entrada/saída. 
É um microprocessador que pode ser programado para funções específicas, em contraste com outros 
microprocessadores de propósito gerais (como os utilizados nos PCs). Basicamente, o uso de um 
microcontrolador consiste no processamento de dados obtidos em um de seus periféricos, tendo como 
saída outro conjunto de dados. Por exemplo, envio de dados via porta serial ou gerar uma reação no 
sistema como acender um led. 
A arquitetura de um microcontrolador em geral consiste em um núcleo de processamento, 
barramento e periféricos: 
 Núcleo de processamento consiste no processador de dados (cálculos, controle de fluxo 
de programa, etc) e na administração dos periféricos. 
 Barramento é dividido em dados e endereços, consiste nas linhas de comunicação entre o 
processador e os periféricos. 
 Periféricos caracterizam o conjunto de funcionalidades disponíveis pelo microcontrolador 
e são controlados pelo processador. Por exemplo, memória, porta serial, porta paralela e 
conversor AD. 
Microcontroladores são geralmente utilizados em automação e controle de produtos e 
periféricos, como sistemas de controle de motores automotivos, controles remotos, máquinas de 
escritório e residenciais, brinquedos, sistemas de supervisão, etc. Dentre os disponíveis no mercado, 
destaca-se a família de microcontroladores AVR da Atmel, em especial o modelo ATmega8, o qual 
vai ser utilizado nos projetos do grupo de Instrumentação da UnBall. 
 
 
 
 
 
 
 
 
 
2. Microcontrolador Atmel AVR ATmega8 
O ATmega8 é um microcontrolador de 8-bit com baixo consumo de tecnologia CMOS e 
arquitetura RISC. Apresenta a capacidade de executar uma instrução por ciclo de relógio devido à 
conexão direta de seus 32 registradores gerais com a unidade lógica aritmética e uma freqüência de 
funcionamento numa faixa de 0 a 20 MHz. Além disso, apesar de ser RISC, possui um grande 
número de instruções, o que permite melhor otimização do código de alto nível em linguagem C. 
Outras características que permitem a maximização do desempenho e do paralelismo são a 
arquitetura Harvard e a técnica do pipeline Além disso, destacam-se a presença de memórias Flash, 
EEPROM e SRAM, de três temporizadores/contadores e acionar interrupções. \ 
2.1 A Arquitetura AVR RISC 
A arquitetura RISC, (Reduced Instruction Set Computer), requer menos instruções que, por 
exemplo, a tradicional arquitetura CISC, permitindo que os sistemas, nela baseados, possam rodar 
mais rápido porque o microprocessador tem funções limitadas, em benefício de seu desempenho. 
O AVR utiliza o conceito de arquitetura Harvard na qual os barramentos de dados e de 
instruções são fisicamente separados. A memória de programa é executada em pipeline de dois 
estágios. Enquanto uma instrução está sendo executada, a próxima instrução é previamente buscada 
da memória de programa. Esse conceito habilita a execução de instruções em todo ciclo de clock. 
A memória de programa é do tipo flash, ou seja, com as instruções relativas de “jump” e “call”, 
todo o espaço de endereçamento de 8 K é diretamente acessado. A maioria das instruções AVR tem 
um único formato de palavra de 16-bit. Todo endereço da memória de programa contém uma 
instrução de 32-bit. 
2.2 Memória EEPROM 
A EEPROM presente no AVR possui 512 bytes e está ligada ao barramento de dados 8-bit 
interno permitindo que possa ser escrita diretamente sobre o microcontrolador durante o processo de 
gravação ou que o próprio microcontrolador escreva os dados nas posições desta memória. O tempo 
de acesso de gravação é em média de 2,5 a 4ms, dependendo da tensão a qual é submetida. 
2.3 Memória Flash 
A memória flash ou flash ROM pode ser definida como uma EEPROM que utiliza baixas 
tensões de apagamento, e este é feito em um tempo reduzido. O apagamento da memória flash é 
extremamente rápido e, ao contrário da EEPROM, não é possível reprogramar apenas um único 
endereço, isto é, quando a memória é apagada, todos os seus endereços são zerados. O AVR 
apresenta 8 Kbytes de memória Flash Programável on-chip para armazenamento de programas. 
2.4 Memória SRAM 
As informações existentes em uma memória RAM (Random Access Memor) não são estáveis 
e, caso não sejam salvas fisicamente, são perdidas ao se desligar o computador. Os 608 endereços 
baixos pertencem às alocações da Memória de Dados do Register File, à Memória de I/O e a SRAM 
interna. Os primeiros 96 endereços representam o Register File + Memória de I/O, e os próximos 512 
endereços a SRAM interna. 
2.5 Registradores do AVR 
Uma característica básica é a presença de um grupo de registradores internos. A arquitetura 
AVR, apresenta 32 registradores de 8 bits, que podem ser manipulados tanto para leitura como para 
escrita, como 16 palavras de 16-bit. Há também os registradores de I/O, os quais são em número de 
64 e podem ser endereçados diretamente em instruções de apenas um ciclo de clock. 
O grupo de instrumentação propõem o desenvolvimento de um tutorial sobre as diversas 
funcionalidades que o ATmega8 pode oferecer para o usuário. Além disso, introduzir alguns 
conhecimentos básicos sobre a arquitetura de um programa e sobre comandos de entrada/saída. 
A partir desse tutorial, o grupo acredita ser possível que os próximos integrantes do mesmo 
possam adquirir informações importantes para manter a continuação dos projetos em 
desenvolvimento. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3. Tipos de Variáveis 
Para fazer o processamento, muitas vezes é necessário uso de variáveis para armazenar valores a 
serem usados posteriormente. Como a memória é limitada, é interessante que o compilador saiba o 
tanto de espaço na memória para reservar em relação a cada tipo de variável, e que o programador 
saiba utilizá-las de forma a otimizar o uso de memória. 
O compilador gcc-avr nos permite a criação dessas variáveis através de funções que alocam 
essas variáveis em endereços na memória do microcontrolador. A biblioteca referenciada pelo 
cabeçalho inttypes.h, define os seguintes tipos: 
typedef signed char int8_t; 
typedef unsigned char uint8_t; 
typedef short int16_t; 
typedef unsigned short uint16_t; 
typedef long int32_t; 
typedef unsignedlong uint32_t; 
typedef long long int64_t; 
typedef unsigned long long uint64_t; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4. Arquitetura de um Programa 
4.1 Estrutura Fundamental de um Programa 
Existem basicamente dois métodos de se escrever um programa, independentemente da 
linguagem utilizada, para um microcontrolador: Programação Seqüencial e Programação com 
Interrupções Controladas. 
4.1.1 Programação Seqüencial 
 Nessa técnica, temos que o programa fica envolvido por um laço continuo em que os dados de 
saída retornam rotina inicial indefinidamente, como observado na Figura 4.1. 
 
Figura 4.1 – Estrutura básica de um programa seqüencial 
4.1.2 Programação com Interrupções Controladas 
Neste método, primeiramente, são ativadas as entradas das interrupções para permitir a utilização 
das mesmas. Assim, dentro do loop contínuo do programa, temos que, se uma interrupção é ativada, 
automaticamente o código referente à interrupção é executado. 
 
Figura 4.2 – Estrutura básica de um programa com interrupção controlada 
4.2 Códigos exemplos 
Uma simples implementação de um programa seqüencial pode ser visualizado na Figura 5.3. O 
loop contínuo é caracterizado pelo while(1) {} em que toda seqüência do código deve está presente 
em seu interior. 
 
Figura 4.3 – Exemplo de um programa seqüencial 
Para um programa com interrupções controladas, temos uma implementação que pode ser 
visualizada na Figura 4.4. Neste caso, temos que o programa responde a uma interrupção externa, a 
qual é feita através de um botão para alterar o estado de um LED. 
 
Figura 4.4 – Exemplo de um programa com interrupção controlada 
 
 
 
5. Registradores e Comandos I/O 
Os microcontroladores AVR possuem múltiplos registradores, mas a maior parte deles é 
utilizada para entrada/saída. Outros possuem funções especiais e alguns para acesso de dados na 
memória do microcontrolador. 
Além disso, há registradores exclusivos em alguns modelos de AVR. Os nomes dos registradores 
são definidos nos header files para os tipos apropriados de AVR, por exemplo, #include<avr/io.h>. 
 
5.1 Registradores I/O 
Os registradores de I/O são bastante utilizados para as diversas funções de controle no AVR. 
Eles controlam os acessos as portas e as interfaces com o microcontrolador. Deve-se ressaltar que há 
diferenciação entre os registradores de 8-BITS e os de 16-BITS. 
5.1.1 Leitura de um registrador de I/O 
Para leitura, podem-se acessar os registradores de I/O como simples variáveis. Em códigos 
fonte, o acesso de leitura é feito pela função inp(). Em versões mais atuais do compilador o acesso 
pode ser feito de forma direta e a função inp() não é mais necessária, como observado no código 
abaixo. 
#include <arv/io.h> 
 
Uint8_t foo; 
... 
 
int main(void) 
{ 
 // Copia o status dos pinos da porta B na variavél foo 
 foo = PINB 
 ... 
} 
5.1.2 Leitura de um bit 
A biblioteca do AVR possui funções para averiguação de um bit individual do registrador: 
bit_is_set (<Register>, <Bitnumber>): 
A função examina se um bit foi ativado, retornando um valor diferente de 0. 
bit_is_clear (<Register>, <Bitnumber>): 
A função examina se o bit foi desativado, retornando um valor diferente de 0. 
5.1.3 Escrevendo em um registrador I/O 
Para escrita, podem-se acessar os registradores de I/O como simples variáveis. Em códigos fonte 
o acesso de leitura é feito pela função outp(). Em versões mais atuais do compilador o acesso pode 
ser feito de forma direta e a função outp() não é mais necessária, como observado a seguir. 
#include <arv/io.h> 
... 
int main(void) 
{ 
 DDRA = 0xff; // Define todos os pintos como saída 
 PORTA = 0x03 // Define o nivel de lógico de cada saída 
 ... 
} 
5.1.4 Escrita de Bits 
Uma das maneiras de se alterar o valor de um bit individual é através de operações lógicas. 
 
X |= (1 << BitNumber); // A bit in X is set 
X &= ~(1 << BitNumber); // A bit is deleted in X 
 
No exemplo abaixo, temos que o segundo bit do registrador está sendo ativado e, em seguida, 
está sendo desativado. 
#include <arv/io.h> 
#define MyBIT 2 
 
PORTA |= (1 << MyBIT); // O bit 2 da Porta A é igual a 1 
PORTA &= ~(1 << MyBIT); // O bit 2 da Porta A é igual a 0 
5.2 Acesso às portas do AVR 
Há três endereços de memória (registradores) que são alocados para cada uma das portas do 
AVR: PORTx (Data Register), DDRx (Data Direction Register) e PINx (Port Inputs Pins). Este 
último só é utilizado para leitura enquanto que os outros dois podem ser utilizados tanto para leitura 
como escrita. Estes estão especificados na Tabela 5.1. 
Tabela 5.1 – Registradores para direcionar as portas do Avr 
 
Para definir os pinos de 0 a 4 da porta B como saída, podemos utilizar os seguintes comandos: 
DDRB=0x0F; ou DDRB = (1 << DDB0)|(1 << DDB1)|(1 << DDB2)|(1 << DDB3); 
Assim, para definir uma saída de nível lógico alto, podemos utilizar os seguintes comandos: 
PORTB |=(1 << PB2)|(1 << PB4); 
6. Interrupções 
Interrupções são eventos de software ou de hardware que ocasionam uma mudança no fluxo do 
programa para uma sub-rotina que tratará esse evento. 
6.1 Funcionamento Básico 
Após ocorrer o evento de interrupção, o programa é desviado (instrução “jump”), para um 
endereço fixo pré-definido para cada CPU. Cada tipo de evento tem um endereço distinto, dessa 
forma o compilador avr-gcc dispõe da macro ISR( _vect ) que, a partir do vetor de interrupção, se 
encarrega de carregar o código no endereço destinado a interrupção. Os eventos que podem 
ocasionar uma interrupção, junto com respectivos vetores de interrupção, são: 
RESET 
External interrupt 0 - (INT0_vect) 
External interrupt 1 - (INT1_vect) 
Timer/Counter 2 Compare match - (TIMER2_COMP_vect) 
Timer/Counter 2 overflow - (TIMER2_OVF_vect) 
Timer/Counter 1A Compare match - (TIMER1_COMPA_vect) 
Timer/Counter 1B Compare match - (TIMER1_COMPB_vect) 
Timer/Counter 1 overflow - (TIMER1_OVF_vect) 
Timer/Counter 0 overflow - (TIMER0_OVF_vect) 
UART indication receive - (USART_RXC_vect) 
UART indication sent - (USART_TXC_vect) 
UART data pointer empty - (USART_UDRE_vect) 
 
Versões antigas no iom8.h 
 
6.2 Registradores de Controle 
No AVR, as interrupções são controladas por registradores específicos. 
I) MCU Control Register - MCUCR 
 
Este registrador contém os bits de controle para interrupções e funções gerais do MCU. 
Bit 3,2 – ISC11, ISC10: Interrupt Sense Control 1 Bit 1 and Bit 0 
A interrupção externa 1 é ativada pelo pino INT1 (PD3) caso o 1-bit de SREG e a mascara de 
interrupção correspondente no registrador GICR está ativados. Para mais informações de como gerar 
uma interrupção a partir de INT1, observar a Tabela 6.1. 
Tabela 6.1 – Bits de controle para a interrupção externa 1 
 
Bit 1,0 – ISC01, ISC00: Interrupt Sense Control 0 Bit 1 and Bit 0 
A interrupção externa 0 é ativada pelo pino INT0 (PD2) caso o 1-bit de SREG e a mascara de 
interrupção correspondente no registrador GICR está ativados. Para mais informações de como gerar 
uma interrupção a partir de INT0, observar a Tabela 6.2. 
Tabela 6.2 – Bits de controle para a interrupção externa 0 
 
II) General Interrupt Control Register - GICR 
 
Bit 7 – INT1 – External Interrupt Request 1 
Quando este bit é ativado junto com o 1-bit de SREG, temos que o pino de interrupção externa é 
ativado, no caso, o pino PD3. Os bits de controle ISC11 e ISC10 vão definir o modo como a 
interrupção será ativada. 
Bit 6 – INT0 – External Interrupt Request 0 
Quando este bit é ativado junto com o 1-bit de SREG, temos que o pino de interrupçãoexterna é 
ativado, no caso, o pino PD2. Os bits de controle ISC01 e ISC00 vão definir o modo como a 
interrupção será ativada. 
III) General Interrupt Flag Register - GIFR 
 
Bit 7 – INTF1 – External Interrupt Flag 1 
Quando um evento no pino INT1 dispara um pedido de interrupção, temos que ITNF1 é ativado. 
Se o 1-bit de SREG e o bit INT1 do GICR estão ativados, o MCU vai para o correspondente vetor de 
interrupção. O flag é desativado quando a rotina de interrupção é executada. 
Bit 6 – INTF0 – External Interrupt Flag 0 
Quando um evento no pino INT0 dispara um pedido de interrupção, temos que ITNF0 é ativado. 
Se o 1-bit de SREG e o bit INT0 do GICR estão ativados, o MCU vai para o correspondente vetor de 
interrupção. O flag é desativado quando a rotina de interrupção é executada. 
6.3 Códigos exemplos 
Para nosso exemplo, utilizaremos a interrupção para alterarmos o valor dos pinos da porta B à 
medida que fazemos uma transição de 0 para 5V na porta PD2. Antes de qualquer coisa habilitamos a 
interrupção geral no registrador SREG (Status-Register, Accumulator flags) através do comando 
sei(), para mais detalhes: http://www.avr-asm-tutorial.net/avr_en/beginner/PDETAIL.html#top. 
Ativando a habilitação geral, definimos os registradores de controle para podermos perceber a 
interrupção em INT0 na borda de subida. Observemos que, logo após configurarmos, um loop 
infinito em um for é iniciado, isso é, para mostrar que o processamento não ficará gastando 
processamento com esse evento e ele só irá para o endereço de INT0_vect, quando o evento 
ocorrer, ou seja, a rotina principal poderá atender outras possíveis prioridades. 
// Funcao que responde aa interrupcao externa 0 
ISR(INT0_vect) 
{ 
 PORTB = ~PORTB; 
} 
 
int main(void) 
{ 
 // Configurando a interrupcao 
 sei(); // habilitacao global das interrupcoes 
 MCUCR = _BV(ISC01) | _BV(ISC00); // Transicao positiva em PD2 
(INT0) 
 GICR = _BV(INT0); // habilita interrupcao INT0 
 DDRB = _BV(DDB1); // Definindo Port B como saída 
 
 for(;;) 
 { } 
} 
 
Por último, é comum encontrarmos exemplos que usam as macros INTERRUPT() ou SIGNAL() 
em programas mais antigos. A diferença de uma e da outra é que a primeira permite que outras 
interrupções ocorram durante outra interrupção que ainda está sendo executada, enquanto que a 
segunda não permite assim como IST() que é a versão mais nova de SIGNAL(). 
 
 
7. Timers/Counters 
Os timers são facilidades presentes no AVR responsáveis por realizar contagens de eventos 
externos, geração de freqüência e de sinais PWM (Pulse Width Modulation) e outros. 
Em termos simples, todos os timers incrementam ou decrementam em 1 o valor de um 
registrador (TCNTx) para cada pulso de clock. Assim, o que nós podemos fazer com esses valores é 
que se torna bastante interessante. 
Tais valores podem ser o máximo valor disponível pelo contador, constantes, valores de outros 
registradores ou zero. O AVR compara continuamente o valor do contador com algum outro 
especificado por nós e, assim, pode realizar algum evento caso ocorra uma igualdade. 
Cada timer difere na sua resolução (8 bits ou 16 bits), nos valores que podemos definir como 
TOP, em quais I/O pinos são acessíveis pelo contador e quais eventos os timers podem fornecer 
durante a contagem. Estes eventos podem ativar certo tipo de interrupção (a qual é a única forma para 
executar um código arbritário) ou set/clear/toggle o valor de um I/O pino. 
Há três tipos de timers no ATmega8: timer0 (8-bit), timer1 (16-bit) e timer2 (8-bit). O timer2 
tem acesso a um I/O pino (OC2) e o timer1 tem acesso a dois I/O pinos (OC1A e OC1B). Enquanto 
que o timer0 não possui acesso externo. 
A contagem para cada um é armazenada no registrador TCNTx. Os contadores sempre 
incrementam a partir do zero, exceto quando decrementam durante a segunda metade do modo 
“Phase Correct PWM” em que os timers 1 e 2 são capazes de fazer. O timer0 sempre incrementa. Há 
alguns registradores que são compartilhados pelos três temporizadores como o TIFR (Timer/Counter 
Interrupt Flag Register) e TIMSK (Timer/Counter Interrupt Mask Register), os quais são 
responsáveis por controlar a execução de interrupções. 
7.1 Características dos Temporizadores 
7.1.1 Timer0 
7.1.1.1 – Características Gerais 
É o mais simples dos temporizadores no ATmega8 e não possui acesso a I/O pino. Assim, ele 
não pode ser utilizado diretamente para PWM ou como um gerador de freqüência externa. O 
registrador que armazena o valor da contagem é o TCNT0. 
Em relação à forma que o contador pode ser clockeado, depende de valores atribuídos aos bits 
CS02:0 que estão definidos no registrador de controle do timer0 (TCCR0). Basicamente, há duas 
formas: internamente (diretamente ou por frações do clock interno) ou externamente. 
De qualquer forma, o timer0 não apresenta uma unidade de comparação, ou seja, ele 
simplesmente inicia a contagem de 0 (BOTTOM) a 255 ou 0xFF (MAX) repetidamente. Há somente 
uma interrupção quando ocorre overflow (retorna de 255 a 0). Além disso, a freqüência de operação é 
igual a de entrada divida por 256. 
 
7.1.1.2 – Timer/Counter Register Description 
I) Timer/Counter Control Register 0 – TCCR0 
 
Bit 2:0 – CS02:0 – Clock Select 
Esses três bits selecionam a fonte do clock a ser usado pelo contador. Para informações 
complementares, observar Tabela 7.1. 
Tabela 7.1 – Clock Select Bit Description 
 
II) Timer/Counter Register 0 – TCNT0 
 
 
Oferece direto acesso e permite operações de escrita e leitura para o contador. 
 
III) Timer/Counter Interrupt Mask Register – TIMSK 
 
No caso do timer0, somente o bit 0 se referem a ele. 
Quando o TOIE0 (Timer/Counter0 Overflow Interrupt Enable) é ativado, temos que uma 
interrupção pode ser executada se ocorrer um overflow no timer2. 
 
IV) Timer/Counter Interrupt Flag Register – TIFR 
 
No caso do timer0, somente o bit 0 se refere a ele. 
TOV1 (Timer/Counter2 Overflow Flag 1) é ativado quando ocorre um overflow no timer0 e 
pode ser utilizado para que uma interrupção seja executada neste instante, logo TOIE0 também precisa 
está ativado. 
7.1.2 Timer2 
7.1.2.1 – Características Gerais 
O MAX para o timer2 é 255 já que ele possui uma resolução de 8 bits. É possível determinar o 
TOP de duas formas: 0xFF (MAX) ou qualquer valor armazenado no registrador OCR2. Este contador 
incrementa na maioria das vezes, mas, no modo “Phase Correct PWM” ele pode decrementar. 
Algumas definições bastante utilizadas, as quais podem ser visualizadas na Tabela 7.2. 
Tabela 7.2 – Definições padrão para o timer2 
 
A Unidade de Comparação continuamente compara TCNT2 com OCR2. Toda vez que ocorre 
uma igualdade entre estes dois registradores, OCF2 = 1 para o próximo ciclo de clock. Caso OCIE2 = 
1, temos que uma interrupção pode ser gerada. Assim, após a execução da interrupção, temos que 
OCF2 = 0. 
O timer2 apresenta 4 modos de geração de onda definidos por WGM20 e 21 bits: 
NORMAL MODE 
 O contador sempre incrementará; 
 Overflows para o zero após atingir o MAX (255); 
 Pode disparar alguma interrupção quando o temporizador overflows de volta até o zero; 
 Pode disparar alguma interrupção quando TCNT2 = OCR2; 
 Pode “set/clear/toggle” o pino OC2 quando TCNT2 = OCR2; 
 Freqüência = clock/(2 * prescale * 256) ; 
 
CTC (Clear Timer on Compare) MODE 
 Pode ser utilizado para uma base de tempo bem variável ou geração de uma onda 
quadrada de freqüência variável no pino OC2; 
 O contador sempre incrementará; 
 Recomeça a contagem quando TCNT2 = OCR2; 
 Pode disparar alguma interrupção quando TCNT2 = OCR2 ( e overflows se OCR2 = 
MAX); Freqüência = clock/(2 * prescale * ( 1 + OCR2) ); 
FAST PWM MODE 
 Utilizado para PWM (Pulse Width Modulation); 
 O contador sempre incrementará; 
 Overflows para o zero após atingir o MAX (255); 
 Pode disparar alguma interrupção quando o temporizador overflows de volta até o zero; 
 Pode disparar alguma interrupção quando TCNT2 = OCR2; 
 Freqüência = clock/(2 * prescale * 256) ; 
 A forma de onda PWM é gerada pelo “setting” (ou “clearing”) o registrador OC2 quando 
TCNT2 = OCR2, e “clearing” (ou “setting”) o registrador OC2 quando o contador 
retorna ao inicio; 
PHASE CORRECT PWM MODE 
 Possibilita a geração da forma de onda PWM com alta resolução no pino OC2; 
 A forma de onda de portadora é triangular (dual-slope operation), ou seja, o contador 
incrementa do BOTTOM ao MAX e, em seguida, do MAX ao BOTTOM; 
 OC2 sofre o toggle quando TCNT2 = OCR2 durante o processo de incremento ou 
durante o processe de decremento; 
 Preferido para aplicações que envolvam o controle de motores; 
 Freqüência = clock/(prescale * 510) ; 
Normal mode e CTC mode são bons para temporização interna e não necessita do pino OC2, ao 
menos que se deseja fazer uma geração de freqüência externa. Os outros dois modos necessitam que o 
pino OC2 esteja conectado a algo. 
7.1.2.2 – Timer/Counter Register Description 
I) Timer/Counter Control Register – TCCR2 
 
 
Bit 7 - FOC2 – Force Output Compare 
O bit FOC2 é somente ativo quando WGW bits especificam Non-PWM mode (Normal ou CTC 
Mode). Quando ativado, imediatamente uma comparação é forçada, logo, OC2 vai apresentar um 
comportamento de acordo com valores presentes nos bits COM2:0. 
Bit 6:3 – WGM21:0 – Waveform Generation Mode 
Estes bits são responsáveis por controlar a seqüência de contagem do contador, definir o valor de 
TOP e qual o tipo de geração da forma de onda a ser utilizada. Informações complementares seguem 
na Tabela 7.3. 
Tabela 7.3 – Wave Generation Mode Bit Description 
 
Bit 5:4 – COM21:0 – Compare Match Output Mode 
O COM21:0 determinam o comportamento do pino OC2. Dependendo do modo de geração de 
onda, OC2 pode se comportar de maneiras diferentes como se pode observar nas Tabelas 7.4, 7.5 e 
7.6. 
Tabela 7.4 – Comportamento de OC2 para o Non-PWM Mode 
 
Tabela 7.5 – Comportamento de OC2 para o Fast PWM Mode 
 
 
Tabela 7.6 – Comportamento de OC2 para o Phase Correct PWM Mode 
 
Bit 2:0 – CS22:0 – Clock Select 
Esses três bits selecionam a fonte do clock a ser usado pelo contador. Para informações 
complementares, observar Tabela 7.7. 
Tabela 7.7 – Clock Select Bit Description 
 
II) Timer/Counter Register 2 – TCNT2 
 
 
Oferece direto acesso e permite operações de escrita e leitura para o contador. Escrevendo no 
registrador, temos que a comparação entre TCNT2 e OCR2 é bloqueada no próximo intervalo de 
clock. 
III) Output Compare Register 2 – OCR2 
 
 
O registrador armazena o valor de 8-bit que é constantemente comparado com o valor de 
TCNT2. Uma igualdade entre os valores pode ser utilizada para gerar uma forma de onda (saída) no 
pino OC2. 
 
IV) Timer/Counter Interrupt Mask Register – TIMSK 
 
No caso do timer2, somente os bits 7 e 6 devem se referem a ele. 
Quando OCIE2 (Timer/Counter2 Output Compare Match Interrupt Enable) é ativado, 
temos que uma interrupção pode ocorrer se a igualdade entre TCNT2 e OCR2 for válida. 
Quando TOIE2 (Timer/Counter2 Overflow Interrupt Enable) é ativado, temos que uma 
interrupção pode ser executada se ocorrer um overflow no timer2. 
V) Timer/Counter Interrupt Flag Register – TIFR 
 
No caso do timer2, somente os bits 7 e 6 devem se referem a ele. 
Quando OCF2 (Output Compare Flag 2) é ativado, uma interrupção será executada quando a 
igualdade entre TCNT2 e OCR2 for válida, logo OCIE2 também precisa está ativado. 
Quando TOV2 (Timer/Counter2 Overflow Flag 2) é ativado, uma interrupção será executada 
quando ocorrer um overflow no timer2, logo TOIE2 também precisa está ativado. 
7.1.3 Timer1 
7.1.3.1 – Características Gerais 
Diferentemente dos dois outros contadores, esse apresenta a resolução de 16 bits. Essa 
característica permite que se alcance mais precisão no tempo de execução de eventos, geração de 
ondas e medições envolvendo sinais. 
Um ponto importante a se ressaltar é capacidade de gerar sinais PWM de forma mais eficiente 
que o timer2. Isso se deve há presença de duas unidades de comparação (OC1A e OC1B) e, além 
disso, com 16 bits em vez de 8 aumenta-se a quantidade de diferentes de duty cycles disponíveis (256 
para 65536). 
Em relação aos registradores, temos que TCNT1 (Timer/Counter 1), OCR1A/B (Output 
Compare Registers) e o ICR1 (Input Capture Register 1) são todos de 16 bits. Há também o 
TCCR1A/B (Timer/Counter Control Registers), mas esses são de 8 bits. As interrupções são realizadas 
mediante aos bits de controle presentes nos registradores TIFR e TIMSK. 
Sabe-se que os valores armazenados em OCR1A/B são comparados com valor presente no 
contador todo o tempo. O resultado dessa comparação pode ser utilizado na geração de formas de onda 
ou um sinal PWM. 
O valor de TOP, ou o máximo valor permitido pelo contador, pode, em alguns modos de 
operação, ser definido pelo registrador OCR1A, pelo ICRI ou por valores já fixados. No entanto, a 
utilização de cada um pode causar algumas desvantagens, por exemplo, se utilizarmos o OCR1A como 
TOP no modo PWM, este não pode ser utilizado para a geração de sinais PWM na saída. Além de 
TOP, algumas outras definições para o timer0 são importantes de serem analisadas, como podemos 
observar na Tabela 7.8. 
Tabela 7.8 – Definições padrão para o timer1 
 
Em relação à forma que o contador pode ser clockeado, depende de valores atribuídos aos bits 
CS12:0 que estão definidos no registrador de controle B do timer0 (TCCR1B). Basicamente, há duas 
formas: internamente (diretamente ou por frações do clock interno) ou externamente. 
A seqüência de contagem será determinada a partir dos valores atribuídos aos bits WGM13:0, os 
quais estão definidos nos registradores de controle A e B do timer0 (TCCR1A e TCCR1B). 
Escolhendo o modo de operação é que vai ser possível determinar como será a forma de onda gerada 
na saída. Além disso, a geração de uma interrupção é determinada a partir de uma flag especifica do 
timer1 TOV1. 
Assim, a partir da combinação entre os bits CS12:0 e WGM13:0, podemos definir um dos 5 
modos de operação do contador. O primeiro grupo de bits não interfere na seqüência de contagem 
enquanto que o segundo interfere. 
Além disso, os bits CS12:0 se comportam de forma diferente entre os modos. Naqueles que 
fornecem um sinal PWM na saída, temos que são responsáveis por determinar se a saída deve ser ou 
não invertida. No outro caso, temos que são responsáveis por determinar se a saída vai ser ativada, 
desativado ou invertida (toggle) quando a unidade de comparação informa que ocorreu uma igualdade. 
Os diagramas de tempo para cada um dos modos pode ser visualizado do datasheet. As 
características gerais de cada um podem ser visualizadas a seguir. 
 
 
NORMAL MODE 
 Dentre todos, é o mais simples; 
 A contagem é sempre no sentido de incrementar o valor; 
 Ao atingir o MAX (0xFFFF), o contador retorna ao BOTTOM (0x0000); 
 No momento que o contador retorna ao inicio, a flag TV01 é ativada, permitindo, assim, 
que uma interrupção possa ser executada nesse instante; 
 Pode-se utilizar o a unidade de comparação para gerar interrupções em um dado instante; 
 Não é recomendado para a geração de formas de onda; 
 
CTC (Clear Timer on Compare) MODE 
 Utilizam-se os registradores OCR1A ou ICR1 para manipular a resoluçãodo contador, ou 
seja, definem o valor máximo do contador (TOP); 
 O contador retorna a zero quando TCNT1 = OCR1A ou TCNT1 = ICR1; 
 Uma interrupção pode ser gerada a cada momento que o contador chega ao TOP 
utilizando a flag OC1A ou ICF1 flag, de acordo com que registrador vai definir TOP; 
 Em relação à geração de onda, a saída OC1A pode ser invertida (toggle) a cada momento 
que a unidade de comparação reconhece uma igualdade de valores. A freqüência máxima 
obtida é a metade da freqüência de clock. 
 No caso geral, temos que freqüência = clock/(2 * prescale * ( 1 + OCR2) ); 
 Como no modo Normal, TOV1 é ativado no ciclo de clock que o contador vai do MAX 
até BOTTOM; 
 
FAST PWM MODE 
 Utilizado para geração de sinais PWM (Pulse Width Modulation) de alta freqüência; 
 Difere dos modos seguintes ao utilizar uma onda dente-de-serra (single-slope operation) 
para geração dos sinais PWM; 
 O contador somente incrementará; 
 No modo não-inversor, temos que OC1x será desativado (cleared) quando TCNT1 = 
OCR1x, enquanto que será ativado (set) quando o contador retorna ao BOTTOM. No 
modo inversor, ocorre a situação contrária; 
 Utilizados para regulação de potência e retificação; 
 TOP é definido a partir dos valores atribuídos aos bits WGM13:0 podendo ser: valores 
fixos definidos, ICR1 ou OCR1A. Ao atingir o TOP, o contador voltará a zero no ciclo de 
clock seguinte; 
 TOV1 é ativado a cada vez que o contador atingir TOP. Além disso, as flag OCF1A e 
ICF1 também são ativadas no mesmo ciclo de clock que TOV1 quando um deles é 
definido como TOP; 
 Para sinas PWM, temos que freqüência = clock/(prescale * ( 1 + TOP) ) ; 
 
PHASE CORRECT PWM MODE 
 Utilizado para geração de sinais PWM (Pulse Width Modulation) de alta freqüência; 
 Utiliza uma onda triangular (dual-slope operation) para geração dos sinais PWM, ou seja, 
o contador incrementa do BOTTOM ao MAX e, em seguida, do MAX ao BOTTOM; 
 No modo não-inversor, temos que OC1x será desativado (cleared) quando TCNT1 = 
OCR1x durante o processo de incremento, enquanto que será ativado (set) durante o 
processo de decremento. No modo inversor, ocorre a situação contrária; 
 TOP é definido a partir dos valores atribuídos aos bits WGM13:0 podendo ser: valores 
fixos definidos, ICR1 ou OCR1A (recomendado). Ao atingir o TOP, o contador voltará a 
zero no ciclo de clock seguinte; 
 A atualização do registrador OCR1x pode ser feita durante um período; 
 Para sinas PWM, temos que freqüência = clock/(2* prescale * (TOP)); 
 Utilizado para aplicações que envolvem controle de motores; 
PHASE and FREQUENCY CORRECT PWM MODE 
 Utilizado para geração de sinais PWM (Pulse Width Modulation) de alta freqüência; 
 Utiliza uma onda triangular (dual-slope operation) para geração dos sinais PWM, ou seja, 
o contador incrementa do BOTTOM ao MAX e, em seguida, do MAX ao BOTTOM; 
 No modo não-inversor, temos que OC1x será desativado (cleared) quando TCNT1 = 
OCR1x durante o processo de incremento, enquanto que será ativado (set) durante o 
processo de decremento. No modo inversor, ocorre a situação contrária; 
 TOP é definido a partir dos valores atribuídos aos bits WGM13:0 podendo ser: ICR1 ou 
OCR1A; 
 A principal diferença, em relação ao modo anterior, é que a saída gerada será simétrica 
em todos os períodos. Isso se deve ao fato que o valor dos registradores OCR1x só são 
atualizados no fim de um período, garantido assim a simetria da saída; 
 Para sinas PWM, temos que freqüência = clock/(2* prescale * (TOP)); 
 Utilizado para aplicações que envolvem controle de motores; 
7.1.3.2 – Timer/Counter Register Description 
I) Timer/Counter 1 Control Register A – TCCR1A 
 
Bit 7:6 - COM1A1:0 – Compare Output Mode for channel A 
Bit 5:4 – COM1B1:0 – Compare Output Mode for channel B 
Esses pares de bits controlam o comportamento dos pinos OC1A e OC1B respectivamente. Além 
disso, o modo de operação é fundamental para determina esse junto com os bits como podemos ver nas 
Tabelas 7.9, 7.10 e 7.11. 
Tabela 7.9 – Comportamento de OC1A e de OC1B para o Non-PWM Mode 
 
 
Tabela 7.10 – Comportamento de OC1A e de OC1B para o Fast PWM Mode 
 
Tabela 7.11 – Comportamento de OC1A e de OC1B para o Phase Correct e Phase and 
Frequency Correct PWM Mode 
 
Bit 3 – FOC1A – Force Output Compare for channel A 
Bit 2 – FOC1B – Force Output Compare for channel B 
Esses pares de bits somente são ativados quando estamos em Non-PWM mode. Assim, deve-se 
garantir que eles estão desativados quando estivermos operando em modo PWM. Quando ativamos 
FOC1A/FOC1B, força-se uma comparação que pode ser utilizada para gerar uma forma de onda. A 
saída é determinada a partir da Tabela 09. 
Bit 1:0 – WGM11:0 – Waveform Generation Mode 
Combinado com os pares de bits WGM13:2 presentes no registrador TCCR1B, são responsáveis 
por controlar a seqüência de contagem do contador, o valor definido para TOP e que tipo de geração 
da saída (forma de onda) a ser usada. Para informações mais detalhadas, observar a Tabela 7.12. 
Tabela 7.12 – Wave Generation Mode Bit Description 
 
II) Timer/Counter 1 Control Register B – TCCR1B 
 
Bit 7 – ICNC1 – Input Capture Noise Canceler 
Quando ativado, requere-se que 4 amostras iguais na entrada para que se possa alterar a saída, ou 
seja, ocorre uma filtragem para garantir a qualidade do sinal de entrada, no entanto, teremos um atraso 
na resposta da saída. 
Bit 6 – ICES1 – Input Capture Edge Select 
O nível lógico deste bit indica qual a borda utilizada para definir um evento no pino ICP1. Caso 
seja devido uma mudança 1 para 0 (borda negativa), devemos desativar ICES1. Caso contrário, seja 
devido por borda positiva, devemos ativá-lo. Em cada um dos casos, temos que o valor do contador 
será copiado para ICR1. 
Bit 5 – Reserved Bit 
Este bit é reservado para uso futuro, logo se deve mantê-lo desativado. 
Bit 4:3 – WGM13:2 – Waveform Generation Mode 
Observar a descrição do TCCR1A. 
 
Bit 2:0 – CS12:0 – Clock Select 
Esses três bits selecionam a fonte do clock a ser usado pelo contador. Para informações 
complementares, observar Tabela 7.13. 
Tabela 7.13 – Clock Select Bit Description 
 
III) Timer/Counter 1 – TCNT1H e TCNT1L 
 
 
Oferecem direto acesso e permite operações de escrita e leitura para o contador de 16 bits. 
IV) Output Compare Register 1A (OCR1AH e OCR1AL) e Output Compare Register 1B 
(OCR1BH e OCR1BL) 
 
Cada registrador armazena um valor de 16-bits que é constantemente comparado com o valor em 
TCNT1. Uma igualdade entre os valores pode ser utilizada para gerar uma forma de onda (saída) no 
pino OC1A ou OC1B. 
 
V) Input Capture Register 1 – ICR1H e ICR1L 
 
É atualizado com o valor armazenado em TCNT1 a cada vez que um evento ocorre no pino 
ICP1. Além disso, esse registrador pode ser utilizado para definir o valor de TOP. 
VI) Timer/Counter Interrupt Mask Register – TIMSK 
 
No caso do timer1, somente os bits de 5 a 2 se referem a ele. 
Quando TICIE1 (Input Capture Interrupt Enable) é ativado, temos que uma interrupção pode 
ocorrer caso ocorra uma captura de evento no pino de entrada ICP1. 
Quando OCIE1A (Output Compare A Match Interrupt Enable) é ativado, temos que uma 
interrupção pode ocorrer se a igualdade entre TCNT1 e OCR1A for válida. 
Quando OCIE1B (Output Compare B Match Interrupt Enable) é ativado, temos que uma 
interrupção pode ocorrer se a igualdade entre TCNT1 e OCR1B for válida. 
Quando TOIE1 (Overflow Interrupt Enable) é ativado, temos que uma interrupção pode ser 
executada se ocorrer um overflow. 
VII) Timer/Counter Interrupt Flag Register – TIFR 
 
No caso do timer1, somente os bits de 5 a 2se referem a ele. 
ICF1 (Input Capture Flag) é ativado quando ocorre a captura de um evento no pino ICP1, logo 
pode ser usado para executar uma interrupção. 
OCF1A (Output Compare A Match Flag) é ativado no ciclo de clock após a igualdade entre 
TCNT1 e OCR1A é válida, logo podendo ser usado para executar uma interrupção caso OCIE1A 
também esteja ativado. 
OCF1B (Output Compare B Match Flag) é ativado no ciclo de clock após a igualdade entre 
TCNT1 e OCR1B é válida, logo podendo ser usado para executar uma interrupção caso OCIE1B 
também esteja ativado. 
TOV1 (Overflow Flag 1) tem seu comportamento definido, ou seja, será ativado de acordo com 
os WGM13:2 e WGM11:0. Além disso, TOIE1 também precisa está ativado. Para maiores detalhes, 
observar a Tabela 12. 
7.2 Códigos exemplos 
Para melhor compreender a forma de utilizar os registradores de controle junto com os timers 
para a geração de sinais PWM, vamos analisar o seguinte código. De forma geral, podemos dizer que o 
programa se resume a definir os registradores de controle para o timer1 com o propósito de utilizar o 
“Phase and Frequency Correct PWM Mode” e, em seguida, determina uma interrupção para quando 
ocorrer um overflow no contador. 
/* Geração de sinais PWM a partir do contador1 utilizando o modo 
de correção de fase e frequencia */ 
 
#include <inttypes.h> 
#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <avr/sleep.h> 
 
#define OC1A 1 
#define OC1B 2 
 
/* Esta funcao servira para definir o modo de operacao do 
contador1, assim como estabelecer o valor de TOP, que constitui uma 
segunda maneira de alterar a frequencia de operacao, alem do fator 
divisor do clk de entrada */ 
 
void inicializa_pwm(void) 
{ 
 
/* Primeiro, vamos definir os pinos OC1A e OC1B como saida. Para 
isso devemos inicializar a mascara de i/o da porta correspondente, o 
registrador DDROC */ 
 
DDRB = (1<<OC1A)|(1<<OC1B); // OC1A = PB1 e OC1B = PB2 
 
OCR1A = 0; 
OCR1B = 0; 
 
/* Vamos configurar o modo de operacao do PWM. Para isso serao 
necessarios os registradores TCCR1A:B */ 
 
/* TCCR1A: bit7(COM1A1) bit6(COM1A0) bit5(COM1B1) bit4(COM1B0) 
bit3(FOC1A) bit2(FOC1B) bit1(WGM11) bit0(WGM10) 
COM1A1:0: Para o Phase and Frequency Correct PWM Mode, eles 
serao inicializados como 3, fazendo com que OC1A seja ativado (1) 
quando o valor do contador1 igualar o valor de comparacao OCR1A na 
subida, e desativado (0) na descida; 
 
COM1B1:0: Serao inicializados como 2, para observar o PWM 
invertido; 
 
FOC1A:b: Serao inicializados como 0, pois estamos operando no 
modo PWM e, como vimos, são exclusivos para modos Non-PWM; 
 
WGM11:0: Para operar no modo de operação desejado nesse exemplo, 
serã inicializados como 0; */ 
 
TCCR1A = 0xC0; // Simplificando a configuração de TCCR1A 
 
/* TCCR1B:bit7(ICNC1) bit6(ICES1) bit5(void) bit4(WGM13) 
bit3(WGM12) bit2(CS12) bit1(CS11) bit0(CS10) 
 
ICNC1: Nao tem utilidade nesta aplicacao, portanto sera 
inicializado como 0 para evitar algum problema. 
 
ICES1: Neste exemplo, utilizaremos ICR1 para definir o valor de 
TOP, logo esse bit será inicializado como 0. 
 
WGM13:2: Para operar no modo de operação desejado nesse exemplo, 
serã inicializados como 2. 
 
CS12:0: Vamos inicializa-lo como 1, para utilizar o valor 
original do clk. */ 
 
TCCR1B = 0x11; // Simplificando a configuração de TCCR1B 
 
/* Em seguida vamos definir o valor maximo do contador1(TOP) 
utilizando o registrador ICR1. Para isso vamos utilizar o 
registrador ICR1 */ 
 
ICR1 = 0xFF; // TOP = MAX 
 
/* Para garantir que a interrupção ocorra no momento em que 
ocorrer um overflow no timer1, precisamos definir alguns bits no 
registrador TIMSK. */ 
 
/* TIMSK:bit7(OCIE2) bit6(TOIE2) bit5(TICIE1) bit4(OCIE1A) 
bit3(OCIE1B) bit2(TOIE1) bit1(void) bit0(TOIE0) 
 
Como estamos utilizando o timer1, apenas os bits5:2 interessam. 
Por precaução, os outros serao definidos como 0. 
 
TICIE1: Como não interfere em nada, neste caso, iguala-se a 0. 
 
OCIE1A: Como não estamos interessados em habilitar uma 
interrupção quando o valor do contador atinge o valor armazenado no 
registrador OCR1A, iguala-se a 0. 
 
OCIE1B: Segue o mesmo raciocinio do bit anterior. 
 
TOIE1: Para habilitar interrupcao quando ocorre overflow no 
contador1, iguala-se a 1. De acordo os bits definidos para WGM13:0, 
temos que a interrupcao correspondente(TOV1) será ativada quando o 
contador1 atinigir o valor de BOTTOM. */ 
 
TIMSK = 0x04; // Simplificando a configuração de TIMSK 
 
// Definindo a rotina a ser executada durante a interrupção 
ISR(TIMER1_OVF_vect) 
{ 
 static uint16_t pwm; 
 static uint8_t sentido; 
 
 switch(sentido) 
 { 
 case 1: 
 if(++pwm == ICR1) 
 sentido = 0; 
 break; 
 
 case 0: 
 if(--pwm == 0) 
 sentido = 1; 
 break; 
 } 
 
 OCR1A = pwm; 
 OCR1B = pwm; 
} 
 
// Rotina principal do programa 
int main(void) 
{ 
 inicializa_pwm(); 
 
 while(1) 
 sleep_mode(); 
 
 return(0); 
} 
 
Assim, após a definição de todos os registradores de controle, observamos que a interrupção é 
utilizada para fazer com que o contador incremente de BOTTOM até MAX e, em seguida, de MAX 
até BOTTOM, como desejado no modo de operação utilizada em nosso exemplo. Toda vez que a 
interrupção é executada, temos que o nível lógico do sinal PWM no pino de saída é alterado. 
8. USART 
Em diversas situações, a execução de programas e a tomada de decisões por parte do 
microprocessador empregado no controle de alguma ou uma série de tarefas depende de ordens ou 
dados externos. Uma maneira simples e versátil de estabelecer a comunicação entre AVR‟s ou entre 
um AVR e um hardware periférico ou mesmo um PC ou qualquer que seja o dispositivo a se 
comunicar com o AVR, é a USART (Universal Synchronous Asynchronous serial Receiver and 
Transmitter). 
A USART difere da tradicional RS232 somente pelos níveis de tensão utilizados (na RS232 „0‟ є 
(3V,25V) e „1‟ є(-3V,-25V) ). Desta forma, com o auxilio de apenas um adaptador de nível de tensão 
(MAX232, por exemplo), podemos acoplar um PC diretamente a um AVR através da porta serial. 
Existem diversas configurações possíveis para a interface USART, dado que se deve escolher 
tanto entre o modo síncrono (clock MASTER ou SLAVE) ou o assíncrono de operação, quanto às 
características de protocolo como nº de bits de dados, nº de bits de parada, tipo de paridade e taxa de 
transmissão. O controle dessas variáveis, que definem a transmissão, é realizado obviamente através 
de registradores. 
No entanto, antes de descrever estes registradores é importante saber como determinar o fator 
UBRR (USART Baud Rate Register). Ele especifica a taxa de amostragem da porta, portanto é 
fundamental inicializá-lo com um valor correto, para que transmissor e receptor estejam 
sincronizados. Como o AVR possui um clk interno, o calculo de UBRR está atrelado a este valor, 
dessa forma podemos calcular UBRR: 
 
É importante lembrar que esta formula é adequada para o modo de operação que seguiremos 
neste tutorial. Caso fosse utilizado um modo alternativo, como o Asynchronous Double Speed 
Mode(fator 8 ao invés de 16 no denominador), ou os Modos síncronos obteríamos uma formula 
diferente (fator 2 ao invés de 16 no denominador). 
8.1 Registradores de Controle 
Agora, podemos prosseguir e detalhar os registradores envolvidos. 
I) USART Data Register - UDR 
 
Registrador que contém os dados recebidos e a serem enviados. Apesar de estarem endereçadosno mesmo registrador, os dados recebidos e transmitidos estão atrelados a pinos diferentes da porta 
D: RXD(PD0) e TXD(PD1). 
Deve-se ressaltar que só é permitido utilizar a operação de escrita quando a flag UDRE alocada 
no registrador UCSRA está ativada, se não, a mesma é simplesmente ignorada. 
II) USART Control and Status Register A – UCSRA 
 
Bit 7 - RXC – USART Receive Complete 
Este bit sinaliza quando há dados não-lidos no buffer de entrada. Pode ser utilizado como flag de 
interrupção através do bit RXCIE alocado no registrador UCSRB. 
Bit 6 – TXC – USART Transmit Complete 
Este bit sinaliza quando o buffer de transmissão está vazio. Pode, da mesma forma, ser utilizado 
como flag de interrupção através do bit TXCIE alocado no registrador UCSRB. 
Bit 5 – UDRE – USART Data Register Empty 
Indica quando o buffer de transmissão esta pronto para receber dados. Basicamente nos diz que o 
AVR está pronto para enviar uma mensagem nova. Também é um flag que, se habilitado através do bit 
UDRIE alocado no registrador UCSRB, pode ser utilizado para realizar interrupções. 
Bit 4 – FE – Frame Error 
Sinaliza quando ocorre um erro no formato da recepção, ou seja, o primeiro bit de parada possui 
um valor incorreto. Este flag só é válido enquanto o valor de UDR não é lido, portanto, para ser 
monitorado, este deve ser lido antes de UDR, o mesmo vale para DOR e PE. É importante que quando 
formos escrever em UCSRA, deveremos escrever 0 neste bit. 
Bit 3 – DOR – Data OverRun 
Indica que houve uma indicação de nova mensagem enquanto os buffers de entrada estavam 
cheios, ou seja, uma nova mensagem chegou e não pôde ser lida. É importante que quando formos 
escrever em UCSRA, deveremos escrever 0 neste bit. 
Bit 2 – PE – Parity Error 
Avisa quando ocorre um erro de paridade na mensagem recebida. É importante que quando 
formos escrever em UCSRA, deveremos escrever 0 neste bit. 
Bit 1 – U2X – Double the USART Transmission Speed 
Dobra a velocidade de funcionamento assíncrona. Quando for utilizada a velocidade normal ou 
modos síncronos deve ser inicializado como 0. 
Bit 0 – MPCM – Multi-processor Communication Mode 
Habilita a comunicação multiprocessador, que será abordada posteriormente. Atua no sentido de 
filtrar as mensagens que contem endereços, ignorando as que contêm dados. 
III) USART Control and Status Register B – UCSRB 
 
Bit 7 - RXCIE – RX Complete Interrupt Enable 
Quando é ativado, temos que este bit habilita interrupções para a flag RCX. 
Bit 6 – TXC – USART Transmit Complete 
Quando é ativado, temos que este bit habilita interrupções para a flag TCX. 
Bit 5 – UDRE – USART Data Register Empty 
Quando é ativado, temos que este bit habilita interrupções para a flag UDRE. 
Bit 4 – RXEN – Receiver Enable 
Ativa o receptor da USART. Caso não seja ativado, o pino comporta-se como um i/o 
normalmente. 
Bit 3 – TXEN – Transmitter Enable 
Ativa o transmissor da USART. Caso não seja ativado, o pino comporta-se como um i/o 
normalmente. Entretanto, enquanto houver mensagens pendentes ou mensagens sendo transmitidas não 
surtirá efeito. 
Bit 2 – UCSZ2 – Character Size 
Combinado com UCSZ1:0, o qual está alocado no registrador UCSRC, define a quantidade de 
bits de dados em cada mensagem. 
Bit 1 – RXB8 – Receive Data Bit 8 
Comporta-se como nono bit de dados recebido quando a quantidade de bits de dado em cada 
mensagem é igual a 9. Deve ser lido antes de UDR, pois após a leitura deste, RXB8 é apagado. 
Bit 0 – TXB8 – Transmit Data Bit 8 
Mesma função de RXB8, mas para transmissão. Neste caso, deve ser escrito antes de UDR, para 
que seja mandado. 
IV) USART Control and Status Register C – UCSRC 
Existe um detalhe com relação ao UCSRC. Ele compartilha com UBRRH a mesma localização 
de i/o. Sendo assim, para escrevê-lo, é necessário ativar URSEL, caso contrário o valor será escrito em 
UBRRH. 
 
Bit 7 - URSEL – Register Select 
Como explanado anteriormente, este bit seleciona qual dos registradores será escrito. 
Bit 6 - UMSEL – USART Mode Select 
Seleciona o modo de operação: assíncrono (0) ou síncrono (1). 
Bit 5:4 – UPM1:0 – Parity Mode 
Estes dois bits definem os bits de paridade da mensagem. Para maiores informações, observar a 
Tabela 8.1. 
Tabela 8.1 – Configurações dos bits UPM 
 
Bit 3 - USBS – Stop Bit Select 
Seleciona o número de bits de parada: 1-bit (0) ou 2-bits (1). 
Bit 2:1 – UCSZ1:0 – Character Size 
Como exposto anteriormente, junto com UCSZ2 estes bits definem o Character Size, ou seja, a 
quantidade de bits de dados em cada mensagem. Para maiores informações, observar a Tabela 8.2. 
Tabela 8.2 – Configurações dos bits UCSZ 
 
Bit 0 – UCPOL – Clock Polarity 
Define as bordas utilizadas para amostragem e transmissão de dados quando se utiliza o modo 
síncrono. Deve ser escrito como 0 quando o modo a ser utilizado é o assíncrono. Para maiores 
informações, observar a Tabela 8.3. 
Tabela 8.3 – Configurações do bit UCPOL 
 
V) USART Baud Rate Registers – UBRRL e UBRRHs 
 
São os registradores que armazenam o valor que será utilizado para calcular a taxa de 
amostragem e transmissão de dados, de acordo com a fórmula apresentada anteriormente. 
UBRRH constitui os 4 bits mais significativos de UBRR. Além disso, temos que definir URSEL 
como 0 para que a operação de escrita seja em UBRRH e não em UCSRC. Os outros bits são 
reservados, mas devem ser escritos como 0 quando estivermos escrevendo em UBRRH por segurança. 
Além disso, temos que UBRRL armazena os bits menos significativos de UBRR. 
 
8.2 Códigos Exemplos 
Uma vez que descrevemos os registradores envolvidos na interface USART e como cada um 
funciona, estamos aptos a gerar um código. Inicialmente, vamos a um exemplo simples de envio de 
mensagem. 
Primeiramente vamos escrever a função “transmitir”. Esta função recebe a mensagem a ser 
enviada, espera pela sinalização de que o buffer está apto a receber dados e, portanto, enviar uma nova 
mensagem. 
No programa principal devemos definir o modo de utilização. Neste caso, foi configurada uma 
transmissão feita a 9600 bps, considerando um clk interno de 1MHz, assíncrona, com 8 bits de dados, 
paridade ímpar e apenas 1 bit de parada. Em seguida, habilitamos UDRE. 
Os registradores foram escritos explicitando-se cada bit, mas poderiam ter sido simplesmente 
atribuídos seus valores hexadecimais, por exemplo, poderíamos ter escrito UCSRC = 0xB6. 
 
 
Figura 8.1 – Primeiro programa para enviar mensagem pela interface serial 
 
Agora um programa que recebe uma mensagem. Neste caso, devemos habilitar a RXC, que 
sinalizará a chegada de uma mensagem e habilitar o próprio receptor. 
 
Figura 8.2 – Segundo programa para receber mensagem pela interface serial 
 
Os dois programas anteriores realizam suas tarefas de enviar e receber mensagens, entretanto 
este código pode ser considerado extremamente ineficiente. Numa aplicação real, é bastante provável 
que diversas mensagens sejam enviadas e recebidas. 
Nos exemplos anteriores, o tempo gasto para esperar as sinalizações de que existia uma 
mensagem nova ou que o AVR estava pronto para enviar mensagens era tempo gasto de CPU, ou 
seja, o processador estava exclusivamente dedicado à incumbência de monitorar estes eventos, 
impossibilitando a realização de outras tarefas. 
Sendo assim, é mais eficiente utilizar os recursos disponíveis de interrupção, desta forma, é 
possível nos dedicarmos a processar outras tarefas enquanto novas mensagens não chegam ou 
enquanto não podemos enviar novas mensagens. Para tal, será utilizada a macro ISR (Nome do vetor 
de interrupção), onde também necessitaremos de outra macro, a sei (void), para habilitar as 
interrupções.Cli (void) é a macro que devemos utilizar para desabilitar as interrupções. 
Outro aspecto importante é o consumo. Supondo que tivéssemos um sistema simplesmente 
reativo, ou que, apenas enviasse mensagens na ocorrência de novas mensagens recebidas, poderíamos 
simplesmente deixar o AVR em standby até a ocorrência destes eventos, economizando bastante 
energia e, muitas vezes até viabilizando aplicações que sofreriam por limitações de bateria e etc. Para 
isto, é necessário acrescentar duas bibliotecas: a <avr/interrupt.h> e a <avr/sleep.h>. 
Agora escreveremos um programa que simplesmente espera por uma mensagem e responde a 
mesma mensagem. 
Observe que, desta vez, habilitamos tanto o receptor como o transmissor, além da flag de 
interrupção RXC, mantendo a mesma configuração de transmissão dos exemplos anteriores. Observe 
também que o programa principal tornou-se leve, já que o loopback da mensagem é realizado por 
interrupção. 
 
 
 Figura 8.3 – Terceiro programa para receber mensagem e enviá-la pela interface serial 
 
 
 
 
 
9. Conclusão 
Este tutorial procurou desenvolver uma breve descrição das características do AVR e, em 
seguida, aprofundar um pouco mais a forma como o AVR as disponibiliza para os seus usuários. 
Assim, servindo como fonte de consulta durante o desenvolvimento dos protótipos no decorrer de sua 
participação no grupo de Instrumentação. 
 Acredita-se que há ainda outros diversos pontos a serem abordados dentro deste tutorial a fim 
de, cada vez mais, deixá-lo mais completo, logo se espera lançar novas versões à medida que o grupo 
obter novas informações sobre o microcontrolador. 
A partir das informações presentes nesse tutorial, espera-se que o leitor se estimule a buscar 
outras fontes de consultas na internet ou no próprio datasheet do AVR com o objetivo de incrementar 
seu conhecimento teórico e, assim, iniciar o desenvolvimento de projetos práticos utilizando o 
microcontrolador como, por exemplo, a construção de um carrinho de controle remoto. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10. Bibliografia 
 
I. [Atmel2004] ATMEL. ATmega8 - CompleteDatasheet.[S.l.],2004. 
II. Desenvolvimento com microcontroladores Atmel AVR – Geovany Araujo Borges – 
Departamento de Engenharia Elétrica – Universidade de Brasílai – 2006 
III. http://www.atmel.com/ 
IV. http://www.societyofrobots.com/step_by_step_robot.shtml 
V. http://forum.electronicapt.com/index.php/topic,1561.0.html 
VI. http://www.avrbeginners.net/ 
VII. http://www.avrfreaks.net/ 
VIII. http://members.shaw.ca/climber/avr.html 
IX. http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106&sid=20
d788f89772f7a108c5d6a8f8655654 
X. http://www.avrfreaks.net/index.php?module=FreaksArticles&func=viewArticles 
XI. http://paul.graysonfamily.org/thoughts/avrlinux/ 
XII. http://www.ime.eb.br/~pinho/micro/index.html 
XIII. http://homepage.hispeed.ch/peterfleury/index.html

Outros materiais