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!