目录
概述
本篇文章介绍如何使用STM32引用 cJSON开源库,JSON格式在互联网数据交互时常用的一个格式,现嵌入式物联网方向,经常使用到,如:MQTT协议,LwM2M协议等等,只要是把数据上传到后台,方便格式查阅与统一处理,终端设备有必要使用JSON格式来封装数据。
GitHub:https://github.com/DaveGamble/cJSON
硬件:STM32F103CBT6最小系统板
软件:Keil 5.29 + STM32CubeMX6.01
一、使用方法
详细步骤请移步到官网介绍,不过也没有关系,按照下面的步骤来也行。
二、STM32CubeMx配置
三、Examples
打开STM32CubeMx生成的keil工程,新建cJSON文件夹,把代码仓库cJSON下载下来的代码,添加cJSON.c、cJSON_Utils.c、test.c 3个文件即可,test.c文件是开源库,编写的json格式字符的测试示例。
在keil添加上图的文件即可。
添加包含头文件路径
添加完后,编译项目。
打开test.c文件,修改以下地方
再次编译
修改堆栈大小
方式1
方式2
生成代码后,startup_stm32f103xb.s汇编文件就会修改,跟方式1 一个样。
1、test.c文件
-
/*
-
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
-
-
Permission is hereby granted, free of charge, to any person obtaining a copy
-
of this software and associated documentation files (the "Software"), to deal
-
in the Software without restriction, including without limitation the rights
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
copies of the Software, and to permit persons to whom the Software is
-
furnished to do so, subject to the following conditions:
-
-
The above copyright notice and this permission notice shall be included in
-
all copies or substantial portions of the Software.
-
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
THE SOFTWARE.
-
*/
-
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include "cJSON.h"
-
-
-
/* We don't do anything about it */
-
#define exit(a) \
-
if(#a == "1") \
-
; \
-
else \
-
; \
-
-
-
/* Used by some code below as an example datatype. */
-
struct record
-
{
-
const
char *precision;
-
double lat;
-
double lon;
-
const
char *address;
-
const
char *city;
-
const
char *state;
-
const
char *zip;
-
const
char *country;
-
};
-
-
-
/* Create a bunch of objects as demonstration. */
-
static int print_preallocated(cJSON *root)
-
{
-
/* declarations */
-
char *out =
NULL;
-
char *buf =
NULL;
-
char *buf_fail =
NULL;
-
size_t len =
0;
-
size_t len_fail =
0;
-
-
/* formatted print */
-
out = cJSON_Print(root);
-
-
/* create buffer to succeed */
-
/* the extra 5 bytes are because of inaccuracies when reserving memory */
-
len =
strlen(out) +
5;
-
buf = (
char*)
malloc(len);
-
if (buf ==
NULL)
-
{
-
printf(
"Failed to allocate memory.\n");
-
exit(
1);
-
}
-
-
/* create buffer to fail */
-
len_fail =
strlen(out);
-
buf_fail = (
char*)
malloc(len_fail);
-
if (buf_fail ==
NULL)
-
{
-
printf(
"Failed to allocate memory.\n");
-
exit(
1);
-
}
-
-
/* Print to buffer */
-
if (!cJSON_PrintPreallocated(root, buf, (
int)len,
1)) {
-
printf(
"cJSON_PrintPreallocated failed!\n");
-
if (
strcmp(out, buf) !=
0) {
-
printf(
"cJSON_PrintPreallocated not the same as cJSON_Print!\n");
-
printf(
"cJSON_Print result:\n%s\n", out);
-
printf(
"cJSON_PrintPreallocated result:\n%s\n", buf);
-
}
-
free(out);
-
free(buf_fail);
-
free(buf);
-
return
-1;
-
}
-
-
/* success */
-
printf(
"%s\n", buf);
-
-
/* force it to fail */
-
if (cJSON_PrintPreallocated(root, buf_fail, (
int)len_fail,
1)) {
-
printf(
"cJSON_PrintPreallocated failed to show error with insufficient memory!\n");
-
printf(
"cJSON_Print result:\n%s\n", out);
-
printf(
"cJSON_PrintPreallocated result:\n%s\n", buf_fail);
-
free(out);
-
free(buf_fail);
-
free(buf);
-
return
-1;
-
}
-
-
free(out);
-
free(buf_fail);
-
free(buf);
-
return
0;
-
}
-
-
/* Create a bunch of objects as demonstration. */
-
static void create_objects(void)
-
{
-
/* declare a few. */
-
cJSON *root =
NULL;
-
cJSON *fmt =
NULL;
-
cJSON *img =
NULL;
-
cJSON *thm =
NULL;
-
cJSON *fld =
NULL;
-
int i =
0;
-
-
/* Our "days of the week" array: */
-
const
char *strings[
7] =
-
{
-
"Sunday",
-
"Monday",
-
"Tuesday",
-
"Wednesday",
-
"Thursday",
-
"Friday",
-
"Saturday"
-
};
-
/* Our matrix: */
-
int numbers[
3][
3] =
-
{
-
{
0,
-1,
0},
-
{
1,
0,
0},
-
{
0 ,
0,
1}
-
};
-
/* Our "gallery" item: */
-
int ids[
4] = {
116,
943,
234,
38793 };
-
/* Our array of "records": */
-
struct record fields[2] =
-
{
-
{
-
"zip",
-
37.7668,
-
-1.223959e+2,
-
"",
-
"SAN FRANCISCO",
-
"CA",
-
"94107",
-
"US"
-
},
-
{
-
"zip",
-
37.371991,
-
-1.22026e+2,
-
"",
-
"SUNNYVALE",
-
"CA",
-
"94085",
-
"US"
-
}
-
};
-
volatile
double zero =
0.0;
-
-
/* Here we construct some JSON standards, from the JSON site. */
-
-
/* Our "Video" datatype: */
-
root = cJSON_CreateObject();
-
cJSON_AddItemToObject(root,
"name", cJSON_CreateString(
"Jack (\"Bee\") Nimble"));
-
cJSON_AddItemToObject(root,
"format", fmt = cJSON_CreateObject());
-
cJSON_AddStringToObject(fmt,
"type",
"rect");
-
cJSON_AddNumberToObject(fmt,
"width",
1920);
-
cJSON_AddNumberToObject(fmt,
"height",
1080);
-
cJSON_AddFalseToObject (fmt,
"interlace");
-
cJSON_AddNumberToObject(fmt,
"frame rate",
24);
-
-
/* Print to text */
-
if (print_preallocated(root) !=
0) {
-
cJSON_Delete(root);
-
exit(EXIT_FAILURE);
-
}
-
cJSON_Delete(root);
-
-
/* Our "days of the week" array: */
-
root = cJSON_CreateStringArray(strings,
7);
-
-
if (print_preallocated(root) !=
0) {
-
cJSON_Delete(root);
-
exit(EXIT_FAILURE);
-
}
-
cJSON_Delete(root);
-
-
/* Our matrix: */
-
root = cJSON_CreateArray();
-
for (i =
0; i <
3; i++)
-
{
-
cJSON_AddItemToArray(root, cJSON_CreateIntArray(numbers[i],
3));
-
}
-
-
/* cJSON_ReplaceItemInArray(root, 1, cJSON_CreateString("Replacement")); */
-
-
if (print_preallocated(root) !=
0) {
-
cJSON_Delete(root);
-
exit(EXIT_FAILURE);
-
}
-
cJSON_Delete(root);
-
-
/* Our "gallery" item: */
-
root = cJSON_CreateObject();
-
cJSON_AddItemToObject(root,
"Image", img = cJSON_CreateObject());
-
cJSON_AddNumberToObject(img,
"Width",
800);
-
cJSON_AddNumberToObject(img,
"Height",
600);
-
cJSON_AddStringToObject(img,
"Title",
"View from 15th Floor");
-
cJSON_AddItemToObject(img,
"Thumbnail", thm = cJSON_CreateObject());
-
cJSON_AddStringToObject(thm,
"Url",
"http:/*www.example.com/image/481989943");
-
cJSON_AddNumberToObject(thm,
"Height",
125);
-
cJSON_AddStringToObject(thm,
"Width",
"100");
-
cJSON_AddItemToObject(img,
"IDs", cJSON_CreateIntArray(ids,
4));
-
-
if (print_preallocated(root) !=
0) {
-
cJSON_Delete(root);
-
exit(EXIT_FAILURE);
-
}
-
cJSON_Delete(root);
-
-
/* Our array of "records": */
-
root = cJSON_CreateArray();
-
for (i =
0; i <
2; i++)
-
{
-
cJSON_AddItemToArray(root, fld = cJSON_CreateObject());
-
cJSON_AddStringToObject(fld,
"precision", fields[i].precision);
-
cJSON_AddNumberToObject(fld,
"Latitude", fields[i].lat);
-
cJSON_AddNumberToObject(fld,
"Longitude", fields[i].lon);
-
cJSON_AddStringToObject(fld,
"Address", fields[i].address);
-
cJSON_AddStringToObject(fld,
"City", fields[i].city);
-
cJSON_AddStringToObject(fld,
"State", fields[i].state);
-
cJSON_AddStringToObject(fld,
"Zip", fields[i].zip);
-
cJSON_AddStringToObject(fld,
"Country", fields[i].country);
-
}
-
-
/* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root, 1), "City", cJSON_CreateIntArray(ids, 4)); */
-
-
if (print_preallocated(root) !=
0) {
-
cJSON_Delete(root);
-
exit(EXIT_FAILURE);
-
}
-
cJSON_Delete(root);
-
-
root = cJSON_CreateObject();
-
cJSON_AddNumberToObject(root,
"number",
1.0 / zero);
-
-
if (print_preallocated(root) !=
0) {
-
cJSON_Delete(root);
-
exit(EXIT_FAILURE);
-
}
-
cJSON_Delete(root);
-
}
-
-
int CJSON_CDECL cJSON_main(void)
-
{
-
/* print the version */
-
printf(
"Version: %s\n", cJSON_Version());
-
-
/* Now some samplecode for building objects concisely: */
-
create_objects();
-
-
return
0;
-
}
2、main.c文件
-
/* USER CODE BEGIN Header */
-
/**
-
******************************************************************************
-
* @file : main.c
-
* @brief : Main program body
-
******************************************************************************
-
* @attention
-
*
-
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
-
* All rights reserved.</center></h2>
-
*
-
* This software component is licensed by ST under BSD 3-Clause license,
-
* the "License"; You may not use this file except in compliance with the
-
* License. You may obtain a copy of the License at:
-
* opensource.org/licenses/BSD-3-Clause
-
*
-
******************************************************************************
-
*/
-
/* USER CODE END Header */
-
/* Includes ------------------------------------------------------------------*/
-
#include "main.h"
-
#include "usart.h"
-
#include "gpio.h"
-
-
/* Private includes ----------------------------------------------------------*/
-
/* USER CODE BEGIN Includes */
-
#include "stdio.h"
-
#include "cJSON.h"
-
/* USER CODE END Includes */
-
-
/* Private typedef -----------------------------------------------------------*/
-
/* USER CODE BEGIN PTD */
-
-
/* USER CODE END PTD */
-
-
/* Private define ------------------------------------------------------------*/
-
/* USER CODE BEGIN PD */
-
/* USER CODE END PD */
-
-
/* Private macro -------------------------------------------------------------*/
-
/* USER CODE BEGIN PM */
-
extern int CJSON_CDECL cJSON_main(void);
-
/* USER CODE END PM */
-
-
/* Private variables ---------------------------------------------------------*/
-
-
/* USER CODE BEGIN PV */
-
-
/* USER CODE END PV */
-
-
/* Private function prototypes -----------------------------------------------*/
-
void SystemClock_Config(void);
-
/* USER CODE BEGIN PFP */
-
-
/* USER CODE END PFP */
-
-
/* Private user code ---------------------------------------------------------*/
-
/* USER CODE BEGIN 0 */
-
-
//__use_no_semihosting was requested, but _ttywrch was
-
//void _ttywrch(int ch)
-
//{
-
// ch = ch;
-
//}
-
-
#ifdef __GNUC__
-
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
-
set to 'Yes') calls __io_putchar() */
-
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
-
#else
-
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
-
#endif /* __GNUC__ */
-
/**
-
* @brief Retargets the C library printf function to the USART.
-
* @param None
-
* @retval None
-
*/
-
PUTCHAR_PROTOTYPE
-
{
-
/* Place your implementation of fputc here */
-
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
-
HAL_UART_Transmit(&huart1, (
uint8_t *)&ch,
1,
0xFFFF);
-
-
return ch;
-
}
-
-
int fgetc(FILE * f)
-
{
-
uint8_t ch =
0;
-
HAL_UART_Receive(&huart1, (
uint8_t *)&ch,
1,
0xffff);
-
return ch;
-
}
-
-
//PM2.5接口 https://www.nowapi.com/api/weather.pm25
-
//使用天气预报接口测试程序 http://api.k780.com/?app=weather.pm25&weaid=1&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json
-
//json 格式预览网址 https://www.sojson.com/
-
int cJSON_Parse_Test(void)
-
{
-
-
const
char *line =
"{ \"success\": \"1\", \
-
\"result\": { \
-
\"weaid\": \"1\", \
-
\"cityno\": \"beijing\", \
-
\"citynm\": \"北京\", \
-
\"cityid\": \"101010100\", \
-
\"aqi\": \"96\", \
-
\"aqi_scope\": \"50-100\", \
-
\"aqi_levid\": 2, \
-
\"aqi_levnm\": \"良\", \
-
\"aqi_remark\": \"可以正常进行室外活动\" \
-
} \
-
}";
-
-
cJSON *json;
-
//char *out;
-
-
json = cJSON_Parse( line );
//
-
-
if(json ==
NULL)
-
printf(
"json fmt error:%s\r\n.", cJSON_GetErrorPtr());
-
else
-
{
-
cJSON *object = cJSON_GetObjectItem(json,
"result");
-
-
cJSON *item = cJSON_GetObjectItem(object,
"citynm");
-
printf(
"result->citynm: %s\r\n", item->valuestring);
-
-
item = cJSON_GetObjectItem(object,
"cityid");
-
printf(
"result->cityid: %s\r\n", item->valuestring);
-
-
item = cJSON_GetObjectItem(object,
"aqi_levid");
-
printf(
"result->aqi_levid: %d\r\n", item->valueint);
-
-
item = cJSON_GetObjectItem(object,
"aqi_remark");
-
printf(
"result->aqi_remark: %s\r\n", item->valuestring);
-
-
cJSON_Delete(json);
-
}
-
-
return
0;
-
}
-
-
/* 生成字符串 */
-
void cJSON_Creat(void)
-
{
-
cJSON* cjson_test =
NULL;
-
cJSON* cityInfo =
NULL;
-
cJSON* cjson_week =
NULL;
-
char* str =
NULL;
-
-
/* 创建一个JSON数据对象(链表头结点) */
-
cjson_test = cJSON_CreateObject();
-
-
/* 添加一条字符串类型的JSON数据(添加一个链表节点) */
-
cJSON_AddStringToObject(cjson_test,
"time",
"2021-04-16 12:37:21");
//系统更新时间
-
-
/* 添加一条整数类型的JSON数据(添加一个链表节点) */
-
cJSON_AddNumberToObject(cjson_test,
"date",
20210416);
//当前天气的当天日期
-
-
/* 添加一条浮点类型的JSON数据(添加一个链表节点) */
-
cJSON_AddNumberToObject(cjson_test,
"pm25",
15.0);
//pm2.5
-
-
/* 添加一条字符串类型的JSON数据(添加一个链表节点) */
-
cJSON_AddStringToObject(cjson_test,
"quality",
"优");
//空气质量
-
-
/* 添加一个嵌套的JSON数据(添加一个链表节点) */
-
cityInfo = cJSON_CreateObject();
-
cJSON_AddStringToObject(cityInfo,
"country",
"China");
-
cJSON_AddStringToObject(cityInfo,
"city",
"Shenzhen");
-
cJSON_AddNumberToObject(cityInfo,
"cityid",
440303);
-
cJSON_AddStringToObject(cityInfo,
"updateTime",
"12:32");
-
cJSON_AddItemToObject(cjson_test,
"cityInfo", cityInfo);
-
-
/* 添加一个数组类型的JSON数据(添加一个链表节点) */
-
cjson_week = cJSON_CreateArray();
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期日" ));
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期一" ));
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期二" ));
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期三" ));
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期四" ));
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期五" ));
-
cJSON_AddItemToArray(cjson_week, cJSON_CreateString(
"星期六" ));
-
cJSON_AddItemToObject(cjson_test,
"week", cjson_week);
-
-
/* 添加一个值为 False 的布尔类型的JSON数据(添加一个链表节点) */
-
cJSON_AddFalseToObject(cjson_test,
"message");
-
-
/* 打印JSON对象(整条链表)的所有数据 */
-
str = cJSON_Print(cjson_test);
-
printf(
"%s\n", str);
-
-
}
-
-
/* USER CODE END 0 */
-
-
/**
-
* @brief The application entry point.
-
* @retval int
-
*/
-
int main(void)
-
{
-
/* USER CODE BEGIN 1 */
-
-
/* USER CODE END 1 */
-
-
/* MCU Configuration--------------------------------------------------------*/
-
-
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
-
HAL_Init();
-
-
/* USER CODE BEGIN Init */
-
-
/* USER CODE END Init */
-
-
/* Configure the system clock */
-
SystemClock_Config();
-
-
/* USER CODE BEGIN SysInit */
-
-
/* USER CODE END SysInit */
-
-
/* Initialize all configured peripherals */
-
MX_GPIO_Init();
-
MX_USART1_UART_Init();
-
/* USER CODE BEGIN 2 */
-
cJSON_main();
-
printf(
"\r\n");
-
cJSON_Parse_Test();
-
printf(
"\r\n");
-
cJSON_Creat();
-
/* USER CODE END 2 */
-
-
/* Infinite loop */
-
/* USER CODE BEGIN WHILE */
-
while (
1)
-
{
-
HAL_Delay(
1000);
-
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
-
/* USER CODE END WHILE */
-
-
/* USER CODE BEGIN 3 */
-
}
-
/* USER CODE END 3 */
-
}
-
-
/**
-
* @brief System Clock Configuration
-
* @retval None
-
*/
-
void SystemClock_Config(void)
-
{
-
RCC_OscInitTypeDef RCC_OscInitStruct = {
0};
-
RCC_ClkInitTypeDef RCC_ClkInitStruct = {
0};
-
-
/** Initializes the RCC Oscillators according to the specified parameters
-
* in the RCC_OscInitTypeDef structure.
-
*/
-
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
-
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
-
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
-
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
-
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
-
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
-
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
-
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
-
{
-
Error_Handler();
-
}
-
/** Initializes the CPU, AHB and APB buses clocks
-
*/
-
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
-
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
-
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
-
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
-
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
-
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
-
-
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
-
{
-
Error_Handler();
-
}
-
}
-
-
/* USER CODE BEGIN 4 */
-
-
/* USER CODE END 4 */
-
-
/**
-
* @brief This function is executed in case of error occurrence.
-
* @retval None
-
*/
-
void Error_Handler(void)
-
{
-
/* USER CODE BEGIN Error_Handler_Debug */
-
/* User can add his own implementation to report the HAL error return state */
-
__disable_irq();
-
while (
1)
-
{
-
}
-
/* USER CODE END Error_Handler_Debug */
-
}
-
-
#ifdef USE_FULL_ASSERT
-
/**
-
* @brief Reports the name of the source file and the source line number
-
* where the assert_param error has occurred.
-
* @param file: pointer to the source file name
-
* @param line: assert_param error line source number
-
* @retval None
-
*/
-
void assert_failed(uint8_t *file, uint32_t line)
-
{
-
/* USER CODE BEGIN 6 */
-
/* User can add his own implementation to report the file name and line number,
-
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
-
/* USER CODE END 6 */
-
}
-
#endif /* USE_FULL_ASSERT */
-
-
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
在线解析JSON格式数据工具
https://www.bejson.com/
https://www.sojson.com/
四、运行结果
参考文章:
拓展文章:
传送门->代码
五、总结
好了,就介绍到此,有了这个神器,解决JSON格式的数据就变得简单很多了,特别适合物联网终端设备开发引用,上报数据到后台非常方便。
转载:https://blog.csdn.net/qq_36075612/article/details/115754746