MCU & FPGA C,C++ Usando JSON e cJSON em Microcontroladores

Usando JSON e cJSON em Microcontroladores


Preparando a cJSON para uso em microcontroladores

A biblioteca cJSON é composta basicamente por dois arquivos principais:

cJSON.h
cJSON.c

Em um projeto embarcado simples, normalmente copiamos esses dois arquivos para uma pasta do firmware, por exemplo:

project/
├── main.c
├── cJSON/
│   ├── cJSON.c
│   └── cJSON.h
├── app/
│   ├── sensor_mock.c
│   ├── sensor_mock.h
│   ├── web_mock.c
│   └── web_mock.h
└── build/

Essa estrutura é genérica. Ela pode ser adaptada para STM32CubeIDE, ESP-IDF, PlatformIO, CMake, Makefile puro, Zephyr, FreeRTOS ou até um projeto bare-metal simples. O ponto importante é que o compilador consiga encontrar o arquivo cJSON.h e compilar o arquivo cJSON.c junto com o restante do projeto.

Em um projeto com gcc, por exemplo, a compilação poderia ser representada assim:

gcc main.c app/sensor_mock.c app/web_mock.c cJSON/cJSON.c -I./cJSON -I./app -o firmware_sim

Em um microcontrolador real, o comando não seria exatamente esse, pois dependeria do compilador cruzado, como arm-none-eabi-gcc, riscv-none-elf-gcc, xtensa-esp32-elf-gcc ou outro toolchain. Ainda assim, a lógica é a mesma: o arquivo cJSON.c precisa entrar no build e o caminho do cJSON.h precisa estar configurado nos includes.

A cJSON trabalha criando uma árvore de objetos em memória. Quando fazemos algo como:

cJSON *root = cJSON_CreateObject();

a biblioteca aloca memória dinamicamente para representar o objeto JSON. Depois, cada campo adicionado também pode exigir novas alocações internas. Isso é muito confortável em computadores, mas exige atenção em microcontroladores, porque a memória RAM é limitada e fragmentação de heap pode se tornar um problema.

Por isso, a regra prática é: crie o JSON, use o JSON e libere o JSON o mais rápido possível. A função principal para liberar uma estrutura criada pela cJSON é:

cJSON_Delete(root);

Se esquecermos essa chamada, teremos vazamento de memória. Em firmware que roda continuamente por dias ou meses, um pequeno vazamento repetido dentro de uma tarefa periódica pode derrubar todo o sistema.

A cJSON também pode gerar uma string textual a partir da árvore JSON. Isso normalmente é feito com:

char *json_string = cJSON_PrintUnformatted(root);

Essa função também aloca memória dinamicamente para armazenar o texto final. Depois de usar essa string, precisamos liberar a memória com:

free(json_string);

Portanto, um fluxo básico e seguro é:

Criar objeto JSON
Adicionar campos
Converter para string
Usar a string
Liberar a string
Liberar o objeto JSON

Em C, isso fica conceitualmente assim:

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

int main(void)
{
    cJSON *root = cJSON_CreateObject();

    if (root == NULL)
    {
        printf("Erro ao criar objeto JSON.\n");
        return 1;
    }

    cJSON_AddStringToObject(root, "device_id", "mcu-001");
    cJSON_AddNumberToObject(root, "temperature", 28.75);
    cJSON_AddNumberToObject(root, "voltage", 3.29);
    cJSON_AddNumberToObject(root, "uptime", 15240);

    char *json_string = cJSON_PrintUnformatted(root);

    if (json_string == NULL)
    {
        printf("Erro ao converter JSON para texto.\n");
        cJSON_Delete(root);
        return 1;
    }

    printf("JSON gerado: %s\n", json_string);

    free(json_string);
    cJSON_Delete(root);

    return 0;
}

Esse exemplo ainda não simula sensores nem serviço web. Ele apenas mostra o ciclo mínimo de uso da biblioteca: criar, preencher, imprimir e liberar.

A saída esperada seria parecida com:

{"device_id":"mcu-001","temperature":28.75,"voltage":3.29,"uptime":15240}

Em microcontroladores, geralmente preferimos cJSON_PrintUnformatted() em vez de cJSON_Print(), porque a versão formatada adiciona espaços, quebras de linha e indentação. Isso facilita a leitura por humanos, mas aumenta o tamanho da mensagem transmitida. Para comunicação via UART, Wi-Fi, LoRa, BLE, Ethernet ou modem celular, bytes extras significam mais tempo de transmissão e, em alguns casos, mais consumo de energia.

Outro ponto importante é que o uso direto de printf() no exemplo é apenas didático. Em um firmware real, poderíamos substituir por:

uart_write(json_string);

ou:

http_post("/api/sensors", json_string);

ou ainda:

mqtt_publish("devices/mcu-001/data", json_string);

Neste tutorial, para manter o código independente de plataforma, vamos criar uma função mock chamada web_mock_post(). Ela vai fingir que envia o JSON para um servidor e vai retornar uma resposta também em JSON.

0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x