|
串口通信原理 想必玩过一点单片机的人都懂一点串口通信,而恐怕我们印象中的串口通信不过如此,两个芯片通过串口通信,需要共地、Tx(发送)和Rx(接收)相互连接即可:
0 u$ H$ F, M j3 J% @
$ P9 @ M ~- S! A( |/ \而实际上,串口通讯种类繁多,即使是通用异步收发器UART也有RS-232和RS-485等不同接口,有兴趣可以深入学习。
" a2 m/ d' c/ \5 H( x0 E `首先串口通信指的是一种设备通信的协议而不是指接口。串口通信的概念非常简单,串口按位(bit)发送和接收字节。而我们所使用的USART和UART的区别是可以同步,你在STM32的datasheet里可以看到USART2_CK,而实际上我们很少使用,我们完全可以把USART当UART来用。
* w. Z, i7 _' Y) g a: A( v
HC06蓝牙模块/ L+ q* \/ d+ x, w- L
无线蓝牙透传模块。
+ x! y6 d( i( A2 `默认名字HC06、波特率9600bps、配对密码00000。
- b- l' e# h$ D/ q' n& t) p' D& w9 N4 Z' l! {. m
! y/ M( c* `# o4 @用Arduino的时候想必是很傻瓜式的,如果用STM32来做还是要了解一番的。
5 E0 k( i8 E2 W* T4 c4 j' a ~
# c& [3 X x9 I. q- y" D1 n% d. @首先好好看一下datasheet,看一下AT指令集,然后用一个USB转TTL的模块(这里用的是CH340)和电脑连接:# m K- S6 ^! l" y6 V3 V8 s
# Q- S& X+ \3 h* h% h7 K
' I9 t' j! t ^& K$ L& w. {9 ^
可以看到HC06的指示灯一直在闪,说明蓝牙未连接。打开串口助手,试一试AT指令是否有效,然后你就可以设置波特率(建议就选默认的9600,据说快了会降低通信的稳定性),改名字和密码,详见datasheet。4 L m! k! Y3 Z% V# v) K: I
c9 A% A! k1 j" @7 ^4 l
% G0 q3 l9 X0 G" u% s) a* A- c
9 A$ h* d) d& H4 z! R8 |
& b! j' l- X0 D) d打开蓝牙串口APP,会自动连接,连接以后指示灯就从闪烁变成常亮了。在串口助手里把HEX显示给勾上,然后用APP发几条指令,会发现收到这样:
$ \% f% i f0 \: j7 h! g' T) c( a5 G* U \4 _7 G
F8 \. f6 G; c5 L# C5 t B
那就说明蓝牙这边不会出问题了,专心调试STM32吧 - -‘
1 v. \# o( ]' l4 H STM32F407的USART2配置& `- y2 Q2 K8 A# a" n6 J" h
h% q d- o' k
首先查datasheet表,找USART2对应的是哪个GPIO:; v2 E) G7 T( ?1 ~' D# r/ B- R
) h& x/ Q! W+ g" A7 l( K
x4 W; p( @* _4 N+ ? u' v' t6 p% ~ 千万不要忘记查看总线!+ J& q; w& I& l3 I4 B+ W: Q x- ?
q9 G- y) b* |9 [; {# t
, S( e# Z1 C/ A2 w
; F, ]: s8 V1 O: q# K" h
* f3 k4 F3 t. K; ^) d' W) g看了系统架构就会知道,F103和407的GPIO挂在不同的总线上。103挂在APB2上,而407挂在AHB1上,所以初始化时钟的时候千万要注意~ & {# R& Y/ Q8 Q- _
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
复制代码
4 O( t+ n. p* w8 Y另外在配置GPIO时的参数也有不同:- _9 @, t w- a& V. ~: ? v
我们查看GPIO_InitTypeDef的定义:
- d B3 M' N1 m5 a- f
- //STM32F103中的定义:
. x' z+ f+ L( D# A# B1 K# Q - typedef struct
. V" W( t4 n0 C; _( L5 _# Z - {
6 p5 r$ `, K; h' @ J1 i - uint16_t GPIO_Pin;
0 j' ` q+ T8 q0 w0 ~8 n - GPIOSpeed_TypeDef GPIO_Speed;3 j }; U+ w9 ?" q3 Z5 q
- GPIOMode_TypeDef GPIO_Mode;
9 S; K/ v) q$ b( m+ A0 U5 \0 ? - }GPIO_InitTypeDef;' ]8 }9 n. n6 x: Q: _
- ; n; J s1 a+ P1 u2 t' ~$ C; D3 k
- //STM32F407中的定义:& O; y0 S/ J% C' e
- typedef struct( q3 Q- w; z# S- N/ o" v4 o' c
- {
9 g3 O x% F) H4 L - uint32_t GPIO_Pin;
. z# [( G- y9 [5 l" o3 Y - GPIOMode_TypeDef GPIO_Mode;
% u! N T# E6 U I" Z; G5 m# j: P" D9 G - GPIOSpeed_TypeDef GPIO_Speed;
# F( Z" x D7 } - GPIOOType_TypeDef GPIO_OType;
, P' ^* L5 b A/ v9 L - GPIOPuPd_TypeDef GPIO_PuPd; * r4 x; H* l8 l7 L# _
- }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
0 G$ K6 E& d: {# d; q7 Z - #define __USART2_H
* \& l- ^0 J$ l/ \( k& C6 g - #include "stdio.h"
$ V: F9 D L1 r+ o. ?- y, L3 v' P - #include "stm32f4xx_conf.h"- t& O# G$ x6 D3 Q5 z
- #include "sys.h"
5 ^- P& H& Q n7 ?: M
5 k4 H) I" v+ P- #define USART2_REC_LEN 200
( `7 F- E/ K# D. F - #define EN_USART2_RX 1
6 v7 I! }* m7 W9 i2 I, u
/ L4 q3 g3 g& b- extern u8 USART2_RX_BUF[USART2_REC_LEN];* I' q& a2 Y5 E% X: s1 M
- extern u16 USART2_RX_STA;
' u7 E. C. d) q' ~ - 2 X2 u: t# T3 A9 K/ v- x' K& c
- void bluetooth_init(u32 bound);& A2 a) R; n7 a! C4 a ]
- #endif</font>
复制代码bluetooth.c: - <font face="Tahoma" size="3">#include "sys.h"0 T- I" b" a: S3 P+ v# i" u. y9 C
- #include "bluetooth.h"! d! K5 ^0 e y
- //这个是一个舵机控制板的驱动,感兴趣的可以看我下一篇博客9 }! [8 \" L3 `8 f* ^" S% l9 I
- #include "pcf8574.h"
( }# D8 P5 d( F) ^( x& J8 {2 ?
: T: B/ ^ M2 g& }/ E- R- a- #if SYSTEM_SUPPORT_OS' i& T C3 X z1 o8 g9 R9 ]
- #include "includes.h"
9 t6 x: ^+ }$ z/ q - #endif. t+ R; ~% l7 k
- 4 S! p) A1 Q% [8 C0 x A
- #if EN_USART2_RX
, ^# o2 y" W0 ]/ w3 A
0 |% o4 R% u# c- u8 USART2_RX_BUF[USART2_REC_LEN];, P5 [, m' e2 c; R
- 2 V# {, r+ U$ D' }
- u16 USART2_RX_STA=0;
9 {5 [+ [2 P) u8 {- {- W. C
( c, o6 H/ W$ f3 `. W- void bluetooth_init(u32 bound){* p5 V& D2 \% Y a
1 e$ ]5 C# W/ R x- GPIO_InitTypeDef GPIO_InitStructure;
1 }. z) q' N+ Q3 A$ R) s6 A - USART_InitTypeDef USART_InitStructure;
1 Z3 N n2 i& ^, X - NVIC_InitTypeDef NVIC_InitStructure;
0 A3 n! i3 F+ C8 @/ ] - " t4 s* G* x/ m% x- K0 n6 M: V5 u
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
" K; Q3 V5 M1 I8 s6 V, x - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
2 n }: w- [* m# f) u: T% D - 0 Y8 o( R7 {6 n! B9 F# [) S
- GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
7 h2 D2 u1 J2 C$ n - GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
7 Z$ O9 u$ q' }, U
0 K0 ~: Q( q. D3 g( f3 U- //GPIOA2,3->USART2RxTx
" a6 W/ n$ k" F/ l+ e* @8 X! _ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
: s. v1 B$ L; I) K4 y. t - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ h3 ~# X' s# Z' u. {. q - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;( E, }9 P& G% v( h" T( R% G
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
7 a8 L! O' x. n( c1 h7 f' i+ S0 y - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
! i: R! w4 Y2 ~% s$ m" b) z - GPIO_Init(GPIOA,&GPIO_InitStructure);. W1 X3 R& c9 p9 ~% p
* a# \9 I8 c2 F- [- S* n4 o5 u- //USART2 init, ~6 l/ I* z' ?% X- S1 w
- USART_InitStructure.USART_BaudRate = bound;) D/ j0 m# A* T
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
% G5 d& a; V2 w1 I% P% }6 E- Y - USART_InitStructure.USART_StopBits = USART_StopBits_1;, o& @( Y) u+ u% h6 j0 }: t
- USART_InitStructure.USART_Parity = USART_Parity_No;% P' F$ w* t/ V( g" i
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
! {; u V1 a" ~2 E8 y4 D. F - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;4 t' L! }# N/ l( n0 [
- USART_Init(USART2, &USART_InitStructure);; F. O2 x8 d8 F; P0 ?" Z3 {- y
- 6 [) G$ s }+ Y& i% R
- USART_Cmd(USART2, ENABLE); " b; l2 }' G% k% h8 i7 Z) e; h5 b
- T6 v& Q/ M, W2 o# n- //USART2_ClearFlag(USART2, USART2_FLAG_TC);
- R5 [% `% S4 w# y9 A% E
0 F- Q, d7 K0 g% N5 `5 x- #if EN_USART2_RX
. C) v6 X4 O4 S2 T+ J+ U - USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//interrupt- W) c4 B2 W; V& \' N4 V" C
- : f" D" O$ n+ V4 P- V& T4 F4 r
- //USART2 NVIC" r+ W" E% B m& s8 e
- NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//USART2 interrupt channel0 J( ~4 T' I8 @5 }
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;7 x6 ]% j% H$ m: k, \
- NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;5 s, Z% b% C& G" z/ K
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IQR enable
1 _3 h9 I* ]# b8 ~ - NVIC_Init(&NVIC_InitStructure);7 h; n! x) c% ~# l
- 3 D: M1 w, d. G E6 b& Z
- #endif
9 D8 h7 v ]" r/ ~ - }# a; e7 g% f/ q
! C8 L* n7 D4 e0 {' R( l- 1 B+ |; Z# R+ A: {+ m
- void USART2_IRQHandler(void)
, t8 Y( ?$ A$ Z# d - {
# @, ^" E n8 b6 t$ E& U - u8 Res;0 U7 y) n! ?* j2 M
- #if SYSTEM_SUPPORT_OS7 A# Y! _; }. E& [( u
- OSIntEnter(); H7 @7 t; U/ f \
- #endif
$ r0 z+ b t( C' A4 X/ Y' f/ o - if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
; t5 ~+ U& b6 F - {
( g# F X3 x) E' m - Res =USART_ReceiveData(USART2);//(USART2->DR)
7 I9 G" t: @! Y" P4 L+ { - // USART_SendData(USART2,Res);
4 Y, a. e$ ]: n) i9 A - if(Res == 0x00)
9 |5 d. c( c3 V; p - down();* P q! d3 w& ]0 k+ x% M
- if(Res == 0x01)5 ~' w) M5 ]" A& A& C" `" H
- up();
# r0 W2 {/ P: L m - }
# {2 b( f0 h- t - #if SYSTEM_SUPPORT_OS6 e7 a0 {2 ?2 r
- OSIntExit();
4 E: {' x9 G3 r' b0 \4 D# P - #endif
- s3 ]: i" x0 N+ Y. p8 r9 Z* ~ - }
$ t" r' r$ G* e4 M; D; o6 d# K - #endif </font>
复制代码& l( b0 w, z+ X7 a7 f. U4 H
8 F1 M1 Y; Y! S) z9 V6 {
6 J! z7 O6 D3 l% @0 G! I( N
# f) w0 y0 }! r: y$ a
' @4 F" h: W# o |