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