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