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

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

[复制链接]
STMCU小助手 发布时间:2022-2-11 22:08
问题:; O$ h/ j! e8 q, F. s
该问题由某客户提出,发生在 STM8S105C6T6 STM8S105C6T6 器件上。据其工程师讲述:当他所撰写的程序不使用奇偶校验的时候,程序工作是正常的;但是当他把奇偶校验改成偶检验 EVEN 时,程序无法正常工作;现象为:一、不管上位机发送的数据是不带校验位的,还是带奇偶校验位的,STM8S 都可以正常地接收到数据;二、当奇偶校验位使能后,接收到的数据再返回上位机,显示的数据不一定是正确的。% h8 S( h) f  e' @# }7 x' d

! Q# I' [) A) I: }' h- v& M% T3 H4 \; f2 n) s# w8 T6 Q
调研:6 H+ v2 }" D3 [! J: j
检查客户的 UART 程序,UART 初始化程序如下:
  b4 U5 C: f' p+ M5 A, k
  1. static void UART_Config(void)3 |5 T& K6 l; o* x
  2. {
    ' h. Z: `; `1 \" n$ T+ t1 [9 i  x
  3. /* UART2 configured as follow:  v6 O7 c% \% L$ j" L3 p0 ]" r
  4. - BaudRate = 9600 baud
    / B* Z# [( H' @- O, ]" H. y
  5. - Word Length = 8 Bits
    ; i7 c4 a" m! X# i! n) T2 ~/ J
  6. - One Stop Bit
    ! I1 w8 H2 t6 T2 o( g
  7. - No parity
    8 L- |4 Z( p  x4 N
  8. - Receive and transmit enabled' o$ b' \& O/ ~8 _6 v* B
  9. */
    0 P' x, ~* y: y4 Z" [8 s  k
  10. UART2_DeInit();
    , S9 z* v3 {6 Y
  11. UART2_Init((uint32_t)9600, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_EVEN,7 h" T. c0 @- f1 r
  12. UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
    . Z; |' h6 y5 M$ @# X2 |

  13. % ?, m) t( ?* _( j, j: [5 q
  14. /* Enable UART2 */, ^8 p* {& J. n& ~4 h
  15. UART2_Cmd(ENABLE);
    , ~7 \, `* j0 F) ^( I! Y; N7 V
  16. }
    1 q0 U2 S$ N0 V' p3 r9 s
复制代码
- S& ?3 }1 G7 g: ^$ d3 T
主程序可简化为:4 p; o" y3 w  x& R7 m( _

% o6 j9 x' |8 Y. ?  I- m- o6 Y; Z2 T" u8 W3 o# h# z
  1. void main(void)7 C8 c' h+ v7 t* z$ Y0 j
  2. {, K# g2 |- j! i
  3. unsigned char val = 0x00;6 D2 a" G5 r7 ~$ E. g
  4. /* CLK configuration -----------------------------------------*/
    . a9 P* d3 h/ N3 c
  5. CLK_Config();
    ) b- U3 b% f! H& f
  6. /* UART configuration -----------------------------------------*/
    6 v! _" y# L' R! \3 k
  7. UART_Config();1 s6 n) J3 q; k
  8.   I* @' O5 C# Q6 F
  9. while(1)7 {7 a# o% u1 |3 @
  10. {4 Y, v) b' p4 M) U& }
  11. /* Wait the byte is entirely received by UART2 */
    7 m1 _+ @5 q8 }. l- |2 S) B* d% D
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
    2 V  V' D7 L1 d) r/ r
  13. {
    ) Q& o( X8 {) t* y. }
  14. }9 [, A3 w: R% }9 ]7 m, t
  15. /* Get data */
    " [9 `, }, j& @6 f4 h5 P
  16. val = UART2_ReceiveData8();
    0 X1 S5 Q9 ~: n/ N5 I

  17. 3 j  {6 }: |6 Z3 T" {3 a& H$ J
  18. /* Wait until end of transmit */
    & N' B- D* P* N1 V: h
  19. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
    $ ]* f; b  H4 [/ c, l) C( a) L
  20. {
    , U( Y# `! l" g+ ?3 o# U
  21. }
    8 P# W: D1 R- O: s+ T

  22. * \" D8 b! s5 v5 L9 Y& M7 m2 T& E
  23. /* Send data */2 o: \4 ?4 m! ]3 C
  24. /* Write one byte in the UART1 Transmit Data Register */6 r$ R  a: R( X: h' b/ t4 S& U
  25. UART2_SendData8(val);1 k% ]# h" z  s8 V# [
  26. }5 |/ Y" z6 k+ u# ^1 [- |3 ]
  27. }
复制代码

3 e( x- p. }4 U0 q5 U2 A# @观察客户的程序,把 UART2_PARITY_EVEN 改回 UART2_PARITY_NO,确实就是正常的 8 个数据位不带奇偶校验的程序。那么为什么修改成带奇偶校验后,就会有客户所描述的问题呢?) I- b, f! f6 d1 b
继续使用 UART2_PARITY_EVEN,我们用串口分析工具、示波器或逻辑分析仪来分析一下数据。; I. O( {/ q7 k) I! Z# y. z7 b
• 当上位机发送 0x01 时(数据中有 1 个“1”),从串口分析工具可以看到上位机收到回来的数据变为 0x81;观察示波器波形,发现 STM8S 发出来的数据位在 Bit7 确实变为 1;
" C" z/ U: V2 M• 当上位机发送 0x03 时(数据中有 2 个“1”),从串口分析工具可以看到上位机收到回来的数据为 0x03;观察示波器波形,发现数据倒是正确的,可是校验位“0”并不存在。) |5 v5 C' p3 c& I8 s2 g
通过这两个实验,我们可以看到,好像是数据的位数不一致,STM8S 发出来的数据是 7 位的数据,也就是只有 Bit0~Bit6,Bit7 变成了奇偶校验位!
# l' e# c" X% i6 c, \2 B% t, p/ N; h
我们来看一下 STM8S 的参考手册是如何描述奇偶校验控制的,我们看一下帧格式的表格:
3 Y2 [$ @& y! B
; }" ]# m0 r/ k$ U: i) Z/ m R_XFG3SJC6T~O8[S~$F)C_7.png ) B$ W* u. u9 {& q/ R6 J. j" M
9 C9 v1 }8 C5 s9 w/ A4 j# c, v% J% o& s
我们发现,在 STM8S 中 M 位所定义是帧长度,而不是数据位的长度!也就是说 M 位所定位的长度为“数据位+奇偶校验位”个数的总和。当数据位为 8 位时,不使用奇偶校验的时候,M 的长度为 8 位;而要使用奇偶校验的时候,M 的长度应该为 9 位!* T( ]. p. B" w6 I) f0 A

; G. l$ M" s5 D; v3 J- e; U7 f; T9 f到此,我们应该知道如何去修改程序了,我们将主程序和 UART 的初始化程序分别修改为:
, X# T. T1 g! O: C& ~! _( J
  1. void main(void)6 f6 w6 ]- [% j% _2 w/ N$ o, r
  2. {
    $ ~- W5 k9 V( X
  3. unsigned char val = 0x00;' `( r0 p9 {3 W0 J9 G
  4. /* CLK configuration -----------------------------------------*/
    - w$ n  ]- ^; d6 v) y4 E
  5. CLK_Config();
    ! I$ g$ Q1 Q. H) \3 t" [
  6. /* UART configuration -----------------------------------------*/
    2 J5 A  j$ _7 u9 r* ^, Y1 K
  7. UART_Config();
    ) w! X5 w9 @* J: p- c, Q3 S

  8. - U) U# h+ v' q7 A/ a7 k5 P0 Y# L
  9. while(1)
    * e5 ?3 U! Q  `2 d  _1 q' Y
  10. {/ S! [- |. _* z/ ]1 X
  11. /* Wait the byte is entirely received by UART2 */
    & s- J5 x, R$ t
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)* |: _9 h, e4 ^1 [5 R% T
  13. {  R; ^0 Q, y& @# `1 ^4 c
  14. }+ O2 e" J' i* o/ S- S1 ~5 L
  15. * c& g( M( U8 A& G5 k" c
  16. /* Get data */: ?! S# ~7 `+ O- @3 q2 s
  17. val = UART2_ReceiveData9();
    6 f' m- w2 A* d; g! i5 a; z

  18. 9 y; y3 i! j2 G7 o% t: ]1 X
  19. /* Wait until end of transmit */
    ' x, X/ r% n1 X( P
  20. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
    ! m3 i* ]' ~! e& l, u: v
  21. {& r" Z' ^2 C  U4 F. g3 _
  22. }1 D/ N/ W5 s/ c4 a6 I# `

  23. : k9 ~0 M9 ]  g; P5 \+ H0 G
  24. /* Send data */9 W5 o- i1 `2 F+ O+ e% s: \
  25. /* Write one byte in the UART1 Transmit Data Reg+ O' v3 x* ^" ~+ d/ {" {- Z5 i& f. w
  26. CLK_Config();4 E$ n! \- X4 ]; |
  27. /* UART configuration -----------------------------------------*/
    + _( }( q1 E0 ~, @9 o8 o' l$ M
  28. UART_Config();
    ; @' h. e' @, O/ g7 N  r# @

  29. # M2 V+ o5 ]# P- w& X; z
  30. while(1)
    1 C# J  E/ v# L0 n$ }
  31. {
    ) O: O- [4 c% |2 q* l) a* A# ]
  32. /* Wait the byte is entirely received by UART2 */1 b/ y, G% y: C" V2 u0 H
  33. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)
    & I# s/ J( J) Y- M; R4 `$ ^
  34. {
    9 [1 N* C9 J9 v2 [8 q1 w; o
  35. }8 c0 S+ _1 P- W8 G

  36. + c8 E7 _# C$ \( n9 \8 C0 n2 q9 B# W
  37. /* Get data */, M' I- w9 E* F
  38. val = UART2_ReceiveData9();4 _: m/ I& Z1 @- \( @: I

  39. - T6 g6 C9 t% o
  40. if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)
    : e5 y8 s$ t% Y. u5 v
  41. {
    " F5 K2 V3 ?) z9 n  H- d
  42. /* Wait until end of transmit */
    $ j. T6 A* P) X: t" T2 G
  43. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)+ N  f. F0 a) b3 D' B& S# L. Z3 S
  44. {
    , A4 r8 T4 c. k% V, v- Y3 m8 N$ B1 U
  45. }
    . ^+ t1 u6 A+ a$ F! i$ D0 P6 }7 S
  46. 6 {1 O( g+ d/ u( J& @
  47. /* Send data */1 {, W: T/ t% h2 _
  48. /* Write one byte in the UART1 Transmit Data Register */" U8 N3 A) v9 t$ M
  49. UART2_SendData9(val);$ v" F  P5 `# b1 q: Q+ o) N" E. t0 d) E
  50. }
    9 J" Z7 H& A, y& @3 C. \9 S
  51. }
    ! W& M; l+ A* J- l" H7 @
  52. }
复制代码
- }. k0 x# A: L7 @+ F
编译,再测试看看。我们将上位机端的串口分析软件的奇偶校验位仍然修改为 ODD,上位机发送“0103 07 0F”,结果发现上位机还是可以收到 STM8S 发来的“01 03 07 0F”!这是为什么呢?难道 PE是不起作用的,奇偶校验仍然是假的?当然,我们还是得来查一下为什么 PE 会检测不到呢。
0 S( M# O4 U! k% s, p6 a
+ j5 p, P' K/ I我们再来看一下 PE 标志位是在什么情况下被清除的,我们在参考手册可以看到:要清除 PE 标志位,软件要按以下操作顺序进行执行:先读取 UART_SR,再读取 UART_DR。于是我们再看一下上面的程序,可以看到,程序中先执行了 UART2_GetFlagStatus(UART2_FLAG_RXNE),这是一个读取UART_SR 的过程,然后再执行 UART2_ReceiveData9(),这是一个读取 UART_DR 的过程,那么,至此,PE 标志即使之前已经置位,那么经过这两个操作后,早已被清除,这个时候再执行  {, T, Z" F6 H6 I3 A  }
if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)显然没什么意义。- m0 |6 ~- ?! d
# y7 ~. Q1 ]3 K! G

/ {- I- p' B8 g% T所以,我们还得再继续修改一下程序:% L( ?; F/ U  _" u1 [+ ?
  1. void main(void)
      c  u8 s+ A4 [! w, F% M6 x6 d
  2. {8 z0 N1 m2 k- t4 R( f
  3. unsigned char val = 0x00;
    " g+ O$ Z# t6 ?' [
  4. /* CLK configuration -----------------------------------------*/' \; t8 r; o+ w, K/ h# p
  5. CLK_Config();# z7 a8 c  D7 P" t& ~& m
  6. /* UART configuration -----------------------------------------*/. `) `0 s( w4 @) g8 k
  7. UART_Config();
    7 ^! {  d% f6 |
  8. ( C+ x, P# v/ l' I6 U# ?+ [1 ]' V
  9. while(1)
    ( O) q  X  m& {5 Y: A8 L0 x
  10. {% X" r' g, p6 p9 Z9 d( I4 R, v+ W
  11. /* Wait the byte is entirely received by UART2 */5 F8 L, f8 M" ~! v6 v
  12. while (UART2_GetFlagStatus(UART2_FLAG_RXNE) == RESET)' L- i3 g' m& L( R' i
  13. {
    : |* q# r' G+ _" Q/ c
  14. }
    5 {' t/ c1 \5 K( c% e

  15. 4 K) D9 i& v- A+ t5 S& N$ F! N& z
  16. if(UART2_GetFlagStatus(UART2_FLAG_PE) == RESET)
    * n/ N4 w5 q2 l* p
  17. {  F+ j. i$ l' z. s* f
  18. /* Get data */% \, ~5 c/ \1 R: k3 x7 p8 P* {
  19. val = UART2_ReceiveData9();
    # j. e( _2 G: h/ D
  20. 6 d0 S- J) d  C( {6 ^
  21. /* Wait until end of transmit */
    * S6 J! ]+ Y5 G/ O( h' e
  22. while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)8 G+ Y: g* y# ]! p$ N
  23. {
    : a! ~! V2 B  s! Q
  24. }( B! H7 l; q# V( ]5 F
  25. + T7 ~1 V* f3 w9 f, {5 m2 r; A
  26. /* Send data */
    0 _8 l; g8 d% a" b7 r
  27. /* Write one byte in the UART1 Transmit Data Register */
    , `1 L+ z% ~3 A. s( Z
  28. UART2_SendData9(val);2 {" H4 c, h; _$ F
  29. }( Z" f1 d& y- R+ K
  30. else
    + d# H) o! _3 P- G. C
  31. {
    8 H( b" [) ~" S6 N/ U
  32. /* Get data */
    % B; o/ I6 L3 S. z+ M/ ]0 I# o7 i
  33. val = UART2_ReceiveData9(); // For clear PE4 s9 }5 ]8 ~% p* D
  34. }& g( s0 ^' g2 ~2 ~9 J, a0 w
  35. }
    " n6 k) ]4 u' j8 m) B0 U. R2 v
  36. }
复制代码

( y, U( n5 W$ k  C3 b( \" I1 j$ F再编译,再测试,得到了正确的结果:' m( E9 l( e' E
• 将上位机端的串口分析软件的奇偶校验位设置为 ODD,上位机发送“01 03 07 0F”,STM8S发现奇偶校验位不对,没有回传任何数据给上位机;: u! X' i  F- {7 Q" D; O
• 将上位机端的串口分析软件的奇偶校验位仍然设置为 EVEN,上位机发送“01 03 07 0F”,上位机正确地收到 STM8S 发回来的“01 03 07 0F”。. J, r) r+ {* Q# L1 B4 A0 |
) D) J4 w& d' v( \, h" ]1 y
结论:
! Z4 O; t" K' @5 k& h由于客户对 STM8S 的参考手册没有详细研究,误以为只要在程序中将 UART2_PARITY_NO 改为( b% P+ F* f( b
UART2_PARITY_EVEN,就可以实现 UART 的奇偶校验功能。
: ~4 z+ U1 E! d" t* y' ]# B" S% I: Y% c
处理:
1 |" u; n7 G' e3 ^$ W$ \修改程序,将帧长度相应的都改成 9 位,加入对 PE 标志位的判断,并且经过正确的操作顺序来进行判# z& D- w* ~, X$ _. W" }# y
断处理。
$ k! Q0 L" T% t: T+ K- g' s, Z8 k
建议:# v0 s6 f8 ]8 p! T: G  U! H

& z! e5 m% B' X8 J3 w# u当需要使用 UART 的奇偶校验功能时,需要注意以下几个方面:
8 c* f, y7 A* O
& t+ _) N9 e+ g, f2 ?9 _' L1. M 所代表为帧长度,而不是数据位的长度。当使用奇偶校验的时候,帧长度=数据位长度+奇偶校验位长度;
5 M4 F/ M# z# k% u2. 不管数据奇偶校验位是否正确,UART 都会将数据接收回来。要对奇偶校验进行判断的话,必须对 PE 标志位进行检测,PE 标志位由硬件置位,当 PE=1 时,奇偶校验出错,做相应处理;
& H7 J) T9 |# w6 a3. PE 标志位的清除方式是:先读 UART_SR,再读 UART_DR。所以在程序中一定要注意:在判断RXNE 之后,必须在读取 UART_DR 之前就得先读取 PE,否则 PE 将在读取之前被清除;* P, ?: W) ]! c. c7 Q
4. 必须在 RXNE 标志位被置位的情况下才可对 PE 位进行清除。: R( S: S, \- E2 j6 G3 {4 o
) f3 o2 E/ h1 E$ `& v' f1 e# W
收藏 评论0 发布时间:2022-2-11 22:08

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版