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

【经验分享】STM32串口多机通信

[复制链接]
STMCU小助手 发布时间:2022-1-23 15:26
最近在做多节点无线通信,用到STM32 USART多机串行通信。
记录下多机串行通信配置要点。
下面是我封装的会用到的函数:
  1. // .h
      Q$ |9 ]. d7 S& @) M" |- _
  2. #ifndef _MULTIUSART_H( e7 D2 w4 p0 @9 \) W
  3. #define _MULTIUSART_H1 D% g' X$ G4 m$ Q) _7 Y
  4. #include "sys.h"
    3 e; E; x+ e! H
  5. #include "stm32f10x_usart.h"
    0 H, T; h' l7 P  A2 y

  6. 5 _/ L3 m+ [  E
  7. /*
    8 U( d5 a, ?* y7 H: G
  8.     USART_SR状态寄存器
    $ i5 \6 I, j& ]
  9.     USART_DR数据寄存器
    0 n9 }  R5 ~3 ?) _8 g! z- P
  10.     USART_BRR波特率寄存器
      `& ^: ]5 K" V) c2 f
  11.     + g' P4 k, c7 p& s0 H
  12.     TXD-PA9
    & R1 W5 A) N& _/ f; P
  13.     RXD-PA10" D% a* U1 t4 T
  14. */
    " J6 i1 N0 A$ h, f3 K$ k* C' d0 E2 R

  15. , @9 V# g6 a1 p; y3 I4 w/ n
  16. #define USART_REC_LEN              60      
    : }' T1 L* L* G9 w! x1 h- I
  17. #define EN_USART1_RX             1        //使能(1)/禁止(0)串口1接收; C7 q, \2 ~) M" x2 {
  18.          
    5 K( ]( ]0 ?7 n7 b) e5 c! |! n
  19. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 ' O) u; j; ~: R4 p. x0 k
  20. extern u16 USART_RX_STA;                 //接收状态标记    3 G3 S8 m$ y* h4 L0 W
  21. ( y9 e+ K: y) {, k9 O' w# U3 s
  22. extern void USART_InitEx(u32 bound);; u% M+ a) ~: e2 o: k0 r& O9 c
  23. extern void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data);
      P' _0 x! ^  u$ v
  24. extern void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr);/ l" E; g/ K$ K$ O9 b- @8 V
  25. * _2 r9 d8 a$ ?) J, v/ A

  26. * h1 p4 G/ N9 ]% x7 i  b7 T! W. l
  27. #endif
复制代码
  1. // .c
    - B& w! l9 N0 j" w2 m$ Y' O( g
  2. #include "MultiUSART.h"# u. I; j) k1 f8 q
  3. - M& D: P$ }8 U1 z
  4. ! N! b/ p* c$ J) {( b

  5. ; ^' u  c/ A/ ~4 g$ z
  6. //串口1中断服务程序
    % y9 B  \8 o, V: w! T/ j8 s9 [
  7. //注意,读取USARTx->SR能避免莫名其妙的错误       2 D" w2 I1 w+ _$ N+ Y, d7 ^7 A
  8. u8 USART_RX_BUF[USART_REC_LEN] = "";     //接收缓冲,最大USART_REC_LEN个字节.
    7 T. `1 m5 E3 [* y+ |
  9. //接收状态/ [7 C$ j) F' p
  10. //bit15,    接收完成标志
    + r. F1 B, F3 v* j
  11. //bit14,    接收到0x0d! O/ I7 I, U8 U5 }1 M: w( a# T
  12. //bit13~0,    接收到的有效字节数目
    ' e( z" _: t2 @7 D/ y
  13. u16 USART_RX_STA=0;       //接收状态标记      2 y4 Q4 b1 {+ |
  14. ( T) y+ K5 \: f+ a* ]
  15. ! \7 R6 L4 M0 g2 w" ]) q, q
  16. 4 v0 h0 B2 p6 v- Z* V: P
  17. void USART_InitEx(u32 bound)
    . D* Q  s3 Y( F2 J
  18. {
    - P# |0 X! y7 {0 G% M* H9 k2 E
  19.     GPIO_InitTypeDef GPIO_InitStructure;
    # X& z( M) i- k
  20.     USART_InitTypeDef USART_InitStructure;( R$ c9 C  r  N/ L) v  M1 R
  21.     NVIC_InitTypeDef NVIC_InitStructure;4 J9 S6 T9 v1 L5 f
  22.      
    . U. K/ \& e2 h$ Y0 r# b
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    //使能USART1,GPIOA时钟
    # f2 T8 g7 t$ `5 a1 |9 w5 B( R
  24.      USART_DeInit(USART1);                                      //复位串口1
    " y) Y1 c6 H7 G" F
  25.    
    - q6 Z- m% X( x" G3 Q9 l" O
  26.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         6 i* p5 g7 `0 e$ w% V; _
  27.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;9 ], }/ o" T, m9 [( r# N
  28.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;            //复用推挽输出* K! j8 L9 U0 E  }9 u* b/ Q/ [3 ?
  29.     GPIO_Init(GPIOA, &GPIO_InitStructure);            
    ! o3 O1 Y0 c( v# D
  30.    
      c3 O) v0 M- X3 @
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;9 p  S4 \- X' W# M9 a
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    //浮空输入& J& r# K: O8 H5 u7 Z* ?7 ]: u9 D
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);          - w& `* E! T: ?  C1 a
  34. ! X; t. [. t+ b2 ~' e
  35.    //Usart1 NVIC 配置, f. w) _" u% K6 V8 j6 c# u& u5 z
  36.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    ' U8 P1 B4 u9 _2 l
  37.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    4 a# B9 @. g1 ]! B0 l( u4 }
  38.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    # n/ M$ Z! ~+ z
  39.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能5 ^2 G8 s! c) m
  40.     NVIC_Init(&NVIC_InitStructure);   
    3 n$ c7 s. }. i& u- J
  41.   2 r) J) U" m- d1 X  e
  42.    //USART 初始化设置) H! |& \3 |0 z1 f/ p" b" v
  43.     USART_InitStructure.USART_BaudRate = bound;
    ' ]/ I! i$ s; i3 \. I2 P/ x9 q
  44.     USART_InitStructure.USART_WordLength = USART_WordLength_9b;$ a' b: l- }/ |' g) n
  45.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
    * t# i% s5 |7 |5 p1 o
  46.     USART_InitStructure.USART_Parity = USART_Parity_No;        
    . j' k7 h4 D, Q" J. @( ?
  47.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    * X3 f. N- K* L4 X2 I) }
  48.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   
    1 O) d: S% B* C9 w! \9 z, ^/ {+ w6 Q

  49. 5 @7 h' m$ X) ~% b, \+ m8 B
  50.     USART_Init(USART1, &USART_InitStructure);         //初始化串口
    1 e( i( [% T: b$ a4 L
  51.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);    //开启中断   接收中断
    , J3 h! ^4 i! M, R
  52.     USART_Cmd(USART1, ENABLE);                        //使能串口 ! \3 z* {2 \' L8 A5 ^( S# ^
  53.     - \, a) c5 W" z0 d
  54.    
    + j9 A( H9 V) |! V7 A7 t9 ^
  55.     USART_SetAddress(USART1, 0x01);                    //设置USART1节点地址  M+ U/ `7 X6 R' a9 t  M% O# O1 S
  56.     //USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark);//地址标记唤醒$ |: T' k2 j; n9 k
  57.     * ]: V1 l' P) Y
  58.     //USART_ReceiverWakeUpCmd(USART1,ENABLE);8 W) U/ E  V3 n0 f, b
  59. }
    2 K- W; n2 A( h2 _

  60. % ?) u$ i  E& B2 U: z- P
  61. 7 \3 M3 E- G$ @) l
  62. void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data)6 `! o( o6 ?8 K/ C
  63. {
    ! A, |; ?$ d6 K  S# t$ P
  64.     /* Check the parameters */9 s5 z. n! M9 I2 n. \
  65.     assert_param(IS_USART_ALL_PERIPH(USARTx));# m# `% e, {5 J6 }2 Q+ f! B& a
  66.     assert_param(IS_USART_DATA(Data)); 1 F, O- b3 t2 }
  67.    
    4 n# ~; M5 B) m3 [- n; `6 I4 I# k
  68.     /* Transmit Data */
    0 l5 z: M, k& f5 }8 O+ ]
  69.     USARTx->DR = (Data & (uint16_t)0x01FF);% h, P- |6 u+ p0 i0 R8 X, E
  70.     9 X5 s  y$ s5 V2 M9 w
  71.     //等待发送缓冲区空2 ]! R" P; m( E  t7 E' |3 I
  72.     //或   等待发送结束
    ' w, }( d. d5 ~! Y' s: ]
  73.     //while((USART1->SR&0X40)==0);6 b$ X, Y. K8 Q7 y" }
  74.     while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){};6 j! @2 {2 z  B, _, T8 N3 Q
  75. }5 O* T7 R" q. X6 P% c; I* J
  76. " e/ U' a2 T  c- x- D
  77. void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr)& @* S$ x7 ~: ^0 Z0 E- ?
  78. {8 m* h0 \: ?! K! z, T3 D5 c9 Q
  79.     /* Check the parameters */+ d; E/ {  S$ C" b6 E4 [
  80.     assert_param(IS_USART_ALL_PERIPH(USARTx));5 I. O/ O# l: H
  81.    6 L* Z! V4 h8 h7 V$ Z
  82.     // 9位字长, 最高位为1,低四位为地址
    * W, ?' {  f* j7 l; R) A" v& X
  83.     //USARTx->DR = (1<<8) | Addr;4 c1 ]% E1 {( @, \2 B) t, H
  84.     Addr |= (uint16_t)0x0100;
    0 e, z* b' ?" U+ u* ~
  85.     USARTx->DR = (Addr & (uint16_t)0x010F);; O$ @2 m2 E" |# d
  86. }$ {  X1 K( b. e5 ~* ?' E0 H. ~
  87. 9 [# W/ h9 x5 Y# p. K
  88. #if EN_USART1_RX - l$ i* C" E7 ~1 ^9 J
  89. void USART1_IRQHandler(void)                                //串口1中断服务程序6 p! H0 n% \6 V  Z9 }, i( p
  90. {
    * R0 k8 V* e% d$ ~2 e1 \
  91.     u8 Res;) l( y$ y" r$ b' \$ T7 X( I
  92.     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)      //接收中断(接收到的数据必须是0x0d 0x0a结尾)( s% |* H# g5 \( T. m  h
  93.     {
    ; X6 u  D& C' K& s6 h
  94.         Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据% v5 h- Q( ?9 |
  95.         . E, i) y$ r% n4 f& F
  96.         if((USART_RX_STA&0x8000)==0)                        //接收未完成9 Y2 n* j; e2 N6 K! k% H% U
  97.         {
    7 C. Z2 |8 L' T
  98.             if(USART_RX_STA&0x4000)                            //接收到了0x0d6 D- ~4 ?& ^' }) S3 `5 O$ S3 r7 j
  99.             {( q* v$ I' w  J' |' ]7 J
  100.                 if(Res!=0x0a)2 N1 P: T5 c# O* T% _
  101.                     USART_RX_STA=0;                            //接收错误,重新开始4 p; E3 S& o: B7 A+ k% E
  102.                 else
    3 a$ x# S0 \: ~$ y+ N! ?6 W* s0 z! H5 [
  103.                     USART_RX_STA|=0x8000;                    //接收完成了 7 ]8 D$ D, _7 ^! t$ `
  104.             }/ q+ e+ \* C# k9 |+ B* E' x4 R1 @
  105.             else                                             //还没收到0X0D
    / P( ~$ |; G% u# U: E
  106.             {    9 w- B2 [: ^9 c! I3 O+ [
  107.                 if(Res==0x0d)
    ' ^, q+ L+ Q! @1 w3 F: j+ V, ?7 s
  108.                     USART_RX_STA|=0x4000;
    2 a  R3 i" m. n9 A) o5 p5 Q
  109.                 else
    0 _4 @+ `" H! A* D3 `" N
  110.                 {
    . ]: R# h6 h, ?: ~
  111.                     USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;& x0 t  G# E/ G! g: Z( J' X+ v
  112.                     USART_RX_STA++;
    ) C' P9 ~6 ?# ~* s4 ]- _# o( ]# ~" W
  113.                     if(USART_RX_STA>(USART_REC_LEN-1))6 e, K- Z9 E- L- A1 v! c
  114.                         USART_RX_STA=0;                        //接收数据错误,重新开始接收      
    " ^* X2 c+ w$ G. e/ u8 X8 S5 B
  115.                 }         
    $ I; S% \; h9 f8 e  V
  116.             }* g# R! k" i+ O, A3 W( z
  117.         }            
    $ g' w3 Q1 K, h  o/ e0 I# ~
  118.      }
    " {6 P' S/ p- k9 I+ G9 |5 T
  119. }
    0 l. q) @- y4 I2 [: N: S* Y
  120. #endif
复制代码
在主机端,可以写个键盘控制发送地址,类似:
switch(KeyValue)# Q# Z0 o% ~. x' i0 ?3 K
        {
$ h8 x# F: B1 g4 z& e9 b1 w            case 1: USART_SendAddr(USART1, 0x01); break;  //从机1
8 R/ g5 G4 j# d, ?            case 2: USART_SendAddr(USART1, 0x02); break;  //从机2
.............
然后即可自己设定通信协议分别处理从机发过来的数据了。

& S! Z4 A- T3 [- K0 i1 H# D9 U9 {
在从机端,由于要设为静默模式:
USART_SetAddress(USART1, 0x01);    //设置USART1节点地址 如从机1设为0x01
USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark);  //地址标记唤醒
USART_ReceiverWakeUpCmd(USART1,ENABLE);  //使处于静默模式
这几句在串口初始化时要开启。

" {3 I3 a& q# J( c5 o
当主机发出正确地址给从机时,下面if 语句便成立可执行。
//从机被唤醒, 接收中断恢复正常   
if((USART1->CR1 &((uint16_t)0x0002)) == 0)8 p' `" L+ J$ ?1 ~( C# l/ E; g" c
{........}
从而可在其中添加从机要给主机发送数据的程序。
7 E* v! y8 b- I+ U3 J
赞 收藏 评论0 发布时间:2022-1-23 15:26

举报

0个回答

所属标签

相似技术帖

官网相关资源

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