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

【经验分享】STM8S 中 UART 奇偶校验的使用方法

[复制链接]
STMCU小助手 发布时间:2022-2-11 22:08
问题:) b- N# a* E+ z; X
该问题由某客户提出,发生在 STM8S105C6T6 STM8S105C6T6 器件上。据其工程师讲述:当他所撰写的程序不使用奇偶校验的时候,程序工作是正常的;但是当他把奇偶校验改成偶检验 EVEN 时,程序无法正常工作;现象为:一、不管上位机发送的数据是不带校验位的,还是带奇偶校验位的,STM8S 都可以正常地接收到数据;二、当奇偶校验位使能后,接收到的数据再返回上位机,显示的数据不一定是正确的。3 Z% c- e6 ]' ~* _$ |! D; v: Y
/ O' y$ R1 n3 e5 J. c0 f

3 X" X2 V0 z3 x9 ?  S调研:$ Y1 n0 R! v* k. p. o  o8 r! G
检查客户的 UART 程序,UART 初始化程序如下:
( n- s/ M1 f: D2 F5 q* s) f
  1. static void UART_Config(void)
    5 _6 V' F; L2 J7 k- k/ T1 w
  2. {
    - {( q5 q# i3 z
  3. /* UART2 configured as follow:
    8 S- A# n- ~# m& _! G( P, B3 T
  4. - BaudRate = 9600 baud$ G6 M4 m3 l3 B" S
  5. - Word Length = 8 Bits0 b7 e0 C. i6 g4 _( |% e  [
  6. - One Stop Bit
    ! b% D6 l) u: b' `1 Q. J& T
  7. - No parity
    9 y0 R! L  E: h
  8. - Receive and transmit enabled5 `: F) ^* O8 X0 G
  9. */# o+ V( X& K5 ~  a& z, E' R
  10. UART2_DeInit();
    ' K; `( K) q9 l4 l. l' r
  11. UART2_Init((uint32_t)9600, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_EVEN,( g, T/ d5 D1 `2 o4 M' C
  12. UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);2 V2 S0 v  I! X9 s3 c8 O  ~0 c

  13. 2 v. r3 i2 [9 w; B% e+ P9 f
  14. /* Enable UART2 */6 m& D$ h7 [+ T: a) F( Y
  15. UART2_Cmd(ENABLE);
    ! h% z) P/ V& ~! N* P1 h
  16. }
    " q& Y/ j. g8 c/ H3 U
复制代码
7 G+ E6 }4 ?% m6 c$ C
主程序可简化为:* ?7 X9 v, G8 h4 o

, I0 S. b2 z1 b" @, s  B: ^1 Z; m7 [+ t6 ~
  1. void main(void)
    ! c% h& F$ r1 ^0 ]  i
  2. {
    # g5 p0 c# M2 K7 A1 Y# u
  3. unsigned char val = 0x00;4 j5 A0 s: i( e1 |: S/ a
  4. /* CLK configuration -----------------------------------------*/  z$ R5 P6 N& h2 d- M/ G; S  K
  5. CLK_Config();" Q& W# u7 T5 w2 ?1 u; V/ D
  6. /* UART configuration -----------------------------------------*/
    $ j/ x1 U1 n$ A
  7. UART_Config();: e9 j  @- A( D6 o# h& ]! E% @
  8.   v' W% j; R) N$ F* o. u5 G6 s
  9. while(1)
    6 {6 v  A$ f! Z) J
  10. {
    ( f; J! w$ q% Y( m- j- f
  11. /* Wait the byte is entirely received by UART2 */
    6 b  a+ L2 j/ I8 n, |. M5 H
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)& @; D4 {( a$ }9 ~5 y+ a$ |
  13. {
    5 U9 y4 S0 D0 |4 j5 i* J9 t) C/ ^) \
  14. }
    - D/ @6 @& i5 l  O
  15. /* Get data */
    3 c& R! t* }" l6 d1 D1 {
  16. val = UART2_ReceiveData8();
    9 F# _! k. \4 O5 H, Z

  17. " w# |/ g0 u+ q5 ~; }$ `+ I2 M$ m
  18. /* Wait until end of transmit */
    ! S2 I6 b( k( |8 ]
  19. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)! i0 y! n& Q0 N8 i  r/ l& I1 P
  20. {
    " C' B3 }/ W$ K) m
  21. }
    4 ^1 i6 D* w9 }% k5 }6 V. [  U

  22. 7 s1 N& T4 U  ]  W
  23. /* Send data */
    , [# x9 }% n/ x/ O6 g
  24. /* Write one byte in the UART1 Transmit Data Register */  z% Z* D3 c: N$ L6 a
  25. UART2_SendData8(val);- \# z0 Y: x" z* H) R+ X9 ]
  26. }
    % ^! C+ ~1 f3 q; }8 L, e
  27. }
复制代码

6 ]# ~6 o, r$ t$ L. x观察客户的程序,把 UART2_PARITY_EVEN 改回 UART2_PARITY_NO,确实就是正常的 8 个数据位不带奇偶校验的程序。那么为什么修改成带奇偶校验后,就会有客户所描述的问题呢?  p! l, |1 j" B. c/ _- k
继续使用 UART2_PARITY_EVEN,我们用串口分析工具、示波器或逻辑分析仪来分析一下数据。
$ y" H# T1 h- i6 Z$ W• 当上位机发送 0x01 时(数据中有 1 个“1”),从串口分析工具可以看到上位机收到回来的数据变为 0x81;观察示波器波形,发现 STM8S 发出来的数据位在 Bit7 确实变为 1;- Y7 m- H* v9 ?8 ^4 c
• 当上位机发送 0x03 时(数据中有 2 个“1”),从串口分析工具可以看到上位机收到回来的数据为 0x03;观察示波器波形,发现数据倒是正确的,可是校验位“0”并不存在。
$ S- j' ~8 h$ c/ r" z" f6 s通过这两个实验,我们可以看到,好像是数据的位数不一致,STM8S 发出来的数据是 7 位的数据,也就是只有 Bit0~Bit6,Bit7 变成了奇偶校验位!
5 a% g) X. H& n; y  e$ g( G( }& d6 B2 X" ?6 D1 Z' L. f* f* P
我们来看一下 STM8S 的参考手册是如何描述奇偶校验控制的,我们看一下帧格式的表格:
  y( H' q/ H" ~4 I4 `; h" W" r4 K- K  t9 v
R_XFG3SJC6T~O8[S~$F)C_7.png ) U3 ]. f/ T7 A/ r1 `7 |

' L8 p6 f! y/ Q" ?' C我们发现,在 STM8S 中 M 位所定义是帧长度,而不是数据位的长度!也就是说 M 位所定位的长度为“数据位+奇偶校验位”个数的总和。当数据位为 8 位时,不使用奇偶校验的时候,M 的长度为 8 位;而要使用奇偶校验的时候,M 的长度应该为 9 位!- L5 K4 }  z, k1 y5 ?
% d) i$ ?* k- d- b3 S9 I
到此,我们应该知道如何去修改程序了,我们将主程序和 UART 的初始化程序分别修改为:
, ~5 P6 U8 C/ a# s
  1. void main(void)+ }6 [. [* e/ k7 l* x  u8 v. P
  2. {
    ; L) P* E/ u. j4 R9 l4 O) t
  3. unsigned char val = 0x00;& q2 I  E. o$ U
  4. /* CLK configuration -----------------------------------------*/8 A( H2 @& M; f1 A- T: T* u
  5. CLK_Config();$ m6 I+ q" Z1 R9 ^& L* T
  6. /* UART configuration -----------------------------------------*/
    % u2 C7 L1 M+ D! H: c5 n
  7. UART_Config();
    : Y! j' X* W& D! ]# d

  8. # W* y1 e6 f8 Y; I3 m1 S* v
  9. while(1), Z6 I; H, W; [4 W  x0 b# @
  10. {
    " j0 m$ g, B- ^7 d1 ]9 u& L
  11. /* Wait the byte is entirely received by UART2 */; e8 P  ?' o$ O5 _8 x: b
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
    7 ~% n* K' b4 R2 d% g- W
  13. {, M3 j' p9 S4 o8 L
  14. }7 e5 Q, D* V# v" e; }9 ^2 u
  15. 7 ]& Y3 C- T& q/ {7 L6 `: }
  16. /* Get data */- F* Y$ L  R8 u& @& P
  17. val = UART2_ReceiveData9();, I* Z: _3 l$ a' f; M( U8 E
  18. ) @- Z# M$ u0 w: n
  19. /* Wait until end of transmit */* ]; z8 [0 v9 }$ y
  20. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)+ P& U2 }, _) E8 l8 y$ S1 `
  21. {5 Z# v  l# Y" J4 i2 M# a6 G
  22. }2 R0 k; C  g, P' f) r, t2 g  X: [" w

  23. 9 O5 ?( ?. a; \9 \" ]
  24. /* Send data */' W8 U8 y3 Q' y/ O& c! d( T5 J% b
  25. /* Write one byte in the UART1 Transmit Data Reg
    ; F& V1 f5 j- x% F
  26. CLK_Config();
    , _9 @: ^# {" L- `- l; ]' J! r
  27. /* UART configuration -----------------------------------------*/' e! H5 n) k. k4 D' i
  28. UART_Config();2 {% n* i( }" @' U; c
  29. ' P! `; S5 a/ ]/ {( X
  30. while(1)* z- Y- J- K+ G, v& t7 m% V3 \
  31. {! Z0 B! N0 R6 K8 f! Q
  32. /* Wait the byte is entirely received by UART2 */
    : T) r/ h+ Z, q
  33. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
    7 J6 m; @5 G" ?6 E
  34. {
      C: }- g& R/ R6 ^! Q' D. j# v
  35. }% R# F0 }/ n" t0 R
  36. 7 b! J7 v* \+ Y9 l4 S% w1 J' ~8 C
  37. /* Get data */
    . N+ Y: Z7 K- t, p# P/ W1 j& H
  38. val = UART2_ReceiveData9();3 Q5 L* K; {3 w9 c  l# D
  39. , a+ K) J4 [# R# M5 V
  40. if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)5 }( f% S1 ~: d% O2 S& j
  41. {
      K9 S$ M2 `4 f1 N/ F
  42. /* Wait until end of transmit */
    # K  V- ]  v( H/ N0 E" ?$ I
  43. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)6 ~( _( D, D2 P* Y5 B5 u$ q- X$ {/ @
  44. {, ^) R2 J8 I0 L8 ]! n3 E
  45. }
    1 U/ e% @7 I8 r) W
  46. & G3 d4 [% E& {4 J$ M9 b
  47. /* Send data */1 v( T. B- }" r1 L) f8 f. ]
  48. /* Write one byte in the UART1 Transmit Data Register */
    0 p0 b# }' {7 j  U# }) j) ]6 Y
  49. UART2_SendData9(val);7 X& r1 r& @1 V) z1 |1 v3 X
  50. }4 o& L8 M9 ^2 r2 N+ @* b* Z
  51. }( ?! A  w" X3 O
  52. }
复制代码

9 y) b2 k. }' R. @; B6 B编译,再测试看看。我们将上位机端的串口分析软件的奇偶校验位仍然修改为 ODD,上位机发送“0103 07 0F”,结果发现上位机还是可以收到 STM8S 发来的“01 03 07 0F”!这是为什么呢?难道 PE是不起作用的,奇偶校验仍然是假的?当然,我们还是得来查一下为什么 PE 会检测不到呢。  h5 A0 @% ]7 n6 o3 J0 F" y; W9 b
& m) @1 @. {6 `3 j8 d  @
我们再来看一下 PE 标志位是在什么情况下被清除的,我们在参考手册可以看到:要清除 PE 标志位,软件要按以下操作顺序进行执行:先读取 UART_SR,再读取 UART_DR。于是我们再看一下上面的程序,可以看到,程序中先执行了 UART2_GetFlagStatus(UART2_FLAG_RXNE),这是一个读取UART_SR 的过程,然后再执行 UART2_ReceiveData9(),这是一个读取 UART_DR 的过程,那么,至此,PE 标志即使之前已经置位,那么经过这两个操作后,早已被清除,这个时候再执行
6 O" \; _0 w3 j: G. }if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)显然没什么意义。+ K4 F# J$ U9 L: j0 W
0 N% ^* F  z: A* o- }* W
' f: r2 E% B% l; h0 ]! {) d- H+ R( p
所以,我们还得再继续修改一下程序:
# o+ x8 v2 @& J
  1. void main(void); ~+ @2 E- u4 D% y
  2. {8 T# Q9 E1 o; T3 I( p
  3. unsigned char val = 0x00;, [+ ]" X/ v% ]3 C+ u, u
  4. /* CLK configuration -----------------------------------------*/. N- M$ w' ]+ q6 T  h
  5. CLK_Config();6 j, C8 \1 ^$ q$ n6 g$ D- H
  6. /* UART configuration -----------------------------------------*/
    ! g3 H, E# Y, ]
  7. UART_Config();! u! U$ i2 ?0 V0 P. T  T! \$ i
  8. " t: L- V9 x. f9 ~  q
  9. while(1)
    8 T0 B3 e- ]& S3 O4 {! }0 l
  10. {! u1 m$ J5 T4 {3 S/ \+ p
  11. /* Wait the byte is entirely received by UART2 */. M+ z3 r& ?/ j" C7 g7 R: F7 a$ y
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
      P# q+ C3 s% Z* t3 Q
  13. {  @, c' _0 C$ z  c/ `
  14. }
    0 @" h/ S) ], t, S, D* ~

  15. ) Y7 k; K* u0 b# L, |" n3 K
  16. if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)1 N) `. K0 b. Z9 C! G; p
  17. {- S/ n0 r4 ^4 u+ H' `9 q9 H
  18. /* Get data */
    , J( g3 \& K& R! U8 G' o7 ?
  19. val = UART2_ReceiveData9();
    $ U6 X. J& U' O. j

  20. ' b: j) [6 h# ]! O2 {* G4 G1 n( g
  21. /* Wait until end of transmit */& K1 A$ c# j5 ]- l- U# f
  22. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
    7 o- \0 u( c4 b* I
  23. {
    ) J; e, D6 \; V  Z5 j7 B
  24. }  r2 y: L& I3 I* C5 [

  25. 1 f9 P. F6 }! G
  26. /* Send data */
    # i0 t+ k% Y: x. _3 B
  27. /* Write one byte in the UART1 Transmit Data Register */
    : Y: f! D2 n3 G; `; c7 o5 a, Q
  28. UART2_SendData9(val);* m4 W: m( x$ S, _$ n
  29. }" {$ F% I2 K' G
  30. else
    6 {- \3 q7 C5 b* b( ]8 N  N
  31. {
    + M6 w% M7 Z) Z4 c" P
  32. /* Get data */
    1 T/ K. _8 Y* R' h. |1 B' A! Y
  33. val = UART2_ReceiveData9(); // For clear PE
    ; x+ u' S& [2 f1 d" S; U" e7 y) k
  34. }) Q; j9 l5 U1 a# F  D
  35. }
    * R. `, \8 l4 m6 [4 Q9 K
  36. }
复制代码

) I" [7 q% S5 t9 b再编译,再测试,得到了正确的结果:
( k2 Y, R% N2 f3 x! \, [' j6 _. e# T• 将上位机端的串口分析软件的奇偶校验位设置为 ODD,上位机发送“01 03 07 0F”,STM8S发现奇偶校验位不对,没有回传任何数据给上位机;
: F% i3 n, v9 ]• 将上位机端的串口分析软件的奇偶校验位仍然设置为 EVEN,上位机发送“01 03 07 0F”,上位机正确地收到 STM8S 发回来的“01 03 07 0F”。5 c# F: u" L& W: n* J
0 E3 \- k" J; t% z9 O+ \# l; x! y
结论:
+ H/ ?2 y$ d- _. n- X由于客户对 STM8S 的参考手册没有详细研究,误以为只要在程序中将 UART2_PARITY_NO 改为
3 h; \% y9 g! E+ M, `7 _2 _UART2_PARITY_EVEN,就可以实现 UART 的奇偶校验功能。8 _' `- |( T# h

8 C% C% d4 d- Z/ P+ e7 ~1 ^9 v7 O处理:
' u! V/ c- Z+ J4 u- s4 b# g修改程序,将帧长度相应的都改成 9 位,加入对 PE 标志位的判断,并且经过正确的操作顺序来进行判: b4 I' M. K' `% v0 Y
断处理。
  G. o% S2 J1 y! c+ @# a& |  l
1 i- {, F% p, x' }+ D5 ^0 y建议:9 I# x9 Q; {& v- @0 N3 H! I
- x/ M9 {1 S$ a0 g
当需要使用 UART 的奇偶校验功能时,需要注意以下几个方面:& y) H2 G) X  @
9 m" q6 f  B  r: j
1. M 所代表为帧长度,而不是数据位的长度。当使用奇偶校验的时候,帧长度=数据位长度+奇偶校验位长度;" K8 j. z# D7 [7 Z
2. 不管数据奇偶校验位是否正确,UART 都会将数据接收回来。要对奇偶校验进行判断的话,必须对 PE 标志位进行检测,PE 标志位由硬件置位,当 PE=1 时,奇偶校验出错,做相应处理;
" ^" n# }9 x$ R* P: R3. PE 标志位的清除方式是:先读 UART_SR,再读 UART_DR。所以在程序中一定要注意:在判断RXNE 之后,必须在读取 UART_DR 之前就得先读取 PE,否则 PE 将在读取之前被清除;$ X. V) [/ q9 }" p0 M& I
4. 必须在 RXNE 标志位被置位的情况下才可对 PE 位进行清除。
& Z9 o& r1 z2 A5 P4 A: Q6 ~8 V- H) Z0 m* Q% d
收藏 评论0 发布时间:2022-2-11 22:08

举报

0个回答

所属标签

相似技术帖

官网相关资源

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