你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 FOTA 例程之 cJSON 使用

[复制链接]
STMCU小助手 发布时间:2022-3-4 18:36
前言+ \0 P2 m5 ?0 y" v/ d4 J& s
在 STM32 OTA 例程中,设备端(stm32F769 探索版)与云端交换数据使用的是 json 格式。在本篇文章中,将对 json 格式以及 Cjson 的使用及注意事项进行说明。
9 ?# J/ j* X" x
% F/ x* L9 W. p3 ~9 Q4 IJSON 格式
) v, y6 C+ s# f+ B* o; rJSON(JavaScript Object Notation)是一个轻量级的数据交换格式。既便于开发者读写,也便于机器分析和构建。它独立于开发语言,是一种文本格式,很适用描述在各个系统间交换的数据。
# j! U; D9 Q7 v. b7 o" T( ?JSON 格式的数据看起来就像下面这个样子:
: T2 X% C+ h2 d2 Y: u; y{
9 f, j0 ?" {0 G  P! O% j. M: p“Room1”: {
6 g% z, S6 D% |( T6 S4 ~: D- |( [“LED”: “on”,) @, Z/ G. b+ Z; S
“Temperature”: “36”9 O9 U6 d7 b) G5 [2 ?8 g
}
5 l3 U9 }0 u* I2 q9 D9 G}3 d) `& P7 p0 o9 ]. O6 {" J
这个 JSON 数据描述的是 Room1 的 LED 灯状态以及温度值。它由一组“名称(key)”以及对应的“ 值(value)”组成。“名称”和“ 值”间由“ :”分开。各组“名称:值”对之间由“,”符号进行分割。
; I$ ^- q+ T! N8 n* h5 O; A- [5 N8 c6 V$ B
cJSON 的使用
. }2 p) H1 Q& V" T& B: x) V8 M针对不同的开发语言,网上有很多 JSON 的实现, demo 里使用的是 Cjson,版本 1.6。
% o3 y0 A; E8 M; O
: a" j$ D' j0 a: }; C将 Cjson 添加到工程5 {: _4 @. I0 a
Cjson 只有一个 C 文件 Cjson.C 和一个头文件 Cjson.h。所以只需要将这两个文件拷贝到工程文件夹中,并将 Cjson.C 添加到工程中就可以了。& b5 H% V9 j9 {4 H: x2 [0 k8 \
# S* B# u1 j" c! P. I0 c, ^  y
数据结构3 z; w# W) P. E
Cjson 中使用下面的数据结构来表示 JSON 数据。
  G$ i* n; B5 n4 w. p% S4 S" N- e' D4 x5 p2 k
}E$LN1AD)@5TAKGS[YQFWAP.png
/ A! i! w2 N: e* ^) h! R6 V
1 K# u) W' M" t9 H0 B*next 和*prev 指针可以用来遍历“矩阵”或者“对象”类型的 JSON 数据链表;这两种类型的 JSON 数据还会有一个子数据指针*child
( N! p+ O+ q8 {1 c; |type : 表示该 json 数据的类型,比如数字,字符串、矩阵、对象等*valuestring, valueint, valuedouble 和*string 指针分别指向该 json 数据类型具体的值,视其类型而定。
- G  e1 P3 R2 j: I
. `: _& e, v5 h. v5 F' N使用 cjson 生成 json 数据7 U3 F, n' b- o, G  }
下面我们看看如何使用 cjson 来生成下面的数据:0 r2 m3 x: ]7 k. i" q. a
{9 t. A3 b5 r4 @$ s* ?1 y
“reported”: {3 F' Y2 n8 [9 {' Z# i5 ]. a% Q
“LED”: “on”," c! K% [& I/ L: E
“status” : “normal”$ q5 f" D4 |/ R8 l
}$ s% H; G, p, L: E# J+ D) }1 V8 U( Z( ]5 B
}
& u  |& _1 S9 n3 x见下面的代码:
7 s, i4 Z) @$ x: _2 A
  1. cJSON * reported_obj;  h7 k2 D" G9 M' O, t# D7 U
  2. cJSON * device_obj;" ]/ S0 @! ^! g; }; u7 m

  3. / m7 `  j3 U, {
  4. reported_obj = cJSON_CreateObject();                                             <font color="#00ff00"> //创建空的对象:reproted_obj和 device_obj</font>9 h$ y7 N, S8 k# _+ d! x

  5. ! H# `1 w; F- s
  6. device_obj = cJSON_CreateObject();6 X1 c/ e9 Q* j; j7 {) I1 K# F
  7. 9 N- z. N) L) T4 D$ `/ p. N
  8. //add LED status) K$ F" s/ Z! w% }( _
  9. if(flag_led)
    # s+ g8 T1 h1 |" ~6 }. t
  10. cJSON_AddStringToObject(reported_obj, "LED", "on");
      q: M9 ~. p5 Z; ?' G8 ~5 {
  11. else                                                                                           <font color="#00ff00">   //在 reproted_obj 中添加对象“LED”作为它的子集</font>
    , ^+ o7 C2 [( \( u
  12. cJSON_AddStringToObject(reported_obj, "LED", "off");
    , M/ i, @+ p: t/ c$ a

  13.   G2 c, I9 m0 u; }' T2 o6 |7 E
  14. //add device status
      m! T) C7 t! K& `
  15. cJSON_AddStringToObject(reported_obj,"status", "normal");              <font color="#00ff00">//在 reproted_obj 中添加对象“status”作为它的子集</font>8 I2 C1 f' ]! h; |
  16. cJSON_AddItemToObject(device_obj, "reported", reported_obj);      <font color="#00ff00" style=""> //reproted_obj 添加到device_obj,作为它的子集</font>
复制代码

8 c: v8 d) U; |2 K$ z# b% O, w现在就已经在 cjson 中,构件好了和前面的数据对应的数据结构。但现在这个数据结构还不能发送出去,需要调用% ]& T) Z9 S3 o& K% B
cJSON_Print 将其打印成串行的数据,存放在 buffer 中,以便后面进行发送。. w% @; m. \$ m& Z: X
  1. cjson_print_buf = cJSON_Print(device_obj);
复制代码
$ g; [: S3 ^& _* K! J4 l
cJSON_Print 执行的时候会向系统申请一段内存来保存串行化了的数据,并返回其指针。这里一定要注意的是,cJSON_Print中申请的内存,一定要记得释放(cjson 的代码中不会自动去做释放动作),否则就会出现内存泄漏。8 q% u  }' \  m! ]# V4 L: j5 R4 v
通过 cJSON_CreateObject 创建的对象,也需要调用 cJSON_Delete 来进行删除并释放占用的内存。否则也会出现内存泄漏。见下面的代码:
! |" q0 h- Y0 Q7 `$ k; U1 W# V
  1. if(cjson_print_buf!=NULL)2 v! k2 P/ b, W# a
  2. {
    7 z5 J3 v5 B" h  `" V# \# V
  3. snprintfreturn = snprintf(buf,bufsize,cjson_print_buf);
    6 G" U8 x$ @7 l- n; X
  4. cJSON_free(cjson_print_buf);$ O# v1 @6 k; r* T) Q& n
  5. }
    ' u: m& H4 Q1 W6 p) A$ _# ^
  6. cJSON_Delete(device_obj);
复制代码

! {* x! `9 Z# a2 h7 G仔细的同学可能会发现为什么调用了两次 cJSON_CreateObject,但只看到释放了其中的 device_obj。这里也是需要注意的一个地方,从前面的代码中,我们可以看到,reported_obj 最终是作为子对象添加到了 device_obj 中,所以在删除 device_obj时,cJSON_Delete 会自动删除 device_obj 中所有的子对像,故而不需要再调用 cJSON_Delete 对 reported_obj 进行删除。1 s. }  B! x" d2 o9 ?
. @8 R# }* ^- ~& n; F0 n1 y4 e
9 o7 n5 f+ q" V/ J+ c2 t3 {
使用 cjson 解析 json 数据; u; T$ Z/ j9 ~3 |* `! `3 X
可以通过 cJSON_Parse()函数来解析接收到的 json 数据,cJSON_Parse()函数会对数据进行解析,并申请一段内存保存解析后的 cjson 的数据结构,并返回指针。
! v! C. A& u- q  z9 P通过 cJSON_GetObjectItem()函数可以获取解析后的 cjson 数据结构中的第一级子对象。2 a7 c& I& j7 R
使用 cJSON_Parse()后,切记也一定要通过 cJSON_Delete 释放之前所申请的内存。
) h6 q* ^1 K) Z+ L4 H( V下面代码是对收到的 json 数据的解析过程。收到的数据内容为:
( `" S$ b0 Z' w3 e{
! L6 P* N0 r; b6 _/ r- x“desired”: {* O; a: u" o$ `* E( d
“LED”: “on”,; k2 [' [( ]+ m: Z6 l; ~; G
“SW_Version” : “02010100”6 @2 B8 ^( K. i9 \
}% R- x1 U: ?% m* M0 K0 `4 _) |
}1 j2 ^* a# o- L- d2 h- P5 H
6 A  ]0 ~$ S2 Y" I
  1. receive_obj = cJSON_Parse((char*)message->payload);                 <font color="#00ff00">//解析收到的消息 message-> payload</font>+ o; t; p2 m) L
  2. desired_obj = cJSON_GetObjectItem(receive_obj, "desired");         <font color="#00ff00">//提取 desired 对象</font>
    $ ?3 o) Z2 ~( O) g) E2 a+ P8 B
  3. item_obj = desired_obj->child;            
    2 t. ]6 I4 u' u
  4. while(item_obj)                                                
    % p9 |! [- H; e( @0 b0 ^" J% ~
  5. {0 q9 R/ A5 f- ]' w9 L
  6. string = item_obj->string;" R3 W' X* g0 X
  7. if(!strcmp(string, "LED")){$ b% _1 y* b3 K  h) ~" {; f* X3 S1 y
  8. if(!strcmp(item_obj->valuestring,"on"))        <font color="#00ff00">    //依次解析 desired 对象下的子对象值</font>: ^, I, \% g3 X/ ]0 Z8 ]! d
  9. {! f3 t) G$ }/ d  D
  10. Led_On();* S1 N5 |: S" v7 T
  11. flag_led = 1;
    6 G4 L! z) V2 o2 t% J/ i
  12. msg_info("LED On!\n");( n+ j1 J5 y* L" \
  13. }- i6 v9 `3 S" V" d# `
  14. else
    2 ?4 K/ I$ B( [+ U) m3 g0 T, N" r
  15. {
    ; p, W/ |0 _4 L: q2 S
  16. Led_Off();9 K  a: V( P/ J1 X' o0 }+ m3 u5 D& X
  17. flag_led =0;
    ! l7 y" l' H( z  P* q! d' o1 Y
  18. msg_info("LED Off!\n");
    & m1 L$ u( E! ?3 j& r& o/ C3 F
  19. }
    0 [, ]$ ^: a. ]. Z6 [
  20. }
    ! J& I( ?  F" v1 e3 f  a9 {
  21. 6 R/ k: L( _- _+ d) r3 |! ?. t
  22. item_obj = item_obj->next;
    3 _8 t( y5 e! X% o9 J+ \
  23. }
    , |+ i, \/ ]$ i0 ?

  24. 3 Z; e8 |, F$ ?, k; R
  25. cJSON_Delete(receive_obj);             <font color="#00ff00"> //释放 receieve_obj 及其子对象</font>
复制代码

1 l) H% x! A$ o3 a9 p总结
3 N0 w' |6 C+ J4 X; ccJSON 代码量不大,用起来也方便。使用的时候一定要注意前面提到对使用完的内存空间进行释放。否则会造成内存泄漏。9 U+ `! J9 `- d3 _. ]  Q

2 v) G3 T$ k. m5 @0 ^' G& Z
! ?7 ]8 t; p- C" w
赞 收藏 评论0 发布时间:2022-3-4 18:36

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版