一、蓝牙通信技术7 U- \5 Z; t% b5 z E1 Z5 X9 l
蓝牙技术是一种点对点点对面的网络构架,他可以在限制的范围内以很快的速度传输网络数据,在物联网应用中,支持网状网络的物联网短距离无线通信。目前它还被广泛用于智能可穿戴设备、智能门锁、智能医疗设备、智能照明设备、智能家电等消费电子、工业采集、汽车电子、智能建筑等所有的物联网智能产品中。
; L& m7 S" F5 q3 X4 j! ?
; g7 j2 f2 A+ Q/ K( M5 _6 | 蓝牙是无线个人局域网,最初由爱立信制作,后来由蓝牙技术联盟制定了技术标准。蓝牙产品包括小型蓝牙模块,以及支持连接的蓝牙无线电和软件。 如果两台蓝牙设备想相互交流,则需要进行配对,一台设备将成为主设备,所有其他设备都将成为从设备。 通信时,主站侧需要进行检索并开始配对,如果构建链成功,则双方需要能够发送接收数据。在通信状态下,主侧和从侧的设备都开始切断,可以切断蓝牙链接。蓝牙通信本质上就是无线电传输技术,蓝牙的工作波段为2400–2483.5MHz(包括防护频带)。这是全球范围内无需取得执照(但并非无管制的)的工业、科学和医疗用(ISM)波段的 2.4 GHz 短距离无线电频段。
5 w& ?3 p- T* g2 v4 I" g
" U+ p% a; k4 }% f! _4 j( }
X. S# i+ B0 i9 e, L二、MCU及蓝牙模块
* X9 q5 O( \& z/ T, n 本文采用STM32F103C8T6的芯片及JDY-08 蓝牙透传模块,相关引脚如下:
5 v6 z) m% m' q5 Q C# N( c1 @+ G3 R1 b- m$ Q) F9 W3 y
MCU引脚设定:PA9、PA10作为USART1引脚,用于下载程序、调试显示,PA2、PA3作为USART2引脚,并与蓝牙模块进行通信,PA8作为GPIO_OUTPUT模式,用来控制蓝牙模块上的PWRC。& y$ H9 ?$ }" }( ~* V9 u' f
4 h" ]8 P9 x$ v
4 o- T, s( r2 B( R- H7 d" t- I$ }* ~2 g# o3 Q5 G+ h& D; N
蓝牙模块为JDY-08 蓝牙透传模块,基于蓝牙 4.0 协议标准,工作频段为 2.4GHZ 范围,调制 方式为 GFSK,最大发射功率为 0db,最大发射距离 80 米,采用 TICC2541 芯片设计,支持用户通过 AT 命令修改设备名、服务 UUID、发射功率、配对密码等指令。3 V2 R# N! ~9 B3 R
- ~' @8 P2 B) y) W, E TICC2541 芯片 引脚:: G+ U, { `2 [! @ D1 i
9 {/ z. G9 P6 @8 z$ d
! K7 l/ p5 n1 d3 V( W9 v2 m
! O5 e+ [" E* k2 {
引脚功能定义,在使用串口发送命令时,请将模块的 PWRC 引脚接地,并接上模块的电源(VCC、GND),电源电压为3~ 3.3V:0 J( J" c# L; l4 B
2 O$ s- W0 \8 ~. @% l9 u+ g
/ e( ?5 o& B1 O v3 g
' p2 f, Z, S A# n V7 x
以及本文用到两个AT指令:
. M8 j. J- `: j) @
7 h1 P& j- W- h5 W5 d$ P w
* e1 ]) M9 H# i6 [
* t+ G6 V% Y% H: X) Y& V
三、cubeMX配置MCU及蓝牙接口
) F6 J# G5 z" [) z 本工程设计功能如下:9 i) {- A2 k0 g( ~
/ F6 B9 `, m f
MCU(STM32F103C8T6)的引脚PA2、PA3的与蓝牙模块(TICC2541 )的11、12引脚连接,实现数据通信;MCU的PA8引脚与蓝牙模块的22引脚连接实现,实现蓝牙模块唤醒。
* \, x; b8 N! }4 D. \2 q& ^$ V" x5 ?( M: z% y8 F& W9 a
通信逻辑:电脑(com4)<->(Usart1)MCU(Usart2)<->蓝牙模块->手机(蓝牙调试器,需要开启手机蓝牙功能)。) Q% d7 {2 {0 ~5 d9 G, Z3 }
@5 `1 U( M9 G! K
功能:& D0 y% k) l7 C# ]9 L8 x! z# ~7 {1 U( g
按键功能,用于按键时向蓝牙模块发送AT指令;
+ D) m2 g9 S5 {% w LED功能,用于接收蓝牙模块数据时做出闪灯响应;) V) a" ~, F" O3 o( }
蓝牙功能,接收来自MCU端的串口通信,接收手机端的无线传输(即蓝牙通信);/ V1 K. z0 n- a* ?: t+ m! Y }
串口调试功能,MCU执行程序可以向Usart1发送信息到电脑端,既可实现日志输出,也可以实现指令转发到蓝牙模块。
/ \5 Y) M9 U% n2 g' J 【1】创建工程
. T' m, H; Q$ |7 C3 R5 t 1)新建stm32工程,选择芯片STM32F103C8T6
- r8 |% s- X+ X* V' r0 G O% ^* f3 v/ s3 x# {) U$ O
6 Q9 j# Y( ~# w. G# M* Y4 C5 U+ [' U% V
; h0 Y4 p }* J: J e& V) @ 2)为工程命名完成创建: {. d; n2 q4 g! T3 m+ u
$ N2 t2 y1 J& J" B- y" b1 J
, r m. N6 M ^5 ~7 P4 g* M5 G; _% S7 x' q
【2】CubeMX配置2 Y6 H9 c4 H w8 w
1)开启sys mode接口
* A* u- W, Q. W( ^3 g3 S2 H n5 i4 R( o* n- T
b+ |) A% ?" h6 p2 o Y2 r
1 m! v% |: \) `) Y
2)开启RCC
$ X% h. k& W) ]* i/ M9 Y' e/ B6 P8 F' s* ^$ f* Q
# p$ H Q% _& }7 [2 v
, m4 {- u. f* s& l @7 M8 _
3)开启USART1(下载、调试)、USART2(连接蓝牙模块)。4 D( f6 t0 j }6 l4 n. m
3 i. r* ]; f1 q! ^; a
; o* V3 t) b. @& M
% Q. I5 p8 a1 G5 W# O3 T4 m$ t 4)开启串口USART1、USART2中断功能
5 N( E* b# N" N( Z7 N/ N. V8 \! a& j9 y+ \
6 q: |, o4 H5 J& [
+ t8 y+ g5 \, V n' |* @/ T) D. U2 E 5)串口引脚参数配置
6 b3 f+ `- z) q4 [% V: i* ^- G: b( y
, N! G: M' P, ~/ u! V2 ~! E' B+ ~+ Q: {0 m
6)蓝牙测试辅助接口及按键、LED灯GPIO引脚添加:
" ]8 r% n5 g9 L' h+ b! @& H$ {1 U% R& j
N" g) n. f' F2 i
" `- g0 e l2 o/ W" V( }
7)系统 时钟配置,直接拉满STM32F103C8T6能支持到的72MHz。6 L; q2 U5 {* | o/ k" M
) b4 e2 b2 u( t0 U+ F
4 K% T+ t2 K3 B! [
' q4 @! M" x/ X% T r1 _, n 8)本工程配置页面保持默认,没有为每个外围设备驱动创建独立源文件,点击保持或生成代码按钮输出代码。
' [/ H+ Q' T- t+ s0 u' ~8 A
+ H1 f ?9 p. q: C
U. m" `8 g8 d& l, f, o* |
$ `; ]( C( H; I# p
# d0 q8 ?, f* I/ X9 B 四、代码设计( c/ i* u! `+ t1 f9 v* d
【1】首先创建usart1接口的调试输出支持
7 M. G/ e7 |7 C& V+ a# A 1)禁用syscalls.c,右键选择该文件进入属性页面设置。8 t8 j; l6 @+ }4 `7 p0 l- g
4 I0 M3 }" L/ _% Q: C7 d, y5 Q# T; r0 S0 y
" {# {0 x# _& G4 q& b
0 n* h6 Z/ N% y 2)在工程目录下创建源码目录ICore,添加文件夹print及print.h/print.c,实现对系统printf函数的映射到usart1输出显示功能。
0 B0 V' U6 C2 t5 z7 P
7 T& n. |/ M& l. h K% v print.h
2 Q& x, _# k# A! Y; Z8 c& d- #ifndef INC_RETARGET_H_
. g s/ l# f1 a. h - #define INC_RETARGET_H_) {: E/ e* ]/ N3 ] ~$ O4 n
-
2 z) E: l5 s$ b7 X+ j& A: H# g - #include "stm32f1xx_hal.h"
- l* j( `' E5 Q - #include "stdio.h"//用于printf函数串口重映射
) O V8 ^* \) |: z) D5 A! E& J- S - #include <sys/stat.h>. P- @( ~% U* Z2 y9 q
-
0 R& t7 q( z( Z& l3 m+ O7 D( |, U - void ResetPrintInit(UART_HandleTypeDef *huart);
8 S( A: o, v$ `- T8 r - * z% _5 O5 Z6 H
- int _isatty(int fd);
* [$ {) a- L- R3 |# m6 L- O - int _write(int fd, char* ptr, int len);
+ {" t7 l: _9 f* ~ F' P( K - int _close(int fd);
1 X* K3 }0 b, P6 X - int _lseek(int fd, int ptr, int dir);
7 t# ~+ L, [2 l* l - int _read(int fd, char* ptr, int len);
2 o4 h B2 \9 {/ m( Q) N( t - int _fstat(int fd, struct stat* st); M2 Z2 y- \& Z2 i2 D; G
-
% J/ D4 X1 Y+ S - #endif /* INC_RETARGET_H_ */
复制代码 ' c/ ]' Q. y% W: H# a/ A+ }
print.c
* j% {* R/ ~1 ]# h! V, e" k; w' A3 x2 `( v- #include <_ansi.h>
) r j- o2 F5 t9 f, k7 R - #include <_syslist.h>) ?+ A7 x/ T5 @9 R
- #include <errno.h>
1 G# r K; x/ _7 I* d/ g - #include <sys/time.h>
9 U/ ]5 q, A. V. r - #include <sys/times.h>% w) k$ h0 ^* m- H% u
- #include <limits.h>
) l# y( |7 {3 O& H - #include <signal.h>
4 t) h8 B- Q& _+ H e5 v0 G - #include <stdint.h>
8 S4 e# s2 k7 \ I) M3 i: t - #include <stdio.h>
: c, N& E& D- N, u - + w, S0 U; }8 C) I/ ~/ {
- #include "print.h"
2 E: }0 \- y y - * J4 S& g, f4 ?# j; P& z
- #if !defined(OS_USE_SEMIHOSTING)
, Z$ @+ r0 K0 o2 t7 L - #define STDIN_FILENO 0
9 F9 `+ H# n$ T2 o2 j7 I - #define STDOUT_FILENO 11 U. h( Z; G2 b7 R. w3 j
- #define STDERR_FILENO 2' V: z, t: s- a5 s
-
2 _' V8 f- u3 x' C4 B- _ - UART_HandleTypeDef *gHuart;: e* n. M/ G* z/ o7 t7 u
-
! {0 R8 ~8 G/ I* K E: I - void ResetPrintInit(UART_HandleTypeDef *huart) {
: ^1 N& q' l! N, n; M9 d - gHuart = huart;
4 b1 @3 E/ B# g - /* Disable I/O buffering for STDOUT stream, so that
3 n3 S8 Z0 c( n) t {; t+ b& p - * chars are sent out as soon as they are printed. */
. _' w; m- S( u9 k& ~ - setvbuf(stdout, NULL, _IONBF, 0);6 O6 i! l8 w5 n0 V! h; ]. o* ~
- }+ Q5 b4 u. J5 N5 i4 g! |+ W2 m) M
- int _isatty(int fd) {
5 } ~/ F4 l8 M8 G0 z# o5 O1 y; G+ q: D - if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
& U" w# b( c6 \/ \) W. Y - return 1;
7 a% B" r! [% e1 a/ u# ~ - errno = EBADF;
' F: u4 }; R( k. V3 S - return 0;" S b7 a4 m: _8 @) g
- }$ s6 ?* q8 c5 G) W2 {2 N
- int _write(int fd, char* ptr, int len) {2 @ R7 X, Z6 D- w; Q+ O
- HAL_StatusTypeDef hstatus;" n: {7 G" R! |
- if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {/ e' H8 X' t- D9 l
- hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);" |4 @; b) E% x8 ]% e1 q
- if (hstatus == HAL_OK)
, H2 Q6 o- s( C; b; M - return len;
% ^& y. U9 {7 o8 B* w - else5 a8 _0 E% x3 t9 @
- return EIO;" q- x" D) y8 {( X$ `: G
- }' g6 r/ G* m7 v
- errno = EBADF;% D9 o6 Z. v( g: L0 `; @0 y) |
- return -1;/ z4 [. |" ^. {: ]( } V" b; _5 K2 I
- }+ N/ r( R4 \# k r& w
- int _close(int fd) {
" c$ Y& S* ~. ~9 S( D8 \, m2 l- D$ t - if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
6 N( t( m% ?% E+ @ - return 0;
, ?; } `, r- u- q0 t k9 ` - errno = EBADF;
$ g {1 x8 W1 I/ R - return -1;+ E2 ^) U. c- g2 q: j+ s* [$ L: D' B6 S
- }/ P; k: |) W* i" x$ ~7 [) U
- int _lseek(int fd, int ptr, int dir) {
0 T( N7 L0 e/ O - (void) fd;
1 T/ f! Z) |' \( V1 X2 [; C - (void) ptr;, c0 H9 W2 b& n3 f5 `1 M1 V0 Q
- (void) dir;0 D: q% r8 L/ F ^, ^% T
- errno = EBADF; U9 I9 S: ]: Q
- return -1;* K0 E% R1 Q, r; b8 Q% J4 w
- }' ^$ N) U8 Q2 i i
- int _read(int fd, char* ptr, int len) {
3 [5 q3 f! v F - HAL_StatusTypeDef hstatus;0 r7 G- a. F, T) R, Z1 B% C
- if (fd == STDIN_FILENO) {
: ?2 h) e3 d3 [, j$ I5 c/ c7 Y - hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
. p+ |+ o3 ?6 {, ]8 I5 J1 |, y& R - if (hstatus == HAL_OK)
! _9 X2 y9 K. ?$ `" v! m' I - return 1;
! b v# w7 h8 Z - else
* L) ~7 @6 p, W% d - return EIO;
4 [# B8 e# c& J9 h# } - }
# ?4 |, F$ |) i0 Q - errno = EBADF;
# {6 e, x; n1 c3 C/ f - return -1;
5 p% ?6 F. i: ^6 p$ E7 b% n: G - }
+ n* F( H7 T5 r - int _fstat(int fd, struct stat* st) {
6 D) B# ~ h( G0 R9 J7 W `( f - if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {* f2 a( L3 v2 `5 V: d
- st->st_mode = S_IFCHR;$ H/ ?! ^# n3 u$ e
- return 0;
6 \- ^- d q0 u# r0 U+ E - }9 B. j; h+ k8 }. ~9 e/ ?4 a
- errno = EBADF;
/ C5 p# ]6 H6 R1 [5 L - return 0;
: M# ?2 x+ z) Y' i2 F5 l( D- B - }+ d& [& ^- k) r( X* e' k
- ( a9 p* T) h8 G; P
- #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码 ' X0 G/ n# V- ]$ S2 m* f: d4 f1 D7 S
【2】创建按键驱动、LED驱动、延时函数功能的支持
+ ?8 Z) r) c+ S7 \1 R3 V& w 1)在ICore添加delay目录,并添加delay.h/delay.c源文件- I; m' W. ]2 r& A- U. G- F( w
delay.h* a9 @, f. r# W p
- #ifndef DELAY_DELAY_H_5 E E( v' c3 `* |: v4 P; `
- #define DELAY_DELAY_H_
) b6 h; z) X- h( Z3 E0 u7 t - ) \5 Q! l( D: M' h$ l! ?: s
- #include "stm32f1xx_hal.h" //HAL库文件声明4 G$ M; `5 X c& W; e
- void delay_us(uint32_t us); //C文件中的函数声明
$ o/ {, G" g5 g) `# W9 d* z -
2 P: T7 s' b7 i - #endif /* DELAY_DELAY_H_ */
复制代码
4 X( \4 H% g# s$ y' N8 v delay.c
* R2 c. m$ B; {' T- #include "delay.h"" ]5 J; O, J, W3 s) V* m: p8 y, u
- 9 |/ j; F9 z8 K* `) q: W
- void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
( r5 X: N' D0 o$ ~2 ^ - {/ I: ~; l, \& G8 n
- uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数7 z" m8 |- c6 g6 F4 l! u
- while (delay--); //循环delay次,达到1微秒延时1 ^3 U9 x7 c- k. I$ p- d1 F: p* l
- }
复制代码 8 I, v! T }& g8 F. o$ L+ W; J
2)在ICore添加key目录,并添加key.h/key.c源文件
9 ~' v$ i" @2 T1 Y1 y4 K' U W8 X# [1 I1 j* b/ d4 X
key.h3 Z) p* M9 R* K& H3 A( {; v
- #ifndef KEY_KEY_H_) H! q1 |5 q3 R( j1 y
- #define KEY_KEY_H_
9 |+ t# \# n: f6 S3 d7 h -
2 u- L$ l4 u, } - #include "stm32f1xx_hal.h" //HAL库文件声明
- P" a+ {/ z/ b( q9 \9 P - #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用
9 l% b8 J2 ~! x% S - #include "../delay/delay.h"
( w' `" q' Q7 F0 ? - / \0 t1 {/ c" O" w1 d# g: v/ L; r
- uint8_t KEY_1(void);//按键1' A+ y7 L% W) l* }2 z& P4 N6 S. `
- uint8_t KEY_2(void);//按键2
4 T# K; k0 @3 @! f$ K3 z: F -
9 Q: m# q2 X( m3 |+ j0 D# Q/ i - #endif /* KEY_KEY_H_ */
复制代码 ; F ^- x6 [4 S, S) Y# X
key.c
; d6 [0 E0 a0 C) X0 P- #include "key.h"
( ?4 ?" W) I% j% |# p, k, b - # K* P/ @, B) K& H
- uint8_t KEY_1(void)
( w6 ~/ Z/ l" ~ - {2 ?3 J; T2 f6 H/ b7 h* b2 E- z7 t1 O
- uint8_t a;
# y1 j) @) d: ?- P; t+ ~& } - a=0;//如果未进入按键处理,则返回0
9 Q0 M# Z" M. g3 N9 j# _ - if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平' ^6 ^; N' a7 L+ K
- // HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
3 U$ R/ ]) _9 T0 {1 V& n* u - delay_us(20000);//延时去抖动
/ N; Y3 k# r4 I, Y9 ^5 K( ~' G - if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
/ d7 s1 [2 @5 J5 a - a=1;//进入按键处理,返回1* p7 f0 N6 A) R, K6 ]6 O
- }& Q" P9 K$ Q3 n# Q4 |7 }* X% f3 l- B
- }
j J7 W+ C0 X l K - while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开, d7 s7 P: H% a1 f. X$ R& W( f3 j+ f* e
- delay_us(20000);//延时去抖动(避开按键放开时的抖动)1 W' v5 L* P% r3 a* n4 J
- return a;' l4 ]2 y7 V- r) C1 y3 f/ `
- }
0 a& ~% B+ a5 g -
( L- w% ?, p5 I$ F- |6 V6 O - uint8_t KEY_2(void)
1 U5 ^8 I6 W: |0 C/ I" a7 X( E B - {
7 g2 W2 C d* P* D8 d4 _1 E - uint8_t a;
' U3 }3 N, k' L) p9 B$ t. D. u - a=0;//如果未进入按键处理,则返回08 l4 M+ n/ a4 c8 a
- if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平* ?+ O' ?+ _! l! w
- // HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)3 |8 n2 I0 i4 K7 E9 N/ F g. X
- delay_us(20000);//延时去抖动 p& F3 l1 P! r# g
- if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平/ |3 M: ]- B r, |/ }/ t s
- a=1;//进入按键处理,返回12 w' |% ~/ V6 E% w& g, ^% ]0 c
- }
& I& v7 y: S. T8 _6 @ - }
% q3 @' {4 ?, z3 J+ o" @ - while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
O6 F/ O3 l$ F- g% o* u9 p) _ - delay_us(20000);//延时去抖动(避开按键放开时的抖动)! {0 E6 x( V7 y: k# ]& c {6 T
- return a;
( v% a) C$ Q! Q( ]5 B - }
复制代码
: s6 }, E6 ~$ B3 j5 }/ U6 l 3)在ICore添加led目录,并添加led.h/led.c源文件* Y: ?. g/ q" j( ~/ |7 L
1 C- {' D" u" i" i) @1 } F key.h
- M+ K& ?' L w/ W# Q, ` U/ y5 P5 ^1 z- #ifndef LED_LED_H_8 Q4 q% ^. x. F, s+ O. H2 {
- #define LED_LED_H_
, ~' e; u2 x& B% t - 0 D) t: J3 m" |) M3 w
- #include "stm32f1xx_hal.h" //HAL库文件声明' s. s+ q$ {2 c( Q& w" G2 b, X
- #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用9 H; d( P4 S" o+ `: D' h v
-
6 p, U+ u. j1 @' k6 t+ }- ? - void LED_1(uint8_t a);//LED1独立控制函数(0为熄灭,其他值为点亮): @1 J. @; H+ y( }5 Q
- void LED_2(uint8_t a);//LED2独立控制函数(0为熄灭,其他值为点亮)
& e6 {# p8 x& u# N: E% K - void LED_ALL(uint8_t a);//LED1~4整组操作函数(低4位的1/0状态对应4个LED亮灭,最低位对应LED1)
. R! v6 v: S& k3 P - void LED_1_Contrary(void);//LED1状态取反
6 j6 A! ~8 h1 x# j& X - void LED_2_Contrary(void);//LED2状态取反1 c# t' P s4 Q0 S
- 2 e. W! k m' b7 C! r) C. j- D
- #endif /* LED_LED_H_ */
复制代码
; B4 c* w" Z+ g key.c5 Y t* i) |! n( e* N
- #include "led.h"( \! _+ l z. v/ k0 B, x1 g6 U
- ' t8 c( ] x+ o+ R3 Y8 m
- void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)
, Y; s: i* J; P5 M, N/ I - {
8 h- z( R! t) B1 e7 m- q - if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
/ h% k' D" {. B( r3 V- Q4 n% ` - else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
, e( X+ g x- b2 L) Y - }2 c! @. C( B# d$ R
- void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)1 f+ K" t7 Q( x" B1 c4 }1 P7 U
- {0 t' Y5 V* A9 D& W# ^( O
- if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
* h, V( f! m* }, `/ v - else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
, y6 X' V! R9 Q% K! F - }1 ?! ^, O! k- N
- void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1)" D" [/ h" n! ^
- {
) _( s- ]8 L; p6 m - if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
! l& y2 ]- i; O4 g+ K - else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);$ R/ l( J3 h8 v/ H: r( S) X
- if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);9 W2 f$ d% m0 r# \5 F# V" J6 u
- else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
1 K4 B2 F4 p# C$ Q6 g/ ^) y - }
% [3 b6 l: z6 R5 S6 H - void LED_1_Contrary(void){
; k# j" l# W+ w. A; l; ` - HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));+ G( ]! n& d) c- k2 X4 i
- }
@# Q- Y" ] `% }- A - void LED_2_Contrary(void){1 L+ |8 i8 I E9 V& p# ]& i6 w
- HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));; H( o1 s% l- W' X/ |
- }
复制代码
, X5 M5 R. j v- \) l2 A% _ 【3】创建串口驱动程序,主要是复写串口回调功能
& A5 }, a9 j- B: X5 C 1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能 g; F f' E0 b) Z$ b
/ q5 x% ~; R& k( B usart.h: q# b4 Q5 ?/ I5 v. H, R
- #ifndef INC_USART_H_
' C2 v4 Z, A8 v, ~ z2 o3 f - #define INC_USART_H_) r* z. y+ w9 F% U" F1 v
-
' Q; H' K) j' q( x. O - #include "stm32f1xx_hal.h" //HAL库文件声明5 z/ i9 ^& ~/ ?3 \' ~) V U
- #include <string.h>//用于字符串处理的库
2 d+ n$ \. q/ I9 R! B: K - #include "../print/print.h"//用于printf函数串口重映射
$ ^1 r0 V7 s2 g" m! o- D6 g& z1 T c -
- g/ {# B/ E. b3 @; f" t - extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体# y6 q( E0 \* s6 A
- extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体: ]) S2 e! P( A7 N* |5 o
-
- [6 @" N6 e. Y - #define USART1_REC_LEN 200//定义USART1最大接收字节数) Z7 Y0 J" z2 A! U
- #define USART2_REC_LEN 200//定义USART1最大接收字节数
5 n* q7 ~- k8 w -
& N7 c) {/ d' a8 J* {7 Z - extern uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符; E4 {2 r/ j& j
- extern uint16_t USART1_RX_STA;//接收状态标记% e/ F$ _+ e* W+ B, }2 d) E0 f
- extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存2 ?, A- I1 O6 M/ \3 m
- , I, ^4 H/ ~/ z. P. v
- extern uint8_t USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符6 l! ]" {: p0 k% N8 K3 u
- extern uint16_t USART2_RX_STA;//接收状态标记$ n; i( k. c- o7 x7 A* {
- extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存$ E7 ~7 J G8 e. @3 n4 e
-
% m" S- ^; S1 ]- d8 G) t" @# `4 K8 h6 ~+ o -
; P3 l. N* o' }; j; p. f - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//串口中断回调函数声明
/ ?) n' Y, `( f* w; H. t) l/ } -
: k1 I5 W8 r+ @$ Q- q9 T2 O* a; E - #endif /* INC_USART_H_ */
复制代码
6 a0 ?$ Z- r5 m) \; H" q |: S- \ usart.c
8 P5 G* \1 h2 }* @, q* g/ A$ V- #include "usart.h"* d. v) H! B/ }% u1 F
- # x) n9 Y7 u8 d! w3 Z
- uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
. V Y0 U* r+ w) p - /*
* a: p3 U. L. J7 n0 L5 [ - * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;9 T- v& X; v8 G4 g% @$ a6 J" K
- * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
8 L. \& i1 _* u; V - * bit13:预留; t+ e, p; E. k9 |" B, [. W$ d
- * bit12:预留
; P5 _2 y0 M; G7 C+ ^' d; [& R - * bit11~0:接收到的有效字节数目(0~4095)
# N5 i" q6 m7 A. H: E: ?, \- c& T - */
+ D; H# u) t$ g; O! \& u; ? - uint16_t USART1_RX_STA=0;$ K" b5 P6 O; _3 A/ T$ t
- uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存: T8 t, f& F. i/ P# k2 E( H
- 6 ~% i5 P1 V( X
- uint8_t USART2_RX_BUF[USART2_REC_LEN];
/ @) D% d/ `+ _; n - uint16_t USART2_RX_STA=0;
# h' p+ O1 b6 S! G. J& { - uint8_t USART2_NewData;
- J) C. q( ?1 X! O1 p - ' N2 X- ~% a+ T, g; T U2 V6 f' F
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口中断回调函数
) y; ^( n$ i# v - {
1 w* E1 Q& A4 X* o5 A, ], ?2 M - if(huart ==&huart1)//判断中断来源(串口1:USB转串口)
1 b( }" a5 N: u% l) j) b$ d - {% O2 e: U7 {: u( T& a9 Z# a
- // printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑6 h" S, v- G9 d/ R" N
- if(USART1_NewData==0x0d){//回车标记0 z; ]4 V) A# h" T3 j2 O* ^" [4 ?% r' T
- USART1_RX_STA|=0x8000;//标记接到回车
$ s+ F: K$ t8 a, ^. O - }else{, f( z3 D3 { r" q. ~
- if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){1 V3 U& P2 ]9 z8 ]& y8 l" P+ F c
- USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组
$ f; ]' T Q$ F% U! K6 d" ]9 y - USART1_RX_STA++; //数据长度计数加1
0 _+ | F2 p* x) Q3 r7 d. G( N - }else{
8 u0 M. Q( g4 e8 e3 ^- w - USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
4 o2 ?- s5 b6 }( \* i - }
) l' D5 {- E& O) R - }% X( R0 c% U) m
- HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断8 M7 C3 t8 M) s7 ]. m
- }" M, V0 i# t. F. b( z5 C, Q# d) Y
- if(huart ==&huart2)//判断中断来源(串口2:BT模块)
9 Q" |3 r; q$ \5 a5 e - {
! M& _/ X$ f# g5 C6 z& ]7 X - // printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
4 s. T0 l4 x9 X' q( B6 Z+ T - if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)
7 B! l2 a) O2 T9 b& ~! f - USART2_RX_STA|=0x8000;//标记接到回车
, _0 R. h* e% K* I {4 b+ ] - }else{8 Y% y, h; [! c! t
- if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){1 b6 W* ~1 Q% ?* Q# `+ I5 Q/ \/ b
- USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组
5 d3 S5 F! l4 K) o+ t1 E) @& K, l% h9 e - USART2_RX_STA++; //数据长度计数加1) I8 s# _- B: G# F7 O* S8 C
- }else{" f0 o! T7 D- x! T6 w, Q
- USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
2 ?4 R/ ?6 n. U - }
" w7 e8 U5 C+ ]' X9 D' v - }) Z! i5 C V; _; @( l' c& R" M
- HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断
8 M5 S' ^2 c3 `/ X R - }, x& `8 S' i' N* I5 A& i8 |
- }
复制代码 8 s, i% ~8 h) V3 }9 t+ l; h
【4】创建蓝牙驱动
9 g: g$ A, x |) ~$ F 该驱动主要实现通过usart2向蓝牙模块写入数据,(读取数据主要通过串口usart2回调,在usart.c中实现)。在ICore添加bt目录,并添加bt.h/bt.c源文件,实现蓝牙驱动功能6 f9 \) o; U6 \5 u/ p7 w
* a1 i) z8 F9 x e
bt.h# y! v1 h9 p: Q3 _+ O$ v" C
- #ifndef BT_BT_H_
' r# r; m3 z$ {$ K - #define BT_BT_H_
1 R3 W6 l- i9 h d! w - 9 h2 _" z* @5 L: ]' _
- #include "stm32f1xx_hal.h" //HAL库文件声明* k! x6 @2 W* f: g W, V
- #include "main.h" f; R& e) M% z/ s0 _! q
- #include "../usart/usart.h"
3 q4 ?, e! T9 T. [, Y3 g2 R - #include "../delay/delay.h"
% d1 j8 C2 m7 {5 T - #include <string.h>//用于字符串处理的库
- R! e1 f l$ }& z& f9 t- n - #include <stdarg.h>
/ }" Y0 _, {" u) v - #include <stdlib.h>
# W$ @% p# _2 X - #include "stdio.h"
. @$ K! p% |- C& V! \6 v& S, N+ X1 E - 6 S( i8 a5 W5 K0 i; H @
- extern UART_HandleTypeDef huart2;//声明UART2的HAL库结构体- {( \. ~% l, B; k( i; b2 J. z$ J
- void BT_WEEKUP (void);//蓝牙模块唤醒函数& H- o3 A4 h' \1 U7 j/ E. Z: P$ M
- void BT_printf (char *fmt, ...); //BT蓝牙模块发送
" {! n6 {& @8 o - - N& J9 E- z' p T/ a; H; W4 \
- #endif /* BT_BT_H_ */
复制代码 ' i; [; }! r( P% \. @
bt.c4 z: E' T" _* ~& a+ H# x
- #include "bt.h"
0 c4 m3 u: G8 i9 D2 J1 v4 ~" s - 3 y X" ?8 V- W
- //蓝牙模块唤醒函数
- d- ^1 x5 Q$ S( H; z! c9 m - //对蓝牙模块上的PWRC(P00)接口一个低电平脉冲,如不使用睡眠模式可忽略此函数# k7 }% o( I% Q
- void BT_WEEKUP (void)2 e) f: {- r, t# e
- {
: F( ^: X+ H' e- o' M( S+ I( }2 X: O - HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_RESET);//PWRC接口控制) Q0 j6 a4 Y q' \5 t( }
- delay_us(100);
4 n$ M. J" P, U5 F, k$ E0 G1 | - HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_SET);//PWRC接口控制
! R& O6 j7 T/ |% `! m; i - }
" s7 v) `1 x* A% S1 J - //蓝牙模块通信,使用UART2,这是BT蓝牙的printf函数
/ }6 J( A2 B5 P% o' K% M- u, v1 ^9 A - //调用方法:BT_printf("123"); //向UART2发送字符123
; R4 K! c6 R7 m! E6 o" |' M - void BT_printf (char *fmt, ...)
* n' j; R6 `* T e* E - {
a5 N( F: T: j9 [# d u - char buff[USART2_REC_LEN+1]; //用于存放转换后的数据 [长度]7 n; O8 N3 J2 |* ?2 ]* P7 y
- uint16_t i=0;5 k) L! J0 K" k
- va_list arg_ptr;
+ j N b" A' P% F( S+ G - va_start(arg_ptr, fmt);
" F1 y# T6 z) f& h- H - vsnprintf(buff, USART2_REC_LEN+1, fmt, arg_ptr);//数据转换. z& k- T6 A+ r6 b/ E
- i=strlen(buff);//得出数据长度
3 N! [* O9 o5 z - if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
& T) t- d, h( Q - HAL_UART_Transmit(&huart2,(uint8_t *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)
* ~. X# h' B* v5 C - va_end(arg_ptr);: b( {8 z3 g- Y1 D" t
- }
/ Y: f; p, x/ a - //所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在USART.C文件中。
复制代码 ! X. G. T: t# U/ |; X4 C" e5 Q3 `
五、编译及测试
% q9 {' Y% O' N2 Y+ { 【1】功能调用及编译* U4 [* u3 {$ [
1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:
2 s7 c0 z( j2 p+ ^- /* USER CODE END Header */
( [7 [$ `- @, [" q6 T) Y/ d& X$ u5 h - /* Includes ------------------------------------------------------------------*/
: H5 t, J# o* H/ T7 k7 K' b: F - #include "main.h"& ^+ i6 Y9 y! b# s0 i
-
4 `) u/ O: s0 `5 O - /* Private includes ----------------------------------------------------------*/! I" u; v( e7 x8 D& `
- /* USER CODE BEGIN Includes */
5 g9 X5 t# G @# c0 m) o - #include "../../ICore/led/led.h"- G* J' v) X) v3 W4 I4 v, _& ?8 o
- #include "../../ICore/key/key.h"
1 X1 C$ n' I' G, A& D - #include "../../ICore/delay/delay.h"8 `* P6 K W( q6 S
- #include "../../ICore/print/print.h"//用于printf函数串口重映射
2 i( p$ [+ p, l1 P$ ^$ e - #include "../../ICore/bt/bt.h"
0 c% G; }3 y% Y/ _7 e - /* USER CODE END Includes */# e8 Q" p. D3 r5 u2 _) t
-
. y4 O2 p1 K' i1 j: X - /* Private typedef -----------------------------------------------------------*/* m W: U8 {; }; i
- /* USER CODE BEGIN PTD */1 L$ ?2 m( i9 j$ _) K# t9 J
- # M* y4 i( P! q, V6 X h
- /* USER CODE END PTD */
1 P: A1 ~2 @$ t$ W: A -
# T9 _0 n0 [, I% c, s* J/ { - /* Private define ------------------------------------------------------------*/ I' s7 ]- L1 R# q% [
- /* USER CODE BEGIN PD */$ k& p$ b) b/ X& l7 x
- /* USER CODE END PD */
$ U# t% k, q8 Z6 `0 y1 e# J -
4 Q5 @4 k- c P% v1 c/ ]/ Z% {& B - /* Private macro -------------------------------------------------------------*/+ O3 m* ?* Z6 `) R. ^
- /* USER CODE BEGIN PM */7 B8 Y Z" p9 z# D
-
9 B2 Z9 m M& R" _7 e - /* USER CODE END PM */3 w$ @% j3 X$ S2 {5 @
-
1 e2 o a* o" N2 a - /* Private variables ---------------------------------------------------------*/% S b \ `* B8 U$ F
- UART_HandleTypeDef huart1;
1 T2 P2 h7 q2 H% w, y - UART_HandleTypeDef huart2;/ G! r8 ~0 o w1 \) ?8 h
- ! M& {1 U u0 @% |
- /* USER CODE BEGIN PV */+ U) B- w+ O1 N# X. s4 t3 {
- ) D% r' v; d q; o" M0 y
- /* USER CODE END PV */
( w+ r9 y/ f5 U5 i, |5 u9 S3 V - ) \8 [! Q4 w1 [( m* z( g
- /* Private function prototypes -----------------------------------------------*/
: C1 f% V+ ?( X. u( T, H - void SystemClock_Config(void);5 j- k# {* b! y8 j( P! k- Z
- static void MX_GPIO_Init(void);! T- _5 Q% w0 p" A
- static void MX_USART1_UART_Init(void);
( {* W- Q4 D7 y% j' g/ x - static void MX_USART2_UART_Init(void);
' V+ g. \! v7 A% a' i |( a - /* USER CODE BEGIN PFP */
# `6 O; h9 [/ N+ B! L, Q2 ^0 ` -
# Y. x! \6 A& e( b) A; Q - /* USER CODE END PFP */
$ @0 |" \9 M2 g, v& ^ - : ~: x+ o/ \2 }
- /* Private user code ---------------------------------------------------------*/- |' I j) l1 ^ M5 L5 C& u
- /* USER CODE BEGIN 0 */( A. M7 e: b2 }2 G- o9 X5 d
-
& U. S, E0 P; E) S# e: V - /* USER CODE END 0 */
# z+ Y& w4 u- `- n8 ]9 r# u; w" x - - I" Q' w7 W; A. h0 h! x
- /**& ~+ ^* p( ?0 D8 m4 i2 N/ v
- * @brief The application entry point.
. o5 e/ g2 u- `, O3 P) n- T - * @retval int: i# `5 J( w6 Y$ e+ a9 Q" x
- */
+ a3 c5 O0 w9 h" n3 f/ D - int main(void)
1 r. ]6 Q& n6 N' ^ - {
; J4 E8 w7 Z/ f% r - /* USER CODE BEGIN 1 */
7 V! Y; d* S9 ~# _0 [ -
/ ^+ W7 r% C! e6 n1 d5 _ - /* USER CODE END 1 */
% W# e) I) w8 W5 f- b T -
D; {' I- X7 E6 ~) @ - /* MCU Configuration--------------------------------------------------------*/
x/ |! R8 b5 [3 \, S -
/ ~ D+ L+ E% [- G3 r% e6 J - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ O. w4 c, A% e
- HAL_Init();
/ s& j4 P9 j/ |! }3 W: l -
0 E5 h5 f; X. G4 i1 R - /* USER CODE BEGIN Init */
4 ~- ] |" l, y: x -
2 j0 p, @( `7 {6 | - /* USER CODE END Init */1 A& c! p; c: p% o' z$ s9 ~
- , p9 A* N" P( o7 M
- /* Configure the system clock */
0 ~! x# O2 a9 `6 S - SystemClock_Config();
2 T" Z3 W6 ~: ]$ r4 j" M0 | -
B0 I% @% J+ u& T& L2 T2 ?! O - /* USER CODE BEGIN SysInit */
" U( e; L6 R+ [7 t% W2 O' ~ -
9 M$ ?4 a; h0 c, L - /* USER CODE END SysInit */. D4 l1 W- I9 _5 m0 `. q7 s
-
: o6 L3 b- I/ K+ p1 N1 c( W& Q - /* Initialize all configured peripherals */
0 M4 M& _# W3 R: M1 X - MX_GPIO_Init();
. o, l" W A( z. j T0 V9 E - MX_USART1_UART_Init();
4 t+ @+ z* X- l - MX_USART2_UART_Init();* Q8 R+ G0 G* x, }
- /* USER CODE BEGIN 2 */# h# o! D; j8 |( w$ V$ b
- ResetPrintInit(&huart1);//将printf()函数映射到UART1串口上+ C: g: `+ K3 O8 A |1 o3 O, t
- HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);//开启串口1接收中断9 X0 B; [- t* O3 G6 @6 a
- HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启串口3接收中断
$ B& z# @* t7 f7 H - /* USER CODE END 2 */3 m3 V2 o5 u% B5 z6 P
-
1 o$ j& Y+ T! G! M6 U4 m; i - /* Infinite loop */
0 l) T+ M8 S( [% [ c8 x; N1 F! B - /* USER CODE BEGIN WHILE */
$ R# @, s3 m. E5 [$ n- i - while (1)( y1 ]9 I+ [: v; {( X) Z
- {
: g* Y) Q: K- N6 t: h - //demo 蓝牙02
: e9 e$ B0 z4 L3 ]+ N - if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)
) f0 M! r* _9 y - BT_printf("%c",USART2_RX_STA);* ~" m, d& |8 ^/ m1 Z. [6 e
- if((USART2_RX_STA&0x7FFF) == 1) //判断接收数量1个(手机控制程序)
4 ?- r: ~" M# i6 T! j - {* s# H/ e# s* a: e4 h# s9 c
- BT_printf("%c",USART2_RX_BUF[0]);
& |+ l- i5 c N/ }) l( f% }8 }& k* c - switch (USART2_RX_BUF[0]){//判断接收数据的内容
) A/ f1 U, ~7 G* s) }% S7 W - case 0x41:
. J2 }- v! g$ w. G% G6 X7 m$ Q - LED_1(1);//LED1控制
, ?/ l4 U8 @, V; x# p - BT_printf("Relay ON");//返回数据内容,在手机APP上显示
: n6 W. z! t" K+ z4 A - break;* Y/ n+ v8 l) X% O+ `
- case 0x44:
4 S6 K0 Z6 D: W% J' k5 J P8 n# c - LED_1(0);//LED1控制" b* W+ s s. m7 [
- BT_printf("Relay OFF");//返回数据内容,在手机APP上显示
3 P \0 U% s9 {* e - break;
; }/ W+ W% ^. q: ^) [7 R' p - case 0x42:
) p# j+ Q# k1 u, @6 @ - LED_2(1);//LED1控制: a$ |7 H2 E# c1 b
- BT_printf("LED1 ON");//返回数据内容,在手机APP上显示, R k3 O: w6 G7 \, G
- break;
( P$ P9 w2 ]% {1 e - case 0x45:$ ~* ?5 D, x6 ^8 v& X6 N( u/ h
- LED_2(0);//LED1控制$ K1 m- b" u3 s8 }
- BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示
- y! r1 S. p2 {2 q6 F9 i - break;& p2 S, K @6 z4 f3 N' X2 i1 U
- case 0x43:
- Y- r( K. Y5 }+ R - LED_1(0);//LED1控制
j7 E2 U+ w w% h - LED_2(0);//LED1控制3 d! W% s# ?, ~! @2 ~& k
- BT_printf("BEEP");//返回数据内容,在手机APP上显示- Q: G8 q$ E3 _$ E! V6 X
- break;3 B5 \( p! L4 \) [# o: [
- case 0x46:, B8 {6 S- d' `3 c9 V* W+ `
- BT_printf("CPU Reset");//返回数据内容,在手机APP上显示
3 l, S9 ~& w, w+ d8 u* i3 c- _ - HAL_Delay(1000);//延时
& A, {2 f& S, V' ]' X# w - NVIC_SystemReset();//系统软件复位函数
- Z S% U' C* x9 a+ q a - break;
+ j/ i, n4 l' s- n5 x1 y- d/ K - default:# z6 y. n/ B) f( I" q
- //冗余语句9 ]1 F+ Y. [* j3 V2 u6 \+ G
- break;6 l1 w9 o( q/ t: I8 Y+ k
- }* A4 y1 W0 A c m5 X1 n
- }
( I/ N! p- u% E8 T - printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1
* L3 _2 j# B( k. x# R! K - USART2_RX_STA=0;//标志位清0,准备下次接收. Y4 O# q, A! o }' W7 Y5 s8 l% F* |
- }! t6 L3 Q: i* O; m* R4 h# g
- //接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块
2 i6 C5 p* n5 b6 L, h+ N: m - if(USART1_RX_STA&0xC000){//结束标记
9 y' |: C+ E" q% E1 ]% q7 s b - BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);
2 H! |3 y8 s) S/ K5 Q$ I& Y - USART1_RX_STA=0;//接收重新开始
8 h* d2 h9 X: i; p: O y& ~ - HAL_Delay(100);//等待: a" l3 X' O: G2 o! W( J
- }
# ?# X& u1 A4 O( F' W { - if(KEY_1())//按下KEY1判断) }! N5 U& Z- E" z
- {
1 h% R% k+ J8 F% m' t3 L: V - LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
+ y8 S; {5 G, h. \ - LED_2(0);//LED2控制
& V9 X0 {% V1 K, Q$ l' e# U - BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
4 \0 S C5 n8 @- F - }
a( |$ {% |3 I: ^6 i - if(KEY_2())//按下KEY2判断# m3 W+ C' [* ?8 F h7 f
- {/ k: o6 F8 f4 `" A9 ]4 ]3 R
- LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位3 e$ o% Y: s- q5 {+ P' C
- LED_2(1);//LED2控制+ f9 \( I M2 G- _" T
- BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)! I/ }: ?- a$ `9 ?( a
- }$ n2 w" F% F3 g1 F9 U w7 m7 f2 Y
- /* USER CODE END WHILE */
2 A, n) ?% C# a+ R, l* M, @ -
. y, k' D2 k; u% Q7 t2 ]' u - /* USER CODE BEGIN 3 */7 n2 k/ j3 S- q- a! n* G; J
- } ~* e/ S/ ?. w6 Y9 G. d# i
- /* USER CODE END 3 */1 n/ r- o: B& d, I$ ~- R
- }
复制代码 3 |" R8 h$ \6 n4 Z: j- V% g- b
2)设置编译输出支持,右键工程进入项目属性设置页面:5 g8 m# ^/ |1 X/ @2 I/ {
6 i8 I f1 J* ?
7 W( j% N" k$ p5 R2 j0 v
- z: D3 {, F; L1 B* [+ ^; K1 H K7 M 3)点击编译按钮,完成编译(整个工程需要源码修改或添加的源文件如下):, ?+ E( s2 ?4 W& ]2 R2 Z# N- u* [4 W
8 S) O9 r1 l3 A
3 L0 a0 d2 F5 n) e$ ^" g4 [2 d" G: R. _
【2】程序测试
# d4 e9 q% P. f# @( I8 i4 g& J8 ] 1)测试过程需要三个工具文件支持,读者可以自网上搜索最新版本或采用其他同功能工具替代测试:* ?) P( H4 t. |
FlyMCU加载工具,将生成的.hex程序文件加载到板子上
2 R$ f4 a2 i; { SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入
1 V2 v4 M; R5 E) ^2 \ 蓝牙调试器工具,本文用的是1.9安卓版本。
: d! k8 t( v& X5 v3 G
8 p# [) f$ k7 w/ n2 ~8 h
3 {0 U+ t" q' T# V8 F0 L/ k& e9 ^+ ^
# f( b% t0 M$ k; ^# d% ?
- m2 ~$ P! b7 o9 z1 A9 r 2)加载程序,选择串口,选择程序(.hex),点击开始编程按钮:
. h) _6 o9 i; D) S7 Y$ Z
. Q$ P# Q' I- O( Y3 ?
& X. I4 F7 C9 {8 D1 |$ s% S2 a' f* f$ W& n/ v) m
3)手机打开蓝牙调试器(别忘了开启手机蓝牙功能),进入界面,搜索蓝牙,点击蓝牙边上“+”按钮连接蓝牙模块,采用SSCOM串口工具连接到usart1上,就可以通过蓝牙通信实现手机(蓝牙调试器)与电脑(串口工具)的通信了,在蓝牙调试器发送数据时,十六进制时需要加上“0A”作为结尾,如果十进制发送时,注意加上换行再发送:3 M# }8 h/ m: K3 s* j
# f- r+ s2 Q: B
8 n. N( h" E" O1 C6 f
+ L6 q5 C& m1 E @* | 注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:1 [( |4 z7 X Y, `" E
- if(KEY_1())//按下KEY1判断+ S) b7 `9 |6 p/ k( K4 P$ i& b
- {
3 ?$ V. B" P E* g, |3 S8 r" q - LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
: m* G Y! l* { {8 p2 a* M5 w - LED_2(0);//LED2控制
4 t. y9 U# e3 s3 t" Z; R! j - BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT) z/ ]$ S$ b2 L. E+ m9 y) n
- }
复制代码
: A K/ ^' a& p( h. u 串口发送数据:0 B1 |' E2 [" n) h
3 F- x8 D6 |3 v0 H
% y/ F' k& O# `: y$ I
- h- X3 q( V: C8 t% k# a- Z* {( u& O
可以进入按钮控制页面进行指令定制设置
9 w* e; O: g; R, B) U) e& v8 V- V" I" Y ?3 J6 p: a) b
/ _+ g& W/ {- j* l% C- w4 B; A" y; W
. ~' j* \5 c& H1 ]5 B6 Y 至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。& ?* B$ i A9 F* I/ c& k8 A
————————————————7 p7 Q( `/ b6 P
版权声明:py_free-物联智能
s+ R' ?( l) P% F如有侵权请联系删除
1 g* I1 M2 k5 F- K; L9 J; v8 Q' V/ v
# t1 u% k# {; o0 `) q" T p
4 `( c1 m- `3 r, g' Z: ~# D' x5 b8 j. a
|