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

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

[复制链接]
STMCU小助手 发布时间:2022-2-11 22:08
问题:
3 `0 C. N# b: r8 O该问题由某客户提出,发生在 STM8S105C6T6 STM8S105C6T6 器件上。据其工程师讲述:当他所撰写的程序不使用奇偶校验的时候,程序工作是正常的;但是当他把奇偶校验改成偶检验 EVEN 时,程序无法正常工作;现象为:一、不管上位机发送的数据是不带校验位的,还是带奇偶校验位的,STM8S 都可以正常地接收到数据;二、当奇偶校验位使能后,接收到的数据再返回上位机,显示的数据不一定是正确的。- K! V) v  w1 V
4 S$ J& ~: i; L2 y+ {$ p6 N

. j- G( u" x8 O& W7 b9 C# L调研:
; M. W& ?4 Z+ _  k! t7 s检查客户的 UART 程序,UART 初始化程序如下:. f2 |  x3 k  X/ q/ c% n
  1. static void UART_Config(void). V) L1 {  [5 w3 V8 P# H
  2. {; J- v. ]# K# N0 ~9 b% J# W
  3. /* UART2 configured as follow:
    1 s( y5 C7 V; t, ?' r
  4. - BaudRate = 9600 baud
    9 _* I1 o9 o5 N1 e! J: s9 F4 n' J
  5. - Word Length = 8 Bits( t8 c3 j/ M6 f2 b6 ~! e
  6. - One Stop Bit
    * {& ^5 D' u  T" G% A4 \; a3 d
  7. - No parity9 v/ n5 H4 f6 ^! j7 @
  8. - Receive and transmit enabled, H) b9 ~, P, @  u! x, B3 v( t: y& I
  9. */
    + o+ {: T4 g5 ?# I
  10. UART2_DeInit();
    9 c* `+ E4 q# r0 V4 S" c# f2 q
  11. UART2_Init((uint32_t)9600, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_EVEN,& y( A/ _! A# t4 v3 d9 V' K2 b
  12. UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
    " S+ l" o$ {# g: y% Z/ \1 _

  13. , z7 V4 }0 Y# r3 s
  14. /* Enable UART2 */7 f4 V* u  o; b+ s* @- r- h
  15. UART2_Cmd(ENABLE);
    / @5 f# r+ f  E5 u0 H5 B
  16. } 5 B# m5 f0 Q9 G3 l; k0 a. _9 b" ]. l
复制代码
- v- r9 r/ {& G7 K- @
主程序可简化为:
5 J8 g+ ~3 x$ b4 G; F2 M. b, Z+ H* H+ r3 p7 k( G

' _9 o2 L5 ~1 {( k9 q/ k
  1. void main(void)
    & _1 L! G4 y8 I! I
  2. {- c" K' b+ _+ h
  3. unsigned char val = 0x00;" f  W5 T7 s! V" |1 d% N# H7 D
  4. /* CLK configuration -----------------------------------------*/
    ) Y; Q, |& B/ G
  5. CLK_Config();& n8 {6 q7 O; r! f
  6. /* UART configuration -----------------------------------------*/. }  D+ C9 Q0 S* ?
  7. UART_Config();
    ) w  o6 X! }% R' n' H
  8. ! M: u7 @- }& f9 \  t9 t8 v! u, Q
  9. while(1)- q9 h# u+ |! B4 B0 k  {: D
  10. {
    ; k6 K3 t6 @8 r# D$ K
  11. /* Wait the byte is entirely received by UART2 */4 d4 c! {5 h& ]. v4 t1 j
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)& V, v  v: j% K3 G9 f
  13. {
    & C0 ~) F* {8 j
  14. }
    3 J& V: h/ n5 ~* M# O" G: k6 L
  15. /* Get data *// C- g1 d0 V: j% K
  16. val = UART2_ReceiveData8();
    $ Z3 E/ Q0 E$ o3 {* j1 I8 i
  17. % g7 z. W4 F- K$ i: I$ ~2 Z, |
  18. /* Wait until end of transmit */: P7 _  S0 R+ `  Z
  19. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)/ s- b0 F% I; `- h+ Y- M
  20. {
    - F$ O4 o* H5 W0 `" f
  21. }
    1 B' m3 j" z) A8 g* y9 q/ _( |. C
  22. 7 q% i, [- b8 E2 q: R7 Z: ~
  23. /* Send data */
    0 t/ O  ~7 R: r" b4 ~' q) w
  24. /* Write one byte in the UART1 Transmit Data Register */
    / ^6 W' E$ h8 e  V0 v7 }
  25. UART2_SendData8(val);
      i% `3 \5 u* X* I, q$ x# l) G' H
  26. }( _0 y- j+ a9 q( J7 B9 d7 h$ Y4 F
  27. }
复制代码
0 e8 M$ _) A( h8 ~3 M6 s1 G" d
观察客户的程序,把 UART2_PARITY_EVEN 改回 UART2_PARITY_NO,确实就是正常的 8 个数据位不带奇偶校验的程序。那么为什么修改成带奇偶校验后,就会有客户所描述的问题呢?
$ A1 B8 g) o. [继续使用 UART2_PARITY_EVEN,我们用串口分析工具、示波器或逻辑分析仪来分析一下数据。6 F1 f' F, {" M3 V+ p. |! b9 v! n* {
• 当上位机发送 0x01 时(数据中有 1 个“1”),从串口分析工具可以看到上位机收到回来的数据变为 0x81;观察示波器波形,发现 STM8S 发出来的数据位在 Bit7 确实变为 1;
4 w( E* t2 a  T' d, |/ v# E% u• 当上位机发送 0x03 时(数据中有 2 个“1”),从串口分析工具可以看到上位机收到回来的数据为 0x03;观察示波器波形,发现数据倒是正确的,可是校验位“0”并不存在。- P1 u% Z. @9 ]& ^
通过这两个实验,我们可以看到,好像是数据的位数不一致,STM8S 发出来的数据是 7 位的数据,也就是只有 Bit0~Bit6,Bit7 变成了奇偶校验位!
( B# w6 l# U& q/ d3 B: E% l6 D6 W$ _# C/ n7 G9 B
我们来看一下 STM8S 的参考手册是如何描述奇偶校验控制的,我们看一下帧格式的表格:
" i% h/ a9 X" b) K  |2 A3 J( ~, V. c" E% Q/ H/ l' P
R_XFG3SJC6T~O8[S~$F)C_7.png + p5 m3 C: E4 S' S; J

2 y) N3 x4 C) c; c我们发现,在 STM8S 中 M 位所定义是帧长度,而不是数据位的长度!也就是说 M 位所定位的长度为“数据位+奇偶校验位”个数的总和。当数据位为 8 位时,不使用奇偶校验的时候,M 的长度为 8 位;而要使用奇偶校验的时候,M 的长度应该为 9 位!, U9 H- m" O* Z; r" D6 Q

( Z7 E& n% L* L& O0 n* U0 {到此,我们应该知道如何去修改程序了,我们将主程序和 UART 的初始化程序分别修改为:
8 m6 E/ P. W+ d8 I6 c' e( W
  1. void main(void)1 i4 n- B% q! q, w/ g( @9 N
  2. {% H* D" G  ~3 l; X
  3. unsigned char val = 0x00;
    % B: b1 X8 |0 V- l3 S" A
  4. /* CLK configuration -----------------------------------------*/
      Y" n2 H. V% F2 D! i( X
  5. CLK_Config();
    / I9 N1 y: |* B5 K$ T( R7 B
  6. /* UART configuration -----------------------------------------*/
    : M' K/ v/ c) U$ B& c# N
  7. UART_Config();4 V2 c3 D3 N# C" ]
  8. + V- ?' L6 `; e4 R8 p1 L" k+ V: T) b
  9. while(1)
    5 K2 f/ J5 R/ q5 `2 |1 t/ c( ]
  10. {6 g$ a4 \$ I1 S; X# i* i
  11. /* Wait the byte is entirely received by UART2 */* s& n/ ?  X- \2 h2 M/ z7 h
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
    / K/ E4 B& K( Y, j, D2 X
  13. {
    1 M5 }9 }9 O; r8 X" U
  14. }
    " A2 J3 u$ r7 |* g7 Q

  15. % Q; n. P* x2 S4 _0 x' `
  16. /* Get data */' b( W2 v  c: H
  17. val = UART2_ReceiveData9();
    8 \/ B$ Y% R& R" X) @

  18. ; ?" w; D! \: c8 G. [$ U0 g! c
  19. /* Wait until end of transmit */
    * a9 _5 Y- ^3 H& R
  20. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
    . w1 H% x! O6 l9 W% B
  21. {
    6 O+ Y( v) q5 r3 C: D
  22. }5 m" c7 k; q9 X) [* I" @. o

  23. * o$ D& w) v  i9 Z6 r
  24. /* Send data */
    & A8 Z# R* G6 ]' {
  25. /* Write one byte in the UART1 Transmit Data Reg6 Z7 I6 S, Q6 x1 V# l" _3 `- H' O1 C* I
  26. CLK_Config();* k  S& }0 [5 W& n  s
  27. /* UART configuration -----------------------------------------*/( i% {! U2 `, F2 u: o
  28. UART_Config();- G' c- C9 H+ S  @& T* K) C
  29. 7 P  h4 ^( D8 F( J
  30. while(1)
    1 f3 l, @) ?0 v" p2 l7 W
  31. {1 f4 w7 _/ E; v) `( T
  32. /* Wait the byte is entirely received by UART2 */
      ?+ Z) d: J  x1 R. g* _2 k
  33. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
    + Z9 H& P  Z/ x; [, N8 @+ \
  34. {4 g5 N5 I! j! Y& z2 |
  35. }
    ! B4 \7 @7 o# z* K1 v
  36. / R4 k+ ?7 a% o6 k* ]. t
  37. /* Get data */
    ' a4 u& z# _) g3 E6 @7 l- P1 B: ~
  38. val = UART2_ReceiveData9();3 p. m+ y6 r$ u; \0 M& M
  39. ( ]" L2 h+ @: e- V( Q
  40. if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET), F: S0 i' Q+ ?5 d: P
  41. {
    0 V8 T5 r6 b9 b9 y: i
  42. /* Wait until end of transmit */
    7 g1 l& |2 {7 F  _. D
  43. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
    3 O8 K: N' R" U8 i5 B; u% w
  44. {
    ' P0 g, l$ z, T$ P' g, ~5 {% e
  45. }
    8 b1 z5 k* K  j: Z5 e
  46. 6 G5 ^7 ~$ T% j; z# X  P5 F
  47. /* Send data */3 w9 D) q! g" r8 \! y" ]' M
  48. /* Write one byte in the UART1 Transmit Data Register */5 G" n- f5 Z  ]+ q  x
  49. UART2_SendData9(val);% `2 g2 y% P4 D# d
  50. }. @' U( o: Z% p  C, ?
  51. }' t) {0 i" u, o, A  |: w3 l
  52. }
复制代码

4 m5 F$ \2 T& E; q, H编译,再测试看看。我们将上位机端的串口分析软件的奇偶校验位仍然修改为 ODD,上位机发送“0103 07 0F”,结果发现上位机还是可以收到 STM8S 发来的“01 03 07 0F”!这是为什么呢?难道 PE是不起作用的,奇偶校验仍然是假的?当然,我们还是得来查一下为什么 PE 会检测不到呢。
* ?' {1 S- A# R& P, z( k+ ~& c4 z
1 X( x7 H, F: B" Y4 q我们再来看一下 PE 标志位是在什么情况下被清除的,我们在参考手册可以看到:要清除 PE 标志位,软件要按以下操作顺序进行执行:先读取 UART_SR,再读取 UART_DR。于是我们再看一下上面的程序,可以看到,程序中先执行了 UART2_GetFlagStatus(UART2_FLAG_RXNE),这是一个读取UART_SR 的过程,然后再执行 UART2_ReceiveData9(),这是一个读取 UART_DR 的过程,那么,至此,PE 标志即使之前已经置位,那么经过这两个操作后,早已被清除,这个时候再执行$ T/ N8 V5 E3 H0 j. M
if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)显然没什么意义。; a' n0 F5 k" c6 o& ~% J
. A6 Q8 R; O% l4 O2 k9 }4 [

- r8 u% A. x6 w7 z所以,我们还得再继续修改一下程序:
  P4 g4 _* M! t6 O5 Q/ T+ A
  1. void main(void)
    , Q: B# E0 e$ X' {
  2. {- i: k% o0 ^& |. ~
  3. unsigned char val = 0x00;% O$ z: g* g& A( M% }: M
  4. /* CLK configuration -----------------------------------------*/
    ( u  I1 T$ \6 K) T) a: t
  5. CLK_Config();
    7 n0 p( U& Y- i% b1 u) D. _
  6. /* UART configuration -----------------------------------------*/
    + v; }' t+ J: A/ c0 S  S
  7. UART_Config();- b) d& J3 ^# _3 `

  8. & u; `" }1 J2 e: E- q# b$ Q( I
  9. while(1)
    2 u5 D: k. X6 \: W# L, u
  10. {
    7 \* V9 j, \. e+ t" D. r
  11. /* Wait the byte is entirely received by UART2 */; }, J2 k: v& E. [9 z& Z9 E' x
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)8 u# Q9 n& i  m# e0 e) K
  13. {8 S$ N6 K5 k* i3 {
  14. }
    + V" Q  L2 g0 S

  15. 4 F* I$ ^7 G* l: F
  16. if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)- z6 U$ [- i, t, n8 C! ?; p
  17. {
    8 `' \7 y8 Q8 D1 r0 i
  18. /* Get data */
    / Z5 ~; |7 J1 i& p  ^3 I! H( q4 ^: |: g
  19. val = UART2_ReceiveData9();& F9 {' u. T) w9 ]* T
  20. $ i9 W3 K# Y# g. P) ^& s/ M
  21. /* Wait until end of transmit */9 v/ M5 e- q. a% ]
  22. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)% i9 C. N0 W7 c& n$ _2 J* B( S- V* g
  23. {4 ?) X" A' Z. P
  24. }5 m9 s% w8 O/ v3 ^
  25. : n8 `; d7 x9 ~
  26. /* Send data */7 T  h3 n: m9 e' i- J& n+ M
  27. /* Write one byte in the UART1 Transmit Data Register */
    # g: _8 k1 p* n$ c) l' J
  28. UART2_SendData9(val);! f3 B6 |9 t' w6 p: H1 u$ R
  29. }& ~! q0 B( }0 _% m' [
  30. else
    7 ]1 Y8 e4 }5 S& d- b
  31. {' f' |% f* ~/ z7 u) |# S5 z6 \; Y* x6 _
  32. /* Get data */
    + O5 W5 M9 Y$ U+ r
  33. val = UART2_ReceiveData9(); // For clear PE; g7 U' U0 e1 s. O2 N% ~% q+ r% u* l
  34. }- w; o' g) a4 `! U
  35. }& K) Z) w. W9 p/ A7 ^
  36. }
复制代码

! q& R2 ^8 P$ A) c& y! m9 n( }再编译,再测试,得到了正确的结果:1 `. y  E; Y2 R  f
• 将上位机端的串口分析软件的奇偶校验位设置为 ODD,上位机发送“01 03 07 0F”,STM8S发现奇偶校验位不对,没有回传任何数据给上位机;' X" J. e, a" k
• 将上位机端的串口分析软件的奇偶校验位仍然设置为 EVEN,上位机发送“01 03 07 0F”,上位机正确地收到 STM8S 发回来的“01 03 07 0F”。
& j: r  p- b  S, u* t2 v
7 d$ d5 P; [8 i4 S* x9 c结论:+ J' w% M7 U( k$ f( d+ Q
由于客户对 STM8S 的参考手册没有详细研究,误以为只要在程序中将 UART2_PARITY_NO 改为
: I( e  B; n/ F6 G, ~0 E$ x' RUART2_PARITY_EVEN,就可以实现 UART 的奇偶校验功能。0 [6 I. F$ {" Q1 u3 U

3 [( `( Q/ z* h( H7 b处理:
: f1 {6 I/ l2 X: o修改程序,将帧长度相应的都改成 9 位,加入对 PE 标志位的判断,并且经过正确的操作顺序来进行判
3 J8 h6 d5 b( a! k断处理。
+ L! S  C; M* O( k3 W. t+ I0 I' x  ~" P3 h+ |5 n
建议:. F( @" V  y! d1 k

; Q$ u( M5 K8 ]: q) H( }# X当需要使用 UART 的奇偶校验功能时,需要注意以下几个方面:
- p. }" U+ I/ x% ]5 x; P7 O$ a$ t7 f$ \  Z! T. @1 M1 x
1. M 所代表为帧长度,而不是数据位的长度。当使用奇偶校验的时候,帧长度=数据位长度+奇偶校验位长度;. Y9 p6 R% c2 c# u" v
2. 不管数据奇偶校验位是否正确,UART 都会将数据接收回来。要对奇偶校验进行判断的话,必须对 PE 标志位进行检测,PE 标志位由硬件置位,当 PE=1 时,奇偶校验出错,做相应处理;# K0 |$ a- X5 N! ^8 i
3. PE 标志位的清除方式是:先读 UART_SR,再读 UART_DR。所以在程序中一定要注意:在判断RXNE 之后,必须在读取 UART_DR 之前就得先读取 PE,否则 PE 将在读取之前被清除;2 t- N8 V+ b; K* u. H
4. 必须在 RXNE 标志位被置位的情况下才可对 PE 位进行清除。0 {/ c! F- D& _; z; w

$ a$ ]. E+ D3 C& ], [+ ?( g
赞 收藏 评论0 发布时间:2022-2-11 22:08

举报

0个回答

所属标签

相似技术帖

官网相关资源

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