Why cJSON Is the Ideal Lightweight JSON Parser for Resource‑Constrained MCUs
This article introduces cJSON, a tiny open‑source C library designed for embedded systems, explains its core features, shows how to create, parse, and manipulate JSON data on microcontrollers, and provides practical code examples for configuration management, command handling, and data logging.
cJSON is an ultra‑lightweight, pure‑C JSON parsing library consisting of a single .h and .c file, making it suitable for memory‑constrained microcontrollers such as STM32F103 or ESP8266.
Key Characteristics
Minimal memory footprint : parsing requires only a few kilobytes of RAM.
Pure C implementation : no third‑party dependencies; builds with Keil, IAR, GCC, etc.
Simple API : can be learned in minutes.
Flexible : supports dynamic creation, modification, serialization and deserialization of JSON objects.
GitHub repository: https://github.com/DaveGamble/cJSON
Basic Usage – Creating JSON
#include "cJSON.h"
void create_json(void) {
// 1. Create root object
cJSON *root = cJSON_CreateObject();
// 2. Add key‑value pairs
cJSON_AddStringToObject(root, "device", "ESP32");
cJSON_AddNumberToObject(root, "temperature", 25.6);
// 3. Add nested object
cJSON *location = cJSON_CreateObject();
cJSON_AddNumberToObject(location, "lat", 35.6895);
cJSON_AddNumberToObject(location, "lon", 139.6917);
cJSON_AddItemToObject(root, "location", location);
// 4. Generate JSON string
char *json_str = cJSON_Print(root);
printf("JSON: %s
", json_str);
// 5. Free resources
free(json_str);
cJSON_Delete(root);
}Resulting JSON:
{
"device": "ESP32",
"temperature": 25.6,
"location": {
"lat": 35.6895,
"lon": 139.6917
}
}Parsing JSON
void parse_json(const char *json_str) {
cJSON *root = cJSON_Parse(json_str);
if (root == NULL) {
printf("JSON parsing failed!
");
return;
}
cJSON *device = cJSON_GetObjectItem(root, "device");
cJSON *temp = cJSON_GetObjectItem(root, "temperature");
cJSON *location = cJSON_GetObjectItem(root, "location");
printf("Device: %s, Temp: %.1f
", device->valuestring, temp->valuedouble);
printf("Lat/Lon: (%.4f, %.4f)
",
cJSON_GetObjectItem(location, "lat")->valuedouble,
cJSON_GetObjectItem(location, "lon")->valuedouble);
cJSON_Delete(root);
}Typical Embedded Use Cases
1. Dynamic Configuration Management
Store configuration in a JSON file and parse it at runtime, enabling OTA updates without recompiling.
// config.json
{
"wifi": {"ssid": "MyIoT", "password": "123456"},
"sampling_interval": 5000
}
void load_config(void) {
char *json_str = read_file("config.json");
cJSON *root = cJSON_Parse(json_str);
cJSON *wifi = cJSON_GetObjectItem(root, "wifi");
char *ssid = cJSON_GetObjectItem(wifi, "ssid")->valuestring;
char *pwd = cJSON_GetObjectItem(wifi, "password")->valuestring;
int interval = cJSON_GetObjectItem(root, "sampling_interval")->valueint;
printf("Wi‑Fi: %s/%s, Interval: %dms
", ssid, pwd, interval);
cJSON_Delete(root);
free(json_str);
}2. Device‑to‑Device Communication Protocol
Use JSON commands for human‑readable, easily debuggable messaging.
void handle_command(const char *json_str) {
cJSON *root = cJSON_Parse(json_str);
const char *cmd = cJSON_GetObjectItem(root, "cmd")->valuestring;
if (strcmp(cmd, "set_led") == 0) {
cJSON *args = cJSON_GetObjectItem(root, "args");
int id = cJSON_GetObjectItem(args, "id")->valueint;
int brightness = cJSON_GetObjectItem(args, "brightness")->valueint;
led_set(id, brightness);
}
cJSON_Delete(root);
}3. Local Data Storage & Logging
Serialize sensor readings to JSON for plain‑text logs, simplifying later analysis.
void log_sensor_data(float temp, float humidity) {
cJSON *root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "temp", temp);
cJSON_AddNumberToObject(root, "humidity", humidity);
cJSON_AddStringToObject(root, "timestamp", "2023-08-15T14:30:00Z");
char *json_str = cJSON_PrintUnformatted(root); // compact output
write_to_sd_card("log.json", json_str);
free(json_str);
cJSON_Delete(root);
}Practical Tips
Always call cJSON_Delete() and free() for allocated objects to avoid memory leaks.
Use short key names to reduce RAM usage and transmission bandwidth.
For large payloads, consider cJSON_ParseWithOpts for incremental parsing, which lowers peak memory consumption.
These techniques enable flexible, human‑readable configuration and communication on even the most memory‑constrained MCUs without sacrificing performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
