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