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

【经验分享】STM32---RS485通讯协议的应用

[复制链接]
STMCU小助手 发布时间:2022-5-24 10:34
RS485缺点:7 ]3 K4 o3 _7 e0 ?4 z% I+ u
  w2 o% @* I$ k6 ~1 q- j
RS485总线是一种常规的通信总线,它不能够做总线的自动仲裁,也就是不能够同时发送数据以避免总线竞争,所以整个系统的通信效率必然较低,数据冗余量较大,对于速度要求高的应用场所不适应用RS485总线。同时由于RS485总线上通常只有一台主机,所以这种总线方式是典型的集中—分散型控制系统。一旦主机出现故障,会使整个系统的通信限于瘫痪状态,因此做好主机的在线备份是一个重要措施。
2 `* N/ j' @6 v0 p2 g4 q0 A4 m; J( g
**传统光电隔离的典型电路:6 |, H* u- x2 i! d' X! A
. e: w: v: D" a& z
1346080571_9835.jpg 9 [6 ~/ F/ W! _8 V. g8 D+ l
" t4 u/ t, t+ Q
VDD与+5V1(VCC485)是两组不共地的电源,一般用隔离型的DC-DC来实现。通过光耦隔离来实现信号的隔离传输,ISL3152EIBZ与MCU系统不共地,完全隔离则有效的抑制了高共模电压的产生,大大降低485的损坏率,提高了系统稳定性。但也存在电路体积过大、电路繁琐、分立器件过多,传输速率受光电器件限制等缺点,对整个系统的稳定性也有一定影响。' C5 A; ~+ \5 m3 r7 L& u

" b6 ?% S1 Q% D" X3 F2 j6 r***RXD1 :串口接收端
; p) {8 _* E7 l3 |( i$ P, i* K" ^8 P  B# W. t; Y; _
***TXD1 :串口传输端; {: I# q, x9 a# ^) ?
4 i3 I  S" g7 u2 `
***TRE1 :为控制位:控制发送还是接收数据;- u7 s8 X  _6 J. f: M& n
, Q+ f; e7 ~, ^8 U( C0 a, v
当TRE1=1(高电平时),光耦电路121截止,/RE=1(无效),DE=1(有效),即发送数据;& x: O! ^1 J/ n5 G$ [! m3 M

+ ]$ m0 U( u( L3 p- W1 V- ]0 w* F当TRE=0   (低电平时),光耦电路导通,/RE=0(有效),即接收数据,DE=0(无效);
' q- h7 v* v, j. _! z6 m1 A4 O# ]4 e
/RE: 485接收端
5 }! ~% E1 n+ x1 b
8 S* q+ ~$ F3 J+ A( }DE:485发送端
8 c. T  I2 K" r% @( X* j6 v2 L2 o3 `& G- c( e& x
1346080697_5449.jpg
" v1 |2 e; r; L+ Z: M 1346080759_4268.jpg
( \9 h; s! h3 E1 L. V
, {7 R) o2 X; u$ T" b) b 1346081022_7993.jpg
3 k( @6 b/ t2 n0 @
1 c; F. G# ~# P* [第一步,配置好串口发送、接收端引脚和485控制引脚;
8 a; R- }3 s0 F1 d. o; K6 y* k& w1 ~" w# N: Y- q
因为RXD1引脚相对于STM32芯片来说是接收外来数据,所以设置为输入;  W/ x; Y, U$ W

% U- U. t' n8 ~: q/ z3 l9 C$ \TXD1引脚相对于STM32芯片来说是对外发送数据,所以设置为输出;' o( x$ a) |: V  F& ^( B

5 D% r0 P$ d/ ]! [6 sTRE1 引脚是对外发送“1”或“0”高低电平命令,所以设置为输出;9 W/ Z+ E& b6 A) ?, R- k6 Q

, W2 r, D5 D/ A( q
  1. /*****************************************************************
    ( H- v! Q9 s0 A) Y5 y
  2. *函数名称:        UART2Init6 X4 S# T. s5 t
  3. *功能描述:        对串口2参数进行设置、485控制端口初始化
    - [0 M& _/ Y/ Z6 R$ i( ^) Z
  4. *
    . o3 c0 q' ?3 A  g; W
  5. *输入参数:无
    4 E7 |# s# u) g. j. }3 L
  6. *返 回 值:无
    ! H8 ^2 Y& _0 ?
  7. *其他说明:无
    ' g- p0 \' U' d7 S, g3 g
  8. *当前版本:v1.05 g' O5 O# o- Y6 K/ a
  9. *作    者: 尹宣
    2 ~3 G- R/ @& y& U
  10. *完成日期:2012年8月3日
    9 K! d: T* [% T) L; S/ t8 U9 G: K
  11. *修改日期      版本号      修改人      修改内容. Q0 T% p9 K! v0 l) d0 O7 w# z
  12. *-----------------------------------------------------------------
    1 `6 T  ^5 I5 V* {( P9 q8 G8 ]
  13. *! _  i% }$ ^& G+ O0 J/ b
  14. ******************************************************************/+ T- m' F/ t9 ]3 u
  15. void UART2Init(void)
    0 w4 [. V7 @' @8 z2 E, |
  16. {+ x/ X9 h8 S$ z% `5 h
  17.         GPIO_InitTypeDef GPIO_InitStructure;/ x$ }; t6 Z- x3 n) i( E
  18.         USART_InitTypeDef USART_InitStructure;9 {" A, k. t& k& z$ c( C, r2 B

  19. ' i- n6 [9 y2 X+ m
  20.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    ' E: V7 \( J& O6 B2 u- C
  21.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    ) t; U# I2 ^1 c1 T  _; |
  22.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    $ f# b+ ^- I, X' @1 L
  23.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能外设时钟         
    * F+ U4 c' ]- S3 s9 n. ]1 `

  24. 7 m  q+ z; `% [0 }3 `" H/ ^
  25.                 //GPIO结构的成员设置如下:* L% [) ~4 d- W9 Q" V# e2 {# _
  26.          /*--------------485控制端初始化------PA1----------*/( |# P6 i: c; _! m  K
  27.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;; m2 N1 ?. w4 c# w
  28.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    5 s1 g; D6 N, J$ C5 ^5 o, M5 R* `
  29.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出$ P( B6 ?* \! T+ @+ X  V- F
  30.         GPIO_Init(GPIOA, &GPIO_InitStructure);9 n( C4 g3 {5 n- o; u" X- J

  31. & k$ [1 m6 [' M9 Y8 M& G9 k

  32. : H6 }- Q& n3 r. ?- X( }: g  s( z
  33.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;          //485_TX
    & m' Q1 m" y( c5 D) ~
  34.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 2 L8 e) ?* Q/ s, v, [
  35.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    & P1 o3 ^. Q( t' m: g
  36.         GPIO_Init(GPIOA, &GPIO_InitStructure);7 ~) N- @9 D9 o4 G8 {

  37. & @4 |# d: j! Q; S( G" s( q
  38.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;           //485_RX
    0 c* a2 ~7 V& b7 G/ n) @- I2 L
  39.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    0 W" X. V+ ~  H/ J7 f) S' d9 @
  40.         GPIO_Init(GPIOA, &GPIO_InitStructure);+ b1 _, T0 N2 e. C! {, ?. B( A

  41. 9 |" V. t7 E9 @, c% D
  42.                 //串口的结构成员设置如下:
    ' D5 [, D, q" p* T1 ^0 U7 G. C
  43.         USART_InitStructure.USART_BaudRate = 9600;         
    / \. \0 d7 _7 L! n. n/ a
  44.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;+ Y1 j' _( Q/ J' u. q! M" E
  45.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
    6 U# w1 G/ v8 d5 Y. f/ x  h) S
  46.         USART_InitStructure.USART_Parity = USART_Parity_No;
    0 d. z" M. s4 ^$ a
  47.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    ) A( @* a# v) ~$ [& h9 s& D
  48.         USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    + R3 U" o5 K8 Y7 D; y+ M5 g  |
  49.         USART_Init(USART2, &USART_InitStructure);+ Z; m' o; u# {
  50. 2 N1 l* T0 U1 B5 w
  51.         USART_Cmd(USART2, ENABLE);
    & _( v( I% m4 x& m
  52. 5 J4 x% e6 X1 L
  53.         /*方法一: 清发送完成标志*/$ n- |2 V8 o2 D
  54.       //  USART_ClearFlag(USART3, USART_FLAG_TC); : H1 P6 G" `/ b! D) W0 V7 `! r6 y
  55. 9 [* b% P0 ~9 X; k
  56.        /*方法二:获取串口1状态标志位*/5 w5 O8 O0 W) D5 k3 W
  57.        USART_GetITStatus(USART1, USART_FLAG_TC);
    + X, U1 T' r8 ~- j5 R# K/ S8 e
  58. 5 U1 S; X. y8 _
  59. }
复制代码

& k2 c' Q3 b8 C( D1 A' t9 I2 C, p+ [7 |! l( D4 C7 U, t+ w
第二步:发送数据. S7 D$ o* z5 J4 Y" a1 K$ A! |
# }8 `  E: F( p2 h/ x0 B
这里需要注意的是:
( y% j- G" k1 p# D6 o
6 W! ?3 Y4 ~8 [; e0 P  S/* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  Q0 p: X! B0 O  C' ?
3 {) W2 e& D5 }( S如下两个方法语句解决第1个字节无法正确发送出去的问题 */7 U9 m; X5 }' K* u3 J; k

9 C+ f. z, E# O2 A% D3 N# ?方法一:USART_ClearFlag(USART3, USART_FLAG_TC); /*清发送完成标志,Transmission Complete flag */- I7 t  J3 ?# C" @' ?& v

! w% w  O+ ?- o# m方法二:/*获取串口1状态标志位*/
6 r/ R- a$ H$ H3 e* O- t7 i# Z& i( |1 X& ~
               USART_GetITStatus(USART1, USART_FLAG_TC);" y$ S7 g1 q- I) _" m  p
2 T" O, t( k8 F( r
刚上电时出现乱码的原因:

' G6 d$ f9 ^% [0 `
1 T7 t3 }; [% `while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);  // USART_FLAG_TXE---检测发送数据寄存器空标志位8 f/ Y) u+ k# A% n6 c1 _. Z' h
0 \7 \# j7 s& ?( _
如果USART_FLAG_TC---发送完成标志位" F# L. z. a; W0 R

8 r+ y8 f- m8 i" L4 n7 \0 f: s& `; ?(1)       当设为USART_FLAG_TXE---检测发送数据寄存器空标志位—为空,但是发送移位寄存器不为空,数据还没有完全的发送出去,又有数据就被写进来了,所以就会容易出现乱码;" K' ]6 Q- H# \. h: E
- Z& j& E1 a1 t6 v  H3 Q
(2)       当设为USART_FLAG_TC—检测发送完成标志位—为空,即发送移位寄存器为空,数据才真正的发送出去,因此此时又有数据被写进来也不会发生乱码3 _. x1 B. t: ]. P- e# a
" I, P* m+ o& `4 B: u5 `
1346081249_2209.jpg
3 f$ B/ h: T* Q8 r9 d/ J9 L
6 r, [* Q( L  p8 f( [# \) K6 Y/ uSTM32的数据发送有两个中断标志,一个是发送数据寄存器空标志,一个是发送完毕标志。两个标志都可以引起中断.
. V* @$ N9 s; C5 R9 I$ E) s
2 _  J6 I) t. A: s" H$ \要以中断的方式发送一个数据包,流程是这样的:7 J1 s* ]: F  `, j6 R
4 c: _5 W* N% O* B' w; J
1.设置RS485的方向为发送,使能发送寄存器空中断,使能完毕进入串口中断。1 p, z/ ?! i9 k& i. M

* `$ D( o4 k- j2.串口中断里读取串口状态,并填充一个数据到发送数据寄存器,硬件自动清除发送数据寄存器空标志,串口数据发送开始。" _7 @7 k% Q- D4 [

5 J' [7 t# ~- |" B5 Y' x+ H1 U+ s3.串口发送完一个数据,发送数据寄存器变空,再进入中断,继续填充下一个数据,直到最后一个数据填充完,使能串口
0 @& l3 N3 T: L' c, n$ d+ D& p" Y/ i% @
发送完毕中断。* y4 I& q7 B3 K4 N# n& l- R

) _7 Q8 b& Z) z2 ^! A4.最后一个数据发送完毕,再次进入中断,清除发送数据寄存器空标志,清除发送完毕中断标志,清除这两个中断标志
& C1 E0 a* d: S) o" D2 L  U5 E9 ^8 h( z; n
的使能位,设置RS485的方向为接收.2 v. l/ r% E& p, i- |

% B( P4 c7 A! H/ {  p5 L& ]
  1. /*****************************************************************% l+ J* P2 H8 {2 o$ k
  2. - k7 U' z8 n* c
  3. *                                      宏定义
    6 `5 w* E7 G/ t) [
  4. - k) d2 v0 E: z# }$ W! ]+ y7 v
  5. ******************************************************************/
    0 x) |8 b9 J+ ^8 X3 q( k
  6. * y# D! q6 d, G' S, B: q
  7. #define RX_485  GPIO_SetBits(GPIOA,GPIO_Pin_1);
    + W" w2 V; [7 m0 o' F5 C

  8. 5 y; e8 B$ h# l
  9. #define TX_485  GPIO_ResetBits(GPIOA,GPIO_Pin_1);# \% m0 H0 h) f3 e1 m- E- [

  10. $ P4 H% T7 _' m# h6 v" P0 _
  11. /*****************************************************************
      N$ P  d! n4 X. h. m! T$ M' U3 \2 L

  12. , z/ Q  D+ p9 y7 p8 P3 h
  13. *函数名称:  UART2_TX485_Puts$ k: z! d- J; u- T7 g9 F

  14. + N8 D4 a/ n' p5 D) T* v1 R
  15. *功能描述:  发送字符串数据
    8 u% s- S- S/ ], w- G: L

  16. & q/ [! k% F' q) m8 ]
  17. * ! g" u, `6 P( b3 @' L  F' S& W
  18. ( c% O6 \$ {3 \( g! x
  19. *输入参数:str:要发送的字符串, T" Y8 t& f. z% L

  20. 6 h, n3 R; D2 L. f" Q
  21. *返回值:无
    " l* G% s! X1 p7 p8 {

  22. 8 g4 t' w. H8 z& J+ U7 Y  K
  23. *其他说明:无" A: L% T% I4 b& x- ^4 k4 ~1 K

  24. . K- Z% I' I( B) [; N4 C3 a- Z1 P  b
  25. *当前版本:v1.0
    / j, N% z  \3 _( N3 o) r5 {

  26. - H, c3 S4 M* h3 l8 T- A0 H) _
  27. *作    者: 梁尹宣9 J6 J( e. g0 D$ q' E5 l

  28. 2 ?0 {2 }& p) i3 l: f
  29. *完成日期:2012年8月3日
    5 L9 M$ ]2 Q0 \9 s
  30. # I1 ~* n7 X; d# K( j
  31. *修改日期      版本号      修改人      修改内容
    % ~1 V, O  }, c, P3 `

  32. ( ~; v: m8 w" G8 w" O' ~
  33. *-----------------------------------------------------------------8 b1 q# y, ]. O
  34. 2 W1 y5 o: j+ l1 Z  n! K
  35. *
    0 b6 |% U2 z; e' g0 u
  36. 5 Z9 F8 W2 h6 a; e
  37. ******************************************************************/
    ' r6 p) e" S7 _, |1 C* v

  38.   T( T" j6 c# o8 v) v: S

  39. + j5 h/ ]  r: n4 q' [4 Q1 P7 c

  40. ( P- S. Y. R" j1 D
  41. void UART2_TX485_Puts(char * str)3 T% h- [9 ^" N' K1 {$ f" T

  42. ! j7 H* a% G5 Y- t
  43. {   6 E$ q5 P7 f% V( z  o! k
  44. & ]1 A0 V- h8 p6 n& ^

  45. ) Z: A( X+ Y- r3 d" U7 {
  46. 2 A+ g$ d, I' \5 U# ], F) }3 H
  47.     while(*str)* O3 P( |( s. o# U1 \

  48. ! k. R  U3 T; v9 w2 r
  49.     {  0 |) a- ^" m+ J  S4 {, Z

  50. - I1 l' m5 [2 U7 Y  Z3 k2 J3 S& ?
  51.        TX_485;     //打开485发送DE端口,关闭接收/RE端口% V5 J) h' A- V7 G# ?* e: \" t

  52. 8 l/ i9 S& v; Y8 o- g: c
  53.        DelayNmS(1);
    ' U; }  k. N. |1 e/ U. O
  54.   |# s/ ]- }: E5 ^6 O. w3 m
  55.         USART_SendData(USART2, *str++);. q) u/ x. {. h, D, |+ K+ @& l& X

  56. : U2 W- D: ?' N) o$ n/ s0 K
  57.         /* Loop until the end of transmission */) g. ?7 C2 W' n' v% l
  58. . g. y' v7 y' k" l$ Y5 E" n
  59.         while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);  //检测发送数据寄存器空标志位# a4 F2 X+ J* I- B0 s9 K4 x
  60. + R1 `4 M% k/ U" X- u$ k
  61.        DelayNmS(1);
    / b- z4 _  x% g) X# N% ]' ^9 K

  62. ( n5 ?# N# K- A: Y+ G3 j7 O
  63.         RX_485;     //关闭发送DE端口,打开接收/RE485端口,5 Y2 ]9 {" a6 [
  64. : B% M& ]% o% T6 J
  65.     }
    4 q" _. }4 i9 v& n

  66. % n$ ~$ c! t" h) L; u; ~
  67. }
    : Q5 Y2 W0 l; T8 c0 v& u: r' g  g
复制代码

# S* P7 g3 A1 D2 k8 h% r在485芯片的通信中,尤其要注意对485控制端DE的软件编程。为了可靠工作,在485总线状态切换时需要做适当延时,再进行数据收发。具体的做法是在数据发送状态下,   先将控制端置“1”,延时1ms左右的时间,在发送有效的数据,一包数据发送结束后再延时1ms后,将控制端置“0”,这样处理会使总线在状态切换时,有一个稳定的工作过程。% {5 x& A( F1 {& }" \( P
2 B: r: [% h% Y6 H3 W& v, [# g7 N

5 ^0 `& [1 K) E" K& h9 K6 N
* F% K" I( S' b6 s- _8 g
赞 收藏 评论0 发布时间:2022-5-24 10:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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