Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

Componentes e Materiais

Software Necessário

Sobre o Projeto

Introdução

As interrupções são extremamente úteis: além de simplificar o código, permitem temporização precisa e acordar o Arduino do modo de suspensão (sleep).

Imagine uma interface de usuário, como um controle remoto alimentado por baterias. Para economizar energia, você colocaria o Arduino (ou um ATmega standalone) no modo power-down. Nesse modo, o chip só pode ser acordado por uma interrupção externa. O ATmega328P (usado no Arduino Uno) possui apenas duas interrupções externas (INT0 e INT1, nos pinos 2 e 3). Como uma interface típica tem mais de dois botões, isso é um problema.

A solução padrão seria conectar todos os botões normalmente e também ligá-los a um pino de interrupção através de diodos. Isso, porém, complica significativamente o circuito.

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

Além das interrupções externas padrão, o ATmega328P também possui interrupções de mudança de pino (pin change interrupts). Existem bibliotecas para gerenciá-las e elas são uma boa solução.

No entanto, durante uma competição de programação, descobri como fazer isso usando apenas interrupções externas padrão, sem componentes elétricos extras.

O Circuito

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

Utilizei dez botões, que couberam perfeitamente na minha protoboard. Você pode ter um botão por pino, o que permite até 20 botões no Uno e até 70 no Mega! (Se realmente precisar de 70 botões, recomendo usar multiplexação; não é necessário um Mega inteiro para isso.)

Cada botão tem um lado conectado a um pino arbitrário (no meu caso, pinos 4 a 13). Os outros lados de todos os botões são conectados juntos a um único pino capaz de interrupção (pino 2 no meu caso).

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

O Código

O código completo está disponível abaixo. Para testar, faça o upload para sua placa e abra o Monitor Serial. Ao pressionar um botão, seu número aparecerá. Note que a função loop() não é usada.

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

Como Funciona?

Existe, obviamente, uma interrupção. No meu caso, ela está anexada ao pino 2, configurada como FALLING (borda de descida).

Para evitar o uso de diodos, o Arduino reconfigura o circuito dinamicamente. Existem dois modos de operação: Modo Comum e Modo Distinto.

Modo Comum

Na maior parte do tempo, o circuito fica no modo comum. O pino de interrupção é configurado como INPUT_PULLUP e os demais pinos dos botões como OUTPUT e LOW.

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
void configureCommon() {
  pinMode(commonPin, INPUT_PULLUP);
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], OUTPUT);
    digitalWrite(buttonPins[i], LOW);
  }
}

Neste modo, pressionar qualquer botão puxará o pino de interrupção para LOW, disparando a interrupção. Quando isso ocorre, a rotina de serviço de interrupção (ISR) reconfigura os pinos para o modo distinto.

Modo Distinto

Assim que a interrupção é disparada, mudamos rapidamente para o modo distinto.

O modo distinto é o oposto do comum: o pino de interrupção torna-se OUTPUT e LOW, enquanto os pinos dos botões viram INPUT_PULLUP.

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
void configureDistinct() {
  pinMode(commonPin, OUTPUT);
  digitalWrite(commonPin, LOW);
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
}

No modo distinto, apenas os pinos correspondentes aos botões efetivamente pressionados serão puxados para LOW. Podemos então varrer todos os pinos para descobrir qual botão causou a interrupção.

Após a leitura, o Arduino pode voltar ao modo comum e aguardar a próxima interrupção. Dependendo da aplicação, pode permanecer no modo distinto processando a entrada do usuário normalmente, voltando ao modo comum apenas antes de entrar em sleep.

Exemplo Mais Complexo: Controle de Servo com Modo Sleep

Vamos a algo mais elaborado: anexamos um servo e mapeamos cada botão para um ângulo diferente (1=0°, 2=20°... 10=120°). O Arduino será alimentado por baterias.

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

Neste exemplo, o Arduino entra em power-down mode após 5 segundos de inatividade para economizar energia. O servo é alimentado através de um transistor, sendo desligado quando não está em uso.

O código completo deste exemplo também está disponível abaixo.

Códigos

Logger Serial (Exemplo Básico)

const int commonPin = 2;
const int buttonPins[] = {4,5,6,7,8,9,10,11,12,13};
unsigned long lastFire = 0;

void setup() {
  configureCommon();
  attachInterrupt(digitalPinToInterrupt(commonPin), pressInterrupt, FALLING);
  Serial.begin(9600);
}

void loop() {
  // Vazio!
}

void pressInterrupt() {
  if (millis() - lastFire < 200) return; // Debounce
  lastFire = millis();
  configureDistinct();
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    if (!digitalRead(buttonPins[i])) {
      press(i);
    }
  }
  configureCommon();
}

void configureCommon() {
  pinMode(commonPin, INPUT_PULLUP);
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], OUTPUT);
    digitalWrite(buttonPins[i], LOW);
  }
}

void configureDistinct() {
  pinMode(commonPin, OUTPUT);
  digitalWrite(commonPin, LOW);
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
}

void press(int button) {
  Serial.println(button + 1);
}

Servo com Modo Sleep (Exemplo Avançado)

#include <Servo.h>
#include <avr/sleep.h>
#include <avr/power.h>

const int commonPin = 2;
const int buttonPins[] = {4,5,6,7,8,9,10,11,12,13};
const int servoEnablePin = A1;
const int servoPin = A0;
Servo servo;
unsigned long lastFire = 0;
int status = 0;

void setup() {
  pinMode(commonPin, INPUT_PULLUP);
  configureCommon();
  attachInterrupt(digitalPinToInterrupt(commonPin), pressInterrupt, FALLING);
  servo.attach(servoPin);
  pinMode(servoEnablePin, OUTPUT);
}

void loop() {
  if (millis() - lastFire > 5000) {
    digitalWrite(servoEnablePin, LOW);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sleep_mode();
  }
  delay(10);
}

void pressInterrupt() {
  sleep_disable();
  power_all_enable();
  if (millis() - lastFire < 200) return;
  lastFire = millis();
  configureDistinct();
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    if (!digitalRead(buttonPins[i])) {
      press(i);
    }
  }
  configureCommon();
}

void configureCommon() {
  pinMode(commonPin, INPUT_PULLUP);
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], OUTPUT);
    digitalWrite(buttonPins[i], LOW);
  }
}

void configureDistinct() {
  pinMode(commonPin, OUTPUT);
  digitalWrite(commonPin, LOW);
  for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
}

void press(int button) {
  digitalWrite(servoEnablePin, HIGH);
  servo.write(map(button, 0, 9, 0, 180));
}

Esquemáticos

Arquivos Fritzing disponíveis:

Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO
Controle Eficiente de 10 Botões com uma Única Interrupção no Arduino UNO

Processo de manufatura

  1. Construa um Decodificador DTMF Usando Apenas um Arduino – Sem CIs Externos
  2. Crie um Sistema Ambilight Impressionante para Monitor com Arduino
  3. Construa um Dispositivo de Levitação Ultrassônica com Arduino – Guia Passo a Passo
  4. Construa um Voltímetro Inteligente com Arduino e Smartphone – Projeto DIY Fácil
  5. Monitor de Frequência Cardíaca IoT em Tempo Real com Arduino e MAX30100
  6. Servidor Web Arduino Uno WiFi: Controle LED via Navegador
  7. Contador Inteligente de Vagas: Rastreamento de Veículos em Tempo Real com Arduino, Processing e PHP
  8. Automatize o Jogo do Dinossauro do Chrome com Arduino e LDR
  9. Construa um Rádio FM Compacto com Arduino Nano e RDA5807M
  10. Shield de Programação Wireless Arduino com HC-05 Bluetooth – Sem Cabo USB