文章目录
JSON(JavaScript Object Notation),即 JS对象简谱,是一种轻量级的数据格式。
它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。
JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式。
JSON是一种语法,用来序列化对象、数组、数值、字符串、布尔值和NULL值。JSON数据的本质就是一段字符串而已,只不过有不同意义的分隔符将其分割开来而已。
我们看上面的符号,里面有[],{}等符号,其中:
我们使用串口接收PC端下发的JSON格式的LED控制指令报文,解析并实现LED灯的控制:
JSON格式控制数据报文定义:
{“RedLed”:“on”,“GreenLed”:“on”,“BlueLed”:“on”}
{“RedLed”:“off”,“GreenLed”:“off”,“BlueLed”:“off”}
JSON作为广泛使用的数据通信格式吗,每种编程语言都会有很多解析库,而C语言中经常用到的JSON解析库有cJSON,但因为嵌入式单片机中的Flash、RAM有限,这里我们就使用单片机中常用的免费开源操作系统FreeRTOS里自带的coreJSON库:
json文件链接:coreJSON库
提取码:5253
配置使能串口USART1的中断,使用中断来接收串口上收到的数据。

/* USER CODE BEGIN 0 */
static uint8_t s_uart1_rxch;//获取到的一个字节的数据保存在这里,相当于中转站
char g_uart1_rxbuf[256];//将s_uart1_rxch获取到的每个字节保存在g_uart1_rxbuf中
uint8_t g_uart1_bytes;//一次累加,最大256
/* USER CODE END 0 */
/*MX_USART1_UART_Init()串口初始化函数中添加HAL_UART_Receive_IT()函数*/
/*使能usart1的中断接收,中断接收到的每个字节的数据保存在s_uart1_rxch中*/
void MX_USART1_UART_Init(void)
{
HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);
}
/* USER CODE BEGIN 1 */
/*printf()函数的定义,可以不用管*/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)/*char类型是以int类型存储的,所以可以用int*/
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/*在这里添加串口中断接收的回调函数,还要g_uart1_rxbuf没有满,就将中断接收到的1字节数据s_uart1_rxch存储到g_uart1_rxbuf中,并将g_uart1_bytes 自加。*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart -> Instance == USART1 )
{
if( g_uart1_bytes < sizeof(g_uart1_rxbuf) )
{
g_uart1_rxbuf[g_uart1_bytes++] = s_uart1_rxch;
}
HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);
}
}
/* USER CODE END 1 */
usart.h
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
/*在这里添加uart1接收buffer 相关变量声明,并添加一个宏clear_uart1_rxbuf()用来清除接收buffer里的数据*/
extern char g_uart1_rxbuf[256];
extern uint8_t g_uart1_bytes;
#define clear_uart1_rxbuf() do { memset(g_uart1_rxbuf, 0, sizeof(g_uart1_rxbuf) ); g_uart1_bytes = 0;}while(0)
/* USER CODE END Private defines */
/* USER CODE BEGIN 2 */
gpio_t leds[LedMax] =
{
{"SysLed", SysLed_GPIO_Port, SysLed_Pin},
{"BlueLed", BlueLed_GPIO_Port, BlueLed_Pin},
{"RedLed", RedLed_GPIO_Port, RedLed_Pin},
{"GreenLed", GreenLed_GPIO_Port, GreenLed_Pin},
};
void turn_led(int which, int status)
{
GPIO_PinState level;
if( which<0 || which>=LedMax)
{
return ;
}
level = status == OFF ? GPIO_PIN_SET : GPIO_PIN_RESET;
HAL_GPIO_WritePin(leds[which].group, leds[which].pin, level);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (Key1_Pin == GPIO_Pin)
{
blink_led(BlueLed, 500);
}
else if(Key2_Pin == GPIO_Pin)
{
blink_led(RedLed, 500);
}
}
/* USER CODE END 2 */
gpio.h
/* USER CODE BEGIN Prototypes */
enum
{
SysLed,
BlueLed,
RedLed,
GreenLed,
LedMax,
};
#define OFF 0
#define ON 1
/*将gpio.c中定义的gpio_t结构体定义移到头文件中来,并在它里面添加一个char *name的字段,其它C文件会用到这个结构体。*/
typedef struct gpio_s
{
const char *name;
GPIO_TypeDef *group;
uint16_t pin;
} gpio_t;
extern gpio_t leds[LedMax];
extern void turn_led(int which, int status);
extern void blink_led(int which, uint32_t interval);
void sysled_hearbeat(void);
/* USER CODE END Prototypes */
需要包含core_json.h这个头文件,.h和.c文件网盘有,下载之后在相关路径放进去然后刷新,会看见加载到STM32IDE中了。
/* USER CODE BEGIN Includes */
#include "core_json.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
static int parser_led_json(char *json_string, int bytes);
static void proc_uart1_recv(void);
/* USER CODE END 0 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
proc_uart1_recv();
}
/* USER CODE BEGIN 4 */
int parser_led_json(char *json_string, int bytes)
{
JSONStatus_t result;
char save;
char *value;
size_t valen;
int i;
printf("BDUG: Start parser JSON string:%s\r\n", json_string);
result = JSON_Validate(json_string, bytes);
if(JSONPartial == result)
{
printf("WARN: JSON document is valid so far but incomplete!\r\n");
return 0;
}
if(JSONSuccess != result )
{
printf("ERROR: JSON doument is not valid JSON!\r\n");
return -1;
}
for(i=0; i<LedMax; i++)
{
result = JSON_Search( json_string, bytes, leds[i].name, strlen(leds[i].name), &value, &valen);
if(JSONSuccess == result)
{
save = value[valen];
value[valen] = '\0';
if( !strncasecmp(value, "on", 2))
{
printf("DBUG: turn %s on\r\n", leds[i].name);
turn_led(i, ON);
}
else if(!strncasecmp(value, "off", 3))
{
printf("DBUG: turn %s off\r\n", leds[i].name);
turn_led(i, OFF);
}
value[valen] = save;
}
}
return 1;
}
void proc_uart1_recv(void)
{
if( g_uart1_bytes > 0)
{
HAL_Delay(200);
if(0 != parser_led_json(g_uart1_rxbuf, g_uart1_bytes) )
{
clear_uart1_rxbuf();
}
}
}
/* USER CODE END 4 */
发送{“BlueLed”:“on”,“RedLed”:“on”,“GreenLed”:“on”}会看见三个灯都亮了。

HAL_UART_Transmit()是STM32 HAL库串口发送函数,我的理解就是串口需要发送的数据函数,我们在printf重定向的时候就是将输出重定向到这个函数嘛。
C语言中printf函数默认输出设备是显示器,如果要实现在串口或者LCD上显示,必须重定义标准库函数里调用的与输出设备相关的函数。比如使用printf输出到串口,需要将fputc或者__io_putchar里面的输出指向串口。
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_UART_Receive_IT是STM HAL库的串口中断接收函数,有数据来了就去读取,而且我们这里是一个字节一个字节读取的。并且读取到的数据保存在s_uart1_rxch中,然后调用回调函数将s_uart1_rxch的数据放在了s_uart1_rxchbuf中,最终发送的所有数据都在s_uart1_rxchbuf中。
HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);
函数原型:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart -> Instance == USART1 )
{
if( g_uart1_bytes < sizeof(g_uart1_rxbuf) )
{
g_uart1_rxbuf[g_uart1_bytes++] = s_uart1_rxch;
}
HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);
}
}
JSON_VALIDATE()函数用于判断value的值是否是有效的JSON数据。
result = JSON_Validate(json_string, bytes);
if(JSONPartial == result)
{
printf("WARN: JSON document is valid so far but incomplete!\r\n");
return 0;
}
if(JSONSuccess != result )
{
printf("ERROR: JSON doument is not valid JSON!\r\n");
return -1;
}
通过JSON_Search()函数去解析json数据并且去寻找匹配。匹配是根据leds[LedMax]循环匹配查找的。
gpio_t leds[LedMax] =
{
{"SysLed", SysLed_GPIO_Port, SysLed_Pin},
{"BlueLed", BlueLed_GPIO_Port, BlueLed_Pin},
{"RedLed", RedLed_GPIO_Port, RedLed_Pin},
{"GreenLed", GreenLed_GPIO_Port, GreenLed_Pin},
};
for(i=0; i<LedMax; i++)
{
result = JSON_Search( json_string, bytes, leds[i].name, strlen(leds[i].name), &value, &valen);
...
}
假设发送的json格式的数据:{“RedLed”:“on”,“GreenLed”:“off”,“BlueLed”:“on”}
头文件:#include <string.h>
定义函数:int strncasecmp(const char *s1, const char *s2, size_t n);
函数说明:strncasecmp()用来比较参数s1 和s2 字符串前n个字符,比较时会自动忽略大小写的差异。
返回值:若参数s1 和s2 字符串相同则返回0。s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值。
if( !strncasecmp(value, "on", 2))
{
printf("DBUG: turn %s on\r\n", leds[i].name);
turn_led(i, ON);
}
else if(!strncasecmp(value, "off", 3))
{
printf("DBUG: turn %s off\r\n", leds[i].name);
turn_led(i, OFF);
}
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新rubygems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems
这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build
我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":