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