Skip to content

Descrição do Firmware Embarcado


Esta seção tem por objetivo apresentar as descrições do firmware embarcado utilizado em cada subsistema que compõe o sistema eletrônico. Aqui são apresentadas as principais bibliotecas, variáveis e funções utilizadas para o correto funcionamento de cada subsistema, assim como a lógica de programação idealizada para as suas operações


Subsistema de Velocidade e Direção do Vento

1. Funções Básicas

O firmware deste subsistemas deve ser capaz de executar 3 funções basicas:

  1. Sensoriamento/Cálculo da velocidade do vento;
  2. Sensoriamento/Cálculo da Direção do vento;
  3. Diposição dos dados para leitura através do modbus.

Então para isso, foi desenvolvido o código a ser descrito abaixo, utilizando o arduino IDE, ambiente de desenvolvimento específico para arduino.

2. Bibliotecas

Com o intuíto de atingir os objetivos do subsitema, foram utilizadas as seguintes bilbiotecas:

bibliotecas_vento

Em que:

  • Arduino.h: Bilbioteca com comandos, botões, e atribuição de nomes específicos do arduino IDE. É utilizada para compilar o código em qualquer placa do sistema arduino;

  • SimpleModbusSlave.h : Biblioteca que integra o funcionamento da comunicação modbus com funções específicas que facilitam a configuração e utilização do Modbus;

  • TimerOne.h: Função que permite e facilita a utilização de interrupções utilizando timers (contadores) internos do arduino, ou seja, podemos executar funções com recorrência e período específico.

3. Atribuições de Pinos

Para facilitar a leitura e desenvolvimento do firmware, é indicado definir anteriormente cada pino a ser utilizado com um nome fixo. Isto também facilita o teste e prototipação, quando não se tem a placa ou o hardware ideal do projeto, basta alterar o valor de cada definição. Aqui estão as atribuições de pinos do código, os pinos atribuidos não estão necessariamente condizentes com o esquemático, pois está implementado em um protótipo.

atribuição de pinos_vento

4. Definição de Constantes

Semelhante ao ítem anterior, é ideal definir constantes que serão utilizadas de forma recorrente no código, para evitar escritas desnecessárias de valores, poluindo o código. Aqui estão as definições de constantes a serem utilizadas no firmware:

constantes_vento

Estas constantes são variadas, desde constantes matemáticas como PI a constantes de calibração medidas do protótipo. Todos os valores de calibração devem ser atualizados para cada versão de hardware do projeto.

5. Definição de Variáveis

Aqui estão as variáveis globais a serem utilizadas no código, de alguns tipos pré definidos como:

  • int ou int16_t:Tipo de variável de valores inteiros de 16 bits, positivos ou negativos;
  • uint16_t: Tipo de variável de valores inteiros de 16 bits somente positivos;
  • uint8_t: Tipo de variável de valores inteiros de 8 bits somente positivos;
  • float: Tipo de variável de ponto flutuante 32 bits;

Abaixo está uma imagem das variáveis a serem utilizadas no código:

variaveis_vento

6. Definição dos Endereços

O registrador modbus é um array, que contém variáveis de 16 bits, cada posição das variáveis do array representa um endereço do registrador. Então, de forma a deixar a escrita do código o mais limpa possível, criou-se um enum que cria uma ordem para os endereços do modbus que, quando formos escrever qualquer valor em uma das variáveis do array, escrevemos no endereço específico pela ordem do enum. Abaixo está uma imagem que mostra a ordem dos endereços dados pelo enum:

enderecos_vento

7. Funções

Para execução do código foram definidas algumas funções, como de inicialização, de interrupções, etc. Elas devem ser discutidas individualmente.

7.1 Funções Principais

Quando criamos um arquivo de firmware no arduino ide, ele já vem dividido em duas funções principais, a setup() de inicialização, executada apenas ao ligar o sistema, e a loop() de recorrência infinita. Abaixo está uma imagem das outras funções inseridas nas duas principais:

init_vento

Na função setup temos a chamada das seguintes funções:

  • MODBUS_INITIALIZE(): Função que inicializa a comunicação modbus;
  • ENCODER_INITIALIZE(): Função que inicializa os pinos e interrupções externas utilizadas para leitura do encoder;
  • Timer1.initialize(T_VEL): Função que inicializa o contador que irá ditar a interrupção com período de 3s para o calculo da velocidade.
  • Timer1.attachInterrupt(Calc_Vel): Função que ativa a interrupção quando o timer terminar a contagem vai chamar a função de interrupção "Calc_Vel()";

Também atribui-se os valores do BaudRate e Slave Address nos registradores modbus para, caso não se saiba estas informações, pode-se utilizar a função modbus de leitura de endereços e enviá-la para o Slave Address, que é o endereço universal, então qualquer escravo modbus responde à esta requisição. Na função loop(), chama-se a função Calc_Dir() recorrentemente. Está função será explicada separadamente.

7.2 Cálculo de Velocidade do Vento

Para este cálculo se utilizam de duas funções, a de interrupção externa Encoder_Count(), e a de interrupção pelo timer Calc_Vel().

A função de interrupção externa Encoder_Count() nada mais é do que um contador que se incrementa toda vez que haja uma transição de borda de descida no sinal entregue pelo encoder, ou seja, sempre que haja a interrupção do sinal por cada um dos vinte furos da roda perfurada, como mostra a imagem a seguir:

calvel_vento

Também se observa a função Calc_Vel(), chamada a cada 3 segundos que calcula a velocidade do vento em metros por segundo [m/s] em ponto fixo com uma casa decimal.

Para o calculo da velocidade se utilizou da seguinte equação:

Vel = Count × (2π / Num) T × Raio

Em que:

  • Vel: É a velocidade calculada em [m/s];
  • Count: Contador de interrupções do sinal do encoder;
  • 2pi / Num : É o ângulo correspondente a cada furo na roda em [rad], ou seja, ao multiplicar pelo contador se obtém o ângulo percorrido pela roda nesse intervalo;
  • T: Período da interrupção, correspondente a 3 [s], até agora na fórmula se obtém a velocidade angular em [rad/s];
  • Raio: Raio da estrutura de medição do vento em [m];

7.3 Cálculo da Direção do Vento

A função Calc_Dir() é muito complexa para ser discutida como as outras então para explicá-la, iremos em etapas.

Primeiramente Realiza-se a medição da tensão entregue pelos sensores hall, e se subtrai o valor de offset observado para centrar o valor em zero, ou seja, a tensão final será de 0 a 512 [ADC] ou 0 a 2.5 [V].

Após isso, realiza-se a busca obtendo o maior e seguindo maior valor de tensão medido, ou seja, o imã estará entre estes dois sensores hall.

Após isso cria-se uma variável de proporção que é: maior/2ºmaior [%] valores medidos, ou seja, a proporção da distância do imâ entre o maior e segundo maior valor.

O maior valor demonstra que o imâ está mais perto deste sensor.

Após isto, criam-se 8 casos de posição do imâ:

  1. Entre Oeste e Norte, mais perto do Norte;
  2. Entre Norte e Leste, mais perto do Norte;
  3. Entre Leste e Norte, mais perto do Leste;
  4. Entre Leste e Sul, mais perto do Leste;
  5. Entre Sul e Leste, mais perto do Sul;
  6. Entre Sul e Oeste, mais perto do Sul;
  7. Entre Oeste e Sul, mais perto do Oeste;
  8. Entre Oeste e Norte, mais perto do Oeste;

Então para cada um destes casos, realiza-se um cálculo diferente:

  1. Dir = Norte360 - 90 x Dir_Propor/100;
  2. Dir = Norte0 + 90 x Dir_Propor/100;
  3. Dir = Leste - 90 x Dir_Propor/100;
  4. Dir = Leste + 90 x Dir_Propor/100;
  5. Dir = Sul - 90 x Dir_Propor/100;
  6. Dir = SUL + 90 x Dir_Propor/100;
  7. Dir = OESTE - 90 x Dir_Propor/100;
  8. Dir = OESTE + 90 x Dir_Propor/100;

Em que:

  • Norte360 = 360º;
  • Norte0 = 0º;
  • Leste = 90º;
  • Sul = 180º;
  • Oeste = 270º;

Como mostra a imagem a seguir:

caldir_vento

Por fim atribui-se os valores calculados a seus respectivos endereços e registradores modbus como mostra a imagem:

fim_vento

Subsistema da Estação Meteorológica

1. Funções Básicas

O firmware deste subsistemas deve ser capaz de executar as seguintes funções:

  1. Sensoriamento da temperaruta ambiente;
  2. Sensoriamento da umidade;
  3. Sensoriamento da pressão;
  4. Sensoriamento da radiação solar;
  5. Diposição dos dados para leitura através do modbus.

2. Bibliotecas

Foram utilizadas as seguintes bilbiotecas:

bib_estacao

Em que:

  • Arduino.h: Bilbioteca com comandos, botões, e atribuição de nomes específicos do arduino IDE. É utilizada para compilar o código em qualquer placa do sistema arduino;

  • Wire.h: Biblioteca padrão do Arduino que fornece as funções necessárias para estabelecer e gerenciar a comunicação I2C, permitindo o envio e recebimento de dados entre o microcontrolador e dispositivos compatíveis, como sensores e módulos.

  • SimpleModbusSlave.h : Biblioteca que integra o funcionamento da comunicação modbus com funções específicas que facilitam a configuração e utilização do Modbus;

  • BME280I2C.h: Biblioteca desenvolvida para facilitar a interação com o sensor BME280, permitindo a leitura de parâmetros como temperatura, pressão e umidade relativa por meio da comunicação I2C de maneira simplificada.

3. Atribuições de Pinos

No firmware, foram definidos os pinos responsáveis pela interação com os componentes do sistema:

pin_estacao

  • RE_DE_PIN: Pino digital 13, utilizado para controlar o RE_DE do módulo MAX485, responsável por gerenciar a transmissão e recepção de dados na comunicação RS485.
  • UV_SENSOR_PIN: Pino analógico A2, conectado ao sensor de radiação UV, utilizado para realizar a leitura do índice UV.

4. Definição de Constantes

No firmware desenvolvido, foram definidas constantes para o funcionamento do subsistema da estação meteorológica:

consts_estacao

  • ALTITUDE: Altitude aproximada do local de medição, utilizada no cálculo da pressão ao nível do mar e altitude estimada.
  • BAUD_RATE: Velocidade de comunicação serial configurada para 9600 bps, garantindo a sincronização de dados entre dispositivos.
  • SLAVE_ADD: Endereço do dispositivo no barramento Modbus, identificando-o como escravo na comunicação.

5. Definição de Variáveis

Definição de variáveis e uma estrutura para organizar e armazenar os dados coletados pelos sensores:

variaveis_estacao

  • Variáveis auxiliares:

    • leitura_porta: Armazena a leitura bruta da porta analógica conectada ao sensor UV.
    • tensao_mV: Converte a leitura bruta em tensão (mV) para cálculo do índice UV.
    • indiceUV: Armazena o índice UV calculado com base na tensão medida.
  • Estrutura SensorData: Agrupa os dados ambientais coletados:

    • temperatura: Temperatura ambiente em °C.
    • pressao: Pressão atmosférica absoluta em hPa.
    • umidade: Umidade relativa em %.
    • pressaoMSL: Pressão corrigida ao nível do mar em hPa.
    • altitude: Altitude estimada em metros.

6. Definição de Endereços e Registradores

Os endereços e registradores Modbus foram configurados para organizar a comunicação e o armazenamento dos dados medidos:

regs_estacao

  • Endereços Modbus (enum): Define identificadores para cada parâmetro monitorado, como temperatura, pressão, umidade, altitude, índice UV, além do baud rate e endereço do dispositivo escravo.
  • Registradores Modbus (HoldingRegs): Array que armazena os valores dos parâmetros, permitindo que sejam acessados ou enviados via protocolo Modbus.

7. Funções

7.1 Função Setup

Na função setup(), são realizadas as inicializações necessárias para o funcionamento do sistema:

setup_estacao

  • MODBUS_INITIALIZE(): Inicializa a comunicação Modbus, configurando o dispositivo como escravo no protocolo.
  • Wire.begin(): Inicializa a comunicação I2C, permitindo a comunicação com o sensor BME280.
  • bme.begin(): Inicializa o sensor BME280, preparando-o para capturar os dados de temperatura, pressão e umidade.
  • HoldingRegs[BAUDRATE] e HoldingRegs[SLAVEADD]: Definem valores imutáveis para a taxa de transmissão (BaudRate) e o endereço do dispositivo escravo Modbus.

7.2 Função Loop

No trecho de código abaixo, a função loop() é responsável pela execução contínua do programa:

loop_estacao

  • medicoes(): é chamada para coletar os dados dos sensores, que são armazenados na variável dados do tipo SensorData.
  • lerIndiceUV(): é chamada para obter o índice UV atual, que é armazenado na variável indiceUV.
  • atualizarDados(): é chamada para converter os dados lidos e atualizar os registradores Modbus com os valores mais recentes.

7.3 Função Inicialização do ModBus

Essa função configura a comunicação Modbus, garantindo que o dispositivo possa trocar dados corretamente com o mestre Modbus:

modbusini_estacao

  • modbus_configure: Chama a função modbus_configure da biblioteca Modbus para configurar a comunicação. Os parâmetros passados para essa função são:
    • &Serial: Indica que a comunicação será feita através da porta serial do Arduino.
    • BAUD_RATE: Define a taxa de transmissão de dados.
    • SERIAL_8N2: Define o formato da comunicação serial com 8 bits de dados, sem paridade e 2 bits de parada.
    • SLAVE_ADD: Define o endereço do escravo Modbus, que é o identificador único do dispositivo.
    • RE_DE_PIN: Define o pino para controle de direção do transmissor/recebedor (usado com o MAX485, que é um driver de comunicação diferencial).
    • TOTAL_REGS_SIZE: Define o número total de registradores que serão usados no sistema Modbus.
    • HoldingRegs: Passa o array de registradores que vai armazenar os dados a serem lidos ou escritos via Modbus.

7.4 Função de Medição das Grandezas Físicas

A função medicoes() realiza a coleta de dados de vários parâmetros ambientais utilizando o sensor BME280. Ela realiza as seguintes leituras:

func_estacao

  • Temperatura: Obtém a temperatura ambiente em graus Celsius.
  • Pressão: Mede a pressão atmosférica absoluta em hectopascal (hPa).
  • Umidade: Lê a umidade relativa em porcentagem.
  • Pressão ao nível do mar (MSL): Calcula a pressão corrigida ao nível do mar utilizando a fórmula baseada na altitude local.
  • Altitude: Estima a altitude local com base na diferença entre a pressão medida e a pressão ao nível do mar, utilizando a fórmula barométrica.
Fórmulas

Para o cálculo da pressão a nível do mar e a altitude do local :

f1_estacao f2_estacao

Esses dados são armazenados em uma estrutura SensorData e retornados para serem utilizados em outras partes do programa.

7.5 Função de Medição de Índice UV

A função lerIndiceUV() realiza a leitura e o cálculo do índice UV com base na tensão fornecida pelo sensor UV. Ela executa os seguintes passos:

uv_estacao

  • Leitura da Porta Analógica: Obtém o valor bruto da porta analógica do sensor UV.
  • Conversão para Tensão: Converte a leitura analógica para uma tensão em milivolts (mV).
  • Cálculo do Índice UV: Compara o valor da tensão com faixas pré-definidas e atribui um valor correspondente ao índice UV, que varia de 0 a 11, indicando a intensidade da radiação ultravioleta.

A comparação do valor da tensão foi realizada com base nas seguintes tabelas: tuv1_estacao tuv2_estacao

7.5 Função de Conversão e Atualização

atuas_estacao

A função atualizarDados() é responsável por converter os valores coletados dos sensores e atualizar os registradores Modbus. Ela realiza as seguintes operações:

  • HoldingRegs[REG_TEMPERATURA]: Converte o valor da temperatura para um inteiro, multiplicando por 100 para manter a precisão (representando a temperatura com duas casas decimais).
  • HoldingRegs[REG_PRESSAO]: Converte o valor da pressão para um inteiro, multiplicando por 10 para preservar a precisão (representando a pressão com uma casa decimal).
  • HoldingRegs[REG_UMIDADE]: Converte o valor da umidade relativa para um inteiro, multiplicando por 100 para manter a precisão (representando a umidade com duas casas decimais).
  • HoldingRegs[REG_PRESSAO_MSL]: Converte o valor da pressão corrigido ao nível do mar para um inteiro, multiplicando por 10 para manter a precisão.
  • HoldingRegs[REG_ALTITUDE]: Converte o valor da altitude para um inteiro, multiplicando por 10 para manter a precisão.
  • HoldingRegs[REG_INDICE_UV]: Atualiza o valor do índice UV diretamente no registrador Modbus.

Após a conversão, a função chama modbus_update() para atualizar os registradores Modbus com os novos valores. Essa função é crucial para garantir que os dados ambientais coletados sejam corretamente armazenados e disponibilizados para leitura via protocolo Modbus.

Subsistema de Monitoramento do Recipiente

1. Funcionalidades

O firmware embarcado desse subsistema deverá realizar as seguintes funções: 1. Monitoramento constante da Temperatura do Recipiente. 2. Monitoramento constante do nível de água no recipiente.

2. Bibliotecas Utilizadas

  • math.h: Biblioteca padrão da linguagem C e C++ utilizada para realizar cálculos matemáticos complexos de forma mais simples, através da utilização de funções pré-estabelecidas. Essas funções são amplamente utilizadas para realizar cálculos como raízes quadradas, exponenciais, logaritmos, funções trigonométricas, etc.

  • OneWire.h: É uma biblioteca para Arduino que implementa o protocolo de comunicação OneWire, um protocolo usado por diversos dispositivos digitais, como é o caso do sensor de temperatura DS18B20. Esse protocolo tem as vantagens de permitir a comunicação unidirecional, utilizando um único fio de conexão, e endereçamento exclusivo, onde cada dispositivo contém um endereço único, permitindo que múltiplos dispositivos sejam conectados no mesmo barramento.

  • DallasTemperature.h: é uma biblioteca projetada para simplificar a interação com sensores de temperatura da família Dallas/Maxim, como o DS18B20, que utilizam o protocolo de comunicação OneWire. Ela abstrai a complexidade do protocolo e fornece uma interface de alto nível para trabalhar diretamente com os sensores, permitindo operações como leitura de temperatura, identificação de dispositivos e gerenciamento de múltiplos sensores no mesmo barramento de forma simplificada.

  • SimpleModbusSlave.h: É uma biblioteca para Arduino que implementa o protocolo Modbus RTU em modo escravo. Ela permite que um dispositivo baseado em Arduino funcione como um escravo Modbus, respondendo a comandos de leitura e escrita enviados por um mestre Modbus. O protocolo Modbus RTU é um protocolo de comunicação serial amplamente utilizado, que permite que dispositivos se comuniquem em uma rede mestre-escravo, onde o mestre faz solicitações e os escravos respondem com dados ou confirmam ações.

3. Atribuição de pinos

atribuição de pinos_recipiente

  • TrigPin: O pino Trig do sensor ultassônico, responsável por realizar a emissão da onda sonora para detecção do obstáculo, é atribuído ao pino digital 11 do microcontrolador, D11.

  • EchoPin:O pino Echo do sensor ultassônico, responsável por captar a onda sonora após ser refletida pelo obstáculo, é atribuído ao pino digital 12 do microcontrolador, D12.

  • DQ:O pino de dados do sensor de temperatura, responsável por transmitir os dados coletados pelo sensor, já convertidos para o formato digital, é atribuído ao pino digital 7 do microcontrolador, D7.

  • RE_DE_PIN: Pino que será utilizado para requisição de dados pelo subsistema de transmissão para envio de dados, é atribuído ao pino digital 4 do micrcontrolador, D4.

4. Definição das Constantes Utilizadas

constantes_recipiente

  • PI_APROXIMADO: Constante com um valor aproximado para o número π, que é necessário para cálculo do volume de líquido no recipiente.

  • Diametro_Base_Recipiente: Constante para a medida real do diâmetro da base da garrafa que será usada como recipiente.

  • Altura_Recipiente: Constante para a medida real do altura da garrafa que será usada como recipiente.

  • Altura_offset: Constante para diferença de altura entre o sensor ultassônico e a parte superior da garrafa.

  • BAUD_RATE: Constante para valor da velocidade da comunicação serial.

  • SLAVE_ADD: Constante para endereço escravo do subsistema perante o subsistema de transmissão.

5. Variáveis Utilizadas

variaveis_recipiente

  • AreaPerfilReservatorio: Uma variável do tipo float (ponto flutuante), que permite trablhar com valores além de números inteiros, utilizada para guardar o valor da área calculada da base da garrafa que será utilizada como recipiente.

  • VolumeReservatorio: Uma variável do tipo float utilizada para guardar o valor calculado do volume da garrafa que será utilizada como recipiente.

  • Volim: Uma variável do tipo float utilizada para guardar o valor calculado do volume não ocupado por líquido na garrafa que será utilizada como recipiente.

  • VolumeF: Uma variável do tipo float utilizada para guardar o valor calculado do volume ocupado por líquido na garrafa que será utilizada como recipiente.

  • Temp: Uma variável do tipo float utilizada para guardar o valor lido de temperatura pelo sensor.

  • cap_80: Uma variável do tipo bool (booleana), utilizada para detectar a ocorrência ou não de uma condição. Nesse caso, essa variável é utilizada para detectar se 80% da capacidade do recipiente está ocupada, e inicialmente deve estar em estado 'false'.

6. Registradores e endreços Modbus

Endereçoes e Registradores Modbus_recipiente

enum é um recurso da linguagem C/C++ que define uma lista de identificadores associados a valores únicos. Então, nesse caso, tem-se que

  • REG_TEMPERATURA = 0

  • REG_VOLUME = 1

  • REG_CAP80 = 2

  • BAUDRATE = 3

  • SLAVEADD = 4

  • TOTAL_REGS_SIZE = 5

Nesse caso está se criando um array (vetor) de registradores do tipo inteiro chamado HoldRings , com o número de posições igual ao valor definido para TOTAL_REGS_SIZE , nesse caso, 5. Esse vetor de registradores serão utilizados para enviar os dados captados para o subsistema de transmissão através da comunicação serial.

7. Funções

7.1 Função para cálculo da área da base do recipiente

Função AreaPerfilReservatorio

Essa função realiza o cálculo da área da base do recipiente, com base em seu formato cilíndrico, a partir dos valores do diâemetro da Base do recipiente e do valor aproximado de π definidos como constantes anteriormente

Área da Base = π ⋅ (Diâmetro da Base)2 2

Na função, a operação da potência quadrática é utilizada pela função pow(), nativa da bibiloteca math.h. O formato dessa função segue pow(base,expoente), por isso é usado o termo (Diametro_Base_Recipiente)/2), equivalente ao raio, e 2 no protótipo da função.

7.2 Função para cálculo do volume do recipiente

Função Calcula_Volume_Recipiente

Essa função realiza o cálculo do volume do recipiente, com base em seu formato cilíndrico, a partir dos valores da altura do recipiente e do valor calculado anteriormente para área da base do recipiente.

Volume do Recipiente = Área da Base ⋅ Altura do Recipiente

7.3 Função para conversão da duração da onda sonora em distância

Função microsecondsToCentimeters

No loop principal, são realizadas as operações para captar a distância do sensor até o obstáculo, neste caso, a água. Porém, o sensor ultrassônico trabalha com a emissão e recepção de uma onda sonora, e o que se obtém de retorno a partir do seu uso é o período que a onda leva para atingir o obstáculo e retornar. Essa função então realiza a conversão de tempo em uma distância a partir do princípio apresentado a diante.

A velocidade com que o som se propaga no ar é de 343 [m/s]. Como a função utilizada para captar o período da onda retorna com um tempo dado em microsegundos e as unidades de comprimento são dadas em centímetros, é conveniente tratar essa velocidade em unidades de [cm/μs], que passa a ser então de 0.0343 [cm/μs]. Então para receber uma distância do obstáculo dada em [cm], basta multiplicar o período de tempo por 0.0343 [cm/μs], ou dividir por 29 [μs/cm]. Porém, também é necessário considerar que o período de tempo leva em conta a ida e volta do sinal, o que implica na distância retornada ser equivalente a distância percorrida na ida e na volta da onda. Então, essa distância ainda precisa ser dividida por 2, para chegar a distância real entre o sensor e o obstáculo.

Distância [cm] = tempo [μs] 29 [μs/cm] 2

Essa é a operação feita nesta função.

7.4 Função para registro de dados nos registradores Modbus

Função Registra_Dados_recipiente

O protocolo Modbus trabalha com inteiros de 16 bits para realizar a comunicação. Portanto, nessa função, os valores de temperatura e volume de líquido no recipiente, juntamente com o indicador de 80% da capacidade cheio são convertidos para inteiros de 16 bits, sendo que os valores de volume e temperatura são multiplicados por 100 para que se mantenha a precisão dos valores ao serem convertidos.

7.5 Função para configuração do protocolo Modbus

Função MODBUS_INICIALIZE_recipiente

Configura o protocolo Modbus do subsistema para que ele possa funcionar como um escravo (slave) na comunicação Modbus. A função modbus_configure é a função que faz a configuração inicial do protocolo Modbus e utiliza os seguintes parâmetros:

  • &Serial: Refere-se à interface serial do microcontrolador que será usada para a comunicação Modbus. No caso do Arduino, Serial corresponde à UART principal.

  • BAUD_RATE: Define a velocidade da comunicação serial em bits por segundo (bps), nesse caso, 9600.

  • SERIAL_8N2: Configuração do formato dos dados seriais. O 8 se refere ao número de bits de dados, já o N sinaliza que não há bits de paridade e 2 se refere ao número de bits de paridade.

  • SLAVE_ADD: Endereço do dispositivo escravo (slave).

  • RE_DE_PIN: Pino do microcontrolador usado para controlar a direção de transmissão (TX) e recepção (RX) em um driver RS485.

  • TOTAL_REGS_SIZE: Quantidade total de registradores Modbus

  • HoldingRegs: array para a memória onde os registros do Modbus serão armazenados. Esses registros contêm os dados que podem ser lidos pelos mestres Modbus.

7.6 Função loop

Função loop_recipiente

A função loop mostra principalmente como é feita a captação dos dados de temperatura e volume e como deve ser feita a sinalização de quando a capacidade de 80% do recipiente for preenchida.

Os dados de temperatura são captados principalmente pela função sensor.requestTemperatures(), e atribuição é feita a variável Temp com a função sensor.getTempCByIndex(0), utilizando os dados do sensor com endereço 0, que é o único, já que o subsistema possui somente um sensor de temperatura.

Também pode ser visto como é feita a captação da distância pelo sensor ultrassônico, colocando o pino do microcontolador ligado ao Trig do sensor como saída digital, e colocando-o em estado lógico alto e baixo, criando o pulso de onda, e o pino do micrcontrolador ligado ao pino Echo é definido como entrada digital, e é feita a captação do tempo em que o pino Echo fica em estado lógico alto, o que simboliza que o sensor está recebendo de volta o pulso de onda criado, através da função pulseIn(). Esse tempo é o que usado para ser convertida para uma distância em [cm] pela função microsecondsToCentimeters, descrita anteriormente.

A partir daí, também é mostrado como o volume de líquido no recipiente é calculado a partir da subtração de volume não ocupado por líquido do volume total do recipiente. E esses valores são divididos por 1000, para converter o volume de centímetros cúbicos [cm3] para litro´[l].

A variável cap_80, destinada a guardar a ocorrência do volume de 80% do total do recipiente ser ocupada, passa a ter estado true se isso ocorrer. No caso do recipiente utilizado, que tem 2 litros de capacidade, isso ocorre ser o volume de líquido for maior ou igual a 1.6 litros.

Por fim, os dados são registrados nos registradores Modbus, através da função Registra_Dados(), descrita anteriormente

Subsistema de Controle da Comporta

1. Funcionalidades

O firmware embarcado desse subsistema deverá realizar as seguintes funções:

  1. Monitoramento a ocorrência de chuva.
  2. Realizar o controle da abertura da comporta quando a chuva começar, e do seu fechamento quando a chuva cessar, de forma automática.
  3. Realizar o fechamento automático da comporta quando 80% da capacidade do recipiente for ocupada.
  4. Permitir que um controle remoto externo possa controlar o funcionamento da comporta em caso de falha do sistema automático.

2. Bibliotecas Utilizadas

  • SimpleModbusSlave.h: É uma biblioteca para Arduino que implementa o protocolo Modbus RTU em modo escravo. Ela permite que um dispositivo baseado em Arduino funcione como um escravo Modbus, respondendo a comandos de leitura e escrita enviados por um mestre Modbus. O protocolo Modbus RTU é um protocolo de comunicação serial amplamente utilizado, que permite que dispositivos se comuniquem em uma rede mestre-escravo, onde o mestre faz solicitações e os escravos respondem com dados ou confirmam ações.

3. Atribuição de pinos

atribuição de pinos_comporta

  • ENA: O pino ENA do driver A4988, responsável por habilitar ou desabilitar as saídas do driver para controle do motor, é atirbuído ao pino digital 9 do microcontrolador, D9.

  • MS1: O pino MS1 do driver A4988, um dos pinos responsáveis por realizar a subdivisão dos passos de resolução para voltas do motor, é atribuído ao pino digital 8 do microcontrolador, D8.

  • MS2: O pino MS2 do driver A4988, um dos pinos responsáveis por realizar a subdivisão dos passos de resolução para voltas do motor, é atribuído ao pino digital 7 do microcontrolador, D7.

  • MS3: O pino MS2 do driver A4988, um dos pinos responsáveis por realizar a subdivisão dos passos de resolução para voltas do motor, é atribuído ao pino digital 6 do microcontrolador, D6.

  • RST: O pino RST do driver A4988, responsável por redefinir as configurações realizadas no drive pelo firmware,é atribuído ao pino digital 5 do micrcontrolador, D5.

  • SLP: O pino SLP do driver A4988, responsável por colocar o driver em modo de economia de enrgia quando não está sendo utilizado, é atribuído ao pino digital 4 do micrcontrolador, D4.

  • STP: O pino STP do driver A4988, responsável determinar quando o motor deverá executar os passos para que complete uma volta, é atribuído ao pino digital 3 do micrcontrolador, D3.

  • DIR: O pino DIR do driver A4988, responsável por determinar a direção de giro do motor, é atribuído ao pino digital 2 do micrcontrolador, D2.

  • pinSensorA: Pino A0 do módulo YL-83, que controla o sensor de chuva FC-37, responsável por captar a leitura analógica da tensão na trilha resistiva do sensor, é atribuído ao pino digital A0 do micrcontrolador.

  • pinSensorD: Pino D0 do módulo YL-83, que controla o sensor de chuva FC-37, responsável por captar o nível lógico digital equivalente a tensão na trilha resistiva do sensor, é atribuído ao pino digital 13 do micrcontrolador, D13.

  • RE_DE_PIN: Pino que será utilizado para requisição de dados pelo subsistema de transmissão para envio de dados, é atribuído ao pino digital 12 do micrcontrolador, D12.

4. Definição das Constantes Utilizadas

constantes_comporta

  • BAUD_RATE: Constante para valor da velocidade da comunicação serial.

  • SLAVE_ADD: Constante para endereço escravo do subsistema perante o subsistema de transmissão.

5. Variáveis Utilizadas

variaveis_comporta

  • PPR: Uma variável do tipo inteira, para determinar o número de passos que que o motor deve realizar para que complete um volta de acordo com a subdivisão de micropassos.

  • passo: Uma variável do tipo inteira, para determinar quantos passos foram dados pelo motor.

  • temp: Uma variável do tipo inteira, utilizada para determinar o tempo entre cada passo dado pelo motor.

  • status_recipiente: Uma variável do tipo bool (booleana), utilizada para detectar a ocorrência ou não de uma condição. Nesse caso, essa variável é utilizada para determinar o estado da comporta, se está aberta ou fechada. Considera-se que no estado 'true', indicaria a comoporta do recipiente estar fechada, enquanto que o estado 'false' indica a comporta do recipiente aberta.

  • chuva: Uma variável do tipo bool utilizada para detectar se está ou não chovendo, iniciando em 'false', assumindo que inicialmente não está chovendo.

  • controle_externo: Uma variável do tipo bool utilizada para realizar o controle da comporta em caso de falha do sistema automático. Presumindo que idealmente o sistema não falhará, esse controle inicia em 'false'.

  • controle_capacidade: Uma variável do tipo bool (booleana), utilizada para detectar se 80% da capacidade do recipiente está ocupada, e inicialmente deve estar em estado 'false'. Essa informação virá do subsistema de transmissão, que por sua vez, será enviado pelo subsistema de monitoramento do recipiente.

6. Registradores e endreços Modbus

Endereçoes e Registradores Modbus_comporta

enum é um recurso da linguagem C/C++ que define uma lista de identificadores associados a valores únicos. Então, nesse caso, tem-se que

  • REG_CHUVA = 0

  • REG_STATUS = 1

  • REG_CAP80 = 2

  • REG_CONTROLE_REMOTO = 3

  • BAUDRATE = 4

  • SLAVEADD = 5

  • TOTAL_REGS_SIZE = 6

Nesse caso está se criando um array (vetor) de registradores do tipo inteiro chamado HoldRings , com o número de posições igual ao valor definido para TOTAL_REGS_SIZE , nesse caso, 6. Esse vetor de registradores serão utilizados para enviar os dados captados para o subsistema de transmissão através da comunicação serial, e também para receber os dados de controle externo e capacidade do recipiente.

7. Funções

7.1 Função para registro de dados nos registradores Modbus

Função Registra_Dados_comporta

O protocolo Modbus trabalha com inteiros de 16 bits para realizar a comunicação. Portanto, nessa função, os indicadores do status da comporta e da ocorrencia de chuva, que serão enviados, são convertidos para inteiros de 16 bits. Já os indicadores de controle externo e capacidade de 80% do recipiente preenchida, que serão recebidos na comunicação, são atualizados com os valores dos registradores em seus respectivos endereços, com o valor inteiro de 16 bits convertido para uma variável booleana.

7.2 Função para configuração do protocolo Modbus

Função MODBUS_INICIALIZE_comporta

Configura o protocolo Modbus do subsistema para que ele possa funcionar como um escravo (slave) na comunicação Modbus. A função modbus_configure é a função que faz a configuração inicial do protocolo Modbus e utiliza os seguintes parâmetros:

  • &Serial: Refere-se à interface serial do microcontrolador que será usada para a comunicação Modbus. No caso do Arduino, Serial corresponde à UART principal.

  • BAUD_RATE: Define a velocidade da comunicação serial em bits por segundo (bps), nesse caso, 9600.

  • SERIAL_8N2: Configuração do formato dos dados seriais. O 8 se refere ao número de bits de dados, já o N sinaliza que não há bits de paridade e 2 se refere ao número de bits de paridade.

  • SLAVE_ADD: Endereço do dispositivo escravo (slave).

  • RE_DE_PIN: Pino do microcontrolador usado para controlar a direção de transmissão (TX) e recepção (RX) em um driver RS485.

  • TOTAL_REGS_SIZE: Quantidade total de registradores Modbus

  • HoldingRegs: array para a memória onde os registros do Modbus serão armazenados. Esses registros contêm os dados que podem ser lidos pelos mestres Modbus.

7.3 Função para divisão de micropassos do motor

Função sixteenth_divisor

Essa função atibui os níveis lógicos necessários aos pinos MS1,MS2 e MS3 do driver do motor. Como explicado na seção de descrição deste subsistema, para que o driver realize a divisão dos passos em 1/16, é necessário colocar estes três pinos em nível lógico alto. Essa subdivisão foi escolhida pois, nos testes realizados para verificar o funcionamento individual do motor, essa é a que garante uma transição mais suave durante os movimentos de rotação do motor, evitando rotações bruscas.

7.4 Funçõs para habilitação e desabilitação do drive do motor

Função ena_ena2_comporta

A função ena2() coloca o pino Enable do driver em nível lógico alto, desabilitando os drivers de saída para que o motor não seja capaz de rotacionar. Já a função ena() coloca o pino Enable do driver em nível lógico baixo, habilitando os drivers de saída para que o motor seja capaz de rotacionar.

7.5 Funçõs para definição do sentido de rotação do motor

Função horario_ahorario_comporta

A função HR() define a rotação do motor no sentido horário, colocando o pino DIR do driver em nível lógico alto. Já a função AH() define a rotação do motor no sentido anti-horário, colocando o pino DIR do driver em nível lógico baixo.

7.6 Função para controle do número de voltas do motor no sentido horário

Função volta_horario_comporta

Essa função realiza o controle do número de voltas do motor para sentido horário. Ela começa utilizando uma das funções descritas anteriormente, HR(), para definição do sentido horário. Enquanto o número de passos dados pelo motor for menor do que o PPR definido, que é o número de passos que o motor deve realizar por volta, o pino step vai sendo colocado em nível lógico baixo e alto repetidamente, sinalizando um passo de rotação, e após isso o número de passos é atualizado. Quando o motor tiver alcançado o número de passos definidos por volta, o número de passos é resetado e o driver do motor é desabilitado rapidamente para que o motor pare a rotação, e depois é novamente hailitado.

7.6 Função para controle do número de voltas do motor no sentido anti-horário

Função volta_horario_comporta

Essa função segue basicamente o mesmo princípio da função de controle de voltas do motor para o sentido horário, visto que os passos de rotação são definidos pela implementação da mesma lógica para o pino STP e o número do PPR é o mesmo, pois está relacionado a divisão dos micropassos e não ao sentido de rotação. A diferença básica é que, no início, é chamada a função para definição do sentido de rotação anti-horário, AH().

7.7 Função loop

A função loop executa uma série de comandos para controle da comporta. Para ilustrar o comportamento dessa função, o fluxograma abaixo mostra de forma mais intuitiva o comportamento nessa função

Função volta_horario_comporta

Subsistema de Transmissão

1. Funcionalidades

O firmware embarcado desse subsistema deverá realizar as seguintes funções:

  1. Requisitar os dados dos outros subsistemas através do modbus.
  2. Monitoramento constante da tensão da bateria.
  3. Enviar os dados obtidos por MQTT.

2. Principais bibliotecas Utilizadas

  • freertos/FreeRTOS.h: É uma biblioteca responsável pela interface de programação para o uso do FreeRTOS, um sistema operacional em tempo real (RTOS - Real-Time Operating System). A biblioteca permite gerenciar, comunicar e sincronizar processos, sendo utilizada na criação de task nesse projeto.

  • mqtt.h: Essa biblioteca permite utilizar as funções do arquivo "mqtt.c", arquivo responsável por estabelecer a conexão do Broker e enviar, em formato CJSON, os dados obtidos por protocolo MQTT.

  • modbus.h: Essa biblioteca permite utilizar as funções do arquivo "modbus.c", arquivo responsável por estabelecer a conexão com os subsistemas adjacentes, fazer a requisição de dados e chamar a task que envia os dados por MQTT.

  • bateria.h: Essa biblioteca permite utilizar as funções do arquivo "bateria.c", arquivo responsável por configurar o canal do ADC e realizar o monitoramento da tensão da bateria.

3. Atribuição de pinos

  • UART: Para a comunicação com os outros subsistemas será utilizada a UART2 da ESP32, tendo o GPIO16 como Rx e o GPIO17 como Tx.

  • RE_DE_PIN: Pino que será utilizado para requisição de dados dos subsistemas adjacentes, definido como o GPIO4 da ESP32.

  • V_BAT: Pino definido para monitorar a tensão da bateria, para esse pino será utilizado o canal 7 do ADC2, representado pelo GPIO27.

4. Registradores e endreços Modbus

Endereçoes e Registradores Modbus

enum é um recurso da linguagem C/C++ que define uma lista de identificadores associados a valores únicos. Então, nesse caso, tem-se que

  • REG_TEMPERATURA = 0
  • REG_PRESSAO = 1
  • REG_UMIDADE =2
  • REG_PRESSAO_MSL = 3
  • REG_ALTITUDE = 4
  • REG_INDICE_UV = 5
  • REG_TEMPERATURA2 = 6
  • REG_VOLUME = 7
  • REG_CAP80 = 8
  • WIND_DIR = 9
  • WIND_SPEED = 10
  • V_NORTE = 11
  • V_SUL = 12
  • V_LESTE = 13
  • V_OESTE = 14
  • DIRPOPOR = 15
  • REG_CHUVA = 16
  • REG_STATUS = 17
  • REG_CONTROLE_REMOTO = 18
  • CID_COUNT = 19

Utilizando essa lista será criado um array (vetor) de descrição chamado device_parameterers , com o número de posições igual ao valor definido para CID_COUNT , nesse caso, 16. Esse vetor configura cada registrador que será utilizado para receber os dados dos outros subsistemas através da comunicação serial.

Vetor de descrição

5. Funções

5.1 Função para inicializar o MQTT

Função init_mqtt

Essa função configura o MQTT e inicia a comunicação, para isso é definido o Broker que será utilizado e define o cliente para esse Broker. Após esse processo são definidos o eventos do MQTT e o cliente é iniciado.

5.2 Função para inicializar o Modbus

Função modbus_init

Essa função configura o modbus, definindo a porta como a UART2, o modo de comunicação como RTU, o baudrate para 9600, define uma comunicação sem sinal de paridade, por fim, define a comunicação como Half-Duplex , forma de comunicação que transmissão de dados em duas direções, mas não simultaneamente. Após esse processo, é inicializado a comunicação pela porta serial definida.

5.3 Função para ler dados pelo modbus

Função modbus_task

A função "master_operation_func" realiza a leitura dos dados recebidos pelos outros subsistemas e é executada pela task "modbus_task" que está em loop.

Função modbus_task1

A função começa definido os parâmetros que serão utilizados, utilizando como base o vetor configurado para cada registrador de dado, definido por "device_parameters". Após esse processo é criado o cJSON que será utilizado para o envio de dados por MQTT.

Função modbus_task2

Em um loop ocorre a leitura de dados dos outros subsistemas utilizando a função do modbus "mbc_master_get_parameter", que aponta para o registrador que deve ser lido e retorna seu valor. O nome da variável lida no registrador e o valor são adicionados ao cJSON.

Função modbus_task3

Por fim, a função realiza a task para monitorar a tensão da bateria e adiciona o valor no cJSON, que é transformado em uma sting que é enviada pela task do MQTT. Com o fim da função a comunicação do modbus é encerrado e as task destruída.

5.4 Função para o envio dos dados por MQTT

Função mqtt_task

A função "send_task" realiza o envio dos dados recebidos pelos outros subsistemas e é executada pela task "mqtt_task" que está no processo de leitura do modbus. A task passa como parâmetro da função a string do cJSON gerada na função do modbus.

Função mqtt_task1

A função recebe a string passada como parâmetro e realiza o envio para o Broker, após esse processo é liberada a memória que estava armazenando o cJSON e a função é destruída.

Versionamento

Versão Data Descrição Responsável
1.0 02/12/2024 Documento inicial criado. Matheus Félix
1.1 02/12/2024 Inclusão do controle de versões. Matheus Félix
1.2 22/12/2024 Inclusão da descrição de firmware relacionada ao subsistema de monitoramento do vento. Pedro Zago
1.3 22/12/2024 Inclusão da descrição de firmware relacionada ao subsistema da estação meteorológica. Pablo Santos
1.4 18/12/2024 Inclusão da descrição de firmware relacionada ao subsistema de monitoramento do recipiente. Matheus Félix
1.5 08/01/2025 Inclusão da descrição de firmware relacionada ao subsistema de controle da comporta. Matheus Félix
1.6 09/01/2025 Inclusão da descrição de firmware relacionada ao subsistema de transmissão. Tiago Caixeta
1.7 13/01/2025 Revisão do arquivo. Matheus Félix
1.8 13/01/2025 Ajustes finais do arquivo. Matheus Félix