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