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