概述
json是一个资源占用极小的json解析器,号称世界上最快,并遵循 MIT 开源许可协议。
GitHub:https://github.com/zserge/jsmn
优点:
- 代码移植性高
- 占用代码小
- 极其简单,只需使用两个API
硬件:STM32F103CBT6最小系统板
软件:Keil 5.29 + STM32CubeMX6.01
一、使用方法
Download jsmn.h, include it, done.
#include "jsmn.h"
...
jsmn_parser p;
jsmntok_t t[128]; /* We expect no more than 128 JSON tokens */
jsmn_init(&p);
r = jsmn_parse(&p, s, strlen(s), t, 128);
Since jsmn is a single-header, header-only library, for more complex use cases you might need to define additional macros. #define JSMN_STATIC hides all jsmn API symbols by making them static. Also, if you want to include jsmn.h from multiple C files, to avoid duplication of symbols you may define JSMN_HEADER macro.
/* In every .c file that uses jsmn include only declarations: */
#define JSMN_HEADER
#include "jsmn.h"
/* Additionally, create one jsmn.c file for jsmn implementation: */
#include "jsmn.h"
API
Token types are described by jsmntype_t:
typedef enum {
JSMN_UNDEFINED = 0,
JSMN_OBJECT = 1,
JSMN_ARRAY = 2,
JSMN_STRING = 3,
JSMN_PRIMITIVE = 4
} jsmntype_t;
Note: Unlike JSON data types, primitive tokens are not divided into numbers, booleans and null, because one can easily tell the type using the first character:
't', 'f' - boolean
'n' - null
'-', '0'..'9' - number
Token is an object of jsmntok_t type:
typedef struct {
jsmntype_t type; // Token type
int start; // Token start position
int end; // Token end position
int size; // Number of child (nested) tokens
} jsmntok_t;
Note: string tokens point to the first character after the opening quote and the previous symbol before final quote. This was made to simplify string extraction from JSON data.
All job is done by jsmn_parser object. You can initialize a new parser using:
jsmn_parser parser;
jsmntok_t tokens[10];
jsmn_init(&parser);
// js - pointer to JSON string
// tokens - an array of tokens available
// 10 - number of tokens available
jsmn_parse(&parser, js, strlen(js), tokens, 10);
This will create a parser, and then it tries to parse up to 10 JSON tokens from the js string.
A non-negative return value of jsmn_parse is the number of tokens actually used by the parser. Passing NULL instead of the tokens array would not store parsing results, but instead the function will return the number of tokens needed to parse the given string. This can be useful if you don't know yet how many tokens to allocate.
If something goes wrong, you will get an error. Error will be one of these:
JSMN_ERROR_INVAL - bad token, JSON string is corrupted
JSMN_ERROR_NOMEM - not enough tokens, JSON string is too large
JSMN_ERROR_PART - JSON string is too short, expecting more JSON data
If you get JSMN_ERROR_NOMEM, you can re-allocate more tokens and call jsmn_parse once more. If you read json data from the stream, you can periodically call jsmn_parse and check if return value is JSMN_ERROR_PART. You will get this error until you reach the end of JSON data.
Other info
This software is distributed under MIT license, so feel free to integrate it in your commercial products.
二、STM32CubeMx配置
此时,需要修改一下堆栈大小,都改为大点。
三、Examples
1、进入GitHub拉取源码
2、打开STM32CubeMx生成的keil工程,新建jsmn文件夹,按照如下步骤进行。
3、把jsmn.h和simple.c文件添加到Keil中来。
4、添加头文件路径
5、编译工程
6、main.c文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
*
© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* 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 "string.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 */
#define ENABLEJSMNSIMPLE 1
#if !ENABLEJSMNSIMPLE
#define JSMN_HEADER
#include "jsmn.h"
#endif
/* 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 */
#if !ENABLEJSMNSIMPLE
jsmntok_t t[128];
static const char *JSON_STRING =
"{"name":"champion666","admin":false,"uid":1000,"heihei":"すごい"}";
static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
return 0;
}
return -1;
}
uint8_t parse_data(jsmn_parser *p)
{
int r;
int i;
r = jsmn_parse(p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t) / sizeof(t[0]));
if(r < 0)
{
printf("Failed to parse JSON: %dn", r);
return 1;
}
printf("[type][start][end][size]n");
for(i = 0; i < r; i++)
{
printf("[%4d][%5d][%3d][%4d]n", t
.type, t.start, t.end, t.size);
}
/* Assume the top-level element is an object */
if (r < 1 || t[0].type != JSMN_OBJECT) {
printf("Object expectedn");
return 1;
}
/* Loop over all keys of the root object */
for (i = 1; i < r; i++) {
if (jsoneq(JSON_STRING, &t, "name") == 0) {
/* We may use strndup() to fetch string value */
printf("- Name: %.*sn", t[i + 1].end - t[i + 1].start,
JSON_STRING + t[i + 1].start);
i++;
} else if (jsoneq(JSON_STRING, &t, "admin") == 0) {
/* We may additionally check if the value is either "true" or "false" */
printf("- Admin: %.*sn", t[i + 1].end - t[i + 1].start,
JSON_STRING + t[i + 1].start);
i++;
} else if (jsoneq(JSON_STRING, &t, "uid") == 0) {
/* We may want to do strtol() here to get numeric value */
printf("- UID: %.*sn", t[i + 1].end - t[i + 1].start,
JSON_STRING + t[i + 1].start);
i++;
} else if (jsoneq(JSON_STRING, &t, "heihei") == 0){
printf("- HeiHei: %.*sn", t[i + 1].end - t[i + 1].start,
JSON_STRING + t[i + 1].start);
i++;
}
}
return 0;
}
#endif
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
#if !ENABLEJSMNSIMPLE
int res;
jsmn_parser p;//jsmn解析器
#endif
/* 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 */
#if ENABLEJSMNSIMPLE
extern int main_test(void);
main_test();
#else
jsmn_init(&p);
res = parse_data(&p);
//printf("res : %drn", res);
#endif
/* 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 */
#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;
}
/* 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 */
/* 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,
tex: printf("Wrong parameters value: file %s on line %drn", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
四、运行结果
传送门->代码
参考文章:https://blog.csdn.net/Mculover666/article/details/106208828
五、总结
好了,就介绍到此,有了这个神器,特别是适合开发物联网产品解析json数据。