|
串口通信原理 想必玩过一点单片机的人都懂一点串口通信,而恐怕我们印象中的串口通信不过如此,两个芯片通过串口通信,需要共地、Tx(发送)和Rx(接收)相互连接即可:& ?1 |1 `7 }. b& C/ U0 o
! K, _' {) \7 Z" v
而实际上,串口通讯种类繁多,即使是通用异步收发器UART也有RS-232和RS-485等不同接口,有兴趣可以深入学习。
) H% Z+ A9 c! k1 V4 d; f: l首先串口通信指的是一种设备通信的协议而不是指接口。串口通信的概念非常简单,串口按位(bit)发送和接收字节。而我们所使用的USART和UART的区别是可以同步,你在STM32的datasheet里可以看到USART2_CK,而实际上我们很少使用,我们完全可以把USART当UART来用。
, d2 [' @3 L/ J: X8 V- Z: y2 d HC06蓝牙模块' u' f+ V1 z/ e0 R0 T, L& Q% z
无线蓝牙透传模块。 . I7 d, m( d% K3 ]1 C
默认名字HC06、波特率9600bps、配对密码00000。
1 {9 Z; h! Q' H# I5 u) ~
+ p: A$ c( J5 [7 p; @* |) p 9 ~% E9 n; a+ I- a- R6 ]# l
用Arduino的时候想必是很傻瓜式的,如果用STM32来做还是要了解一番的。
7 C' n0 t4 |( {$ x A/ x: o, r( Y4 y$ y _5 A5 V" d9 U0 v
首先好好看一下datasheet,看一下AT指令集,然后用一个USB转TTL的模块(这里用的是CH340)和电脑连接:# g, C, d L$ s t4 ~) W( @ F
' u: k& I# Y1 H5 Q, p' k
) ^& j$ B V6 G* V: F& {( h6 s
可以看到HC06的指示灯一直在闪,说明蓝牙未连接。打开串口助手,试一试AT指令是否有效,然后你就可以设置波特率(建议就选默认的9600,据说快了会降低通信的稳定性),改名字和密码,详见datasheet。. l# P {8 w$ t" x, u
- i. W+ J! i4 A
7 h3 f( Z z- e8 n: A0 X1 E
5 L1 S% k( [ [5 b1 Q/ B- o
9 w4 d" W0 @+ s# a打开蓝牙串口APP,会自动连接,连接以后指示灯就从闪烁变成常亮了。在串口助手里把HEX显示给勾上,然后用APP发几条指令,会发现收到这样: . E( k' }/ ~; ^! r0 C5 I7 T
' `9 y, Y9 v% W) h' u- P4 X8 E
+ L* t& G/ f$ |, \那就说明蓝牙这边不会出问题了,专心调试STM32吧 - -‘ 2 [' p& E! @: m/ m
STM32F407的USART2配置
; h5 m2 d1 ]0 E7 {
1 b) o+ X7 w& M5 B5 f% a# V3 S R: l首先查datasheet表,找USART2对应的是哪个GPIO:
$ [6 H5 C; Y6 u1 x, W+ u
8 ~- r `1 v e
/ R5 B7 i n4 h7 g' Y% R6 g 千万不要忘记查看总线!4 |- U) G7 O& R1 q7 Q! s5 R, L4 C% N) k
/ g q& w( p$ a/ t1 ~; S: p" w D' @, r
( r1 k" Z+ N0 t# K( w* h* w- @
+ n0 D4 x+ u1 q% g$ C* e# Y; L8 T6 ^1 U6 B0 ^- G
看了系统架构就会知道,F103和407的GPIO挂在不同的总线上。103挂在APB2上,而407挂在AHB1上,所以初始化时钟的时候千万要注意~
. [, D+ l) ]% a% A4 x; Z0 j- x, K
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
复制代码
% ?. T( O4 P. n; w4 `% E! g另外在配置GPIO时的参数也有不同:
7 }4 l; O9 R# w我们查看GPIO_InitTypeDef的定义: & E% J$ C1 V; |2 G6 M
- //STM32F103中的定义:' E, g& S7 f4 X9 \% S
- typedef struct
/ U. d: p! ~: v% N. o - {/ B) x) u! r& F7 e' B
- uint16_t GPIO_Pin; ) b9 p: b0 d: h
- GPIOSpeed_TypeDef GPIO_Speed;4 o. E) H" {& `* E. d# `! P
- GPIOMode_TypeDef GPIO_Mode;
$ J3 t* \! @# d) b( Y - }GPIO_InitTypeDef;
& | w% o1 {8 |1 Z$ X, q& f
1 l A0 @! n& v6 V& L) y2 s s- //STM32F407中的定义:
; z8 E& E, f2 L) E+ g - typedef struct) a, ~7 D" T6 ]+ M6 V" p
- {
2 v" c# l' \) Q5 d- V - uint32_t GPIO_Pin;
& R% a T8 S/ b8 K1 k - GPIOMode_TypeDef GPIO_Mode; % _, V& _9 O7 g7 G* m, z$ L
- GPIOSpeed_TypeDef GPIO_Speed;5 j& F& {# W/ {4 l0 D* m7 M
- GPIOOType_TypeDef GPIO_OType; ' ^: o! e9 w/ o2 E" W# Y$ K
- GPIOPuPd_TypeDef GPIO_PuPd;
* ^# i. m1 ?7 z: F - }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# Q, x0 W) t F4 [) w- V6 m. p
- #define __USART2_H
! Z+ v, H* d/ G' ?4 B2 k4 N - #include "stdio.h" " j- e$ S& N- N! O0 J8 e: F. M
- #include "stm32f4xx_conf.h"1 G8 z/ V+ n4 I% `* A3 q1 W
- #include "sys.h" 9 c5 K5 p4 u: A; t
- * x: ?6 b+ p& ^# J" U( }! M4 P
- #define USART2_REC_LEN 200
2 Q- X& c% R+ K" k; L% j$ k - #define EN_USART2_RX 17 J" ]4 j5 Z; R6 F" ?8 y, x, T
- ! m, I7 U1 H0 e* _4 |
- extern u8 USART2_RX_BUF[USART2_REC_LEN];
* C5 N- s9 k2 B, b- O6 o+ \ - extern u16 USART2_RX_STA;" ?3 w" q& \$ T, Y; U4 A' z
8 v/ @( L! |$ j- void bluetooth_init(u32 bound);
0 F# f/ q6 j! M5 O- n - #endif</font>
复制代码bluetooth.c: - <font face="Tahoma" size="3">#include "sys.h"$ |' }- ^$ _! m( x
- #include "bluetooth.h"
. ?3 u8 q( |8 T - //这个是一个舵机控制板的驱动,感兴趣的可以看我下一篇博客
n" T! [ {: ?; k - #include "pcf8574.h"
, |1 E' w7 m7 N8 h" Y0 d1 D
V1 K* D4 L3 j! Q; \8 U- #if SYSTEM_SUPPORT_OS
2 u$ ]; O' p% p7 f - #include "includes.h"
: |0 r) U$ x: U) D6 j - #endif
$ J1 r+ d- t! I; K7 e1 ~" Q- D8 M( x8 } - d* s5 ]3 E! j4 B0 `7 b
- #if EN_USART2_RX- _/ ~6 o& z0 U
- ! w0 g0 @( O$ F$ w9 j; S# I
- u8 USART2_RX_BUF[USART2_REC_LEN];# `9 ]. p' ]: s) V2 j7 i: G$ d/ J
- 6 l% _2 T+ K5 ?+ H3 m
- u16 USART2_RX_STA=0;; s" Q2 r- E( w% B
) h8 t) O! V# e' w1 _- void bluetooth_init(u32 bound){7 w' ]6 {' Y( k+ m, z$ ?
- $ p. `3 f0 c" y& b: u/ R/ j
- GPIO_InitTypeDef GPIO_InitStructure;
! E! [0 R6 K+ y/ h - USART_InitTypeDef USART_InitStructure;
5 M. n8 B7 T' K# l3 y0 s0 t; Z - NVIC_InitTypeDef NVIC_InitStructure;
9 t8 N. G0 W( V& I0 T/ N+ P - & o0 R2 A q& K6 X, Y/ B
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);& J3 {- ]' |# B. W) @
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);6 b5 C3 `1 W7 a
- s# E$ [" n c- V
- GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
) \9 M0 C2 }) h* T) Q. [& _" _ - GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
6 g1 a7 V' P# x" H
7 i; S! O7 _ n* e4 ` K' y V- //GPIOA2,3->USART2RxTx
9 P6 W- [3 ~% e- B$ L) K3 ?2 @ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
9 M3 y+ J' d: c9 _+ F- e - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;# {; {' L: z v& g/ Y: C* m
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
( u% u- J# J' |! `% N" D7 o6 M - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
0 h& ` N4 r# Q2 H- _% _$ ^, ? - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;* D& t. @# t: P" ~" [
- GPIO_Init(GPIOA,&GPIO_InitStructure);5 E6 K6 q9 a5 J6 \6 J
- , I0 o$ i+ H! N ^% k
- //USART2 init5 \( b( x9 r" r5 |7 _5 Z
- USART_InitStructure.USART_BaudRate = bound;
/ ^* _" \, [) A# \ - USART_InitStructure.USART_WordLength = USART_WordLength_8b;
5 w Y& j$ h- u& ?( S - USART_InitStructure.USART_StopBits = USART_StopBits_1;/ z' ^% _. I+ I
- USART_InitStructure.USART_Parity = USART_Parity_No;+ t8 \; _- H0 H
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+ W! t p) w2 T) X, ~ - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;9 D) Z3 t# G1 D! T- j) |4 w3 f
- USART_Init(USART2, &USART_InitStructure);
" m) P! [$ j L8 B7 r% Y
4 q% M, L; k" ~9 V& N9 C- USART_Cmd(USART2, ENABLE);
A1 V6 R& G$ f! k2 `' G
: A- n# p" M% q E- //USART2_ClearFlag(USART2, USART2_FLAG_TC);
+ }- E) S% W3 Q7 C6 W
' ~$ ^7 \- m( {9 }' t- X- #if EN_USART2_RX 6 E! \6 U, v2 u$ v/ {, L8 f; d" ~2 W
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//interrupt
& \, `: T/ h7 v; x9 U5 m7 T1 u2 ` - 3 r/ i' ^3 t8 o0 F" T) s, p+ M
- //USART2 NVIC' P! g) {0 u* i
- NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//USART2 interrupt channel
& K" R% i5 n$ z9 C, n - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;( L% O# B; b& l6 W2 S
- NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
; d" T8 `6 p+ B - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IQR enable7 A3 `& a Q4 H6 Z! d8 B
- NVIC_Init(&NVIC_InitStructure);
8 y2 h7 r5 Z" ^# B" e* f u4 Q
( O! Z5 O i5 w# w- #endif1 J% K& H3 K6 U; M2 s6 H
- }
& M0 G5 [# {; c
" T; T1 L% ?0 N# Z
5 G- L- U8 Q2 }! \2 U* t U- void USART2_IRQHandler(void)
' I9 Z- w7 A P- y5 o+ F# b - {* K/ c7 @) q- _6 h5 m
- u8 Res;# M4 Q9 i1 V# `/ ~- b0 t
- #if SYSTEM_SUPPORT_OS
: C4 W T3 i- O0 N5 s$ w - OSIntEnter();
" a* a: z! Q/ N _ - #endif
1 \9 l. n- e% n/ d$ c - if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)' d ]- T5 }- h7 D2 G8 |2 R; M4 A
- {9 h+ O* a' _7 Y) D% ]
- Res =USART_ReceiveData(USART2);//(USART2->DR)& p# D: q4 o7 {" x9 i
- // USART_SendData(USART2,Res);
- L: v4 {0 y$ M m8 \7 R- Y - if(Res == 0x00)
# y1 F) D9 U5 H- m8 o# n- l: X - down();' ]7 I3 p% x) u$ J. @
- if(Res == 0x01)
p2 j. f( v. I" r- Q - up();
' O3 A% Y) n" p' X1 ~2 H& V# a - } ( b9 k5 M4 b: S: L& b
- #if SYSTEM_SUPPORT_OS
% R1 d3 L% M! Z; W- c - OSIntExit(); 2 `4 M2 S( s( Y: s2 U( g
- #endif* n F# b7 U" M& b3 W# g4 _
- }
8 D9 j% a! Y0 T) b/ Z- M! `* u& i1 G V - #endif </font>
复制代码
8 g* X- D# L/ v: Q. T! k
7 m0 Y# ~" Q1 X0 {
& A$ ^7 {7 L; R- Y: ?* A+ j) \) j% @' W
5 j: n& f0 T5 O% N" p0 u8 X: b1 [0 T |