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