quarta-feira, fevereiro 05, 2020

Arduino 33 BLE: Usando Funções do Mbed OS

Vimos no post anterior que o runtime do Arduino 33 BLE roda em cima do Mbed OS. Isto nos permite chamar diversas funções de Mbed OS no nosso código. As funções disponíveis no Mbed podem ser vistas aqui; é claro que algumas delas dependem de hardware não disponível no Arduino 33 BLE, mas ainda sobra muita coisa bacana.


Como um exercício, vamos criar duas threads adicionais no nosso programa, uma para piscar o LED e outra para ler o sensor inercial. O nosso programa principal receberá pela serial o caracter cujo código será piscado no LED e envirá pela serial os valores lidos do sensor.

Vamos começar vendo como criar uma thread, que é uma rotina que roda em paralelo ("simultaneamente") ao nosso programa principal:
#include <mbed.h>

using namespace rtos;

Thread thLed;

void setup() {
  Serial.begin (115200);
  thLed.start(piscaLed);
}

void loop() {
  // put your main code here, to run repeatedly:
}

void piscaLed() {
  pinMode (LED_BUILTIN, OUTPUT);
  for (;;) {
    digitalWrite (LED_BUILTIN, HIGH);
    delay (300);
    digitalWrite (LED_BUILTIN, LOW);
    delay (300);
  }
}

O passo seguinte é fazer a comunicação entre o programa principal e a thread. Para isto vamos usar uma queue (fila):
#include <mbed.h>

using namespace rtos;

Thread thLed;
Queue<int, 20> filaLed;

void setup() {
  Serial.begin (115200);
  thLed.start(piscaLed);
}

void loop() {
  if (Serial.available() > 0) {
    int c = Serial.read();
    filaLed.put((int *) c);
  }
}

void piscaLed() {
  pinMode (LED_BUILTIN, OUTPUT);
  for (;;) {
    // Aguarda ter algo na fila
    osEvent evt = filaLed.get();
    if (evt.status == osEventMessage) {
      // Pisca o valor binário do caracter retirado da fila
      int c = (int) evt.value.p;
      for (int i = 0; i < 8; i++) {
        digitalWrite (LED_BUILTIN, (c & 0x80)? HIGH : LOW);
        delay (300);
        digitalWrite (LED_BUILTIN, LOW);
        delay (200);
        c = c << 1;
      }
      delay (1000);
    }
  }
}

Aqui o código ficou um pouco mais complicado. Indo por partes:

  • Queue<int, 20> indica que estamos criando uma fila com 20 inteiros.
  • filaLed.put((int *) c)  coloca 'c' na fila. O cast (int *) é necessário porque put espera um ponteiro e estamos colocando um inteiro.
  • filaLed.get() aguarda ter algo na fila e o devolve dentro de um objeto osEvent

Estamos usando aqui apenas o básico do objeto Queue, Ele suporta prioridades e timeouts para aplicações mais sofisticadas.

Agora já podemos montar o código completo, usando a classe MemoryPool do Mbed para gerencias as áreas onde colocaremos as leituras:

#include <mbed.h>
#include <Arduino_LSM9DS1.h>

using namespace rtos;

typedef struct {
  float x, y, z;
} LEITURA;
MemoryPool<LEITURA, 5> mpoolLeit;

Thread thLed;
Thread thIMU;
Queue<int, 20>    filaLed;
Queue<LEITURA, 5> filaIMU;

void setup() {
  Serial.begin (115200);
  if (!IMU.begin()) {
    Serial.println ("Erro ao iniciar IMU");
  }
  thLed.start(piscaLed);
  thIMU.start(leIMU);
}

void loop() {
  if (Serial.available() > 0) {
    int c = Serial.read();
    filaLed.put((int *) c);
  }
  osEvent evt = filaIMU.get(0);
  if (evt.status == osEventMessage) {
    LEITURA *pLeitura = (LEITURA *) evt.value.p;
    Serial.print ("Leitura bussola: X=");
    Serial.print (pLeitura->x);
    Serial.print (" Y=");
    Serial.print (pLeitura->y);
    Serial.print (" Z=");
    Serial.println (pLeitura->z);
    mpoolLeit.free (pLeitura);
  }
}

void piscaLed() {
  pinMode (LED_BUILTIN, OUTPUT);
  for (;;) {
    // Aguarda ter algo na fila
    osEvent evt = filaLed.get();
    if (evt.status == osEventMessage) {
      // Pisca o valor binário do caracter retirado da fila
      int c = (int) evt.value.p;
      for (int i = 0; i < 8; i++) {
        digitalWrite (LED_BUILTIN, (c & 0x80)? HIGH : LOW);
        delay (300);
        digitalWrite (LED_BUILTIN, LOW);
        delay (200);
        c = c << 1;
      }
      delay (1000);
    }
  }
}

void leIMU() {
  for (;;) {
    if (IMU.magneticFieldAvailable()) {
      LEITURA *pLeitura = mpoolLeit.alloc();
      IMU.readMagneticField(pLeitura->x, pLeitura->y, pLeitura->z);
      filaIMU.put(pLeitura);
      delay (1000);
    }
    delay (100);
  }
}

Nenhum comentário: