Raspberry Pi

Raspberry Pi Pico com Arduino IDE + Exemplos

Eletrogate 18 de julho de 2023

Introdução

Aprenda neste post como instalar o pacote de placas Raspberry Pi Pico no Arduino IDE para uso do Framework Arduino para programação da placa. Serão explicados e demonstrado 7 exemplos de sketches com o uso do Framework Arduino na placa Raspberry Pi Pico.

Os exemplos serão:

  1. Exemplo Blink: o exemplo mais básico, mostrando como criar um simples programa “Blink” para o Raspberry Pi Pico usando o Framework Arduino. Você aprenderá como utilizar o LED onboard da placa e controlá-lo sem utilizar delay para efeito de “piscar” do LED;
  2. Exemplo Display LCD I₂C: neste exemplo, será explorado como utilizar um display LCD I₂C com o Raspberry Pi Pico. Será detalhado sobre as alterações necessárias nos arquivos das bibliotecas LiquidCrystal_I2C e Wire, incluindo a criação de novos métodos para as classes necessárias. Essas alterações manterão a compatibilidade das bibliotecas alteradas com as placas Arduino, garantindo que seus sketches anteriores feitos com as bibliotecas modificadas ainda funcionem. Para comprovar a compatibilidade, será feito um teste utilizando uma Arduino Uno e um display LCD I₂C com a biblioteca modificada;
  3. Exemplo Scanner I₂C: Será abordado como escanear todos os 12 barramentos I₂C das 2 interfaces I₂C (Wire e Wire1) e detectar todos os dispositivos I₂C conectados;
  4. Exemplo Lendo Temperatura interna do Raspberry Pi Pico: Será explorado a capacidade do Raspberry Pi Pico de ler a temperatura interna do chip. Você aprenderá como acessar essa informação e usá-la em seus projetos, como monitorar a temperatura do processador ou acionar dispositivos de resfriamento com base nas mudanças de temperatura;
  5. Exemplo Usando os dois núcleos simultaneamente do Raspberry Pi Pico: O Raspberry Pi Pico possui dois núcleos, permitindo a execução simultânea de tarefas. Você aprenderá a como aproveitar essa capacidade, tendo dois setups e dois loops para serem executados um para cada núcleo, dividindo, assim, o trabalho entre os núcleos e obtendo melhor desempenho nos seus projetos;
  6. Exemplo Reiniciando o Raspberry Pi Pico via Software: Será abordado como reiniciar o Raspberry Pi Pico via software. Isso é especialmente útil quando se deseja reiniciar o Pico em resposta a eventos ou condições específicas, proporcionando maior controle e flexibilidade aos projetos;
  7. Exemplo Reiniciando o Raspberry Pi Pico via Hardware: Neste exemplo, será abordado como reiniciar o Raspberry Pi Pico por meio de hardware. Você aprenderá sobre como utilizar um botão (push button) para reiniciar o Raspberry Pi Pico. Isso te proporcionará maior comodidade, pois não será mais necessário desconectar o cabo micro USB toda vez que desejar carregar um novo código à placa Raspberry Pi Pico, bastando apenas pressionar o botão para reiniciar.

Instalando o pacote de placas no IDE Arduino

O pacote de placas Raspberry Pi Pico pode ser instalado de forma simples e conveniente por meio do Gerenciador de Placas do Arduino IDE. Com apenas alguns cliques, os usuários podem adicionar o suporte completo para placas Raspberry Pi Pico em seu ambiente de desenvolvimento. Além disso, a utilização do Arduino IDE com as placas Raspberry Pi Pico permite aos desenvolvedores acessar uma ampla gama de bibliotecas e exemplos, facilitando o processo de programação e o desenvolvimento de projetos com as placas Raspberry Pi Pico.

Siga os passos abaixo para instalar o pacote de placas Raspberry Pi Pico:

  1. Abra o Arduino IDE e vá para Arquivo → Preferências.
  2. Clique no botão ao lado da caixa de diálogo “URLs Adicionais para Gerenciadores de Placas”;
  3. Na caixa de diálogo “Entre com URLs adicionais, uma por linha”, vá para uma nova linha (se já tiver linhas ocupadas com um link. Caso contrário basta apenas colar) e cole o link “https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json”;
  4. Clique em OK para fechar a caixa de diálogo.
  5. Vá para Ferramentas → Placa → Gerenciador de Placas.
  6. Digite “Raspberry Pi Pico” na caixa de pesquisa e no pacote de placas Raspberry Pi Pico/RP2040 de Earle F. Philhower, III clique em “Instalar”:
  7. Após a instalação, clique no botão Fechar.

Com os passos acima realizados, o pacote de placas Raspberry Pi Pico foi instalado.

Nota para usuários do Windows: Não use o Arduino IDE baixada da Windows Store porque ela tem problemas para detectar placas Pico conectadas. Use o Arduino IDE baixada direto do site oficial Arduino: https://www.arduino.cc/en/software. Além disso, permitia que o IDE Arduino instale qualquer driver de dispositivo que ele solicitar para instalar. Caso contrário, a placa Pico pode não ser detectada.


Carregando o primeiro sketch

Para carregar um esboço na placa Raspberry Pi Pico, você precisará segurar o botão BOOTSEL enquanto conecta o cabo USB do Pico ao seu computador. Em seguida, pressione o botão de upload no IDE Arduino e o esboço deve ser transferido e começar a ser executado.
Veja abaixo como fazer isso:

  1. Com o IDE Arduino aberta e com um novo sketch, cole o seguinte código na IDE:
    void setup() {
      Serial.begin(115200);
    }
    
    void loop() {
      Serial.println("Olá mundo");
      delay(1000);
    }
    
    
  2. No IDE Arduino, vá em Ferramentas → Placa → Raspberry Pi RP2040 Boards e selecione a placa Raspberry Pi Pico:
  3. Na placa Raspberry Pi Pico, aperte e mantenha pressionado o botão BOOTSEL:
  4. Com o botão BOOTSEL ainda pressionado, clique no botão Carregar do Arduino IDE:
  5. Após o carregamento do sketch na placa, abra o Monitor Serial;
  6. Com o Monitor Serial aberto, veja a placa Raspberry Pi Pico imprimindo na Serial a frase “Olá Mundo”.

Vale lembrar que, embora Serial.begin() permita especificar uma taxa de transmissão, essa taxa é ignorada, pois a Serial na Raspberry Pi Pico é baseada em USB.

Veja o vídeo de demonstração:

Confira nos próximos tópicos exemplos de uso da placa Raspberry Pi Pico utilizando o Framework Arduino programado através do Arduino IDE.


Exemplo 1 - Blink

O exemplo Blink é o mais básico. Nele você aprenderá como utilizar o LED onboard da placa e controlá-lo sem utilizar delay para efeito de “piscar” do LED.
O LED onboard da placa Raspberry Pi Pico está conectado na GPIO 25. Portanto, utilizar ‘LED_BUILTIN’ é o mesmo que utilizar ‘25’.

O uso da função delay() para controlar o piscar de um LED pode ser prejudicial porque ela bloqueia a execução do programa durante o tempo especificado. Durante esse período de bloqueio, a placa Raspberry Pi Pico não pode realizar outras tarefas ou responder a eventos externos.

A função delay() pode parecer uma solução simples e direta para fazer um LED piscar com intervalos regulares. No entanto, o uso excessivo de delay() em um programa pode causar atrasos indesejados e impactar negativamente o desempenho geral do sistema. Isso ocorre porque a placa Raspberry Pi Pico fica inativa durante o tempo definido em delay(), impedindo a execução de outras tarefas ou processamentos que possam ser necessários.

Além disso, se você precisar adicionar funcionalidades adicionais ao seu programa, como ler sensores, controlar outros dispositivos ou responder a eventos específicos, o uso de delay() pode limitar ou impedir a capacidade de resposta da placa Raspberry Pi Pico.

Uma abordagem mais eficiente é utilizar técnicas de temporização não bloqueantes, como a utilização da função millis() ou uma biblioteca de temporização. Essas técnicas permitem que você controle o piscar do LED sem bloquear a execução do programa, permitindo que a placa Raspberry Pi Pico realize outras tarefas simultaneamente.

Ao utilizar temporização não bloqueante, você pode manter o programa responsivo, realizar leituras de sensores, responder a eventos externos e executar outras tarefas importantes enquanto controla o piscar do LED de forma precisa e flexível.

Neste exemplo, usaremos a função millis() do Framework Arduino. Esta função retorna o número de milissegundos passados ​​desde que a placa começou a executar o programa atual.

Sketch

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
                            Sketch Exemplo Blink

                       Criado em 21 de Maio 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 estadoLed = false;               // Variável para armazenar o estado do LED
unsigned long tempoUltimoPisque = 0;  // Variável para armazenar o tempo do último piscar
const unsigned long intervalo = 1000; // Intervalo de tempo entre os piscar (em milissegundos)

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Configura o pino do LED como saída
}

void loop() {
  if (millis() - tempoUltimoPisque >= intervalo) { // Verifica se o tempo decorrido desde o último piscar é maior ou igual ao intervalo definido
    digitalWrite(LED_BUILTIN, estadoLed); // Atualiza o LED com o estado atual
    estadoLed = !estadoLed;               // Inverte o estado do LED
    tempoUltimoPisque = millis();         // Armazena o tempo atual como o último piscar
  }
}

Explicação do Sketch

O sketch utiliza uma variável booleana chamada estadoLed para armazenar o estado atual do LED, onde false indica LED desligado e true indica LED ligado. Em seguida, há a variável tempoUltimoPisque, que armazena o tempo do último piscar do LED. O valor inicial é 0, indicando que ainda não ocorreu nenhum piscar. O intervalo é uma constante que define o tempo entre os piscar do LED, configurado para 1000 milissegundos (1 segundo).

Na função setup(), o pino do LED embutido (LED_BUILTIN) é configurado como saída, indicando que será usado para controlar o LED.

A função loop() é executada continuamente. Dentro dela, há um bloco condicional if que verifica se o tempo decorrido desde o último piscar é maior ou igual ao intervalo definido. Essa verificação é feita utilizando a função millis(), que retorna o tempo decorrido em milissegundos desde o início do programa.

Se a condição for verdadeira, o estado do LED é atualizado usando a função digitalWrite(), onde o valor da variável estadoLed é atribuído ao LED embutido. Em seguida, o estado do LED é invertido através do operador de negação (!). Por exemplo, se o LED estiver ligado, ele será desligado, e vice-versa. O tempo atual é então armazenado na variável tempoUltimoPisque, para registrar o momento do último piscar.

Vídeo de Demonstração


Exemplo 2 - Display LCD I2C

Neste exemplo, você aprenderá como utilizar um display LCD I2C com o Raspberry Pi Pico. Será abordado como realizar as alterações necessárias nos arquivos das bibliotecas LiquidCrystal_I2C e Wire, bem como a criação de novos métodos para as classes pertinentes. Essas modificações garantem a compatibilidade das bibliotecas alteradas com as placas Arduino, possibilitando que os sketches anteriores do leitor, feitos com as bibliotecas modificadas, continuem funcionando corretamente.

Ao realizar as alterações nos arquivos das bibliotecas LiquidCrystal_I2C e Wire, você estará assegurando que o Raspberry Pi Pico possa se comunicar corretamente com o display LCD I2C. Isso envolverá a criação de novos métodos para as classes necessárias, mantendo a compatibilidade com as placas Arduino.

Uma vez que as alterações tenham sido feitas nas bibliotecas, é hora de testar a compatibilidade. Para isso, utilizaremos uma Arduino Umo em conjunto com o display LCD I2C, empregando a biblioteca modificada. Esse teste nos permitirá verificar se a comunicação entre o Arduino e o display continua funcionando adequadamente, mesmo com as alterações realizadas nas bibliotecas.

A possibilidade de utilizar um display LCD I2C com o Raspberry Pi Pico amplia significativamente as opções de visualização e interação em seus projetos. Com as alterações nas bibliotecas LiquidCrystal_I2C e Wire e a criação dos métodos necessários, você poderá aproveitar todo o potencial desse display, mantendo a compatibilidade com placas Arduino. Essa flexibilidade oferece mais liberdade e criatividade na escolha da plataforma de desenvolvimento para seus projetos, permitindo que você explore os recursos do Raspberry Pi Pico junto com a familiaridade do Arduino.

Instalação de Bibliotecas necessárias

Para desenvolvermos o software para este exemplo, devemos fazer o download de uma biblioteca: a LiquidCrystal_I2C (permite controlar displays I2C com funções extremamente semelhantes à biblioteca LiquidCrystal).

Para a instalação da biblioteca, siga os passos abaixo:

  • No gerenciador de Bibliotecas do Arduino IDE (vá em Ferramentas → Gerenciar Bibliotecas), na barra de pesquisa digite: ‘LiquidCrystal_I2C’ (1). Clique para instalar (2) no resultado que seja do autor Marco Schwartz.

Modificando Bibliotecas necessárias

Biblioteca LiquidCrystal_I2C

Para modificar a biblioteca LiquidCrystal_I2C, você deve primeiro localizá-la onde foi instalada. Para isso, siga os passos abaixo:

  1. No Arduino IDE, vá em Arquivo → Preferências.
  2. Copie o endereço da pasta Arduino da caixa de diálogo Local do Sketchbook.
  3. Abra um Explorador de Arquivos (no windows o atalho é tecla Win + E), cole o endereço copiado na barra de endereços do Explorador de Arquivos e acesse o endereço.
  4. Na pasta aberta, entre no diretório libraries. Este diretório é onde as bibliotecas são instaladas.
  5. Nesta pasta, localize a pasta com nome LiquidCrystal_I2C.

Com os passos anteriores realizados, você localizou onde a biblioteca LiquidCrystal_I2C foi instalada. Na pasta da biblioteca LiquidCrystal_I2C, acesse os seguintes arquivos e faça as modificações listadas abaixo:

library.properties

1. Abra o arquivo “library.properties” em um editor de texto de sua preferência (como o bloco de notas ou o vscode).

2. Localize a linha que contém a propriedade “architectures” e o valor atual “avr”. A linha deve ser semelhante a esta: “architectures=avr”.

3. Acrescente o termo “rp2040” à lista de arquiteturas separado por vírgulas, mantendo o formato existente. Após fazer a modificação, a linha deve ficar assim: “architectures=avr,rp2040”.

4. Salve o arquivo “library.properties” com as alterações feitas.

LiquidCrystal_I2C.cpp

1. Abra o arquivo “LiquidCrystal_I2C.cpp” em um editor de texto de sua preferência (como o bloco de notas ou o vscode).

2. Com o editor de texto, substitua as ocorrências de “Wire” para “wire_utilizado”. Faça isso utilizando a ferramenta Substituir (Ctrl + H). Após as substituições, altere #include "wire_utilizado.h" para #include "Wire.h". Exemplo: na linha 9, Wire.write(args) irá ser alterado para wire_utilizado.write(args).

3. Após a inclusão da biblioteca “Wire.h”, instancie a variável global wire_utilizado da classe TwoWire:

TwoWire& wire_utilizado = Wire;

4. No método init da classe LiquidCrystal_I2C, adicione o seguinte código: wire_utilizado = Wire;. Este código é responsável por alterar o tipo de Wire para ser utilizado no código. Neste caso, o Wire utilizado é o Wire (de duas opções disponíveis: Wire e Wire1). O método init ficará assim:

void LiquidCrystal_I2C::init(){
    wire_utilizado = Wire;
    init_priv();
}

5. Crie um novo método para a classe LiquidCrystal_I2C chamado init_v_pico. Este método público faz a inicialização especial para o display que é usado na placa Raspberry Pi Pico. Dentro do método adicione o seguinte código:

wire_utilizado = wire;
init_priv_v_pico(sda, scl);

Este código é responsável por alterar o tipo de Wire para ser utilizado no código. Neste caso, o Wire utilizado é o definido no parâmetro wire (neste caso o programador que usará a biblioteca modificada pode escolher entre Wire e Wire1). O código adicionado também faz a chamada do método init_priv_v_pico passando os parâmetros de pino SDA e SCL para o iniciador privado da classe LiquidCrystal_I2C. Adicione no método init_v_pico os seguintes parâmetros:

  • TwoWire& wire: Esse parâmetro é uma referência a um objeto TwoWire, que representa a interface I2C a ser utilizada para a comunicação com o display LCD. Na chamada da função, você pode utilizar Wire ou Wire1.
  • int sda: Este parâmetro representa o número do pino usado para a comunicação de dados (SDA) entre o microcontrolador e o display LCD. O pino SDA é responsável por enviar e receber dados.
  • int scl: Este parâmetro representa o número do pino usado para a comunicação de clock (SCL) entre o microcontrolador e o display LCD. O pino SCL é responsável por fornecer os pulsos de clock que sincronizam a transferência de dados

O método init_v_pico ficará assim:

void LiquidCrystal_I2C::init_v_pico(TwoWire& wire, int sda, int scl){
    wire_utilizado = wire;
    init_priv_v_pico(sda, scl);
}

6. Crie um novo método para a classe LiquidCrystal_I2C chamado init_priv_v_pico. Este método privado faz as tarefas necessárias para inicializar o display, que neste caso é usado na placa Raspberry Pi Pico. Dentro do método adicione o seguinte código:

wire_utilizado.setSDA(sda);
wire_utilizado.setSCL(scl);
wire_utilizado.begin();	
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin(_cols, _rows);

Como a placa Raspberry Pi Pico tem duas interfaces I2C, i2c0(Wire) e i2c1 (Wire1), deve-se alterar os pinos no código antes de chamar Wire.begin() ou Wire1.begin() usando: bool setSDA(pin_size_t sda); para definir o pino utilizado para SDA e bool setSCL(pin_size_t scl); para definir o pino utilizado para SCL.

O código adicionado define o pino utilizado para a linha de dados (SDA) do protocolo I2C, usando a função setSDA(). O parâmetro sda representa o número do pino correspondente.

Em seguida, é necessário definir o pino utilizado para a linha de clock (SCL) do protocolo I2C, por meio da função setSCL(). O parâmetro scl representa o número do pino correspondente.

Após configurar os pinos, é iniciado a comunicação I2C por meio da função begin(). Essa função prepara o dispositivo para a troca de dados utilizando os pinos definidos anteriormente.

Em seguida, é feita a configuração do display LCD. A variável _displayfunction é utilizada para armazenar as opções de configuração. Essas opções indicam que o display está operando no modo de 4 bits, possui uma única linha de texto e caracteres com uma matriz de 5×8 pontos.

Por fim, é feita a inicialização do display LCD utilizando a função begin() com os parâmetros _cols e _rows, na qual são informados o número de colunas (_cols) e o número de linhas (_rows). Essa etapa configura o tamanho do display e o prepara para exibir texto ou gráficos.

Adicione também no método init_priv_v_pico os seguintes parâmetros:

  • int sda: o pino utlizado para SDA;
  • int scl: o pino utlizado para SCL.

O método init_priv_v_pico ficará assim:

void LiquidCrystal_I2C::init_priv_v_pico(int sda, int scl){
    wire_utilizado.setSDA(sda);
    wire_utilizado.setSCL(scl);
    wire_utilizado.begin();    
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
    begin(_cols, _rows);
}
LiquidCrystal_I2C.h

1. Abra o arquivo “LiquidCrystal_I2C.h” em um editor de texto de sua preferência (como o bloco de notas ou o vscode).

2. Com o editor de texto, adicione o protótipo da função init_v_pico() dentro do bloco de protótipos de funções públicas. Veja na linha 88 o protótipo de função adicionado:

public:
  LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows);
  void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS );
  void clear();
  void home();
  void noDisplay();
  void display();
  void noBlink();
  void blink();
  void noCursor();
  void cursor();
  void scrollDisplayLeft();
  void scrollDisplayRight();
  void printLeft();
  void printRight();
  void leftToRight();
  void rightToLeft();
  void shiftIncrement();
  void shiftDecrement();
  void noBacklight();
  void backlight();
  void autoscroll();
  void noAutoscroll(); 
  void createChar(uint8_t, uint8_t[]);
  void setCursor(uint8_t, uint8_t); 
#if defined(ARDUINO) && ARDUINO >= 100
  virtual size_t write(uint8_t);
#else
  virtual void write(uint8_t);
#endif
  void command(uint8_t);
  void init();
  void init_v_pico(TwoWire& wire, int sda, int scl);

3. Adicione também o protótipo da função init_priv_v_pico() dentro do bloco de protótipos de funções privadas. Veja na linha 113 o protótipo de função adicionado:

private:
  void init_priv();
  void init_priv_v_pico(int sda, int scl);
  void send(uint8_t, uint8_t);
  void write4bits(uint8_t);
  void expanderWrite(uint8_t);
  void pulseEnable(uint8_t);

Biblioteca Wire

Para modificar a biblioteca Wire, você deve primeiro localizá-la onde foi instalada. Para isso, siga os passos abaixo (somente usuáriso Windows):

  1. Abra a caixa de diálogo Executar do Windows, pressionando o atalho Windows + R;
  2. Digite na caixa de diálogo o comando %LocalAppData%, para abrir a pasta AppData,. Em seguida, clique o botão OK para executar 0 comando;
  3. Na pasta aberta, abra a pasta Arduino15;
  4. Na barra de endereços, cole na frente do endereço atual o seguinte texto e, após, tecle enter: \packages\arduino\hardware\avr\1.8.6\libraries\Wire\;

Com os passos realizados, você localizou onde a biblioteca Wire foi instalada. Na pasta da biblioteca Wire (mais precisamente, dentro do diretório \src), acesse os seguintes arquivos e faça as modificações listadas abaixo:

Wire.h

Para manter compatibilidade com outras placas que não sejam a Raspberry Pi Pico, deve-se criar 2 protótipos de função públicos para a classe TwoWire. Para isso siga os passos abaixo:

1. Abra o arquivo “Wire.h” em um editor de texto de sua preferência (como o bloco de notas ou o vscode).

2. Com o editor de texto, adicione o protótipo da função setSDA() dentro do bloco de protótipos de funções públicas. Veja na linha 53 o protótipo de função adicionado:

public:
  TwoWire();
  bool setSDA(int sda);

3. Adicione também o protótipo da função setSCL() dentro do bloco de protótipos de funções públicas. Veja na linha 54 o protótipo de função adicionado:

public:
  TwoWire();
  bool setSDA(int sda);
  bool setSCL(int scl);

Download das bibliotecas modificadas

Caso deseje conferir as modificações das bibliotecas, faça o download do arquivo ZIP contendo as bibliotecas Wire e LiquidCrystal_I2C:

Download do arquivo bibliotecas_modificadas.zip

Esquemático

Sketch

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
                      Sketch Exemplo Display LCD I2C

                       Criado em 29 de Maio 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/
******************************************************************************/

// Inclusão das bibliotecas
#include <Wire.h>               // Biblioteca para comunicação I2C
#include <LiquidCrystal_I2C.h>  // Biblioteca para controle do display LCD I2C

LiquidCrystal_I2C lcd(0x27, 16, 2); // Inicializa o objeto para controle do display
//                                   LCD I2C com endereço 0x27, 16 colunas e 2 linhas.

void setup()
{
  lcd.init_v_pico(Wire, 0, 1);  // Inicializa o display LCD I2C com o método 'init_v_pico',
  //                            passando como parâmetros a interface I2C a ser utilizada,
  //                            o número do pino SDA usado e o número do pino SCL usado.

  lcd.backlight();  // Acende a luz de fundo do display
}


void loop()
{
  lcd.setCursor(0, 0);            // Define a posição do cursor na coluna 0 e linha 0 do display LCD
  lcd.print("Hello, world!   ");  // Escreve "Hello, world!" no display LCD
  delay(1000);                    // Aguarda 1 segundo

  lcd.setCursor(0, 0);            // Define a posição do cursor na coluna 0 e linha 0 do display LCD
  lcd.print("Ola, mundo!     ");  // Escreve "Ola, mundo!" no display LCD
  delay(1000);                    // Aguarda 1 segundo
}

No início do código, são incluídas duas bibliotecas: a biblioteca Wire.h para comunicação I2C e a biblioteca LiquidCrystal_I2C.h para controle do display LCD I2C. Essas bibliotecas permitem a comunicação entre o Raspberry Pi Pico e o display LCD.

Em seguida, é criado um objeto lcd do tipo LiquidCrystal_I2C com o endereço do display (0x27), o número de colunas (16) e o número de linhas (2).

No bloco setup(), é chamada a função init_v_pico() do objeto lcd para inicializar o display LCD I2C. Essa função recebe como parâmetros a interface I2C a ser utilizada e os números dos pinos SDA e SCL a serem usados (0 e 1, respectivamente). Neste exemplo é utilizada a interface Wire (I2C0), mas também pode ser utilizada a interface Wire1 (I2C1) alterando Wire por Wire1, além de alterar a conexão dos pinos do display I2C para um barramento I2C1. Confira a pinagem do Raspberry Pi Pico para ver quais barramentos I2C são I2C0 ou I2C1.

Pode-se ver que este barramento I2C, com os pinos GPIO0 e GPIO1, é da interface I2C I2C0.

Após a inicialização do display, a função backlight() é chamada para acender a luz de fundo do display, permitindo a visualização das informações.

No bloco loop(), é definida a posição do cursor no display usando a função setCursor() do objeto lcd. Neste exemplo, a posição é definida como coluna 0 e linha 0.

Em seguida, a função print() do objeto lcd é utilizada para escrever a mensagem "Hello, world!" no display. Após a exibição da mensagem, a função delay() com parâmetro 1000 (1000 milissegundos) é chamada para aguardar 1 segundo antes de continuar a execução.

O mesmo procedimento é repetido, mas com a mensagem "Ola, mundo!" sendo exibida no display. Novamente, é aguardado 1 segundo antes de repetir o ciclo.

Dessa forma, o código realiza um loop infinito, alternando entre as duas mensagens no display LCD I2C a cada segundo.

Vídeo de Demonstração

Teste de Compatibilidade

Para comprovar a compatibilidade, será feito um teste utilizando uma arduino Uno e um display LCD I2C com as bibliotecas modificadas.

Esquemático

Sketch

O sketch utilizado é o que está abaixo:

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
            Sketch Exemplo Display LCD I2C - Teste de Compatibilidade

                       Criado em 29 de Maio 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/
******************************************************************************/

// Inclusão das bibliotecas
#include <Wire.h>               // Biblioteca para comunicação I2C
#include <LiquidCrystal_I2C.h>  // Biblioteca para controle do display LCD I2C

LiquidCrystal_I2C lcd(0x27, 16, 2); // Inicializa o objeto para controle do display LCD I2C com endereço 0x27, 16 colunas e 2 linhas

void setup()
{
  lcd.init();       // Inicializa o display LCD I2C
  lcd.backlight();  // Acende a luz de fundo do display
}

void loop()
{
  lcd.setCursor(0, 0);            // Define a posição do cursor na coluna 0 e linha 0 do display LCD
  lcd.print("Hello, world!   ");  // Escreve "Hello, world!" no display LCD
  delay(1000);                    // Aguarda 1 segundo

  lcd.setCursor(0, 0);            // Define a posição do cursor na coluna 0 e linha 0 do display LCD
  lcd.print("Ola, mundo!     ");  // Escreve "Ola, mundo!" no display LCD
  delay(1000);                    // Aguarda 1 segundo
}

O código começa incluindo duas bibliotecas necessárias: a biblioteca Wire para comunicação I2C e a biblioteca LiquidCrystal_I2C para controle do display LCD I2C.

Em seguida, é criado um objeto chamado “lcd” usando a classe LiquidCrystal_I2C. O objeto é inicializado com o endereço 0x27, 16 colunas e 2 linhas, correspondendo às especificações do display LCD.

No bloco de configuração do programa (função setup()), o display LCD é inicializado usando o método init() e a luz de fundo é ativada com o método backlight(). Isso prepara o display para exibir as mensagens.

No bloco principal do programa (função loop()), há um loop infinito. A cada iteração do loop, o cursor do display é posicionado na coluna 0 e linha 0 usando o método setCursor(). Em seguida, uma mensagem é impressa no display usando o método print(). Após isso, o programa aguarda 1 segundo usando a função delay() passando como parâmetro o tempo de espera.

Depois de 1 segundo, o cursor é reposicionado e a segunda mensagem é impressa no display. O programa aguarda novamente 1 segundo e o processo se repete, alternando entre as duas mensagens.

Dessa forma, o código permite exibir as mensagens "Hello, world!" e "Ola, mundo!" no display LCD I2C, alternando entre elas a cada segundo.

Vídeo de Demonstração do Teste


Exemplo 3 - Scanner I2C

A placa Raspberry Pi Pico é uma poderosa placa de desenvolvimento baseada no microcontrolador RP2040. Com seu tamanho compacto e ampla gama de recursos, ela se tornou uma escolha popular para projetos de eletrônica e IoT (Internet das Coisas). Um dos recursos mais importantes da Raspberry Pi Pico é sua capacidade de se comunicar por meio do protocolo I2C (Inter-Integrated Circuit), que permite a conexão de vários dispositivos em uma única interface.

Ao desenvolver projetos com a Raspberry Pi Pico, é fundamental ter um scanner I2C para facilitar a detecção e o controle de dispositivos conectados à placa. Um scanner I2C é uma ferramenta que permite identificar todos os dispositivos I2C conectados a um barramento específico. Isso é particularmente útil quando se trabalha com uma variedade de sensores, módulos e displays que utilizam o protocolo I2C para comunicação.

Neste exemplo, será abordado como escanear todos os 12 barramentos I2C das 2 interfaces I2C (Wire e Wire1) e detectar todos os dispositivos I2C conectados e exibir os endereços encontrados na porta Serial. Será utilizado dispositivos I2C, como Displays 16×2 LCD I2C e o RTC DS1307, para que o Raspberry Pi Pico tenha algum dispositivo para escanear.

Curiosidade
Como a placa Raspberry Pi Pico tem 6 barramentos I2C em cada uma das 2 interfaces I2C (Wire e Wire1), e cada barramento I2C pode ter uma faixa de endereços de 7 bits (resultando em um total de 128 (27) endereços possíveis ), é possível, teoricamente, ter 1536 (128 × 12 = 1536) dispositivos I2C conectados na placa no total.

Esquemático

Serão utilizados 4 dispositivos I2C:

  • 2x Display LCD I2C;
  • 1x Módulo RTC DS1307;
  • 1x EEPROM 24C32 I2C (integrado no módulo RTC DS1307).

Veja o esquemático abaixo:

Sketch

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
                         Sketch Exemplo Scanner I2C

                       Criado em 29 de Maio 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/
******************************************************************************/

// Inclusão das bibliotecas
#include <Wire.h>

// Protótipos das funções
void scanI2C_wire(pin_size_t sda_pin, pin_size_t scl_pin);
void scanI2C_wire1(pin_size_t sda_pin, pin_size_t scl_pin);

void setup() {
  while (Serial.available() == 0) {} // É aguardado até que o usuário digite e envie qualquer coisa na porta Serial
  Serial.println();
  Serial.println("I2C Scanner"); // Imprime mensagem de inicialização
}

void loop() {
  Serial.println("\nIniciando Escaneamento Geral I2C do Raspberry Pi Pico.");

  // Inicia o escaneamento I2C
  scanI2C_wire(0, 1);     // Executa o escaneamento I2C na interface I2C0 (Wire) com os pinos SDA 0 e SCL 1
  scanI2C_wire1(2, 3);    // Executa o escaneamento I2C na interface I2C1 (Wire1) com os pinos SDA 2 e SCL 3
  scanI2C_wire(4, 5);     // Executa o escaneamento I2C na interface I2C0 (Wire) com os pinos SDA 4 e SCL 5
  scanI2C_wire1(6, 7);    // Executa o escaneamento I2C na interface I2C1 (Wire1) com os pinos SDA 6 e SCL 7
  scanI2C_wire(8, 9);     // Executa o escaneamento I2C na interface I2C0 (Wire) com os pinos SDA 8 e SCL 9
  scanI2C_wire1(10, 11);  // Executa o escaneamento I2C na interface I2C1 (Wire1) com os pinos SDA 10 e SCL 11
  scanI2C_wire(12, 13);   // Executa o escaneamento I2C na interface I2C0 (Wire) com os pinos SDA 12 e SCL 13
  scanI2C_wire1(14, 15);  // Executa o escaneamento I2C na interface I2C1 (Wire1) com os pinos SDA 14 e SCL 15
  scanI2C_wire(16, 17);   // Executa o escaneamento I2C na interface I2C0 (Wire) com os pinos SDA 16 e SCL 17
  scanI2C_wire1(18, 19);  // Executa o escaneamento I2C na interface I2C1 (Wire1) com os pinos SDA 18 e SCL 19
  scanI2C_wire(20, 21);   // Executa o escaneamento I2C na interface I2C0 (Wire) com os pinos SDA 20 e SCL 21
  scanI2C_wire1(26, 27);  // Executa o escaneamento I2C na interface I2C1 (Wire1) com os pinos SDA 26 e SCL 27
  // Finaliza o escaneamento I2C

  Serial.println("Fim do Escaneamento Geral I2C do Raspberry Pi Pico.");

  Serial.println("Digite qualquer coisa na entrada serial e tecle Enter para realizar um novo Escaneamento Geral I2C...\n");

  while (Serial.available() > 0) { // Aguarda até que o buffer de entrada serial esteja vazio
    Serial.read();  // Lê e descarta os dados disponíveis no buffer de entrada serial
  }

  while (Serial.available() == 0) {} // É aguardado até que o usuário digite e envie qualquer coisa na porta Serial
}

/**
   Realiza um escaneamento I2C na interface TwoWire I2C0 (Wire) especificada pelos pinos SDA e SCL.

   @param sda_pin O pino SDA da interface I2C
   @param scl_pin O pino SCL da interface I2C
*/
void scanI2C_wire(pin_size_t sda_pin,
                  pin_size_t scl_pin) {

  Wire.setSDA(sda_pin); // Configura o pino SDA para a interface I2C0 (Wire)
  Wire.setSCL(scl_pin); // Configura o pino SCL para a interface I2C0 (Wire)
  Wire.begin(); // Inicializa a comunicação I2C na interface I2C0 (Wire)

  byte error, address;  // Variáveis para armazenar o erro de transmissão e o endereço do dispositivo I2C
  int nDevices = 0; // Variável para contar o número de dispositivos I2C encontrados

  Serial.print("Escaneamento iniciado na interface TwoWire I2C0 (Wire) conectada nos pino SDA ");
  Serial.print(sda_pin);
  Serial.print(" e no pino SCL ");
  Serial.println(scl_pin);

  for (address = 1; address < 127; address++ ) // Itera por todos os possíveis endereços I2C (de 1 a 127, totalizando 128 endereços) para realizar o escaneamento
  {
    Wire.beginTransmission(address);  // Inicia a transmissão para o endereço I2C atual
    error = Wire.endTransmission();   // Finaliza a transmissão e verifica se houve algum erro

    if (error == 0) // Se não houve erro na transmissão (0: sucesso), ...
    {
      Serial.print("\t- Dispositivo I2C encontrado no endereço 0x");  // Imprime a mensagem informando que um dispositivo foi encontrado
      if (address < 16) // se o endereço for menor que 16 para formatação correta
        Serial.print("0");  // adiciona um zero à esquerda para formatação correta
      Serial.println(address, HEX); // Imprime o endereço em hexadecimal
      nDevices++; // Incrementa o contador de dispositivos encontrados
    }
    else if (error == 4) // Verifica se houve um erro desconhecido (4: outro erro) durante a transmissão, ...
    {
      Serial.print("\t- Erro desconhecido no endereço 0x");// Imprime a mensagem informando que ocorreu um erro
      if (address < 16) // se o endereço for menor que 16
        Serial.print("0"); // adiciona um zero à esquerda para formatação correta
      Serial.println(address, HEX); // Imprime o endereço em hexadecimal
    }
  }
  if (nDevices == 0) { // se o número de dispositivos for igual à zero, ...
    Serial.println("\t- Nenhum dispositivo I2C encontrado");// Imprime a mensagem informando que nenhum dispositivo I2C foi encontrado no barramento I2C
  }

  Wire.end(); // Finaliza a comunicação I2C
  Serial.println("Escaneamento terminado\n"); // Imprime mensagem de conclusão do escaneamento
}

/**
   Realiza um escaneamento I2C na interface TwoWire1 I2C1 (Wire1) especificada pelos pinos SDA e SCL.

   @param sda_pin O pino SDA da interface I2C
   @param scl_pin O pino SCL da interface I2C
*/
void scanI2C_wire1(pin_size_t sda_pin,
                   pin_size_t scl_pin) {

  Wire1.setSDA(sda_pin);  // Configura o pino SDA para a interface I2C1 (Wire1)
  Wire1.setSCL(scl_pin);  // Configura o pino SCL para a interface I2C1 (Wire1)
  Wire1.begin();  // Inicializa a comunicação I2C na interface I2C1 (Wire1)

  byte error, address;  // Variáveis para armazenar o erro de transmissão e o endereço do dispositivo I2C
  int nDevices = 0; // Variável para contar o número de dispositivos I2C encontrados

  Serial.print("Escaneamento iniciado na interface TwoWire1 I2C1 (Wire1) conectada nos pino SDA ");
  Serial.print(sda_pin);
  Serial.print(" e no pino SCL ");
  Serial.println(scl_pin);

  for (address = 1; address < 127; address++ )  // Itera por todos os possíveis endereços I2C (de 1 a 127, totalizando 128 endereços) para realizar o escaneamento
  {
    Wire1.beginTransmission(address); // Inicia a transmissão para o endereço I2C atual
    error = Wire1.endTransmission();  // Finaliza a transmissão e verifica se houve algum erro

    if (error == 0) // Se não houve erro na transmissão (0: sucesso), ...
    {
      Serial.print("\t- Dispositivo I2C encontrado no endereço 0x");  // Imprime a mensagem informando que um dispositivo foi encontrado
      if (address < 16) // se o endereço for menor que 16 para formatação correta
        Serial.print("0");  // adiciona um zero à esquerda para formatação correta
      Serial.println(address, HEX); // Imprime o endereço em hexadecimal
      nDevices++; // Incrementa o contador de dispositivos encontrados
    }
    else if (error == 4)// Verifica se houve um erro desconhecido (4: outro erro) durante a transmissão, ...
    {
      Serial.print("\t- Erro desconhecido no endereço 0x"); // Imprime a mensagem informando que ocorreu um erro
      if (address < 16) // se o endereço for menor que 16
        Serial.print("0");  // adiciona um zero à esquerda para formatação correta
      Serial.println(address, HEX); // Imprime o endereço em hexadecimal
    }
  }

  if (nDevices == 0) {  // se o número de dispositivos for igual à zero, ...
    Serial.println("\t- Nenhum dispositivo I2C encontrado");  // Imprime a mensagem informando que nenhum dispositivo I2C foi encontrado no barramento I2C
  }

  Wire1.end();  // Finaliza a comunicação I2C
  Serial.println("Escaneamento terminado\n"); // Imprime mensagem de conclusão do escaneamento
}

O código começa incluindo a biblioteca Wire.h, responsável pela comunicação I2C. Em seguida, são declarados os protótipos das funções utilizadas no sketch.

No bloco de código da função setup(), é aguardado até que o usuário digite e envie qualquer coisa pela porta Serial. Em seguida, é exibida uma mensagem de inicialização.

No bloco de código da função loop(), é exibida uma mensagem indicando o início do escaneamento geral I2C do Raspberry Pi Pico.

Em seguida, as funções scanI2C_wire() e scanI2C_wire1() realizam o escaneamento I2C nas interfaces TwoWire I2C0 e TwoWire1 I2C1, respectivamente. Elas recebem como parâmetros os pinos SDA e SCL correspondentes à interface a ser escaneada.

As interfaces I2C são:

Wire (I2C0)Wire1 (I2C1)
SDASCLSDASCL
GPIO0GPIO1GPIO2GPIO3
GPIO4GPIO5GPIO6GPIO7
GPIO8GPIO9GPIO10GPIO11
GPIO12GPIO13GPIO14GPIO15
GPIO16GPIO17GPIO18GPIO19
GPIO20GPIO21GPIO26GPIO27

Dentro dessas funções, são configurados os pinos SDA e SCL para as interfaces Wire e Wire1, respectivamente. A comunicação I2C é iniciada chamando o método begin() da biblioteca Wire.

Em seguida, é realizado um loop para iterar por todos os possíveis endereços I2C (de 1 a 127, o que resulta em 128 endereços) e realizar o escaneamento. Para cada endereço, é iniciada a transmissão com o método beginTransmission() da biblioteca Wire e verificado se ocorreu algum erro durante a transmissão com o método endTransmission() da biblioteca Wire.

O método endTransmission() da biblioteca Wire retorna um inteiro, em que é possível verificar se houve ou não erro presente na transmissão. Este inteiro pode ser:

  • 0 (sucesso): Indica que a transmissão foi concluída com sucesso. Os dados foram enviados corretamente e o dispositivo escravo reconheceu a transmissão;
  • 1 (dados muito longos para caber no buffer de transmissão): Esse retorno ocorre quando a quantidade de dados a serem transmitidos excede o tamanho do buffer de transmissão do dispositivo escravo. Nesse caso, é necessário reduzir a quantidade de dados transmitidos ou dividir a transmissão em partes menores;
  • 2 (NACK recebido na transmissão do endereço): Indica que o dispositivo escravo não respondeu com um ACK (Acknowledge) após a transmissão do endereço. Isso pode ocorrer quando o dispositivo escravo não está conectado corretamente, está desligado ou não está configurado corretamente.
  • 3 (NACK recebido na transmissão de dados): Esse retorno ocorre quando o dispositivo escravo não responde com um ACK (Acknowledge) após a transmissão de dados. Pode indicar que o dispositivo escravo encontrou algum erro durante o processamento dos dados ou não está pronto para receber mais dados.
  • 4 (outro erro): Esse retorno é usado para indicar qualquer outro erro que não se enquadre nas categorias anteriores. Pode ocorrer devido a problemas de comunicação, interferências no barramento I2C, dispositivo I2C não conectado ou outros problemas não específicos.
  • 5 (tempo limite): Esse retorno ocorre quando ocorre um tempo limite durante a transmissão. Pode acontecer se o dispositivo escravo não responder dentro de um período de tempo específico, indicando um possível problema de comunicação ou uma falha no dispositivo escravo.

Se não houver erros, é exibida uma mensagem indicando que um dispositivo I2C foi encontrado no endereço correspondente. Caso ocorra um erro desconhecido, é exibida uma mensagem informando que ocorreu um erro.

Ao final do escaneamento, é verificado se algum dispositivo foi encontrado. Se nenhum dispositivo for encontrado, é exibida uma mensagem informando que nenhum dispositivo I2C foi encontrado no barramento I2C.

Por fim, a comunicação I2C é finalizada chamando o método end() da biblioteca Wire. É exibida uma mensagem de conclusão do escaneamento e o sketch aguarda até que o usuário digite e envie qualquer coisa pela porta Serial antes de iniciar um novo escaneamento.

Vídeo de demonstração do funcionamento

Veja no vídeo abaixo a demonstração do funcionamento do scanner I2C, que exibe os dados no monitor serial do Arduino IDE:


Exemplo 4 - Lendo Temperatura interna do Raspberry Pi Pico

A leitura da temperatura interna de um dispositivo eletrônico pode ser de grande importância em diversas aplicações. A placa Raspberry Pi Pico também oferece a possibilidade de acessar a temperatura interna do próprio dispositivo através de um sensor interno.

Neste exemplo, demonstraremos como ler a temperatura interna do Raspberry Pi Pico utilizando um sketch Arduino. Através dessa leitura, o usuário pode implementar algoritmos em que é possível monitorar e tomar decisões com base na temperatura do microcontrolador, como, por exemplo, ativar ventiladores ou emitir alertas de superaquecimento.

O acesso à temperatura interna do Raspberry Pi Pico é possível por meio do seu sensor de temperatura embutido. No exemplo de código a ser apresentado, a temperatura interna do Raspberry Pi Pico será exibida na porta Serial.

Lembre-se que não se deve usar esta leitura para obter a temperatura ambiente, somente deve ser utilizada para obter a temperatura do chip RP2040.

O sensor de temperatura interna que acompanha o Raspberry Pi Pico é conectado a um dos ADCs (conversores analógico-digitais). O sensor de temperatura não possui um pino físico na placa, mas é acessado como ADC4. A placa Raspberry Pi Pico possui os seguintes pinos ADC, que são acessíveis externamente:

  • ADC0;
  • ADC1;
  • ADC2;
  • ADC_VREF (tecnicamente ADC3).

Esquemático

Não é utilizado nenhum hardware extra:

Sketch

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
          Sketch Exemplo Lendo Temperatura interna do Raspberry Pi Pico

                       Criado em 31 de Maio 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() {
  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.
}

void loop() {
  Serial.print("Temperatura interna: ");  // Imprime a mensagem "Temperatura interna: "
  Serial.print(analogReadTemp()); // Imprime o valor da temperatura lida pela função analogReadTemp()
  Serial.println(" ºC");  // Imprime a unidade de graus Celsius e pula uma linha
  delay(1000);  // Aguarda 1 segundo
}

No bloco setup(), é feita a configuração inicial do programa. A função Serial.begin(115200) inicia a comunicação serial com uma taxa de baud rate de 115200. No entanto, é importante observar que essa taxa de baud rate é ignorada neste caso, pois a comunicação serial na Raspberry Pi Pico é baseada em USB.

No bloco loop(), é definido o código que será executado repetidamente. Primeiro, a mensagem "Temperatura interna: " é impressa na saída serial usando Serial.print(). Em seguida, o valor da temperatura é lido pela função analogReadTemp() e impresso também utilizando Serial.print(). Por fim, a unidade de graus Celsius é impressa seguida de uma quebra de linha usando Serial.println().

Após essa impressão, o programa aguarda 1 segundo usando a função delay(1000) antes de repetir o loop e executar novamente o código.

Vídeo de demonstração do funcionamento


Exemplo 5 - Usando os dois núcleos simultaneamente do Raspberry Pi Pico

O Raspberry Pi Pico é uma placa microcontroladora poderosa que conta com dois núcleos (cores) para realizar tarefas de processamento, que podem rodar independentemente um do outro, compartilhando periféricos e memória entre si. Essa característica permite que os desenvolvedores aproveitem ao máximo o potencial do dispositivo, executando tarefas simultâneas e aumentando a eficiência do sistema.

Neste exemplo, exploramos a capacidade do Raspberry Pi Pico executar códigos em paralelo nos núcleos disponíveis. Neste caso, são utilizadas duas funções, loop() e loop1(), que serão executadas em cada um dos núcleos separadamente.

O loop do Arduino é normalmente executado apenas no núcleo 0 da placa Raspberry Pi Pico, com o segundo núcleo ocioso em um estado de baixo consumo de energia.

Ao adicionar uma função setup1() e loop1() ao sketch, você pode usar o segundo núcleo. Qualquer coisa chamada de dentro das rotinas setup1() ou loop1() será executada no segundo núcleo.

As funções setup() e setup1() serão chamados ao mesmo tempo, e o loop() ou loop1() será iniciado assim que o núcleo setup() for concluído.

A importância de utilizar os dois núcleos simultaneamente é evidente em situações em que é necessário realizar tarefas complexas e que demandam tempo de processamento. Ao dividir essas tarefas entre os núcleos, é possível obter um desempenho melhorado e tempos de resposta mais rápidos.

Ao distribuir as tarefas entre os dois núcleos, é possível realizar operações independentes em paralelo, como a leitura de sensores, o processamento de dados, o controle de dispositivos e muito mais.

Esquemático

Sketch

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
    Sketch Exemplo Usando os dois núcleos simultaneamente do Raspberry Pi Pico

                       Criado em 01 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/
******************************************************************************/

// Definição dos pinos utilizados
const int led_azul = 2;
const int led_vermelho = 3;
const int button = 4;

void setup() {

  // Configuração dos pinos como saída para os LEDs
  pinMode(led_azul, OUTPUT);
  pinMode(led_vermelho, OUTPUT);

  delay(1000); // Aguarda 1 segundo

}

void setup1() {

  // Configuração do pino como entrada com pull-down interno para o botão
  pinMode(button, INPUT_PULLDOWN);

  delay(1000);  // Aguarda 1 segundo

}

void loop() {

  digitalWrite(led_azul, HIGH); // Acende o LED azul
  delay(1000);  // Aguarda 1 segundo
  digitalWrite(led_azul, LOW);  // Apaga o LED azul
  delay(1000);  // Aguarda 1 segundo

}

void loop1() {

  if (digitalRead(button) == true) { // Verifica se a leitura do pino do botão está em nível alto (pressionado)

    digitalWrite(led_vermelho, HIGH); // Acende o LED vermelho

    while (digitalRead(button)) { // Aguarda até que o botão seja liberado (botão seja lido como LOW)
      delay(1); // Aguarda 1 milissegundo
    }

  } else {

    digitalWrite(led_vermelho, LOW);  // Apaga o LED vermelho

  }

  delay(10);  // Aguarda 10 milissegundos
}

Na função setup(), específica para o primeiro núcleo, os pinos são configurados: o led_azul e o led_vermelho como saída. Em seguida, há um atraso de 1 segundo.

A função loop(), específica para o primeiro núcleo, é responsável por acender e apagar o LED azul com intervalos de 1 segundo.

A função setup1() é específica para o segundo núcleo e configura o pino do botão como entrada com pull-down interno. Quando o botão estiver solto, o GND fluirá (internamente) pelo resistor interno da placa chegando na porta digital do botão. Quando o botão for pressionado, o VCC fluirá pelo contato da chave — sem maiores resistências — alcançando o pino do microcontrolador. Novamente, há um atraso de 1 segundo.

Veja mais no post abaixo, do blog Eletrogate, sobre configuração pull-down:

Entendendo os Resistores de Pull-Up e Pull-Down

A função loop1() é executada no segundo núcleo. Ela verifica se o botão está pressionado. Caso esteja, o LED vermelho é aceso. Em seguida, há um loop que aguarda até que o botão seja liberado, verificando a leitura do pino como LOW. Quando isso acontece, o LED vermelho é apagado. Após isso, há um atraso de 10 milissegundos.

Vídeo de demonstração do funcionamento


Exemplo 6 - Reiniciando o Raspberry Pi Pico via Software

Reiniciar um dispositivo eletrônico, como o Raspberry Pi Pico, é uma ação fundamental em diversos contextos, seja para aplicar configurações atualizadas, corrigir possíveis falhas no sistema ou simplesmente iniciar um novo ciclo de funcionamento. No caso específico do Raspberry Pi Pico, reiniciar via software oferece uma série de vantagens e possibilidades, permitindo um controle mais preciso e uma intervenção direta no dispositivo.

O reinício via software proporciona uma forma conveniente e eficiente de gerenciar o Raspberry Pi Pico, evitando a necessidade de intervenção manual e eliminando a dependência de interações físicas com o dispositivo. Essa flexibilidade é especialmente valiosa em ambientes onde o Raspberry Pi Pico está instalado em locais de difícil acesso.

Além disso, reiniciar via software também oferece a possibilidade de implementar rotinas automatizadas, onde o reinício pode ser agendado periodicamente, por exemplo, para manter o dispositivo funcionando de maneira otimizada. Essa prática é particularmente útil quando se lida com aplicações de longa duração, como servidores web, monitoramento de sensores ou sistemas de controle. Ao reiniciar o Pico regularmente, é possível prevenir o acúmulo de erros ou sobrecargas que podem impactar o desempenho e a estabilidade do sistema.

Outro benefício importante do reinício via software é a capacidade de realizar ajustes e configurações em tempo real. Ao reiniciar o Raspberry Pi Pico, é possível aplicar novas versões de software sem a necessidade de desligar completamente o dispositivo. Isso resulta em um tempo de inatividade reduzido e permite uma implementação mais ágil de melhorias e correções.

Como funciona

O reinício via software é feito através da execução do seguinte código: rp2040.restart();.

Esquemático

Sketch

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
            Sketch Exemplo Reiniciando o Raspberry Pi Pico via Software

                       Criado em 29 de Maio 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/
******************************************************************************/

// Inclusão das bibliotecas
#include <Wire.h>               // Biblioteca para comunicação I2C
#include <LiquidCrystal_I2C.h>  // Biblioteca para controle do display LCD I2C

LiquidCrystal_I2C lcd(0x27, 16, 2); // Inicializa o objeto para controle do display
//                                   LCD I2C com endereço 0x27, 16 colunas e 2 linhas.


void setup() {

  lcd.init_v_pico(Wire, 0, 1);  // Inicializa o display LCD I2C com o método 'init_v_pico',
  //                            passando como parâmetros a interface I2C a ser utilizada,
  //                            o número do pino SDA usado e o número do pino SCL usado.
  lcd.backlight();  // Acende a luz de fundo do display

}
void loop() {

  for (int i = 1; i <= 10; i++) { // Loop de 1 a 10, incrementando i a cada iteração

    if (i > 5) {  // Se o valor de i for maior que 5

      lcd.setCursor(0, 0);  // Define a posição do cursor na coluna 0 e linha 0 do display LCD
      lcd.print("Reiniciando...");  // Imprime uma mensagem indicando que vai ser feito o reinício da palca
      delay(1000);  // Aguarda 1 segundo

      rp2040.restart(); // Reinicia o Raspberry Pi Pico via software

    } else {  // Caso contrário, se i não for maior que 5

      lcd.setCursor(0, 0);  // Define a posição do cursor na coluna 0 e linha 0 do display LCD
      lcd.print(i); // Imprime o valor de i
      delay(1000);  // Aguarda 1 segundo

    }

  }

}

No início do código, as bibliotecas necessárias são incluídas, “Wire” para comunicação I₂C e “LiquidCrystal_I2C” para controle do display LCD.

O bloco setup() é responsável pela configuração inicial do programa. Nele, o display LCD I₂C é inicializado utilizando o método init_v_pico(), que recebe como parâmetros a interface I₂C a ser utilizada, o número do pino SDA e o número do pino SCL. Também é ativada a luz de fundo do display com o comando lcd.backlight().

No bloco loop(), encontramos um loop for que itera de 1 a 10, incrementando o valor da variável i a cada iteração. Dentro desse loop, existe uma estrutura condicional if-else. Se o valor de i for maior que 5, o código no bloco if é executado.

No bloco if, ocorre a reinicialização do Raspberry Pi Pico via software através do comando rp2040.restart().

Caso o valor de i não seja maior que 5, o código no bloco else é executado. É feita a exibição no display o valor da variável i.

Dessa forma, o código, que se não fosse reiniciado, exibiria no display LCD uma contagem de 1 a 10. Mas, quando o valor de i ultrapassa 5, a mensagem "Reiniciando..." é exibida e ocorre a reinicialização do Raspberry Pi Pico via software.

Vídeo de demonstração do funcionamento


Exemplo 7 - Reiniciando o Raspberry Pi Pico via Hardware

Neste exemplo, vamos explorar a reinicialização via hardware, fornecendo uma maneira conveniente de reiniciar o Raspberry Pi Pico quando necessário.

Reiniciar um dispositivo pode ser útil em várias situações, como quando ocorre um erro ou travamento no programa em execução. Além disso, o reinício via hardware é especialmente prático quando o usuário deseja carregar um novo programa no Raspberry Pi Pico, pois não é necessário desconectar e reconectar o cabo USB. Basta pressionar o botão de BOOTSEL e durante o pressionamento, pressionar o botão de reset e o dispositivo será reiniciado, pronto para receber o novo programa.

O Raspberry Pi Pico possui um pino de hardware dedicado para reinicialização, chamado de pino RUN. Quando esse pino é momentaneamente conectado ao terra (GND), o Pico é reiniciado imediatamente. Isso significa que podemos usar um botão físico conectado ao pino RUN para realizar a reinicialização.

Neste exemplo, vamos demonstrar como implementar essa funcionalidade usando um botão push-button simples. Conectemos um dos terminais do botão ao pino RUN do Raspberry Pi Pico e o outro terminal ao terra. Quando pressionarmos o botão, ele irá temporariamente conectar o pino RUN ao terra, acionando a reinicialização do Pico.

Esquemático

Sketch

Para demonstrar o reinício via hardware, será utilizado o seguinte sketch:

/******************************************************************************
      Gravando Código em Framework Arduino no Raspberry Pi Pico + Exemplos
            Sketch Exemplo Reiniciando o Raspberry Pi Pico via Hardware

                       Criado em 01 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/
******************************************************************************/

// Inclusão das bibliotecas
#include <Wire.h>               // Biblioteca para comunicação I2C
#include <LiquidCrystal_I2C.h>  // Biblioteca para controle do display LCD I2C

LiquidCrystal_I2C lcd(0x27, 16, 2); // Inicializa o objeto para controle do display
//                                   LCD I2C com endereço 0x27, 16 colunas e 2 linhas.

unsigned int contador = 0;  // Variável para armazenar o valor do contador

void setup() {

  lcd.init_v_pico(Wire, 0, 1);  // Inicializa o display LCD I2C com o método 'init_v_pico',
  //                            passando como parâmetros a interface I2C a ser utilizada,
  //                            o número do pino SDA usado e o número do pino SCL usado.
  lcd.backlight();  // Acende a luz de fundo do display

}
void loop() {

  lcd.clear();  // Limpa o conteúdo do display LCD
  lcd.setCursor(0, 0);  // Define a posição do cursor na coluna 0 e linha 0 do display LCD
  lcd.print(contador); // Imprime o valor de contador
  contador++; // Incrementa o contador
  if (contador > 10) { // Verifica se o valor do contador é maior que 10
    contador = 0; // Zera o contador quando ele atinge o valor 10
  }
  delay(1000);  // Aguarda 1 segundo

}

O código utiliza a biblioteca LiquidCrystal_I2C para controlar um display LCD I₂C de 16 colunas e 2 linhas, e a biblioteca Wire para controlar a comunicação I₂C.

No bloco setup(), o código realiza a inicialização do display LCD I₂C, configurando a interface I₂C a ser usada e os pinos SDA e SCL correspondentes. Além disso, a luz de fundo do display é ativada.

No bloco loop(), o código contém um loop infinito onde são executadas as seguintes ações repetidamente:

O comando lcd.clear() é utilizado para limpar o conteúdo atualmente exibido no display LCD. Em seguida, lcd.setCursor(0, 0) posiciona o cursor do display na coluna 0 e linha 0. A função lcd.print(contador) é utilizada para exibir o valor da variável contador no display LCD. O valor da variável contador é incrementado em 1 por meio do comando contador++.

Após isso, o código verifica se o valor de contador é maior que 10 usando o comando if (contador > 10). Caso seja verdadeiro, a linha contador = 0; é executada para reiniciar o valor de contador para 0.

Para criar uma pausa de 1 segundo antes de repetir o ciclo novamente, é utilizado o comando delay(1000).

Dessa forma, este sketch exibe sequencialmente os valores de contador no display LCD, começando em 0 e incrementando até 10. Quando contador atinge o valor 10, ele é reiniciado para 0 e o processo continua repetindo indefinidamente.

Vídeo de demonstração do funcionamento

Veja no vídeo abaixo como o reinício da placa Raspberry Pi Pico é executado:


Conclusão

Neste post, vimos como o Raspberry Pi Pico pode ser utilizado em conjunto com o Framework Arduino. Exploramos como instalar o pacote de placas na IDE Arduino e carregar o primeiro sketch, além de apresentar exemplos práticos.

Esperamos que este post tenha sido útil para você iniciar suas experiências com o Raspberry Pi Pico e o Arduino. Divirta-se explorando as possibilidades dessa placa microcontroladora e compartilhe suas criações conosco!

Aproveite ao máximo o Raspberry Pi Pico e crie projetos incríveis!

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!


Sobre o Autor


Michel Galvão

Graduando em Engenharia de Software pela UniCV de Maringá/PR. Tem experiência em Automação Residencial e Agrícola. É um Eletrogater Expert. Tem como Hobby Sistemas Embarcados e IoT. É desenvolvedor de software de Sistemas MicSG. Site: https://micsg.com.br/


Eletrogate

18 de julho de 2023

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.

Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!