串口通信原理 想必玩过一点单片机的人都懂一点串口通信,而恐怕我们印象中的串口通信不过如此,两个芯片通过串口通信,需要共地、Tx(发送)和Rx(接收)相互连接即可:
2 g- K$ S$ {' Y( `: W1 n2 a, n* X7 d' ]& w$ }+ g
而实际上,串口通讯种类繁多,即使是通用异步收发器UART也有RS-232和RS-485等不同接口,有兴趣可以深入学习。
5 M2 y+ b; s/ Z5 c, L8 \首先串口通信指的是一种设备通信的协议而不是指接口。串口通信的概念非常简单,串口按位(bit)发送和接收字节。而我们所使用的USART和UART的区别是可以同步,你在STM32的datasheet里可以看到USART2_CK,而实际上我们很少使用,我们完全可以把USART当UART来用。
: R" j( c, X% o* B3 E
HC06蓝牙模块
( K6 W( Z- Q" d( u" V无线蓝牙透传模块。 6 Y! A% O& W9 ~- e5 F
默认名字HC06、波特率9600bps、配对密码00000。
8 e3 I4 V+ @ p$ E. C7 `% W& p% K" g! l8 J; s& f. u
* I) A) B3 w7 K' P7 D用Arduino的时候想必是很傻瓜式的,如果用STM32来做还是要了解一番的。
4 Y" d. Z F- S8 l6 p7 d; p
1 H1 v7 p+ Q! }$ g首先好好看一下datasheet,看一下AT指令集,然后用一个USB转TTL的模块(这里用的是CH340)和电脑连接:
3 S8 ?1 v+ _6 q& ?0 C
1 |2 `& e5 {2 m$ h+ ~" i5 s9 ~8 h X' s
可以看到HC06的指示灯一直在闪,说明蓝牙未连接。打开串口助手,试一试AT指令是否有效,然后你就可以设置波特率(建议就选默认的9600,据说快了会降低通信的稳定性),改名字和密码,详见datasheet。
+ {) o$ L1 l9 z
% M( o; z* ?& L: ~
- K- P) t2 q, l: I% \9 O9 D; I9 v7 P& P- @0 q
7 u# L( Y4 n* ~3 i9 `4 {
打开蓝牙串口APP,会自动连接,连接以后指示灯就从闪烁变成常亮了。在串口助手里把HEX显示给勾上,然后用APP发几条指令,会发现收到这样:
2 V b! c; p3 b! K! t; P5 R- @# j( I4 O3 V) @
' m! L4 \! Z7 d6 P& j t; g* f* u
那就说明蓝牙这边不会出问题了,专心调试STM32吧 - -‘
% \3 N, o: c4 d# e( B, E' k0 K. a1 Z
STM32F407的USART2配置
1 n) }$ V V( j {. U& P( d, n1 @/ S
首先查datasheet表,找USART2对应的是哪个GPIO:/ U0 ] j5 x* U- d" x7 v$ @7 Z9 C; y
* y! ^7 F! r! Z: i, k6 U+ m: ~
/ i% ]! ~% `+ `* W" ^) E! f
千万不要忘记查看总线!. k8 J2 L( s5 g3 F9 X
4 H+ G1 y! N( i3 ?& z4 K
! I0 f# b/ U+ |9 c5 Y& U
# a0 V* B! `/ X7 {- ^/ F( I1 B- D2 E2 n- \$ A
看了系统架构就会知道,F103和407的GPIO挂在不同的总线上。103挂在APB2上,而407挂在AHB1上,所以初始化时钟的时候千万要注意~ 3 e1 U2 @% p. A8 Q1 H
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
复制代码
. L x" D- L8 a+ i& P8 `( @9 _另外在配置GPIO时的参数也有不同:
/ I0 _1 a: D7 a3 X; n$ l0 F我们查看GPIO_InitTypeDef的定义:
- l, U( j5 Z9 {
- //STM32F103中的定义:$ M+ f8 K8 H$ A! h# m
- typedef struct
, v5 W8 X2 m2 u$ G# l - {
0 X; V' \, v; G- b. }! a - uint16_t GPIO_Pin; % E) K1 S: h1 Z' \3 e# o
- GPIOSpeed_TypeDef GPIO_Speed;( w, h* R- ?: y. ?! e& N
- GPIOMode_TypeDef GPIO_Mode;
" `/ F4 w. Y' v+ y+ C! | - }GPIO_InitTypeDef;5 p4 l; j# T7 M0 S8 W# z) f' G. ?
5 i3 e7 P6 ~) x9 U: L1 @7 |& e ], D- //STM32F407中的定义:
* b& E! [$ V- [, W' A1 i M - typedef struct
: v; d+ v) k5 | - {
6 F( \/ m6 |; i: O - uint32_t GPIO_Pin;
# ~7 s" }% ?% y8 h, ~8 n* x - GPIOMode_TypeDef GPIO_Mode; 9 l0 q6 V- p5 O% o
- GPIOSpeed_TypeDef GPIO_Speed;& H: C* ^ Y$ g# J1 d# C
- GPIOOType_TypeDef GPIO_OType; % M6 O G0 U2 T9 p2 S' N8 v
- GPIOPuPd_TypeDef GPIO_PuPd; ; C! C2 i2 e5 q
- }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
$ y" {# k7 W6 G) ` - #define __USART2_H0 ^$ D% q+ M3 e8 s' e0 i6 a+ c
- #include "stdio.h" : x5 J! B# n$ s; v+ ^8 O
- #include "stm32f4xx_conf.h": s; g1 O( t" }2 U* F/ o$ C
- #include "sys.h"
5 J' q, i" H, ~: r3 n$ c, K - / b: {0 d2 U& [
- #define USART2_REC_LEN 200/ |) Y" L G; A2 X2 K3 C6 s
- #define EN_USART2_RX 1
+ J8 I$ D7 j7 j - 4 o ?( v/ v/ D2 N& D4 ?2 z
- extern u8 USART2_RX_BUF[USART2_REC_LEN];6 `4 o$ u# v& d. _/ ]
- extern u16 USART2_RX_STA;
, @7 k- A4 ]! n% l6 L- s7 k. s5 Y
/ g a6 Q5 O; _5 v- void bluetooth_init(u32 bound);; e/ D4 c! y7 L% K
- #endif</font>
复制代码bluetooth.c: - <font face="Tahoma" size="3">#include "sys.h"
4 |/ l- L+ b; S0 l! ? - #include "bluetooth.h"
8 }. x5 B" `9 d* v M - //这个是一个舵机控制板的驱动,感兴趣的可以看我下一篇博客. M9 T8 w) U0 @) A
- #include "pcf8574.h"
, s5 x. B. _5 _( O& Y
7 n8 ?9 s5 c: E# T# _( u5 ]0 X- #if SYSTEM_SUPPORT_OS
0 o: q/ H$ v% ^$ |2 a6 m1 ~ - #include "includes.h"
, o# G- R2 O- M7 {+ I! f' R+ E: ` - #endif
$ _- E9 W* J1 d% U9 T: V# } - " w5 I! T/ o+ y7 X
- #if EN_USART2_RX
g2 f& S) R3 ~, l1 K- Q; ~: I6 h- X
3 r7 d _! \* M8 \& U3 I9 m( |- u8 USART2_RX_BUF[USART2_REC_LEN];% n2 x2 I+ ?8 c, e6 l
& h/ w5 L6 }4 r" E- u16 USART2_RX_STA=0;5 c2 b9 }# r: j+ Q& ?
- ( u# `: R6 c: Z% M
- void bluetooth_init(u32 bound){3 P; s5 J! h+ `$ u2 a3 f
$ k. ^6 M7 ?3 }0 a# R- GPIO_InitTypeDef GPIO_InitStructure;& ?' v) ~& y6 T+ L5 N
- USART_InitTypeDef USART_InitStructure;, e- J* K. u5 Z1 H
- NVIC_InitTypeDef NVIC_InitStructure;# [! h% r* m( K# {1 @+ B
- ; q# X3 n% V$ C0 O
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
/ f' P( J* k1 L! k5 A/ u6 U6 `2 I4 i - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);8 W7 K2 }- w# \ t3 `
8 Z9 p8 J D' i# v8 [! G- GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);+ a2 f& V. @5 d3 m' N$ c6 a
- GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);# H f- _' T, n1 [, e
; e. Q7 z( X% d4 a2 U" K; A; K* Q- //GPIOA2,3->USART2RxTx' N6 B4 P, \3 ^/ W/ [
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;8 p1 q$ s) J b" t0 \
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ a' x8 A. n5 H9 @! ] - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;: F5 }* z7 a# v' n" K
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
5 {. B2 W2 M/ |% T - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
, e; x# o' }# ]" j9 t - GPIO_Init(GPIOA,&GPIO_InitStructure);. n$ \ u$ B" \3 r, [0 ^1 D( f% g% @
0 ^9 S5 ~( E2 H% \) ]- //USART2 init
% j( Z6 Y- q. W4 R4 r7 d4 y - USART_InitStructure.USART_BaudRate = bound;
" n( Q, t9 b3 F* O. N* E - USART_InitStructure.USART_WordLength = USART_WordLength_8b;& b5 n5 w- w6 ^4 |; E6 c/ o9 g9 P& _# `- |
- USART_InitStructure.USART_StopBits = USART_StopBits_1;' l* p; g5 u3 b& m7 V
- USART_InitStructure.USART_Parity = USART_Parity_No;4 ]$ T4 J; f' r$ d
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;2 i& X) N9 g: E/ `9 U( g
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;9 i# z2 ?' d' y4 o) t
- USART_Init(USART2, &USART_InitStructure);$ ?2 u2 z& G" F) N" C' K) V
. X! A4 t5 F9 P8 N8 E# p- USART_Cmd(USART2, ENABLE); 1 E& `* V$ _4 ~5 F5 A" Q" ~8 y
- 9 ` T$ _9 i1 u) y+ S
- //USART2_ClearFlag(USART2, USART2_FLAG_TC);" i! f9 e0 T+ L, G# z3 r* V, w
- 8 x4 F- f5 @& N7 ?7 J
- #if EN_USART2_RX 9 a3 [# I$ ^7 M4 B3 R
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//interrupt5 e& P0 P4 y) t3 {$ o
" F3 h' |/ l! i0 R- //USART2 NVIC2 O) N. Y h4 U1 Y9 q
- NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//USART2 interrupt channel
7 ~: j' w8 h# ^: j+ l - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;9 Y# `% y. f& [
- NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
; B$ a$ T7 c- |0 \5 ? - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IQR enable
8 z% w, O, s W7 _ h) `! K9 |/ r - NVIC_Init(&NVIC_InitStructure);/ n' _/ v, t+ D
- " U( i) G/ g- ]+ ] Q6 v' X4 z) p
- #endif6 G7 i! v; Q( [" _. ~5 }
- }4 g, ~, P# E6 @1 k
- " S" E: o8 S* L& E( Y/ m9 B
; e- _# x, n6 [5 I$ ?& u5 U3 n- void USART2_IRQHandler(void)
7 F: o3 U3 P! v. X - { \* h9 k4 l+ n& O0 O
- u8 Res;: p' `2 q' x! ?5 N. r& q
- #if SYSTEM_SUPPORT_OS
+ h# e, t1 p* l* \4 [ - OSIntEnter();
# {1 Z2 g* r4 a2 p/ E - #endif& y: M& O" a1 a% a. H
- if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)% m" J% L+ _9 \
- {
5 r+ ?1 w$ O1 D* g! H - Res =USART_ReceiveData(USART2);//(USART2->DR)! g- n8 s- k% Y' b, J: t7 A
- // USART_SendData(USART2,Res);+ I& z( ?" _* R0 Q3 N
- if(Res == 0x00). P) |6 m5 V+ c
- down();3 E& T$ e3 x7 Z1 g
- if(Res == 0x01)
, o( D4 }. |$ U o - up();* z4 M2 l6 m( Y' n* Z9 W
- } . g. q( L3 D5 C9 g" W; e# ` z
- #if SYSTEM_SUPPORT_OS$ f! b6 e/ Q1 Y1 C( N
- OSIntExit(); : X0 W% A: f) h3 S" Z
- #endif
. V7 w; o" t- K, G9 B% d - }
, n# W7 z/ ?0 U& d - #endif </font>
复制代码# u( L3 k" b& _2 a
8 e9 D& \6 X7 {+ [' \ b @. h' ?5 ] C
. g9 S: F+ Z9 Y7 w [( l5 s' O: Z. C2 |7 F$ L+ p! e5 X
|