Vous êtes sur la page 1sur 39

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 unsigned long 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ção externa é
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ção do 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 2 se 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çados
no 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

Vous aimerez peut-être aussi