串口通信原理 想必玩过一点单片机的人都懂一点串口通信,而恐怕我们印象中的串口通信不过如此,两个芯片通过串口通信,需要共地、Tx(发送)和Rx(接收)相互连接即可:
8 p6 h: U$ W7 Z: x3 R: k8 C: B# ?. o; C# W/ X
而实际上,串口通讯种类繁多,即使是通用异步收发器UART也有RS-232和RS-485等不同接口,有兴趣可以深入学习。 , s7 k1 g; |1 Q( N$ F, @$ _
首先串口通信指的是一种设备通信的协议而不是指接口。串口通信的概念非常简单,串口按位(bit)发送和接收字节。而我们所使用的USART和UART的区别是可以同步,你在STM32的datasheet里可以看到USART2_CK,而实际上我们很少使用,我们完全可以把USART当UART来用。
! E! o, J# y7 z- B* P3 k( P+ R4 n/ d' v HC06蓝牙模块
( R9 w, N* R- {2 Y6 c无线蓝牙透传模块。
% c9 a! b% }4 {% P默认名字HC06、波特率9600bps、配对密码00000。
$ k2 G+ n \3 Y9 v8 d$ p
7 L- N1 Q# p' O, \* ]
6 I$ j& ]3 Z4 ]" ` L用Arduino的时候想必是很傻瓜式的,如果用STM32来做还是要了解一番的。4 X* `( Q6 |) n3 ^' R; F% D
* p( h) W2 [& B
首先好好看一下datasheet,看一下AT指令集,然后用一个USB转TTL的模块(这里用的是CH340)和电脑连接:
/ ]7 B% A: s9 M! O8 Q, ~
9 d$ z" ?# g: B1 U) Y2 {) ^8 e- @0 c6 s
可以看到HC06的指示灯一直在闪,说明蓝牙未连接。打开串口助手,试一试AT指令是否有效,然后你就可以设置波特率(建议就选默认的9600,据说快了会降低通信的稳定性),改名字和密码,详见datasheet。# g. N3 J: d: j4 z3 W- ~7 u8 I( a
. m9 i) A9 |* A% z% ^* m8 a0 Y4 L3 R# i: O* G5 x4 p6 i
) t: N" X5 s5 ~' v$ b/ B
! {$ f* b1 R. a+ V& ?: Y, V
打开蓝牙串口APP,会自动连接,连接以后指示灯就从闪烁变成常亮了。在串口助手里把HEX显示给勾上,然后用APP发几条指令,会发现收到这样:
! R" e t* ~) i5 D# ]9 j$ q: k) S8 v9 k) X6 U
% d# c2 \4 U# ]" K那就说明蓝牙这边不会出问题了,专心调试STM32吧 - -‘
4 O' s4 @# _1 y4 G, H STM32F407的USART2配置1 `& X7 t9 U& B' @4 l2 k; _
5 @' A' |* k+ F9 s. E* J; B: O% O
首先查datasheet表,找USART2对应的是哪个GPIO:
) k$ I0 F& H) Z) u# `$ {$ \+ L9 H7 H0 N% d( y. s
& d! G% G, K7 _5 G* E$ ~8 h" R
千万不要忘记查看总线!
2 C: l4 r# z$ Z: Y4 j- [$ l0 [. L: ]# Y2 f3 ?8 p G% v' W
) v$ f+ V( X& B
7 {; j: T( }! R8 S0 K) n& g
9 k" n* b; J# G6 ?+ C: S看了系统架构就会知道,F103和407的GPIO挂在不同的总线上。103挂在APB2上,而407挂在AHB1上,所以初始化时钟的时候千万要注意~
5 L# U# c* y9 ]& b3 U9 v$ N
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
复制代码 / O+ y1 g* ]0 Y+ D; ~% F
另外在配置GPIO时的参数也有不同:
5 n3 X& s, T9 x' T我们查看GPIO_InitTypeDef的定义:
/ U, @8 k. F$ ^0 O7 u6 W
- //STM32F103中的定义:
8 e1 D9 d$ Q0 I* N+ r - typedef struct( l' t: Z8 B3 v, I
- {
' |' h. B: A* ~" I% W6 p1 x - uint16_t GPIO_Pin;
+ V3 l5 v, \9 O1 a2 z - GPIOSpeed_TypeDef GPIO_Speed;
1 H! R9 O4 {! U) g. `2 K0 w8 V - GPIOMode_TypeDef GPIO_Mode;
! F0 H4 f9 i1 L0 C9 T8 E3 v9 N8 B$ z - }GPIO_InitTypeDef;% u/ V6 W* F0 C _6 t
- 9 ~. f6 s, v' _" d, }
- //STM32F407中的定义:" {3 n8 d2 ]: N% m* w* B
- typedef struct
4 i- L9 A l- N) w0 ~ - {
/ }' P/ Q0 J+ p; a, `* f - uint32_t GPIO_Pin;
$ P7 g. B; c# h+ N! t4 N- Y - GPIOMode_TypeDef GPIO_Mode;
0 `4 n+ C3 ?5 `: |, s) X - GPIOSpeed_TypeDef GPIO_Speed;
3 r% _7 x; N8 }; I0 @6 ~. z( R - GPIOOType_TypeDef GPIO_OType; " a L/ v1 m# t/ w0 X5 l+ p3 L2 o( T
- GPIOPuPd_TypeDef GPIO_PuPd;
- S2 W! o! ?, r u" E9 i9 J - }GPIO_InitTypeDef;
复制代码可以看到F407多出了两个参数,即GPIO_OType和GPIO_PuPd。 在F103需要分别设置两个引脚的Mode为复用推挽输出(GPIO_Mode_AF_PP)和浮空输入(GPIO_Mode_IN_FLOATING);但是在F407,两个引脚可以一起设置为GPIO_Mode_AF,并且都设置为推挽输出即可(这个我研究了好半天,据说是因为F1和F4的GPIO复用功能不同,F4复用功能不是在配置IO口模式这儿去配置,而是需要单独配置复用模式,然后再映射,总之就是F407配置串口复用的时候不管Rx还是Tx统统设置为复用推挽输出就好了。) 剩下的USART2初始化、中断初始化等都和F1一样。 最后详细代码如下: bluetooth.h: - <font face="Tahoma" size="3">#ifndef __USART2_H
- w: a$ y$ G% E! H6 V: x2 x - #define __USART2_H
# i; \; n- {; n5 b - #include "stdio.h" # Y# {& N( p- g
- #include "stm32f4xx_conf.h"
: e7 r: S7 u7 i+ p+ O% D - #include "sys.h" z% M$ P; d1 f# p
- 3 U8 B/ t) z4 g6 t
- #define USART2_REC_LEN 200
$ e' q s' V1 U+ W3 B- L& ~ - #define EN_USART2_RX 1
9 y0 y! {% E$ E8 c1 t
/ |1 t$ p: h' b1 i4 k& l, F- extern u8 USART2_RX_BUF[USART2_REC_LEN];6 h3 p1 E! f0 ~: p, Q
- extern u16 USART2_RX_STA;% ^5 ^* M: q( ` ]3 W) W
3 g4 j" Q1 A# k; i# O4 {. u- void bluetooth_init(u32 bound);
1 C; p- ?, M( m. m3 O- j( N1 G - #endif</font>
复制代码bluetooth.c: - <font face="Tahoma" size="3">#include "sys.h"7 k y* p5 R5 _4 S& d; @5 e
- #include "bluetooth.h"9 k1 q+ v2 b- v x2 |
- //这个是一个舵机控制板的驱动,感兴趣的可以看我下一篇博客9 N2 O- n+ r. u z) _' _3 S% i x! A
- #include "pcf8574.h"# M. T0 ^, K. y" B7 o$ H
- & N5 O5 x1 v, x7 T# P ]* Y
- #if SYSTEM_SUPPORT_OS; g3 z1 V k7 @7 F1 C& i' h
- #include "includes.h"
, D" x3 G( N9 d2 l2 }8 Y U - #endif; j$ b! c* {0 d8 }% F) \3 [
- 2 P" V# h T4 N! U k
- #if EN_USART2_RX
& D6 K; ]& c; T+ [) W6 w |
m1 [7 m* w& i/ V/ z- u8 USART2_RX_BUF[USART2_REC_LEN];) P) }7 \) A# K: y
. {+ a5 ]" x7 E0 g. V% c- u16 USART2_RX_STA=0;' X4 n# I& M. f6 B- Y' p
U# x; U# Y$ \4 N0 o! W% w! `- void bluetooth_init(u32 bound){8 C; L& j0 g8 U# d# B! e
& q' l9 a2 |. i- GPIO_InitTypeDef GPIO_InitStructure;% W* Z) p' i! D2 ^( n; O4 c! l
- USART_InitTypeDef USART_InitStructure;" [% y$ H; o1 n7 w4 o
- NVIC_InitTypeDef NVIC_InitStructure;& D7 Z4 Q2 s' z7 w" x
- 8 R6 e) _ M" b
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);5 }" E; h' }0 w/ h! _. i1 e
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);- G' J' u7 h1 ?* R" T
- " v* O+ t: f& }2 R
- GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
" e2 k c4 E+ \/ m) Q - GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
. X) R2 w' E& l0 _; q - ! h$ D% y7 n' l% h9 @+ W8 P1 B- T
- //GPIOA2,3->USART2RxTx
, g4 g* k7 `+ R( H+ W2 h, A - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
$ ]2 p8 g, ]5 E2 b - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;8 e+ j+ N8 p* R+ _, X
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
# R8 N- h. q1 @1 S - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
$ o7 V) \& M+ P - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;7 p) v2 ?6 V# q$ I) K5 b
- GPIO_Init(GPIOA,&GPIO_InitStructure);! P9 i0 g/ O' T( q' `
- ) ?0 g; {! R% f; I( v
- //USART2 init' C$ @3 Z) g8 I! d& ^
- USART_InitStructure.USART_BaudRate = bound;
@4 u5 ^0 v# }, B) g - USART_InitStructure.USART_WordLength = USART_WordLength_8b;
" l9 ~' v3 e w3 W7 l - USART_InitStructure.USART_StopBits = USART_StopBits_1;
! h5 u& p+ w0 _+ P - USART_InitStructure.USART_Parity = USART_Parity_No;+ `# y0 v" x; j; K- @3 z
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
7 J4 `8 L, ~! \' |: ~7 S - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; a: _7 r. [! [; W' C L
- USART_Init(USART2, &USART_InitStructure);
: T* l8 l( T$ r, v - $ d9 W4 M$ [# i! q9 F ]
- USART_Cmd(USART2, ENABLE); # v7 c7 l+ Q' W. n* }4 I
/ }( U; B/ L$ V, K( X& K- //USART2_ClearFlag(USART2, USART2_FLAG_TC);
. j$ C% S3 r1 `: S; m, y - - g5 }) Z0 N0 `2 t
- #if EN_USART2_RX
! f/ C% a2 l+ e: { - USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//interrupt
% R- x# O6 A! r* \2 n - # d6 U, z* q- U7 E" _
- //USART2 NVIC
! Q7 Y1 E* d; G - NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//USART2 interrupt channel# Q, t& C, I x2 \1 z% \
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
) ]9 @% H2 ?! N7 G3 s7 v - NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;. k9 j: E% `, }9 R$ N. U
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IQR enable7 l$ S$ u- f' X) }/ `2 A
- NVIC_Init(&NVIC_InitStructure);
- X% {' n c8 s9 U3 y- k1 o
4 K: C* t" J& a$ d' U& X7 y- #endif
4 V$ ]5 L2 Y3 v0 G/ s, E, Q - }
8 a6 _& ?' x" Q, D0 Q6 J3 N - # q1 }9 x7 |2 v
- + S) D$ i v* M$ z
- void USART2_IRQHandler(void)
, m& e4 l' K( t5 b/ k3 p4 F# V& M - {
/ Q' W( [* f6 B4 o) ~ - u8 Res;
: Y! C0 ]3 u2 l8 T7 D+ J6 V - #if SYSTEM_SUPPORT_OS
6 S, Y3 w: v6 b5 R$ P9 D( Q - OSIntEnter(); 0 q1 x% ?$ ^3 C, K5 z# B$ T- p
- #endif
0 D! x. d X7 u9 Q- Y2 I - if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
% z. F, \4 V1 B- H( { - {
, o) w% l" G# f- A5 E( W - Res =USART_ReceiveData(USART2);//(USART2->DR)
" x" m1 s, ^ \8 R8 G( e - // USART_SendData(USART2,Res);( e5 X0 c5 \, I- ]! r$ R
- if(Res == 0x00)3 D1 n: N0 q3 W- z4 Y. k
- down();
! K3 l* x- |1 w; Q5 x - if(Res == 0x01)
" N/ |2 v0 l4 |4 d7 o. H2 [ - up();
' a. i) A- L% {' m - }
" @7 l( F0 E: l1 W: y& ^! \ - #if SYSTEM_SUPPORT_OS
k% w5 o8 d) A) n2 M X" L- d* P2 h - OSIntExit();
0 Z- t6 {* N; ~* u- Q - #endif
, c0 _5 {) |- _9 A5 v* @ - } - w/ p+ S# V! p% o/ e. y
- #endif </font>
复制代码/ |2 e& h4 _& V8 f
0 S0 f d2 u+ l2 h( h- U7 e v# F) `# `0 ]0 W% O' f' A
+ |; I# Z8 J# }. x" ]7 m `4 C _$ j2 E3 Y- S2 E1 J1 I0 H
|