Projeto 82 - Como realizar interrupção externa utilizando registradores do Arduino

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:

  1. Maior velocidade de acesso, pois acionaremos a porta diretamente sem a necessidade de funções.
  2. Otimização de memória do microcontrolador.
  3. Executar duas tarefas quase que simultaneamente.

Desvantagens de se utilizar registradores com interrupção:

  1. Código de difícil entendimento.
  2. 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.
  3. É 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 Resultado de imagem para protoboard 830v

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 3 Pçs 2.2nf X 2kv Capacitor 222 2200 105°c 2kv Capacitores - R$ 21 ...

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:

Entradas-e-Saídas-digitais-Arduino-pull-up-pull-down

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

×

Infomações do site / SEO








×

Adicionar Marcadores