Вы находитесь на странице: 1из 8

Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

02/2011

Migrando do ATmega8 para o ATmega88/168/328 Vetores de Interrupção


Todos os vetores de interrupção do ATmega8 são equivalentes no
(o Microcontrolador do Arduino)
ATmegaX8. Como o ATmegaX8 possui mais interrupções, os vetores foram
deslocados para outras posições de memória. Algumas interrupções
mudaram de nome, mas suas funcionalidades são as mesmas.
Apesar de serem pino a pino compatíveis com o ATmega8, os
ATmegaX8 possuem outros periféricos, registradores e diferentes Tab. 1 – Comparação entre os vetores (endereços) das interrupções.
características elétricas. Em resumo:

• Trabalho até a frequência de 20 MHz.


• Interrupção externa em todos os pinos.
• Contador/temporizador 0-2 com funções estendidas (PWM).
• SPI pela USART.
• Saída de clock em um pino de I/O (PB0).
• Sensor de temperatura do chip com +/- 10 °C de precisão.
• Debug Wire.

Nos ATmegaX8 o X significa o tamanho da memória flash. Assim,


ATmega88/168/328 possuem, respectivamente, 8, 16 e 32 kbytes de flash.
O ATmega328 possui o dobro de memória EEPROM e RAM que os demais,
o que significa 1 kbyte de EEPROM e 2 kbytes de RAM.

Na Fig. 1 é apresentada a pinagem para o encapsulamento PDIP do


ATmegaX8, o mesmo usado no Arduino.

Fig. 1 – Pinagem do ATmegaX8.

1 2
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

Registradores de I/O e Bits


O ATmegaX8 tem mais registradores de I/O que o ATmega8. Os
registradores de I/O fora expandidos. Quase todos os registradores do
ATmega8 foram reorganizados para as novas posições de memória no
ATmegaX8.

Tab. 2 - Registradores do ATmega8 com seus equivalentes do ATmgeaX8.


Registradores em negrito não possuem funções equivalentes (ver Tab. 4).

3 4
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

Tab. 4 - Registradores de I/O que não são funcionalmente iguais aos seus
equivalentes. A tabela mostra onde encontrar os bits dos registradores de I/O que
não estão na mesma posição entre os ATmega.

Tab. 3 - Registradores que mudaram de nome, mas preservaram a mesma


funcionalidade.

5 6
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

Tab. 5 - Bits nos registradores de I/O que tiveram seus nomes alterados, mas
preservaram a mesma funcionalidade.
Registradores de controle da USART
No ATmega8, UCSRC e UBRRH dividem o mesmo endereço nos
registradores de I/O, e deve-se ter cuidado no uso do bit URSEL para
acessar o registrador desejado. No ATmegaX8, UCSRC e UBRRH possuem
endereços separados e devem ser acessados como dois registradores
individuais. O bit MSB no registrador UCSRC, que contém o bit de seleção
(URSEL) no ATmega8, é usado para outro propósito no ATmegaX8.

Tab. 6 – Bits dos registradores da USART que tiveram sua funcionalidade alterada.

Referência Interna de Tensão


Tab. 7 – Valores das tensões internas de referência.

Byte de Calibração do Oscilador RC Interno


O ATmega8 tem quatro diferentes valores de calibração, onde
especiais ações são necessárias para carregar os valores no registrador de
calibração (OSCCAL) quando o microcontrolador está em funcionamento.
O ATmegaX8 tem apenas um valor de calibração, e este valor é carregado
automaticamente durante a inicialização do microcontrolador. O prescaler
do clock pode, então, ser utilizado para mudar a velocidade da MCU.

Tempo de Escrita da EEPROM


No ATmega8 tWD_EEPROM, da CPU, é tipicamente de 8.5 ms.
No ATmegaX8 tWD_EEPROM, da CPU, é tipicamente de 3.4 ms.

7 8
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

int main()
Tensão de Operação {
DDRB = 0x00; //pinos do PORTB como entrada
PORTB = 0xFF; //habilita pull-ups do PORTC
DDRD = 0xFF; //PORTC como saída
Tab. 8 – Tensões e velocidades de operação.
UCSR0B = 0x00; //desabilitar RX e TX (para usar os pinos PD0 e PD1)
//pode ser desnecessário
PCICR = 1<<PCIE0;//habilita interrupção por qualquer mudança de sinal no
//Pino PCINT0..PCINT7 (PB0..PB7)
PCMSK0 = 0xFF; //habilita todos os pinos para gerar a interrupção

sei(); //habilita as interrupções

for(;;);
}
//---------------------------------------------------------------------------
ISR(PCINT0_vect)//quando houver mais de um pino que possa gerar a interrupção,
{ //é necessário testar qual foi.
if(!tst_bit(PINB,PB0))
cpl_bit(PORTD,PD0);
else if(!tst_bit(PINB,PB1))
cpl_bit(PORTD,PD1);
else if(!tst_bit(PINB,PB2))
EXEMPLOS cpl_bit(PORTD,PD2);
else if(!tst_bit(PINB,PB3))
cpl_bit(PORTD,PD3);
else if(!tst_bit(PINB,PB4))
Arquivo trata_bits.h utilizado nos programas abaixo. cpl_bit(PORTD,PD4);
else if(!tst_bit(PINB,PB5))
//------------------------------------------------------------------------// cpl_bit(PORTD,PD5);
//Definições de macros para trabalho com bits else if(!tst_bit(PINB,PB6))
cpl_bit(PORTD,PD6);
#define set_bit(adress,bit)(adress|=(1<<bit)) else if(!tst_bit(PINB,PB7))
#define clr_bit(adress,bit)(adress&=~(1<<bit)) cpl_bit(PORTD,PD7);
#define tst_bit(adress,bit)(adress&(1<<bit))
#define cpl_bit(adress,bit)(adress^=(1<<bit)) _delay_ms(50);
//------------------------------------------------------------------------// }
//---------------------------------------------------------------------------

1 – INTERRUPÇÂO POR TROCA DE ESTADO DOS PINOS DO PORTB

//==========================================================================//
//Cada vez que um botão é pressionado o LED correspondente troca de estado //
// //
//Todos os pinos do ATmegaX8 permitem interrupções externas //
//Entretanto, eles possuem apenas um vetor de interrupção (endereço) //
//Caso exista mais de um pino habilitado, o programador deve verificar qual //
//pino gerou a interrupção. //
//=========================================================================//
//Autor: Charles Borges de Lima - 02/02/2011 //
//=========================================================================//

#define F_CPU 8000000UL //frequência de trabalho


#include <avr/io.h> //definições do componente especificado
#include <avr/interrupt.h> //define algumas macros para as interrupções
#include <util/delay.h> //biblioteca para o uso das rotinas de delay
#include "trata_bits.h" //inclui macros para trabalho com bits Fig. 2 – Exemplo 1.

ISR(PCINT0_vect);

9 10
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

3 - HABILITANDO SINAIS PWM


2 – UTILIZANDO OS TEMPORIZADORES //==========================================================================//
//MODO CTC – PWM RÁPIDO – PWM COM FASE CORRIGIDA //
//==========================================================================//
//Autor: Charles Borges de Lima - 03/02/2011 //
Arquivo definicoes.h utilizado nos programas abaixo. //==========================================================================//
#include "definicoes.h"
//------------------------------------------------------------------------// //---------------------------------------------------------------------------
#define F_CPU 20000000UL //frequência de trabalho int main()
#include <avr/io.h> {
#include <avr/interrupt.h> DDRB = 0xFF;
#include <util/delay.h> DDRD = 0xFF;
#include "trata_bits.h"
//------------------------------------------------------------------------// //T/C0 - MODO CTC
TCCR0A = (1<<COM0A0)|(1<<WGM01); //modo CTC (não PWM)
OCR0A = 100; //determinação do período do sinal gerado
Habilitando a interrupção dos temporizadores TCCR0B = 1<<CS00; //liga T/C0 sem prescaler

//T/C1 - MODO PWM RÁPIDO DE 10 BITS


//==========================================================================// TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11)|(1<<WGM10);
//Habilitando todos os T/Cs para gerar interrupção por estouro para // //PWM não invertido e habilita pino OC1A de saída
//gerar formas de onde quadrada nos pinos PC0, PC1 e PC2 // TCCR1B = (1<<WGM12)|(1<<CS10);//modo do PWM 10, liga T/C1 sem prescaler
//==========================================================================// OCR1A = 950; //ajuste do ciclo ativo
//Autor: Charles Borges de Lima - 03/02/2011 //
//==========================================================================// //T/C2 - MODO PWM COM FASE CORRIGIDA
#include "definicoes.h" TCCR2A = (1<<COM2A1)|(1<<WGM20); //seleção do modo PWM
TCCR2B = 1<<CS20; //liga T/C2 sem prescaler
ISR(TIMER0_OVF_vect); OCR2A = 20; //ajuste do ciclo ativo
ISR(TIMER1_OVF_vect);
ISR(TIMER2_OVF_vect); for(;;);
//------------------------------------------------------------------------ }
int main() //==========================================================================//
{
DDRC = 0xFF;

//T/C0
TCCR0B = (1<<CS02)|(1<<CS00); //prescaler = 1024 4 – USO DO AD COM O SENSOR DE TEMPERATURA LM35
TIMSK0 = 1<<TOIE0; //habilita interrupção por estouro

//T/C1
TCCR1B = 1<<CS11; //prescaler = 8 Arquivo LCD.c utilizado no programa abaixo.
TIMSK1 = 1<<TOIE1; //habilita interrupção por estouro
//========================================================================= //
//T/C2 //FUNÇÕES PARA TRABALHO COM LCD 16x2 (controlador HD44780) //
TCCR2B = (1<<CS22)|(1<<CS21); //prescaler = 256 //========================================================================= //
TIMSK2 = 1<<TOIE2; //habilita interrupção por estouro //Autor: Charles Borges de Lima - 04/02/2011 //
//========================================================================= //
sei(); //habilita as interrupções #define DADOS_LCD PORTD //4 bits de dados do LCD na porta D
#define CONTR_LCD PORTD //para facilitar a troca dos pinos do
for(;;); //hardware e facilitar a re-programação
} #define RS PD2 //pino de instrução ou dado para o LCD
//------------------------------------------------------------------------ #define E PD3 //pino de enable do LCD
ISR(TIMER0_OVF_vect){cpl_bit(PORTC,PC0);}
//------------------------------------------------------------------------ //sinal de habilitação para o LCD
ISR(TIMER1_OVF_vect){cpl_bit(PORTC,PC1);} #define pulso_enable _delay_us(1); set_bit(CONTR_LCD,E); _delay_us(1);
//------------------------------------------------------------------------ clr_bit(CONTR_LCD,E); _delay_us(45)
ISR(TIMER2_OVF_vect){cpl_bit(PORTC,PC2);} //----------------------------------------------------------------------------
//------------------------------------------------------------------------

11 12
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

//Sub-rotina para enviar caracteres e comandos, com via de dados de 4 bits //Sub-rotina de escrita no LCD
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void cmd_LCD(unsigned char c, char cd) void escreve_LCD(char *c)
{ {
unsigned char i=2; for (; *c!=0;c++) cmd_LCD(*c,1);
}
DADOS_LCD=(DADOS_LCD & 0x0F)|(c & 0xF0);//primeiro os 4 MSB. //---------------------------------------------------------------------------
//(PD4-PD5-PD6-PD7) -> (D4-D5-D6-D7 LCD)
do
{ Lendo o sensor de temperatura LM35
if(cd==0)
clr_bit(CONTR_LCD,RS);
else //========================================================================= //
set_bit(CONTR_LCD,RS); //LEITURA DO SENSOR DE TEMPERATURA LM32 COM INTERFACE LCD //
//========================================================================= //
pulso_enable; //Autor: Charles Borges de Lima - 04/02/2011 //
//========================================================================= //
if((cd==0) && (c<4)) //se for instrução de retorno ou limpeza, #include "definicoes.h"
//gasta mais tempo #include "LCD.c"
_delay_ms(2);
//------------------------------------------------------------------------
DADOS_LCD = (DADOS_LCD & 0x0F) | (c<<4);//segundo nibble, 4 LSB unsigned int temp; //variável para o valor da temperatura
unsigned char digitos[4]; //variável global para no máximo 5 dígitos
i--;
ISR(ADC_vect);
}while(i>0); void ident_num(unsigned int valor);
} //------------------------------------------------------------------------
//--------------------------------------------------------------------------- int main()
//Sub-rotina para inicialização do LCD com via de dados de 4 bits {
//--------------------------------------------------------------------------- DDRD = 0xFF;
void inic_LCD_4bits() //sequência ditada pelo fabricando do circuito DDRC = 0x00;
{ // integrado HD44780
//o LCD será só escrito então R/W é sempre zero inic_LCD_4bits(); //inicialização do LCD
clr_bit(CONTR_LCD,RS); //RS em zero indicando que o dado para o LCD será escreve_LCD("LEITURA = ");
//uma instrução
clr_bit(CONTR_LCD,E); //pino de habilitação em zero //Configuração do AD
ADMUX = (1<<REFS1)|(1<<REFS0);//referência interna (1,1V), canal 0
_delay_ms(20); //tempo para estabilizar a tensão do LCD, ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
//após VCC ultrapassar 4.5 V. Como não se sabe o tempo //liga o AD, inicia a conversão, habilita a interrupção, habilita auto-trigger
//que a tensão leva para alcançar 4.5 V , na prática //prescaler=128 para o clock do AD. Deve-se ter cuidado ao selecionar o prescaler
//este tempo pode necessitar ser alterado para centenas //para não utilizar uma frequência acima do limite do AD (de acordo com a
//de milissegundos. //frequência de trabalho da CPU).
ADCSRB = 0x00; //modo de conversão contínuo
DADOS_LCD = (DADOS_LCD & 0x0F) | 0x30; //interface 8 bits DIDR0 = 1<<ADC0D; //desabilita a entrada digital do pino PC0

pulso_enable; //enable respeitando os tempos de resposta do LCD sei(); //habilita a interrupção


_delay_ms(5);
pulso_enable; for(;;)
_delay_us(200); {
pulso_enable; //até aqui ainda é uma interface de 8 bits ident_num(temp);//converte o valor lido para seus dígitos individuais
cmd_LCD(0x89,0);
DADOS_LCD = (DADOS_LCD & 0x0F) | 0x20;//interface de 4 bits, deve ser cmd_LCD(digitos[3],1);
//enviado duas vezes (a outra esta abaixo) cmd_LCD(digitos[2],1);
pulso_enable; cmd_LCD(digitos[1],1);
cmd_LCD(',',1);
cmd_LCD(0x28,0);//interface de 4 bits 2 linhas (aqui se habilita as 2 linhas) cmd_LCD(digitos[0],1);
//são enviados os 2 nibbles (0x2 e 0x8) cmd_LCD(0xDF,1);
cmd_LCD(0x08,0); //desliga o display cmd_LCD('C',1);
cmd_LCD(0x01,0); //limpa todo o display }
cmd_LCD(0x0C,0); //mensagem aparente cursor ativo não piscando }
cmd_LCD(0x80,0); //escreve na primeira posição a esquerda - 1a linha //---------------------------------------------------------------------------
}

13 14
Técnicas de Projetos Eletrônicos com os Microcontroladores AVR Técnicas de Projetos Eletrônicos com os Microcontroladores AVR

ISR(ADC_vect)
{ OBSERVAÇÕES
temp = ADC + (ADC*19)/256;
Quando for necessário configurar algum periférico do ATmegaX8 é
/* O LM35 apresenta uma saída de 10mV/oC
O valor de leitura do AD é dado por ADC = Vin*1024/Vref, imprescindível a consulta ao seu manual. Apesar das semelhanças entre
como Vref = 1,1V, para converter o valor do AD para graus Celsius, é
necessário multiplicar o valor ADC por 1100/1024 os microcontroladores da família AVR, sempre existem diferenças.
(considerando um digito decimal antes da vírgula)
Utilizando a simplificação matemática e mantendo a variável temp com 16
bits, resulta: 1100/1024 = 1 + 19/256 */ A programação do ATmega8 é diretamente portável aos outros
} ATmegaX, tais como: o ATmega16 e o ATmega32 (estes possuem mais
//-------------------------------------------------------------------------
void ident_num(unsigned int valor)//converte um número decimal nos seus pinos de I/O, incluem o PORTA).
{ //dígitos individuais no formato ASCII
unsigned char k=0; Este material foi desenvolvido como complemento ao livro Técnicas
digitos[0]=0; digitos[1]=0; digitos[2]=0; digitos[3]=0;
de Projetos Eletrônicos com os Microcontroladores AVR. Neste são
do
{
apresentados os detalhes para a programação do ATmega8. Maiores
digitos[k] = valor%10 + 48; //pega o resto da divisão/10 e salva no
//dígito correspondente.
detalhes também podem ser encontrados no sítio da ATMEL.
valor /= 10; //pega o inteiro da divisão/10
k++; Para os aficionados do Arduino, a nota é que ele pode ser comandado
}while (valor!=0); por um ATmega8 ou qualquer ATmegaX8 (o Uno, mais atual, emprega o
}
//-------------------------------------------------------------------------- ATmega328).

BIBLIOGRAFIA
Application Note
• AVR094: Replacing ATmega8 by ATmega88
Manuais
• ATmega48A, ATmega48PA, ATmega88A, ATmega88PA, ATmega168A,
ATmega168PA, ATmega328, ATmega328P.
• ATmega8, ATmega8L.

Lima, Charles Borges de. Técnicas de Projetos


Eletrônicos com os Microcontroladores AVR.
Edição do autor - Clube de Autores, 1ª ed. Nov/2010.

ISBN 978-85-911400-0-8

Fig. 3 – Exemplo 4.

15 16

Вам также может понравиться