|
最近在做多节点无线通信,用到STM32 USART多机串行通信。 记录下多机串行通信配置要点。 下面是我封装的会用到的函数: - // .h
1 m9 {" \0 G* O - #ifndef _MULTIUSART_H
: u# Z4 m! t+ O, t! ] - #define _MULTIUSART_H; o4 F" v: y/ [3 f! L4 \
- #include "sys.h"
: |$ u& K8 V+ y: u- }9 J5 Z9 i - #include "stm32f10x_usart.h"3 I# u6 o& ]) Q' v: v* z3 t
+ X: U+ }; k0 p- /** F/ w3 G% s- ]2 o4 w4 ^ Y
- USART_SR状态寄存器
# i5 l4 e/ I" ~ Y v+ [2 D& j - USART_DR数据寄存器
) n2 J: s1 |& g; Q# B& R - USART_BRR波特率寄存器0 P3 Z4 Z2 J+ C8 c2 c, |; a! d
-
4 z7 N0 o1 h, a+ ~ - TXD-PA9) p; g) S k$ h! P0 H5 N# z9 H: Y6 y
- RXD-PA10
6 |( q1 O) y: O3 S2 Y# `" a - *// c# }9 R: T5 D0 ]
- 5 |* W$ \" S' T) g, U" O6 D
- #define USART_REC_LEN 60 6 q+ Z% w% C7 a: _: G
- #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
8 P: P7 I% f a8 C - * x5 a& d" v- v2 h5 v% X! k' c' D% h
- extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
! u6 |1 p/ y# H" M8 ]4 H# R - extern u16 USART_RX_STA; //接收状态标记 + k- x0 L) W5 N+ t
2 r" b9 D3 l7 b4 W/ D- extern void USART_InitEx(u32 bound);
) u! v6 A% U& m' u, B - extern void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data);
, G4 [# S$ G" x; D - extern void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr);# a, n8 c1 {3 g8 x% S
/ R& i6 t, f2 o! ~: _- 2 H+ _1 z! t* R( y7 @0 E0 H( S0 A
- #endif
复制代码- // .c: P' ?! v) E& t8 O: ~
- #include "MultiUSART.h"7 o+ Y* F% M+ j) S, S
. \9 N( j, i: {8 ]: `- ( l+ P" Y4 [" |% l
- {6 {# V0 l1 U7 C- //串口1中断服务程序
; w% R/ X1 g! D ` - //注意,读取USARTx->SR能避免莫名其妙的错误
z1 L& e2 F" f9 k, s9 f - u8 USART_RX_BUF[USART_REC_LEN] = ""; //接收缓冲,最大USART_REC_LEN个字节.3 e' u. r- v5 v3 u+ H
- //接收状态
L- m6 I- ~. i4 Q q - //bit15, 接收完成标志7 k( ]' }4 u% x8 \
- //bit14, 接收到0x0d l& \- T" Z5 \9 P5 \0 t! L# i7 A
- //bit13~0, 接收到的有效字节数目6 o5 t( I4 J% ^/ }- K3 Q
- u16 USART_RX_STA=0; //接收状态标记
, F& V+ v: \) r& U8 K4 e1 `
" N4 c* s! j# @8 A7 W- 4 Y7 O# ?4 ]- s0 r0 S
4 N- a x7 D$ {8 n- void USART_InitEx(u32 bound)+ S r8 I J( X. q3 q
- {: R- ~. v" Q2 g+ \" W) ?
- GPIO_InitTypeDef GPIO_InitStructure;; u2 O% |" G0 N5 g
- USART_InitTypeDef USART_InitStructure;) l4 {5 B5 [3 I" _" B8 b
- NVIC_InitTypeDef NVIC_InitStructure;
8 h+ |7 v9 t- x" l* n6 {% ~ -
1 V0 E7 {8 M0 x; _ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟3 h0 I- }! y9 }. m w
- USART_DeInit(USART1); //复位串口1
& O4 r/ ^& k. Q8 N" k4 m: a7 W% N; | -
0 H5 N7 d! f. O+ Z/ _# V% E - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
2 i6 O E$ H- M! v# ] - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
7 b) i: N2 B" H - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出" C3 W/ ]: x1 T
- GPIO_Init(GPIOA, &GPIO_InitStructure); , m' R1 k: R" _* G
-
; }% E" [, X" F. [0 B1 u - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;5 v3 \8 A# N8 }& v& i6 o6 ]
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
8 x. {' y4 }" c - GPIO_Init(GPIOA, &GPIO_InitStructure); 4 M$ j1 ? G5 ^, y6 l. w
% H8 w+ M9 Q1 U9 x$ ^) Y7 }- //Usart1 NVIC 配置. z+ g/ b8 l& R9 i
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;* e' F8 t" H5 X; K- t4 l3 l
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级34 ]& `: |8 I1 C, x; ~* F1 R8 e
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
$ i# S4 G; O. M - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能2 O4 X" \- x! Q; s" T! F4 x( d
- NVIC_Init(&NVIC_InitStructure); 9 S# ], T3 Y0 S; c2 q4 Z+ }
-
! M, K# A5 p- }; Z' q) m( g - //USART 初始化设置# h: i& h q" m* J3 E" N+ v6 V
- USART_InitStructure.USART_BaudRate = bound;0 q1 C8 F# @+ R! V+ ~
- USART_InitStructure.USART_WordLength = USART_WordLength_9b;( ?# C6 `5 `! Z- k% i
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
* J( L7 h) d" F1 @ - USART_InitStructure.USART_Parity = USART_Parity_No; 6 o; K1 j- z% |% W! t7 O
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;: ]! g |, K9 j! p
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; $ S0 U; o! \, O, y
6 A* h2 t' g6 M3 }- USART_Init(USART1, &USART_InitStructure); //初始化串口: G3 ?7 S5 r S& Y1 y/ c( B
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断 接收中断9 d, r: L. o) w( ~2 {$ O' V
- USART_Cmd(USART1, ENABLE); //使能串口 , R1 S# i1 o3 s, r
- - y5 m4 H/ S" R
-
, s: _$ S3 w- P6 C2 l - USART_SetAddress(USART1, 0x01); //设置USART1节点地址; s5 j1 Q& `) @3 t8 [. z4 i+ d
- //USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark);//地址标记唤醒
" o* I4 A* ~! u+ I, i3 B' y -
4 Y5 f/ `# Y, }# |( F" _$ G- d - //USART_ReceiverWakeUpCmd(USART1,ENABLE);
7 S8 D* k6 E$ p! R: l% [$ a/ P' \) \1 R - } }+ \* R/ |8 A5 J* n
- 3 N/ }+ J9 f. L- ~7 C6 a. Z4 Q) y& ?
7 Z/ w U: l9 A- K1 l F0 p- void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data)1 V4 ?6 k. q% o v0 R
- {
. D& B* n$ c; h3 C# ? - /* Check the parameters */2 h3 ?' y& u* H. a
- assert_param(IS_USART_ALL_PERIPH(USARTx));
7 I6 t9 V6 {- M) C( V* y - assert_param(IS_USART_DATA(Data));
: x) w' f, @" d, T; E+ F - 2 I: h: j+ K7 o5 E+ l
- /* Transmit Data */$ `& X# r. g* N1 T$ q( W+ z! W; {3 Z
- USARTx->DR = (Data & (uint16_t)0x01FF);
6 t8 @. R* o& P$ T - , W3 D$ P! ?8 J0 H
- //等待发送缓冲区空
& h# ~9 }6 n- F/ v/ u - //或 等待发送结束
! b; V# i w6 ~1 ~! L a8 U - //while((USART1->SR&0X40)==0);" k d$ Z. X2 S" K1 }/ s" ]
- while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){};
( t4 N: w1 g4 A; h) l: ` - }
& D* z3 E% t/ M& _" [1 \ - 2 f# n8 A8 v! h5 T1 e- `
- void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr)
1 ?) n' Z6 k0 w - {) `8 h7 }4 H9 Z d1 r& t
- /* Check the parameters */
6 Y0 Z: G0 C+ N1 q - assert_param(IS_USART_ALL_PERIPH(USARTx));
6 k3 b; j, c0 F( _: @+ G -
_" q$ A' O0 @, S- ~4 A1 u ]( t - // 9位字长, 最高位为1,低四位为地址
y3 P* G! n1 V3 O! p3 [ - //USARTx->DR = (1<<8) | Addr;- x+ [0 w- ~. v1 H! t+ n
- Addr |= (uint16_t)0x0100;
+ w8 f7 u% S2 h# l - USARTx->DR = (Addr & (uint16_t)0x010F);8 k, ^" P: y2 t: ~
- }2 I$ L& \' p" J. m0 Y* A( I0 U9 [
- % u; j h$ }* {, U% b" A5 q2 L( p
- #if EN_USART1_RX 4 V2 b* C) A: b6 o* b
- void USART1_IRQHandler(void) //串口1中断服务程序
" T! x! l8 G, A \3 Q - {
. e) |( d- ?- G3 @1 C6 C - u8 Res;
- [ i2 l8 j) I0 Y) @ - if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)# l$ ~ R, B. n$ j$ A
- {
3 ]- Q3 _. I" u, e* m% K6 P0 T) J G - Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
q8 z; ~4 @$ |. Q( r4 z - , O# T; m4 X1 X
- if((USART_RX_STA&0x8000)==0) //接收未完成# \9 B3 b% m: S2 {, ?6 u* Q% s, \
- {8 N. Q& w; k" a
- if(USART_RX_STA&0x4000) //接收到了0x0d: d# c, k1 m* x3 e Z
- {
$ E& `9 [7 f5 \2 J - if(Res!=0x0a)
# N* K; F, r+ V$ Q - USART_RX_STA=0; //接收错误,重新开始3 S5 T, u2 W E! T. `, E6 |
- else
0 y% U1 R: I: k, {' N5 E - USART_RX_STA|=0x8000; //接收完成了
6 _2 G! P8 \; L9 U - }% N' \! e u2 g0 [% j
- else //还没收到0X0D7 }3 o0 b; C2 g/ x
- {
- R2 F) M! P9 t, S - if(Res==0x0d)
# o, n3 y" a. T4 @ - USART_RX_STA|=0x4000;
$ u, m6 j( E; Y1 c/ O - else
" e( `% I0 W8 Z7 o f# }; w - {1 s* N. n K# |
- USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;! r) G; q' x0 }, w; @. ~8 \
- USART_RX_STA++;
& Y9 |" O6 B/ G" F( M0 @( {# S - if(USART_RX_STA>(USART_REC_LEN-1)), ]3 Q* P4 a+ X
- USART_RX_STA=0; //接收数据错误,重新开始接收
2 @+ C0 U7 G0 h3 t; }& ]* \6 m - }
- c6 e6 z4 B' _7 K* J" ]+ N - }$ V3 X, T, O. q7 P+ ^' x
- } 1 ^: ?' b7 n: M$ C
- } , N( k9 D2 K9 ^( C: S% Y7 G
- }# m5 c* k. Q9 @ ?) h/ ?. ~
- #endif
复制代码在主机端,可以写个键盘控制发送地址,类似: switch(KeyValue)3 y3 W6 z; @; O( b
{; s% r9 J8 ]$ A3 `' O9 E" s6 ~
case 1: USART_SendAddr(USART1, 0x01); break; //从机1) ]9 s; w; G4 u
case 2: USART_SendAddr(USART1, 0x02); break; //从机2 ............. 然后即可自己设定通信协议分别处理从机发过来的数据了。 + i! d" K+ i2 K! E* @
在从机端,由于要设为静默模式: USART_SetAddress(USART1, 0x01); //设置USART1节点地址 如从机1设为0x01 USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark); //地址标记唤醒 USART_ReceiverWakeUpCmd(USART1,ENABLE); //使处于静默模式 这几句在串口初始化时要开启。 6 d3 G2 c: F4 C5 Y, s) ~
当主机发出正确地址给从机时,下面if 语句便成立可执行。 //从机被唤醒, 接收中断恢复正常 if((USART1->CR1 &((uint16_t)0x0002)) == 0)$ j; j a; H& U' m: G' M5 p* P
{........} 从而可在其中添加从机要给主机发送数据的程序。 ( l& S9 z" V7 D$ f! ^
|