JSON, sigla para JavaScript Object Notation, é um formato textual usado para representar dados estruturados. Apesar de ter nascido no ecossistema JavaScript, hoje ele é amplamente usado em APIs web, sistemas IoT, serviços REST, comunicação entre dispositivos, arquivos de configuração e troca de mensagens entre firmware e aplicações externas.
Em microcontroladores, JSON aparece principalmente quando o dispositivo precisa conversar com algum sistema externo. Por exemplo, um ESP32 pode enviar leituras de temperatura para um servidor HTTP; um STM32 com modem 4G pode publicar dados em uma API; um RP2040 conectado a um gateway pode receber parâmetros de calibração; ou um dispositivo industrial pode gerar mensagens estruturadas para diagnóstico remoto.
A grande vantagem do JSON é a legibilidade. Uma mensagem como esta:
{
"device": "sensor-01",
"temperature": 27.5,
"humidity": 61.2,
"relay": true
}
é fácil de entender tanto por humanos quanto por máquinas. Isso ajuda no desenvolvimento, no teste, no debug e na integração com sistemas web. Em vez de criar um protocolo binário próprio logo no início do projeto, muitas vezes podemos começar com JSON para acelerar a prototipagem e tornar a comunicação mais clara.
Mas existe um ponto importante: JSON não é o formato mais eficiente para microcontroladores pequenos. Ele consome mais memória que um protocolo binário, ocupa mais bytes na comunicação e exige processamento para converter texto em dados internos. Em um microcontrolador com poucos kilobytes de RAM, isso precisa ser tratado com cuidado.
Por isso, em sistemas embarcados, usamos JSON quando a clareza, a interoperabilidade e a integração com serviços externos são mais importantes do que a máxima economia de memória. Essa é uma decisão típica de projeto embarcado: escolher uma solução que facilite a comunicação, mas sem ignorar restrições de RAM, Flash, tempo de execução e robustez. Esse cuidado está alinhado com a visão clássica de desenvolvimento embarcado em C, onde restrições de memória, desempenho, confiabilidade e custo recorrente influenciam diretamente as decisões de arquitetura.
Neste tutorial, vamos usar a biblioteca cJSON, uma biblioteca em linguagem C para criar e interpretar documentos JSON. A ideia será manter tudo genérico, sem depender de ESP-IDF, STM32 HAL, Pico SDK, Zephyr ou FreeRTOS. Quando precisarmos simular comunicação com um servidor web, usaremos funções mock, ou seja, funções falsas que imitam o comportamento de uma API externa.
A arquitetura básica do nosso exemplo será esta:
+-------------------------+
| Aplicação MCU |
| |
| Lê sensores simulados |
| Monta JSON com cJSON |
| Envia para Web Mock |
| Recebe resposta JSON |
| Interpreta resposta |
+-----------+-------------+
|
v
+-------------------------+
| Serviço Web Simulado |
| |
| Recebe JSON |
| Processa dados fake |
| Retorna JSON |
+-------------------------+
Neste primeiro momento, podemos imaginar que o microcontrolador coleta dados de sensores e envia essas informações para um servidor. O servidor, por sua vez, responde com alguma configuração, como ligar ou desligar um relé, alterar o intervalo de amostragem ou informar se houve erro na requisição.
Um exemplo de mensagem enviada pelo microcontrolador poderia ser:
{
"device_id": "mcu-001",
"temperature": 28.75,
"voltage": 3.29,
"uptime": 15240
}
E uma resposta simulada do servidor poderia ser:
{
"status": "ok",
"relay": true,
"sample_interval_ms": 5000
}
Perceba que o JSON permite representar textos, números, valores booleanos, objetos e listas. Isso é muito útil quando queremos criar mensagens flexíveis. Porém, em firmware, devemos evitar documentos JSON muito grandes, objetos muito profundos e alocações dinâmicas descontroladas.
Ao longo do tutorial, vamos trabalhar com quatro ideias principais: criar JSON, converter JSON para texto, interpretar JSON recebido e proteger o firmware contra erros de formato. A biblioteca cJSON facilita bastante esse processo, mas ela não elimina a responsabilidade do programador embarcado. Sempre será necessário verificar ponteiros, validar tipos, controlar tamanho de buffers e liberar memória corretamente.