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