|
最近在做多节点无线通信,用到STM32 USART多机串行通信。 记录下多机串行通信配置要点。 下面是我封装的会用到的函数: - // .h
Q$ |9 ]. d7 S& @) M" |- _ - #ifndef _MULTIUSART_H( e7 D2 w4 p0 @9 \) W
- #define _MULTIUSART_H1 D% g' X$ G4 m$ Q) _7 Y
- #include "sys.h"
3 e; E; x+ e! H - #include "stm32f10x_usart.h"
0 H, T; h' l7 P A2 y
5 _/ L3 m+ [ E- /*
8 U( d5 a, ?* y7 H: G - USART_SR状态寄存器
$ i5 \6 I, j& ] - USART_DR数据寄存器
0 n9 } R5 ~3 ?) _8 g! z- P - USART_BRR波特率寄存器
`& ^: ]5 K" V) c2 f - + g' P4 k, c7 p& s0 H
- TXD-PA9
& R1 W5 A) N& _/ f; P - RXD-PA10" D% a* U1 t4 T
- */
" J6 i1 N0 A$ h, f3 K$ k* C' d0 E2 R
, @9 V# g6 a1 p; y3 I4 w/ n- #define USART_REC_LEN 60
: }' T1 L* L* G9 w! x1 h- I - #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收; C7 q, \2 ~) M" x2 {
-
5 K( ]( ]0 ?7 n7 b) e5 c! |! n - extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 ' O) u; j; ~: R4 p. x0 k
- extern u16 USART_RX_STA; //接收状态标记 3 G3 S8 m$ y* h4 L0 W
- ( y9 e+ K: y) {, k9 O' w# U3 s
- extern void USART_InitEx(u32 bound);; u% M+ a) ~: e2 o: k0 r& O9 c
- extern void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data);
P' _0 x! ^ u$ v - extern void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr);/ l" E; g/ K$ K$ O9 b- @8 V
- * _2 r9 d8 a$ ?) J, v/ A
* h1 p4 G/ N9 ]% x7 i b7 T! W. l- #endif
复制代码- // .c
- B& w! l9 N0 j" w2 m$ Y' O( g - #include "MultiUSART.h"# u. I; j) k1 f8 q
- - M& D: P$ }8 U1 z
- ! N! b/ p* c$ J) {( b
; ^' u c/ A/ ~4 g$ z- //串口1中断服务程序
% y9 B \8 o, V: w! T/ j8 s9 [ - //注意,读取USARTx->SR能避免莫名其妙的错误 2 D" w2 I1 w+ _$ N+ Y, d7 ^7 A
- u8 USART_RX_BUF[USART_REC_LEN] = ""; //接收缓冲,最大USART_REC_LEN个字节.
7 T. `1 m5 E3 [* y+ | - //接收状态/ [7 C$ j) F' p
- //bit15, 接收完成标志
+ r. F1 B, F3 v* j - //bit14, 接收到0x0d! O/ I7 I, U8 U5 }1 M: w( a# T
- //bit13~0, 接收到的有效字节数目
' e( z" _: t2 @7 D/ y - u16 USART_RX_STA=0; //接收状态标记 2 y4 Q4 b1 {+ |
- ( T) y+ K5 \: f+ a* ]
- ! \7 R6 L4 M0 g2 w" ]) q, q
- 4 v0 h0 B2 p6 v- Z* V: P
- void USART_InitEx(u32 bound)
. D* Q s3 Y( F2 J - {
- P# |0 X! y7 {0 G% M* H9 k2 E - GPIO_InitTypeDef GPIO_InitStructure;
# X& z( M) i- k - USART_InitTypeDef USART_InitStructure;( R$ c9 C r N/ L) v M1 R
- NVIC_InitTypeDef NVIC_InitStructure;4 J9 S6 T9 v1 L5 f
-
. U. K/ \& e2 h$ Y0 r# b - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
# f2 T8 g7 t$ `5 a1 |9 w5 B( R - USART_DeInit(USART1); //复位串口1
" y) Y1 c6 H7 G" F -
- q6 Z- m% X( x" G3 Q9 l" O - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 6 i* p5 g7 `0 e$ w% V; _
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;9 ], }/ o" T, m9 [( r# N
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出* K! j8 L9 U0 E }9 u* b/ Q/ [3 ?
- GPIO_Init(GPIOA, &GPIO_InitStructure);
! o3 O1 Y0 c( v# D -
c3 O) v0 M- X3 @ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;9 p S4 \- X' W# M9 a
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入& J& r# K: O8 H5 u7 Z* ?7 ]: u9 D
- GPIO_Init(GPIOA, &GPIO_InitStructure); - w& `* E! T: ? C1 a
- ! X; t. [. t+ b2 ~' e
- //Usart1 NVIC 配置, f. w) _" u% K6 V8 j6 c# u& u5 z
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
' U8 P1 B4 u9 _2 l - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
4 a# B9 @. g1 ]! B0 l( u4 } - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
# n/ M$ Z! ~+ z - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能5 ^2 G8 s! c) m
- NVIC_Init(&NVIC_InitStructure);
3 n$ c7 s. }. i& u- J - 2 r) J) U" m- d1 X e
- //USART 初始化设置) H! |& \3 |0 z1 f/ p" b" v
- USART_InitStructure.USART_BaudRate = bound;
' ]/ I! i$ s; i3 \. I2 P/ x9 q - USART_InitStructure.USART_WordLength = USART_WordLength_9b;$ a' b: l- }/ |' g) n
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
* t# i% s5 |7 |5 p1 o - USART_InitStructure.USART_Parity = USART_Parity_No;
. j' k7 h4 D, Q" J. @( ? - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
* X3 f. N- K* L4 X2 I) } - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
1 O) d: S% B* C9 w! \9 z, ^/ {+ w6 Q
5 @7 h' m$ X) ~% b, \+ m8 B- USART_Init(USART1, &USART_InitStructure); //初始化串口
1 e( i( [% T: b$ a4 L - USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断 接收中断
, J3 h! ^4 i! M, R - USART_Cmd(USART1, ENABLE); //使能串口 ! \3 z* {2 \' L8 A5 ^( S# ^
- - \, a) c5 W" z0 d
-
+ j9 A( H9 V) |! V7 A7 t9 ^ - USART_SetAddress(USART1, 0x01); //设置USART1节点地址 M+ U/ `7 X6 R' a9 t M% O# O1 S
- //USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark);//地址标记唤醒$ |: T' k2 j; n9 k
- * ]: V1 l' P) Y
- //USART_ReceiverWakeUpCmd(USART1,ENABLE);8 W) U/ E V3 n0 f, b
- }
2 K- W; n2 A( h2 _
% ?) u$ i E& B2 U: z- P- 7 \3 M3 E- G$ @) l
- void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data)6 `! o( o6 ?8 K/ C
- {
! A, |; ?$ d6 K S# t$ P - /* Check the parameters */9 s5 z. n! M9 I2 n. \
- assert_param(IS_USART_ALL_PERIPH(USARTx));# m# `% e, {5 J6 }2 Q+ f! B& a
- assert_param(IS_USART_DATA(Data)); 1 F, O- b3 t2 }
-
4 n# ~; M5 B) m3 [- n; `6 I4 I# k - /* Transmit Data */
0 l5 z: M, k& f5 }8 O+ ] - USARTx->DR = (Data & (uint16_t)0x01FF);% h, P- |6 u+ p0 i0 R8 X, E
- 9 X5 s y$ s5 V2 M9 w
- //等待发送缓冲区空2 ]! R" P; m( E t7 E' |3 I
- //或 等待发送结束
' w, }( d. d5 ~! Y' s: ] - //while((USART1->SR&0X40)==0);6 b$ X, Y. K8 Q7 y" }
- while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){};6 j! @2 {2 z B, _, T8 N3 Q
- }5 O* T7 R" q. X6 P% c; I* J
- " e/ U' a2 T c- x- D
- void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr)& @* S$ x7 ~: ^0 Z0 E- ?
- {8 m* h0 \: ?! K! z, T3 D5 c9 Q
- /* Check the parameters */+ d; E/ { S$ C" b6 E4 [
- assert_param(IS_USART_ALL_PERIPH(USARTx));5 I. O/ O# l: H
- 6 L* Z! V4 h8 h7 V$ Z
- // 9位字长, 最高位为1,低四位为地址
* W, ?' { f* j7 l; R) A" v& X - //USARTx->DR = (1<<8) | Addr;4 c1 ]% E1 {( @, \2 B) t, H
- Addr |= (uint16_t)0x0100;
0 e, z* b' ?" U+ u* ~ - USARTx->DR = (Addr & (uint16_t)0x010F);; O$ @2 m2 E" |# d
- }$ { X1 K( b. e5 ~* ?' E0 H. ~
- 9 [# W/ h9 x5 Y# p. K
- #if EN_USART1_RX - l$ i* C" E7 ~1 ^9 J
- void USART1_IRQHandler(void) //串口1中断服务程序6 p! H0 n% \6 V Z9 }, i( p
- {
* R0 k8 V* e% d$ ~2 e1 \ - u8 Res;) l( y$ y" r$ b' \$ T7 X( I
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)( s% |* H# g5 \( T. m h
- {
; X6 u D& C' K& s6 h - Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据% v5 h- Q( ?9 |
- . E, i) y$ r% n4 f& F
- if((USART_RX_STA&0x8000)==0) //接收未完成9 Y2 n* j; e2 N6 K! k% H% U
- {
7 C. Z2 |8 L' T - if(USART_RX_STA&0x4000) //接收到了0x0d6 D- ~4 ?& ^' }) S3 `5 O$ S3 r7 j
- {( q* v$ I' w J' |' ]7 J
- if(Res!=0x0a)2 N1 P: T5 c# O* T% _
- USART_RX_STA=0; //接收错误,重新开始4 p; E3 S& o: B7 A+ k% E
- else
3 a$ x# S0 \: ~$ y+ N! ?6 W* s0 z! H5 [ - USART_RX_STA|=0x8000; //接收完成了 7 ]8 D$ D, _7 ^! t$ `
- }/ q+ e+ \* C# k9 |+ B* E' x4 R1 @
- else //还没收到0X0D
/ P( ~$ |; G% u# U: E - { 9 w- B2 [: ^9 c! I3 O+ [
- if(Res==0x0d)
' ^, q+ L+ Q! @1 w3 F: j+ V, ?7 s - USART_RX_STA|=0x4000;
2 a R3 i" m. n9 A) o5 p5 Q - else
0 _4 @+ `" H! A* D3 `" N - {
. ]: R# h6 h, ?: ~ - USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;& x0 t G# E/ G! g: Z( J' X+ v
- USART_RX_STA++;
) C' P9 ~6 ?# ~* s4 ]- _# o( ]# ~" W - if(USART_RX_STA>(USART_REC_LEN-1))6 e, K- Z9 E- L- A1 v! c
- USART_RX_STA=0; //接收数据错误,重新开始接收
" ^* X2 c+ w$ G. e/ u8 X8 S5 B - }
$ I; S% \; h9 f8 e V - }* g# R! k" i+ O, A3 W( z
- }
$ g' w3 Q1 K, h o/ e0 I# ~ - }
" {6 P' S/ p- k9 I+ G9 |5 T - }
0 l. q) @- y4 I2 [: N: S* Y - #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
|