Início
/
Projetos Arduino
/
Projetos Squids
/
Básico
/
Projeto 82 - Como realizar interrupção externa utilizando registradores do Arduino
Projeto 82 - Como realizar interrupção externa utilizando registradores do Arduino
Angelo Luis Ferreira | 14/05/2020
Acessos: 11.428
Básico - Projeto 82
Interrupção externa utilizando registradores de portas do Arduino
Objetivo
Neste projeto vamos mostrar como utilizar registradores de portas DDR e PORT para realizar interrupções externas no Arduino. Vamos, desta forma, exemplificar o conceito de interrupção externa utilizando os registradores DDR, PORT, EIMSK e EICRA para apresentar a técnica mais eficiente para ligar e desligar um componente eletrônico através de um botão ou de um sensor de entrada qualquer (no projeto vamos utilizar um botão e um sensor de toque).
Definições
Vantagens de se utilizar registradores com interrupção externa:
- Maior velocidade de acesso, pois acionaremos a porta diretamente sem a necessidade de funções.
- Otimização de memória do microcontrolador.
- Executar duas tarefas quase que simultaneamente.
Desvantagens de se utilizar registradores com interrupção:
- Código de difícil entendimento.
- Criar códigos utilizando registradores não irão funcionar em todos os tipos e versões do Arduino. Cada microcontrolador possui estruturas de pinos digitais e analógicos diferentes.
- É muito mais fácil causar problemas de funcionamento não intencionais com acesso direto à porta.
Observações:
1. Interrupção externa: É quando o programa do Arduino está instruído para reagir à mudança de um sinal externo, por exemplo, mudança do nível lógico de um sinal gerado por um botão ou por um sensor qualquer (Referência Arduino). Veja o tutorial: Projeto 78 - Como realizar interrupção externa no Arduino usando sensor de toque
1.1. ISR - Interrupt Service Routine ou Rotina de Serviço de Interrupções em português, são instruções que são executadas quando ocorre uma interrupção externa. Entretanto, estas instruções são especiais e possuem algumas limitações, sendo:
. Uma ISR não recebe argumentos e não retorna nada.
. Uma ISR deverá ser a mais curta e rápida possível.
. Se o seu programa utiliza múltiplas ISRs, apenas uma poderá ser executada de cada vez.
. A função delay() não funcionara em uma ISR.
. A função millis() não poderá ser incrementada dentro de uma ISR.
. A função delayMicroseconds() ao não utilizar nenhum contador, funcionará normalmente em uma ISR.
2. O conceito DDR e PORT utilizado neste projeto é específico para Arduino UNO R3 que utiliza o microcontrolador ATmega328. Outros microcontroladores podem ter configurações diferentes. Para saber mais, leia os artigos: Arduino - Manipulação Direta de Portas do blog do Renato Aloi, Port Registers - Documento de Referência Arduino e os projetos: Projeto 81 - Ligar e desligar um led por manipulação direta de portas do Arduino, Projeto 61 - Dado eletrônico com leds e uso de manipulação direta de portas do Arduino e Projeto 60 - Dado eletrônico com Arduino (uso de manipulação direta de portas).
3. O conceito de registradores para interrupções externas EIMSK e EICRA também utilizados no projeto são específicos para o microcontorlado ATmega328, onde utilizamos os pinos INT0 e INT1 (pinos 2 e 3 do Arduino Uno). Para se aprofundar mais sobre a arquetetura do microcontrolador ATmega328 leia: http://www.dca.fee.unicamp.br/~rferrari/EA075_2s2017/Cap.%203.1%20-%20Microcontrolador_ATMega328P.pdf
4. Para avançarmos um pouco mais na utilização de registradores de portas do Arduino, vamos precisar de um conhecimento básico sobre operadores bitwise. Para isso, recomendo que leiam o artigo Operadores Bitwise (Bit-a-Bit) do blog Diogo Matheus.
5. ATENÇÃO: Tome muito cuidado em utilizar o conceito de manipulação direta de portas. Qualquer erro pode danificar permanentemente a sua placa de Arduino.
Registradores de portas do Arduino Uno R3
Registradores de portas (DDR, PORT e PIN) permitem o acesso direto às portas do Arduino. Veja abaixo a imagem que mostra todas portas disponíveis do Arduino UNO:
Nos microcontroladores Arduino Uno, existem 3 canais de portas:
- Porta B (portas digitais de 8 a 13)
- Porta C (entradas analógicas)
- Porta D (portas digitais de 0 a 7)
Para exemplificar melhor vamos utilizar o canal de portas D referente às portas digitais 0 a 7 do Arduino UNO. Microcontroladores de 8bits, como o Arduino UNO por exemplo, cada canal de portas possui 8 bits. Portanto, cada bit representa uma porta (ou pino) de cada canal de portas.
Cada porta do microcontrolador possui 3 registradores, sendo eles:
- DDR que configura o sentido da porta se ela é saída (OUTPUT) ou entrada (INPUT). Substitui a função pinMode().
- PORT que controla se a porta está no estado lógico alto (HIGH) ou baixo (LOW).
- PIN que efetua a leitura das portas configuradas como INPUT pela função pinMode().
No nosso projeto vamos utilizar os registradores DDR e PORT conforme as instruções abaixo:
4.1. Para imprimir o valor 1 em um bit, use sempre o padrão:
DDRporta |= (1 << bit que se pretende configurar como OUTPUT);
PORT |= (1<< bit que se pretende enviar HIGH);
4.1.1. No nosso exemplo, teremos as instruções: DDRD |= (1<<3); e PORTD |= (1<<3)
Obs.: DDRD |= (1<<3); pode ser escrito da seguinte forma: DDRD = DDRD | (1<<3);
4.2. Para imprimir o valor 0 em um bit, use sempre o padrão:
DDR &= ~(1<< bit que se pretende configurar como entrada);
PORT &= ~(1 << bit que se pretende enviar LOW);
DDR (Data Direction Register - read/write)
- No caso do registrador DDR, vamos acrescentar o canal de portas D, ficando portanto como DDRD (portas digitais de 0 a 7 no Arduino Uno).
- Definimos para cada porta se é saída (OUTPUT), usando o 1 ou se é entrada (INPUT), usando o 0.
- A ordem das portas é decrescente e vai de PD7 até PD0 e PB5 até PB0 (desconsidere o erro na imagem, leia PB5 no lugar de PB6)
- Como é um número binário, devemos colocar o modificador "B" na frente, veja o exemplo a seguir:
Ex.:
DDRD = B11111110; // configura portas 1 ate 7 como saídas,e a porta 0 como entrada
Usando operadores bitwise, podemos configurar cada pino individualmente da seguinte forma:
- DDRporta |= (1 << bit que se pretende configurar como OUTPUT); // imprime o valor 1 no bit e configura como saída - defina a Porta B, C ou D e o bit específico.
- DDRporta &= ~(1<< bit que se pretende configurar como INPUT); // imprime o valor 0 no bit e configura como entrada - defina a Porta B, C ou D e o bit específico.
Ex.:
DDRB |= (1<<4); // configura o bit 4 da Porta B como OUTPUT - pino 12 saída
DDRD &= ~(1<<3); // configura o bit 3 da Porta D como INPUT - pino 3 entrada
PORT (Data Register - read/write)
- Como no registrador DDR, vamos acrescentar no PORT o canal de portas D, ficando portanto como PORTD (portas digitais de 0 a 7 do Arduino Uno).
- Definimos para cada porta, se está no estado lógico HIGH, usamos 1 ou se está no estado lógico LOW, usamos 0.
- A ordem das portas vai de PD7 até PD0.
- Como é um número binário, devemos colocar o modificador "B" na frente, veja o exemplo a seguir:
PORTD = B10101000; // registra valor HIGH nas portas digitais 7,5 e 3
Usando operadores bitwise podemos controlar cada pino individualmente, como:
- PORTporta |= (1<< bit que se pretende enviar HIGH); // envia um sinal de alto nível (1) para o bit desejado
- PORTporta &= ~(1 << bit que se pretende enviar LOW); // envia um sinal de baixo nível (0) para o bit desejado
- PORTporta ^= (1 << bit que se pretende enviar HIGH e LOW) // liga e desliga a cada vez que o botão é pressionado. Operador XOR - Referência Arduino.
Ex.:
PORTB |= (1<<4); // envia HIGH para o bit 4 da Porta B - pino 12
PORTB &= ~(1<<4); // envia LOW para o bit 4 da Porta B - pino 12
Registradores para interrupção externa
Para configurarmos um interrupções externas nos projetos com Arduino, podemos utilizar basicamente 2 registradores:
- EIMSK - Habilita INT0 e INT1 do Arduino UNO
- EICRA - Define como INT0 e INT1 são ativadas (LOW, RISING, FALLING ou CHANGE)
EIMSK (External Interrupt Mask Register)
- EIMSK |= (1< // habilita a interrupção externa INT0 no pino 2 Arduino
- EIMSK |= (1< // habilita a interrupção externa INT0 no pino 3 Arduino
Atenção: Necessário que a interrupção global também esteja ativa
Funções para habilitar e desabilitar interrupções globalmente
- sei(); // função que habilita as interrupções externas globalmente
- cli(); // função que desabilita as interrupções externas globalmente
EICRA (External Interrupt Control Register A)
EICRA INT0 (pino 2)
- EICRA |= (0< // configura interrupção externa int 0 - CHANGE
- EICRA |= (1< // configura interrupção externa int 0 - FALLING
- EICRA |= (1< // configura interrupção externa int 0 - RISING
EICRA INT1 (pino 3)
- EICRA |= (0< // configura interrupção externa int 1 - CHANGE
- EICRA |= (1< // configura interrupção externa int 1 - FALLING
- EICRA |= (1< // configura interrupção externa int 1 - RISING
Rotina de Serviço de Interrupções (ISR)
- ISR (INT0_vect) { ... } // define a rotina para quando ocorre interrupção no INT0
- ISR (INT1_vect) {... } // define a rotina para quando ocorre interrupção no INT0
Aplicação
Para fins didáticos e projetos exigem a utilização de códigos profissionais.
Componentes necessários
Referência
|
Componente
|
Quantidade
|
Imagem
|
Observação
|
Protoboard |
Protoboard 830 pontos |
1 |
|
No mínimo utilizar protoboard com 400 pontos
|
Jumpers |
Kit cabos ligação macho / macho |
1 |
|
|
Sensor de toque capacitivo |
Sensor touch TP223B |
1 |
|
Tensão de Operação: 2 a 5V
Saída estado Alto (HIGH): 0,8V
Saída estado Baixo (LOW): 0,3V
Tempo de resposta: 220ms (LOW) e 60ms (HIGH)
(datasheet)
|
Led Difuso 5mm |
LEDs 5mm |
1 |
|
1 LED alto brilho ou difuso de qualquer cor
Você poderá utilizar também LEDs de 3 mm na cor que desejar.
|
Resistor |
Resistor
|
1 |
|
1 Resistor de 150Ω ou superior
Se precisar usar outros valores, calcule o resistor apropriado para o led utilizado
|
Push Button |
Push button 6X6X5mm |
1 |
|
|
Capacitor Cerâmico |
Capacitor Cerâmico 2nF a 10nF |
1 |
|
O capacitor será utilizado para estabilizar a função do botão (push button) no caso de se utilizar interrupção externa
|
Arduino UNO R3 |
Arduino UNO |
1 |
|
Você poderá utilizar uma placa Arduino UNO original ou similar
|
Montagem do Circuito
Conecte os componentes no Protoboard como mostra a figura abaixo. Verifique cuidadosamente os cabos de ligação antes de ligar seu Arduino. Lembre-se que o Arduino deve estar totalmente desconectado da força enquanto você monta o circuito.
Atenção
1. Lembre-se que o LED tem polaridade: O terminal maior tem polaridade positiva e o lado do chanfro tem polaridade negativa.
1.1. Portanto, faça a conexão do Arduino no terminal positivo do led (anodo) e o GND no terminal negativo (catodo).
1.2. Para evitar danos ao led é necessário a inclusão de um resistor no circuito. Como o resistor é um limitador da corrente elétrica, ele poderá estar conectado no anodo (terminal maior) ou no catodo (terminal menor) do led, tanto faz.
2. Determinamos o valor do resistor através da tabela prática: Tabela prática de utilização de leds 3mm e 5mm. Entretanto, o mais correto é sempre verificar o datasheet do fabricante do LED para você ter os exatos valores de tensão e corrente do mesmo - leia Leds ligados em série e em paralelo.
2.1. Valores utilizados para nossos projetos: LEDs difusos ou de alto brilho: Vermelho, Laranja e Amarelo: 150 Ω | Led Verde e Azul: 100 Ω
3. Antes de montarmos o botão e o nosso sensor, temos que observar que que os microcontroladores Arduino possuem pinos específicos para desempenhar a função de entrada de sinal para a interrupção externa. No Arduino UNO, por exemplo, as portas digitais 2 e 3 têm esta função, sendo nomeadas como int = 0 e int = 1, respectivamente. Veja a tabela a seguir que mostra os pinos das principais placas Arduino que possuem esta função:
Board |
int.0 |
int.1 |
int.2 |
int.3 |
int.4 |
int.5 |
Uno, Nano, Mini, other 328-based |
pino 2 |
pino 3 |
|
|
|
|
Mega, Mega2560, MegaADK |
pino 2 |
pino 3 |
pino 21 |
pino 20 |
pino 19 |
pino 18 |
Micro, Leonardo, other 32u4-based |
pino 3 |
pino 2 |
pino 0 |
pino 1 |
pino 7 |
|
Due |
número da interrupção = todos pinos digitais = número do pino |
Zero |
todos pinos digitais, exceto 4 = número do pino
|
Veja abaixo a configuração dos pinos do Arduino Uno R3:
4. Conforme vimos na tabela anterior, definiremos o pino digital 2 do Arduino UNO para conectarmos o pino do sensor de toque e o pino digital 3 para conectarmos o botão.
Obs.: Desta forma, podemos nomear o pino 2 como int = 0 e o pino 3 como int = 1.
5. Monte o botão (push button) sem o resistor, pois através da programação vamos habilitar o resistor pull-up interno do Arduino. Desta forma, quando o botão estiver pressionado, o Arduino retornará "LOW" ou "0". Assista o vídeo Arduino: Botão e Resistor de Pull Up Interno
5.1. No nosso exemplo conectamos o botão no pino digital 3 do Arduino.
Obs.: Os resistores pull-up e pull-down garantem um nível lógico estável quando por exemplo uma tecla não está pressionada. Geralmente utiliza-se um resistor de 10KΩ para esse propósito. A seguir é exibida a ligação desses resistores no circuito para leitura de tecla do botão:
Atenção: Observe que neste projeto não utilizaremos o resistor de 10K, pois vamos habilitar o resitor pull-up interno do Arduino através da programação, utilizando registradores de portas do Arduino Uno.
6. Como vamos configurar uma interrupção externa neste projeto, precisaremos utilizar um capacitor cerâmico para evitar o efeito "bouncing" no push button.
6.1. Como a interrupção externa gera uma ação muito rápida, somente o delay utilizado no software não será suficiente para evitar as oscilações geradas pelo efeito "bouncing". Recomendo utilizar um capacitor cerâmico de 2,0nF a 10nF na montagem do botão. Utilizamos no nosso projeto um capacitor de 2,2nF. Veja abaixo como conectar o capacitor cerâmico.
6.1.1. O efeito "bouncing" ocorre sempre quando trabalhamos com chaves mecânicas. Ele é responsável por gerar equivocadamente sinais como se ocorressem diversos acionamentos em um pequeno intervalo de tempo:
6.1.1.1. Veja no gráfico abaixo o exemplo deste efeito. Observe que ao pressionarmos um botão, por exemplo, ocorre algumas oscilações rápidas com idas e vindas do nível lógico alto e do nível lógico baixo, antes da estabilização das partes mecânicas do componente. Estas oscilações podem gerar informações indevidas ao nosso microcontrolador, que interpretará que o botão foi pressionado rapidamente várias vezes, quando na verdade foi pressionado apenas um vez.
6.1.2. Debouncing são técnicas que utilizamos para resolver este problema. O "debouncing" consiste basicamente em atrasar o código, através do software, com o uso da função delay(), função delayMicroseconds() ou da função millis(), ou através do hardware, com a instalação de um capacitor, ou ainda através de bibliotecas específicas.
6.1.2.1. Como configuramos uma interrupção externa para atuar em uma chave mecânica (push button, por exemplo), o sinal será enviado diretamente no pino do microcontrolador quando pressionamos o botão. Por isso, para eliminarmos os efeitos do "bouncing" de forma mais eficiente precisamos criar um atraso primeiro no hardware, usando o capacitor cerâmico e depois no software, podemos usar a função delayMicroseconds() que funciona em uma ISR (Interrupt Service Routine).
7. Monte o sensor touch TP223B conforme imagem abaixo. Desta forma, quando o sensor for tocado, o Arduino retornará "HIGH" ou "1".
7.1. No nosso exemplo conectamos o sensor no pino digital 2 do Arduino.
8. Veja abaixo como realizamos a montagem do nosso projeto utilizando um protoboard.
Utilizando registradores de portas - Arduino Uno R3
Para elucidarmos melhor a utilização dos registradores de portas do Arduino Uno R3 que utiliza microcontrolador ATmega328, vamos trabalhar com alguns exemplos simples. É importante que você reproduza os exemplos para um melhor entendimento. Obs.: Utilize a montagem do projeto original.
OPERAÇÕES EM PORTAS
1. No exemplo abaixo, onde usamos funções do IDE do Arduino, criamos uma aplicação bem simples: fazer com que ao pressionarmos um botão (push button) funcione como um interruptor, acendendo e apagando o led, sendo que:
1.1. No exemplo vamos conectar o led no pino digital 12 e o botão no pino digital 3.
1.2. Vamos configurar o botão como INPUT_PULLUP, ou seja, utilizando o resistor interno do microcontrolador.
1.3. Este exemplo tem a mesma estrutura do Projeto 04a - Push Button como interruptor - liga e desliga, porém, de forma mais otimizada.
1.4. Utilizaremos as funções digitalWrite() e digitalRead().
const byte LED = 12;
const byte BOT = 3;
void setup() {
pinMode(LED, OUTPUT); // pino 12 saida
pinMode(BOT, INPUT_PULLUP); // pino 3 entrada
}
void loop() {
if (!digitalRead(BOT)) {
digitalWrite(LED, !digitalRead(LED));
while(!digitalRead(BOT)) {}
delay(50);
}
}
1.5. Segue abaixo a explicação resumida do código:
1.5.1 Quando acionamos o botão, conectado no pino 12, o valor lido pela função digitalRead() é 0, pois está configurado como PULLUP.
1.5.2. Se invertermos o valor lido através do operador lógico NOT (!) teremos uma condição verdadeira para a expressão if(!digitalRead(BOT), ligando ou desligando o led através da função digitalWrite(LED, !digitalRead(LED));.
1.5.2.1. A função digitalRead(LED) lê qual sinal o pino 3 está recebendo, invertendo-o através do operador lógico NOT (!), ou seja, se se HIGH (5V) ele inverterá para LOW (0V) e vice e versa, acendendo e apagando o led, ligando ou desligando o led
1.5.3. A expressão while(!digitalRead(12)) {}; diz para o Arduino que enquanto estivemos com o botão pressionado, o botão se manterá aceso ou apagado.
1.5.4. Ao soltarmos o botão precisaremos de uma pausa de 50ms necessária para evitar as flutuações de sinal geradas pelo efeito "bouncing", que é a acomodação dos componentes mecânicos do botão. Obs.: Este valor de 50ms poderá variar, dependendo da qualidade do botão utilizado.
1.5.5. Referências: digitalWrite(), digitalRead() e operador NOT.
1.6. Observe que ao utilizarmos as funções digitalWrite() e digitalRead() como no exemplo acima, precisaremos de 1074 bytes (3%) de espaço de armazenamento para programas.
2. No próximo exemplo, vamos gerar a mesma funcionalidade do exemplo anterior, mas utilizando interrupção externa do Arduino através da função attachInterrupt() e da ISR (Interrupt Service Routine).
2.1. ISR são rotinas (funções) a serem executadas após uma interrupção externa. Veja o tutorial Projeto 78 - Como realizar interrupção externa no Arduino usando sensor de toque.
const byte LED = 12;
const byte BOT = 3;
void setup() {
pinMode(LED, OUTPUT); // pino 12 saida
pinMode(BOT, INPUT_PULLUP); // pino 3 entrada
// chama a função "turn" ao tocar no sensor
attachInterrupt(1, turn, FALLING); // int 1 => pino 3
}
void loop() {
}
void turn() {
digitalWrite(LED, !digitalRead(LED));
}
2.2. Entenda como fizemos a configuração da interrupção externa do Arduino:
2.2.1. Primeiro, definimos a função attachInterrupt(1, turn, FALLING); , onde:
2.2.1.1. O parâmetro 1, significa INT = 1, ou seja, o pino digital 3 do Arduino Uno.
Obs1 - Veja nos tópicos acima, onde mostramos como conectar o botão e o sensor de toque.
Obs2 - No Arduino UNO podemos utilizar digitalPinToInterrupt(2) ou digitalPinToInterrupt(3) ao invés de 0 ou 1.
2.2.1.2. O segundo parâmetro define a ISR, ou seja, a função que é executada após uma interrupção externa. No nosso exemplo, a ISR foi denominada como turn.
2.2.1.3. O terceiro parâmetro define o tipo de variação de sinal. No nosso exemplo, utilizamos o parâmetro FALLING, ou seja, dispara a ISR sempre na borda de descida (de 5V para 0V). Isto significa que quando pressionarmos o botão, ocorrerá a interrupção externa, pois o botão está configurado como PULLUP (gera um sinal de baixo nível - LOW - ao ser pressionado).
Obs - Se você utilizar o parâmetro RISING, por exemplo, a interrupção ocorrerá apenas quando você soltar o botão.
2.2.2. Finalmente criamos a função ISR, denominada turn, que fará com que acenda ou apague o led quando o botão for pressionado.
2.3. Observe que ao configurarmos uma interrupção externa no Arduino, como no exemplo acima, precisaremos de 1120 bytes (3%) de espaço de armazenamento para programas.
3. Finalmente, vamos reproduzir o mesmo exemplo anterior, usando agora os registradores de portas do Arduino UNO.
const byte LED = (1<<4); // pino 12 (bit 4 da Porta B)
const byte BOT = (1<<3); // pino 03 (bit 3 da porta D)
void setup() {
DDRB |= LED; // configura pino 12 como saida - led
DDRD &= ~BOT; // configura pino 3 como entrada - botão
PORTD |= BOT; // habilita o pull up interno
EIMSK |= (1<
Atenção: Os conceitos abaixo foram demonstrados no Projeto 81 - Ligar e desligar um led por manipulação direta de portas do Arduino:
3.1. Primeiro configuramos as constantes LED e BOT usando operadores bitwise para definir o pino de conexão
3.1.1. Pino 12 fica na Porta B4. Portanto vamos setar apenas o bit 4 da porta B, ficando desta forma: const byte LED = (1<<4);
3.1.2. Já o pino 3 fica na Porta D3. Vamos setar então o bit 3 da porta D, ficando desta forma: const byte BOT = (1<<3);
3.1.2.1. Observe também que o pino 3 está configurado como INT1.
3.2. Depois, definimos a estrutura void setup() como:
3.2.1. Através da expressão DDRB |= LED; definimos o pino 12 como OUTPUT, ou seja, configuramos o bit 4 da PORTA B com o valor 1.
3.2.2. Através da expressão DDRD &= ~BOT; definimos o pino 3 como INPUT, ou seja, configuramos o bit 3 da PORTA D com o valor 0.
3.2.3. Através da expressão PORTB |= BOT; habilitamos o INPUT_PULLUP interno do microcontrolador, enviando o sinal 1 para o pino 3, ou seja, para o bit 3 da PORTA D.
3.2.4. A configuração do INPUT_PULLUP serve para utilizarmos o resistor interno do microcontrolador e evitar flutuações indevidas de sinal. Leia Como usar push button com Arduino (programação).
3.2.5. Para habilitar a interrupção externa no pino 3 (INT1) utilizamos o registrador EIMSK, como foi demonstrado anteriormente:
EIMSK |= (1< // habilita a interrupção externa int 1
3.2.6. Utilizando o registrador EICRA configuramos o pino 3 para que ocorra uma interrupção externa na borda de descida, ou seja, dispara a ISR sempre na borda de descida, quando ocorre um sinal de HIGH para LOW (de 5V para 0V).
EICRA |= (1< // configura interrupção externa INT1 - FALLING (pino 3)
Obs.: Isto significa que quando pressionarmos o botão, ocorrerá a interrupção externa, pois o botão está configurado como PULLUP (gera um sinal de baixo nível - LOW - ao ser pressionado).
3.2.7. Através da função sei(); habilitamos globalmente as interrupções no circuito. Isto e obrigatório quando se utiliza registradores EIMSK e EICRA.
3.2.8. Através da expressão PORTB &= ~LED; imprimimos um valor 0 (LOW) no bit 4 da PORTA B (pino 12) fazendo com que o programa se inicie com o led apagado. (obs.: LED = (1<<4);)
3.3. Finalmente, através da função ISR(INT1_vect) { PORTB ^= LED; } criamos a função ISR que fará com que acenda ou apague o led quando o botão for pressionado.
3.3.1. A expressão PORTB ^= LED; liga e desliga o led a cada vez que o botão é pressionado. Operador XOR - Referência Arduino.
3.4. Observe que ao utilizarmos registradores de portas para o envio de sinais, como no exemplo acima, precisamos de apenas de 502 bytes de espaço de armazenamento para programas.
3.4.1. Isto demonstra que esta técnica é a mais eficiente para otimizar memória no Arduino Uno quando se utiliza um botão para ligar e desligar um componente. Observe que no exemplo do projeto 81 precisamos de 600 bytes para a mesma funcionalidade.
4. Agora que tivemos uma visão geral do uso de registradores de portas para leitura e escrita digital e registradores para interrupções externas no microcontrolador ATmega328, podemos prosseguir para o nosso projeto final, onde usamos um botão e um sensor de toque para ligar e desligar um led.
Sketch do projeto
1. Faça o dowload e abra o arquivo projeto82.ino no IDE do Arduino: DOWNLOAD - projeto82.ino
Se preferir, copie e cole o código abaixo no IDE do Arduino:
/*******************************************************************************
*
* Projeto 82: Interrupção Externa com Registradores de Portas Arduino
* Autor: Angelo Luis Ferreira
* Data: 15/05/2020
* http://squids.com.br/arduino
*
*******************************************************************************/
const byte LED = (1<<4); // pino 12 (bit 4 da Porta B)
const byte SEN = (1<<2); // pino 02 (bit 2 da porta D)
const byte BOT = (1<<3); // pino 03 (bit 3 da porta D)
void setup() {
DDRB |= LED; // configura pino 12 como saida - led
DDRD &= ~SEN; // configura pino 2 como entrada - sensor
DDRD &= ~BOT; // configura pino 3 como entrada - botão
PORTD |= BOT; // habilita o pull up interno
EIMSK |= (1<<INT0) | (1<<INT1); // habilita a interrupção externa int 0 e int 1
EICRA |= (1<<ISC01) | (1<<ISC00); // configura interrupção externa int 0 - RISING (pino 2)
EICRA |= (1<<ISC11) | (0<<ISC10); // configura interrupção externa int 1 - FALLING (pino 3)
sei(); // flag que habilita as interrupções globalmente
PORTB &= ~LED; // inicia com led desligado (LOW)
}
void loop() {
}
// interrupções ISR's
ISR(INT0_vect) {
PORTB ^= LED;
}
ISR(INT1_vect) {
PORTB ^= LED;
}
Vídeo
Como o projeto deve funcionar
1. Ao iniciar o programa, o led estará desligado.
2. Clicando no botão ou no sensor de toque, o led se estriver desligado irá acender e se estiver ligado irá apagar.
O anúncio abaixo ajuda a manter o Squids Arduino funcionando
Comentários