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