Neste tutorial, será mostrado como ler o botão BOOTSEL da placa Raspberry Pi Pico e utilizar essa informação para controlar o comportamento de um LED externo. Além disso, vamos explorar como implementar diferentes funções para um único botão. O botão BOOTSEL na Raspberry Pi Pico desempenha um papel importante ao iniciar o dispositivo em diferentes modos de inicialização. No entanto, também podemos aproveitar esse botão para executar ações personalizadas no nosso programa, com a vantagem de não precisar adicionar um botão externo em uma protoboard.
Além de mostrar como ler o botão BOOTSEL, será mostrado como dar duas funções a um mesmo botão. Este botão será o BOOTSEL, da palca Raspberry Pi Pico. Estas duas funções irão controlar um LED externo de modos difrerentes.
Para este post, é utilizado o seguinte material:
Para realizar a leitura do botão BOOTSEL da placa Raspberry Pi Pico, basta usar a variável BOOTSEL
. Essa variável é definida no arquivo bootsel.cpp
. Para usar a variável BOOTSEL
, deve-se usar o pacote de placas Arduino-Pico. Caso ainda não o tenha instalado, veja como fazer o processo de instalação do pacote de placas no post Raspberry Pi Pico com Arduino IDE + Exemplos do blog Eletrogate.
Veja um exemplo de uso da variável BOOTSEL
:
/****************************************************************************** Lendo o botão BOOTSEL da placa Raspberry Pi Pico no Framework Arduino Sketch Como ler o botão BOOTSEL Criado em 10 de Junho de 2023 por Michel Galvão (https://micsg.com.br) Eletrogate | Arduino, Robótica, IoT, Apostilas e Kits https://www.eletrogate.com/ Confira mais detalhes deste sketch em https://blog.eletrogate.com/ ******************************************************************************/ void setup() { pinMode(LED_BUILTIN, OUTPUT); // Define o pino do LED_BUILTIN como saída } void loop() { if (BOOTSEL) { // Verifica se o botão BOOTSEL foi pressionado digitalWriteFast(LED_BUILTIN, HIGH); // Define o pino LED_BUILTIN como HIGH, acendendo o LED while (BOOTSEL); // Aguarda o botão BOOTSEL ser solto digitalWriteFast(LED_BUILTIN, LOW); // Define o pino LED_BUILTIN como LOW, apagando o LED } }
Ao utilizar a variável BOOTSEL
em uma condição, como no exemplo de código acima, o programa, internamente, chama a função get_bootsel_button()
para obter o estado do botão BOOTSEL. Essa função desabilita as interrupções, verifica o estado do pino GPIO associado ao botão BOOTSEL, habilita novamente as interrupções e retorna true
se o botão estiver pressionado ou false
, caso contrário.
No código acima, na função loop()
, a condição if (BOOTSEL)
verifica se o botão BOOTSEL está pressionado. Se essa condição for verdadeira, ou seja, o botão estiver pressionado, o programa acende o LED onboard utilizando a função digitalWrite()
, passando como parâmetros o pino do LED (no caso, LED_BUILTIN) e o estado no qual deseja que o pino fique (no caso, HIGH). Em seguida, o programa entra em um loop while
que aguarda até que o botão BOOTSEL seja liberado, ou seja, até que o estado de BOOTSEL
se torne falso. Ao sair do loop while
, o que significa que o botão foi solto, o LED é apagado pela função digitalWrite()
, passando como parâmetros o pino do LED (no caso, LED_BUILTIN) e o estado no qual deseja que o pino fique (no caso, LOW).
Essa abordagem permite ao programa detectar quando o botão BOOTSEL é pressionado e tomar medidas com base nessa informação. É importante mencionar que as informações sobre a implementação do BOOTSEL são baseadas no arquivo bootsel.cpp
, incluído no core do pacote de placas Arduino-Pico da placa Raspberry Pi Pico, que contém a lógica de leitura e verificação do estado do botão BOOTSEL na placa Raspberry Pi Pico. Veja mais detalhes sobre este arquivo em https://github.com/earlephilhower/arduino-pico/blob/master/cores/rp2040/Bootsel.cpp.
Como exemplo de projeto usando o botão BOOTSEL, será mostrado como fazer com que um botão tenha mais de uma função. As duas funções que estarão atribuídas ao botão BOOTSEL são as seguintes:
A transição entre as funções será feita utilizando uma lógica de programação que verifica os padrões de pressionar e soltar o botão BOOTSEL. Veja a descrição do fluxo básico de como será implementado no projeto:
millis()
para medir a diferença entre os tempos de soltar e pressionar o botão. Após reconhecer o padrão de duplo clique, será utilizado uma variável de estado com uma estrutura de condição para verificar se é necessário mudar para a função alternativa;millis()
novamente para verificar se o botão foi mantido pressionado por um período específico.O Sketch do projeto é o abaixo:
/****************************************************************************** Lendo o botão BOOTSEL da placa Raspberry Pi Pico no Framework Arduino Sketch do Projeto de Exemplo Criado em 12 de Junho de 2023 por Michel Galvão (https://micsg.com.br) Eletrogate | Arduino, Robótica, IoT, Apostilas e Kits https://www.eletrogate.com/ Confira mais detalhes deste sketch em https://blog.eletrogate.com/ ******************************************************************************/ bool funcaoBasicaEhAtual = true; // variável indicando se a função básica está ativa (true) ou se a função alternativa está ativa (false) bool statusLed = LOW; // controla o estado do LED (HIGH ou LOW) unsigned long timer = 0; // Timer para controle de tempo const uint8_t pinLed = 0; // Define a constante pinLed como o valor 0, representando o número do pino digital conectado ao LED. void setup() { Serial.begin(115200); // Inicia a comunicação serial com uma taxa de baud rate de 115200. // Lembre-se que esta taxa é ignorada, pois a Serial na Raspberry Pi Pico é baseada em USB. pinMode(pinLed, OUTPUT); // Configura o pino do LED como saída } void loop() { if (funcaoBasicaEhAtual) { // Verifica se a função básica está ativa if (BOOTSEL) { // Verifica se o botão BOOTSEL está pressionado Serial.println("Primeiro clique detectado"); // Informa que foi detectado o primeiro clique statusLed = HIGH; // Define a variável de controle do estado do LED como HIGH (ligado) while (BOOTSEL) {} // Aguarda até que o BOOTSEL deixe de ser pressionado statusLed = LOW; // Define a variável de controle do estado do LED como LOW (desligado) timer = millis(); // Registra o valor atual do tempo em milissegundos, depois de soltar o botão while (!BOOTSEL && millis() - timer <= 100) {} // Aguarda até que o BOOTSEL seja pressionado novamente ou até que tenha // passado 100 milissegundos desde o evento de soltar o botão. if (BOOTSEL) { // Verifica se o botão BOOTSEL está pressionado Serial.println("Segundo clique detectado"); // Informa que foi detectado o segundo clique while (BOOTSEL) {} // Aguarda até que o BOOTSEL deixe de ser pressionado funcaoBasicaEhAtual = false; // Define a função alternativa como ativa, e desativa a básica (false) Serial.println("Troca para função alternativa"); // Informa que está trocando para a função alternativa } else { Serial.println("Continua na função básica"); // Informa que permanecerá funcionando na função básica } Serial.println(); } } else { // Caso contrário, se a função básica não está ativa e sim a alternativa if (BOOTSEL) { // Verifica se o botão BOOTSEL está pressionado statusLed = !digitalRead(pinLed); // Define a variável de controle do estado do LED como o inverso da leitura do valor // atual do pino pinLed, ou seja, inverte o estado do LED. timer = millis(); // Registra o valor atual do tempo em milissegundos, após o botão estar pressionado while (BOOTSEL) {} // Aguarda até que o BOOTSEL deixe de ser pressionado if (millis() - timer >= 1000) { // Verifica se o tempo decorrido desde o botão estar pressionado é igual ou superior a 1000 milissegundos (1 segundo) Serial.println("Troca para função básica"); // Informa que está trocando para a função básica funcaoBasicaEhAtual = true; // Define a função básica como ativa, e desativa a alternativa (true) statusLed = LOW; // Define a variável de controle do estado do LED como LOW (desligado) } else { // Caso contrário, se o tempo decorrido desde o botão estar pressionado for menor que 1000 milissegundos, ... Serial.println("Continua na função alternativa"); // Informa que permanecerá funcionando na função alternativa } } } } void loop1() { digitalWrite(pinLed, statusLed); // Define o estado do LED com base na variável statusLed delay(1); // Aguarda 1 milissegundo antes de continuar a execução do loop1 }
No início do sketch, algumas variáveis e constantes são declaradas. A variável booleana funcaoBasicaEhAtual
indica se a função básica está ativa (true) ou se a função alternativa está ativa (false). A variável booleana statusLed
é responsável por controlar o estado do LED (HIGH ou LOW), indicando se está ligado ou desligado, respectivamente. A variável timer
é um temporizador utilizado para controlar o tempo decorrido. Além disso, é definida uma constante pinLed
que representa o número do pino digital conectado ao LED que é o pino 0 (zero).
bool funcaoBasicaEhAtual = true; // variável indicando se a função básica está ativa (true) ou se a função alternativa está ativa (false) bool statusLed = LOW; // controla o estado do LED (HIGH ou LOW) unsigned long timer = 0; // Timer para controle de tempo const uint8_t pinLed = 0; // Define a constante pinLed como o valor 0, representando o número do pino digital conectado ao LED.
A função setup()
é responsável pela configuração inicial do sketch. Nesse caso, a função Serial.begin(115200)
é chamada para iniciar a comunicação serial com uma taxa de baud rate de 115200. No entanto, é importante destacar que essa taxa é ignorada, pois a comunicação serial na Raspberry Pi Pico é baseada em USB. Em seguida, a função pinMode(pinLed, OUTPUT)
é utilizada para configurar o pino do LED como saída.
void setup() { Serial.begin(115200); // Inicia a comunicação serial com uma taxa de baud rate de 115200. // Lembre-se que esta taxa é ignorada, pois a Serial na Raspberry Pi Pico é baseada em USB. pinMode(pinLed, OUTPUT); // Configura o pino do LED como saída }
O loop principal do sketch é executado na função loop()
. Ele é dividido em duas partes: função básica e função alternativa. Para que o Raspberry Pi Pico saiba qual função executar para o botão, é feita uma verificação na variável funcaoBasicaEhAtual
com a estrutura de condição if
. Caso possuir o valor true
, a função básica é executada. Caso contrário, a função alternativa é executada.
void loop() { if (funcaoBasicaEhAtual) { // Verifica se a função básica está ativa // Código aqui que será executado quando a função básica está ativa // ... } else { // Caso contrário, se a função básica não está ativa e sim a alternativa // Código aqui que será executado quando a função alternativa está ativa // ... } }
Na função básica, o sketch verifica se o botão BOOTSEL está pressionado. Se sim, inicia-se o processo de detecção de cliques. Primeiro, é exibida a mensagem "Primeiro clique detectado"
utilizando a função Serial.println()
. Em seguida, a variável statusLed
é definida como HIGH, o que significa que o LED será ligado. O programa entra em um loop while()
enquanto o botão BOOTSEL estiver pressionado, aguardando até que seja solto. Após o botão ser solto, a variável statusLed
é definida como LOW, desligando o LED. O valor atual do tempo em milissegundos é registrado na variável timer
, utilizando a função millis()
. Em seguida, o programa entra em outro loop enquanto o botão BOOTSEL não estiver pressionado e o tempo decorrido (obtido pela diferença entre o valor atual de millis()
e o valor registrado em timer
) for menor ou igual a 100 milissegundos. Esse segundo loop serve para aguardar até que o botão seja pressionado novamente ou até que tenham se passado 100 milissegundos desde o momento em que o botão foi solto. Se após estes 100 milissegundos passarem e o botão não for pressionado, o programa não mudará de função (ele exibirá a mensagem "Continua na função básica"
utilizando a função Serial.println()
).
Se, dentro desse segundo loop, o botão BOOTSEL for pressionado novamente, é exibida a mensagem "Segundo clique detectado"
utilizando a função Serial.println()
. O programa entra em um novo loop enquanto o botão BOOTSEL estiver pressionado, aguardando até que seja solto novamente. Após o botão ser solto pela segunda vez, a variável funcaoBasicaEhAtual
é definida como false
, indicando que a função alternativa está ativa. Uma mensagem informativa "Troca para função alternativa"
é exibida utilizando a função Serial.println()
.
if (BOOTSEL) { // Verifica se o botão BOOTSEL está pressionado Serial.println("Primeiro clique detectado"); // Informa que foi detectado o primeiro clique statusLed = HIGH; // Define a variável de controle do estado do LED como HIGH (ligado) while (BOOTSEL) {} // Aguarda até que o BOOTSEL deixe de ser pressionado statusLed = LOW; // Define a variável de controle do estado do LED como LOW (desligado) timer = millis(); // Registra o valor atual do tempo em milissegundos, depois de soltar o botão while (!BOOTSEL && millis() - timer <= 100) {} // Aguarda até que o BOOTSEL seja pressionado novamente ou até que tenha // passado 100 milissegundos desde o evento de soltar o botão. if (BOOTSEL) { // Verifica se o botão BOOTSEL está pressionado Serial.println("Segundo clique detectado"); // Informa que foi detectado o segundo clique while (BOOTSEL) {} // Aguarda até que o BOOTSEL deixe de ser pressionado funcaoBasicaEhAtual = false; // Define a função alternativa como ativa, e desativa a básica (false) Serial.println("Troca para função alternativa"); // Informa que está trocando para a função alternativa } else { Serial.println("Continua na função básica"); // Informa que permanecerá funcionando na função básica } Serial.println(); }
Na função alternativa, o sketch verifica se o botão BOOTSEL está pressionado. Caso o botão BOOTSEL seja pressionado, o programa executa uma sequência de ações. Primeiro, o estado do LED é invertido utilizando a função digitalRead(pinLed)
, onde o parâmetro pinLed
é o número do pino digital conectado ao LED, e o resultado é armazenado na variável statusLed
. Em seguida, o valor atual do tempo em milissegundos é registrado na variável timer
. O programa entra em um loop enquanto o botão BOOTSEL não for solto, aguardando até que isso aconteça.
Após o botão BOOTSEL ser solto, o programa verifica se o tempo decorrido desde o momento em que o botão foi pressionado é maior ou igual a 1000 milissegundos (1 segundo). Se essa condição for satisfeita, significa que houve uma troca para a função básica. Nesse caso, é exibida a mensagem "Troca para função básica"
utilizando a função Serial.println()
. A variável funcaoBasicaEhAtual
é definida como true
, indicando que a função básica está ativa. Além disso, a variável statusLed
é definida como LOW, desligando o LED.
Por outro lado, se o tempo decorrido for menor que 1000 milissegundos, significa que o botão BOOTSEL foi pressionado apenas por um curto período. Nesse caso, o programa continua na função alternativa. A mensagem "Continua na função alternativa"
é exibida utilizando a função Serial.println()
.
if (BOOTSEL) { // Verifica se o botão BOOTSEL está pressionado statusLed = !digitalRead(pinLed); // Define a variável de controle do estado do LED como o inverso da leitura do valor // atual do pino pinLed, ou seja, inverte o estado do LED. timer = millis(); // Registra o valor atual do tempo em milissegundos, após o botão estar pressionado while (BOOTSEL) {} // Aguarda até que o BOOTSEL deixe de ser pressionado if (millis() - timer >= 1000) { // Verifica se o tempo decorrido desde o botão estar pressionado é igual ou superior a 1000 milissegundos (1 segundo) Serial.println("Troca para função básica"); // Informa que está trocando para a função básica funcaoBasicaEhAtual = true; // Define a função básica como ativa, e desativa a alternativa (true) statusLed = LOW; // Define a variável de controle do estado do LED como LOW (desligado) } else { // Caso contrário, se o tempo decorrido desde o botão estar pressionado for menor que 1000 milissegundos, ... Serial.println("Continua na função alternativa"); // Informa que permanecerá funcionando na função alternativa } }
Além do loop principal (loop()
), executado no núcleo 1 da placa Raspberry Pi Pico, o sketch também possui uma função chamada loop1()
. Essa função é executada no núcleo 2 da placa Raspberry Pi Pico repetidamente (saiba mais sobre dual-core da placa Raspberry Pi Pico no post Raspberry Pi Pico com Arduino IDE + Exemplos). Neste segundo loop, é feita a atualização de estado do LED com base no valor atual da variável statusLed
utilizando a função digitalWrite(pinLed, statusLed)
, onde o parâmetro pinLed
é o número do pino digital conectado ao LED e o parâmetro statusLed
é a variável que controla o estado do LED (HIGH ou LOW). Em seguida, a função delay(1)
é utilizada para aguardar 1 milissegundo antes de continuar a execução do loop.
void loop1() { digitalWrite(pinLed, statusLed); // Define o estado do LED com base na variável statusLed delay(1); // Aguarda 1 milissegundo antes de continuar a execução do loop1 }
Veja, no vídeo abaixo, a demonstração de funcionamento do projeto:
Aproveite a vantagem de utilizar o botão BOOTSEL da placa Raspberry Pi Pico para o controle de dispositivos, eliminando a necessidade de um botão externo na protoboard. Com a leitura e interpretação do estado do botão BOOTSEL, você poderá implementar diversos projetos facilmente.
Gostaríamos de saber se você curtiu este post! Por favor, avalie e deixe um comentário sobre o conteúdo. E não esqueça de nos seguir no Instagram e nos marcar quando fizer algum projeto nosso: @eletrogate.
Até a próxima!
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!