你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeIDE物联网应用之蓝牙通信经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-7 15:54
一、蓝牙通信技术
8 d' p  T4 `3 w        蓝牙技术是一种点对点点对面的网络构架,他可以在限制的范围内以很快的速度传输网络数据,在物联网应用中,支持网状网络的物联网短距离无线通信。目前它还被广泛用于智能可穿戴设备、智能门锁、智能医疗设备、智能照明设备、智能家电等消费电子、工业采集、汽车电子、智能建筑等所有的物联网智能产品中。
( `3 b: P# e9 U" X2 ?

8 h6 P$ b3 Y1 @2 {9 Q* Z        蓝牙是无线个人局域网,最初由爱立信制作,后来由蓝牙技术联盟制定了技术标准。蓝牙产品包括小型蓝牙模块,以及支持连接的蓝牙无线电和软件。 如果两台蓝牙设备想相互交流,则需要进行配对,一台设备将成为主设备,所有其他设备都将成为从设备。 通信时,主站侧需要进行检索并开始配对,如果构建链成功,则双方需要能够发送接收数据。在通信状态下,主侧和从侧的设备都开始切断,可以切断蓝牙链接。蓝牙通信本质上就是无线电传输技术,蓝牙的工作波段为2400–2483.5MHz(包括防护频带)。这是全球范围内无需取得执照(但并非无管制的)的工业、科学和医疗用(ISM)波段的 2.4 GHz 短距离无线电频段。
& p1 h7 [0 t3 c5 R# C% o1 I2 w1 h  w# T
/ e2 ~6 B, \* ]; Q$ n0 ]% \
二、MCU及蓝牙模块
' O' `& q/ U7 }4 [2 {        本文采用STM32F103C8T6的芯片及JDY-08 蓝牙透传模块,相关引脚如下:) {7 d" X2 q0 ?0 E

1 y9 q% [: {! g. \- c" I+ L        MCU引脚设定:PA9、PA10作为USART1引脚,用于下载程序、调试显示,PA2、PA3作为USART2引脚,并与蓝牙模块进行通信,PA8作为GPIO_OUTPUT模式,用来控制蓝牙模块上的PWRC。' m& k6 h- G/ R% A/ v9 ?
( A. F& u- _' h+ `2 I+ j
2d927f8850734dd683cfc95f270f3604.png ; [5 J0 B, [) @# d

( ~& d$ k" s) B         蓝牙模块为JDY-08 蓝牙透传模块,基于蓝牙 4.0 协议标准,工作频段为 2.4GHZ 范围,调制 方式为 GFSK,最大发射功率为 0db,最大发射距离 80 米,采用 TICC2541 芯片设计,支持用户通过 AT 命令修改设备名、服务 UUID、发射功率、配对密码等指令。8 M. M+ L$ D6 \: c2 c; ^/ A
3 D1 m* I- ?1 J) B$ z9 p% `' l) o
        TICC2541 芯片 引脚:
4 l5 Q) A: f7 c/ W9 v) {% q& P
. o2 Y( E6 b$ P9 q
87b66d3312cc4c23b64182bd2c2496c9.png
  {! ?& S, x- i; B7 g
# p8 e  I$ u" Q$ e/ e# H( y         引脚功能定义,在使用串口发送命令时,请将模块的 PWRC 引脚接地,并接上模块的电源(VCC、GND),电源电压为3~ 3.3V:
$ Q9 O3 \/ i3 V& S. O( e& \: ?
2 S/ h5 m- [. V' a3 t
50c5510d3d8b4234879cc66e8e1a6988.png & F1 m9 v" t* j0 `6 F
) B* h8 X6 r( u! L2 [' ~7 M8 F
         以及本文用到两个AT指令:
3 s4 ^* v7 o: s/ B0 F1 o1 u6 y- t' ^& i" F. {; r( [- i7 e! c9 i: N
d5bc46612e09498c922ad506da5679f4.png
3 N- X" d9 ]1 B6 I5 ~

9 z. a( J# i6 l 三、cubeMX配置MCU及蓝牙接口5 h& ^2 H; K, k9 h' _  ~
        本工程设计功能如下:
& ~: M. q2 d; Y2 M* A7 @
1 N0 f8 d+ P3 L. X: `        MCU(STM32F103C8T6)的引脚PA2、PA3的与蓝牙模块(TICC2541 )的11、12引脚连接,实现数据通信;MCU的PA8引脚与蓝牙模块的22引脚连接实现,实现蓝牙模块唤醒。( }  Z6 F( C, |; A

7 ?. g5 }- D2 V4 m        通信逻辑:电脑(com4)<->(Usart1)MCU(Usart2)<->蓝牙模块->手机(蓝牙调试器,需要开启手机蓝牙功能)。; {. @2 f! x' V+ O2 G; q

# X# a7 a1 i3 ]1 @        功能:
% }' ?7 w6 J5 A! m+ t2 N        按键功能,用于按键时向蓝牙模块发送AT指令;
) z7 w4 Y/ F6 ~; z9 e5 G* q) s        LED功能,用于接收蓝牙模块数据时做出闪灯响应;1 R" @! o8 l, \' x+ G' B
        蓝牙功能,接收来自MCU端的串口通信,接收手机端的无线传输(即蓝牙通信);2 s8 x( t) K% w
        串口调试功能,MCU执行程序可以向Usart1发送信息到电脑端,既可实现日志输出,也可以实现指令转发到蓝牙模块。/ R2 g6 {2 K9 |$ |' }! f
        【1】创建工程' N9 w* f* W% W4 f0 R& U) I9 a
        1)新建stm32工程,选择芯片STM32F103C8T6
$ q% b. C3 }' l, A% y4 x& i9 i3 Q) l
& N9 `0 h% f, E% \) i3 t0 K
a4d9946142d542f3a8ade81b66e0a552.png
% ^1 _2 t4 p% D0 |0 l9 n5 p  q
2 z4 B' H+ {- ~
         2)为工程命名完成创建
4 u% p+ r; r) [, Z7 u& M, c' u- ^- o: k0 G+ g) u( a
8177bd2fea6b478e8c172a4b4604aa43.png   A  T/ D) B7 y) G$ |* T8 X2 r6 f
# F1 A  q4 V6 m' k9 `
         【2】CubeMX配置6 C" L, L: U- X5 A- p5 T
        1)开启sys mode接口! g' r$ z: Y2 q1 w: L
* R* L7 D0 x! }7 r: X5 R& f' g1 C
6945e8635a7a466b83c22611ad53d9c5.png
' Y' S4 z; k6 |4 Z2 y. L: A# R; O: E
$ K. W( O9 d" ~) o: A4 V0 w
         2)开启RCC5 {4 K2 F. d( _' R0 x! C

* I" V/ M+ |" ^- Z9 _7 C& D3 R  V
eb9677e954f14340b91608f89a899e85.png ! `1 }, T' |+ c4 g9 W

2 U) b* n6 J$ p8 F         3)开启USART1(下载、调试)、USART2(连接蓝牙模块)。7 Q, |/ {, s9 @+ u

" L3 i: ^& a( a  ^
8a56a450ae704a66afcd75f588cd2e64.png
8 ?: k% M& C( b" {( J
% l; p& E( y- ~: W         4)开启串口USART1、USART2中断功能
+ p: t% n% L/ ?% ^, C/ Y
9 K6 y  ~! @3 @  _+ ~' l
1a51fe61e16c48fd95cd3c1841c6cf9f.png
  s4 W7 I8 |/ s* V& p! x: H. \! e( e2 T8 {7 I& T, ?9 e6 W' l
         5)串口引脚参数配置+ o2 W5 p) e+ s9 \" [1 r% q, H
1 ]1 O* {& W4 K# k
3c5015317b1643e1b7e9a55510e02cfc.png
* V3 [2 g+ a3 h; Q  x8 n

6 x# o) M& d1 B* R0 g         6)蓝牙测试辅助接口及按键、LED灯GPIO引脚添加:
+ \' K6 Z! ]) \, L" L& S) o. ]+ C% i3 P2 r
70a978fd9ca34aa18d434351ceb7bb5b.png
7 I/ S, w0 L/ I! M
+ ~+ Y% d9 R$ _        7)系统 时钟配置,直接拉满STM32F103C8T6能支持到的72MHz。3 M6 k# s) B/ p

! L% G3 w7 v& ~, W* a/ y
cd5e618b97e54ef1886818cc2b4c1956.png
6 }1 J* Q" J0 m; ^( U$ @: [
0 F% a% ?7 D  r9 }( I  B# R
          8)本工程配置页面保持默认,没有为每个外围设备驱动创建独立源文件,点击保持或生成代码按钮输出代码。* f& A  G- P" Z& D2 q

1 d9 }& d0 g% h7 p& [& P
31870054f08c4b95bfb5f485f13480d6.png
" h6 I7 W" y* c' m" Y  E4 _
, T1 x1 }0 }6 x& Q
/ ?7 i% ~' n4 h# e" u) ~
四、代码设计
1 z0 ~; d% ]& W        【1】首先创建usart1接口的调试输出支持0 k) ~; ~; _% `1 |' l0 Q$ V% p
        1)禁用syscalls.c,右键选择该文件进入属性页面设置。7 U. V% M% E4 B2 q- z% M- U9 j9 W
6 |: g! Q" s: ^* H
aec3533e953447e39024f449845c2564.png
7 g" q( Q6 u, M4 H  P
2 a" D$ ^2 r4 d4 d! e; }
         2)在工程目录下创建源码目录ICore,添加文件夹print及print.h/print.c,实现对系统printf函数的映射到usart1输出显示功能。  v( j2 e( v% |9 l' X1 A
) d% n/ c6 _2 k6 e, L" K9 h
        print.h5 m5 ?: h5 ]# ~5 L
  1. #ifndef INC_RETARGET_H_; T0 N: C  ^* _4 f# A. w. b
  2. #define INC_RETARGET_H_
    ( ~# h) d% R" Q; O# S. C5 z% B

  3. - I3 s* \# E$ [0 l# V0 p! f$ x
  4. #include "stm32f1xx_hal.h"
    4 A5 W. i9 E5 [* B: L+ d: ^
  5. #include "stdio.h"//用于printf函数串口重映射0 K5 g7 s3 y1 Z* Y+ s! ^
  6. #include <sys/stat.h>' a# O7 x1 Z9 N2 }0 t( }

  7. 1 o6 q0 L. \2 ]' v5 O8 f4 p: z
  8. void ResetPrintInit(UART_HandleTypeDef  *huart);8 {* h% ?, a. Z+ I
  9. / {- f% S) k0 j* n# ?
  10. int _isatty(int fd);
    ! U' k2 o6 t0 v3 H
  11. int _write(int fd, char* ptr, int len);
    ) J2 g5 h/ Y7 Z2 s9 [
  12. int _close(int fd);# v! h- r7 k4 p- Q9 s) y( }  `  Q
  13. int _lseek(int fd, int ptr, int dir);6 V* V9 Z. @+ g5 ]- A
  14. int _read(int fd, char* ptr, int len);+ v' G8 t( |( l' k# d8 q
  15. int _fstat(int fd, struct stat* st);8 S( \7 c+ a" l# J* A4 t2 x+ h7 l
  16. % v5 k3 r, l) g  K6 K6 i! k
  17. #endif /* INC_RETARGET_H_ */
复制代码

0 O" ]; E: _+ `        print.c
! x8 g3 K- O9 D0 e# I9 y
  1. #include <_ansi.h>8 h6 `5 c) `8 d% z8 G
  2. #include <_syslist.h>
    * ~/ S& P0 c% F; G
  3. #include <errno.h>
    ( o2 _- Q$ \- [8 O2 e& j) p+ s
  4. #include <sys/time.h>
    ! `1 g% b) C5 X7 d6 y3 S) C
  5. #include <sys/times.h>
    7 T, A, @9 W. \9 e/ H' [+ ~
  6. #include <limits.h>8 ?' j! B: x! y# O3 f. u
  7. #include <signal.h>
    - Z0 }, }9 F/ g! w9 b
  8. #include <stdint.h>  U+ Y8 z5 j% \' ^" d% w3 R
  9. #include <stdio.h>' T/ P. h5 E  n  v. A) ]: X

  10. ; q1 o8 g& d6 |
  11. #include "print.h"
    7 b0 ~6 @" ]& n5 P# m

  12. , f* w: [& w5 d2 l3 ]
  13. #if !defined(OS_USE_SEMIHOSTING)8 a1 g6 W9 R% o
  14. #define STDIN_FILENO  0
    ( w& F9 P: n1 U( b8 {
  15. #define STDOUT_FILENO 1
    1 E" \& Y# E1 c, r
  16. #define STDERR_FILENO 2% W& x8 s7 _& R% L9 \

  17. ' J9 s( H, g/ O1 ^
  18. UART_HandleTypeDef *gHuart;
    , s4 n2 N$ F& C) m: J% Q+ y

  19. ; G) r  W% M4 {) J, ~. \4 k3 K: ?+ o' D
  20. void ResetPrintInit(UART_HandleTypeDef *huart)  {
    7 ~/ ~: S5 P* w( S- a; f, N+ y
  21.   gHuart = huart;' n7 g% p$ u$ b
  22.   /* Disable I/O buffering for STDOUT  stream, so that, H  z: R$ k8 m
  23.    * chars are sent out as soon as they are  printed. */
    7 m# H: e4 i$ M3 H, b' c
  24.   setvbuf(stdout, NULL, _IONBF, 0);
    * F" b* P" g; U! H
  25. }* a6 ?; u& C" t- p8 A1 Z7 x
  26. int _isatty(int fd) {0 g1 @# I" G7 W  l- M% f7 }! K
  27.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
    / m( d4 K+ t' w/ p
  28.     return 1;$ l6 i; w6 Y7 h5 |+ q
  29.   errno = EBADF;% \8 h5 z7 e4 g
  30.   return 0;
      J; W; H9 j  Q) B4 N" [0 p
  31. }9 Y- j6 P: q9 }# p7 G2 e
  32. int _write(int fd, char* ptr, int len) {6 A; B- B4 a, ]& K: \! Y5 a2 t+ A
  33.   HAL_StatusTypeDef hstatus;9 Q  a1 M$ T$ H
  34.   if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {
    - U% n% b6 O5 Q' @
  35.     hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);
    & ]. p9 G# F, }9 n# g' o1 R
  36.     if (hstatus == HAL_OK), E1 u6 y- ~6 m: ]' m& |: @
  37.       return len;
    : c, z" ^$ g! @3 J5 D9 I* @* v1 U5 b
  38.     else
    6 N& K3 J, v+ O- [/ k
  39.       return EIO;
    1 H& Q3 M* d% k; j$ Q& z
  40.   }
    . h) o+ U! Q5 H' k) u3 \
  41.   errno = EBADF;# i- L. T( n4 n
  42.   return -1;
    ! E+ q! L8 P$ Q" V" n
  43. }+ }2 c& G% \# Z9 h/ ^/ g! P) f# E
  44. int _close(int fd) {
    " m+ L$ D. r) L: D, r  k2 v
  45.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO): q+ O- Q/ _# D3 F
  46.     return 0;
    1 N; P+ \2 V. s  r+ R+ H8 N
  47.   errno = EBADF;
    # e' ?; e" q3 [- M  g1 U" O
  48.   return -1;
    1 ^$ }/ G9 k: i6 ~! N
  49. }: ]" y, A3 v- F. l  U
  50. int _lseek(int fd, int ptr, int dir) {
    " n( ^6 _8 o2 B; b$ L) x9 C
  51.   (void) fd;0 w0 i( A: T  N- H) p. v% e
  52.   (void) ptr;
    : R. |  i# J5 _4 ~5 H9 \$ C) e
  53.   (void) dir;
    1 m7 N' w& ?' J4 p) ]7 F& v
  54.   errno = EBADF;, B: i5 h/ t& s* O+ U6 e. J
  55.   return -1;- g! F. u: q' O' r8 Q, ~) e
  56. }/ o/ g9 p6 L6 ?$ L( Y
  57. int _read(int fd, char* ptr, int len) {) U6 a3 P0 O  B' ^1 P; u, q9 m
  58.   HAL_StatusTypeDef hstatus;
    ) ]- V) k4 q" _6 G; L
  59.   if (fd == STDIN_FILENO) {; R# p3 v/ B" z2 R$ V2 n& ]
  60.     hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);- g6 W6 a' H) D/ ?& V3 L" t) ~/ Y
  61.     if (hstatus == HAL_OK)
    . p+ {5 \. {: H
  62.       return 1;; }9 K9 A" w2 o, w& O
  63.     else
    8 t0 ^3 Z, Q# Y8 j, i
  64.       return EIO;# [3 k9 m& {$ _2 ?0 Y5 ^& y
  65.   }. \9 a$ b& w7 b: a( ~
  66.   errno = EBADF;
    2 Z- m" ^3 E/ H8 F
  67.   return -1;
      R8 x/ j4 w) @& F- e) ?9 e
  68. }
    2 S/ K7 ]2 R4 M0 p7 I( Y
  69. int _fstat(int fd, struct stat* st) {3 V! n- ]- x/ D0 ~, Y0 V
  70.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {+ D/ {, `' w9 C$ L) `& b3 a
  71.     st->st_mode = S_IFCHR;
    1 y& y9 H6 M, x, f# k
  72.     return 0;; b8 E2 P3 l& T/ X  W
  73.   }
    2 h8 R: m4 x- ~! L
  74.   errno = EBADF;3 Z- |/ y1 U  {/ b
  75.   return 0;# A% k) j  ^+ P! X
  76. }
    % ~7 |2 ^" ]) K1 D3 \& f: w

  77. 9 e! m! ?0 @* \( Z5 F
  78. #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码
+ d5 D3 |' r; p" y: z
        【2】创建按键驱动、LED驱动、延时函数功能的支持, f9 X0 F3 M' U- q/ z
         1)在ICore添加delay目录,并添加delay.h/delay.c源文件
7 R7 k5 @, m  |, X% t" n# l        delay.h
( Z6 d9 U4 w% B1 _: ~
  1. #ifndef DELAY_DELAY_H_
    - }1 {' a' o& Y0 R  \# F( z3 V
  2. #define DELAY_DELAY_H_7 v  x1 e1 E; |2 {7 ], j8 t

  3. ( Q! ~( L9 V* J1 w% N4 {: R
  4. #include "stm32f1xx_hal.h" //HAL库文件声明/ t& N4 j! m( K' L0 T: h
  5. void delay_us(uint32_t us); //C文件中的函数声明
    4 O2 j3 W, ?( ^
  6. 7 J* e8 q. G% W' C
  7. #endif /* DELAY_DELAY_H_ */
复制代码
0 y& m! Y+ m+ \1 Z
        delay.c
$ N7 k& ^9 G$ t: j: A. }5 @
  1. #include "delay.h"  B  W2 e. V( r7 l: V
  2. + n8 J$ }/ |, B7 u. H
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
    3 Z" G! }; ]0 R4 u. q0 [- ]
  4. {% b: ?, m5 N  W  n
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数
    9 [3 x+ R9 ?! D2 W$ K
  6.     while (delay--); //循环delay次,达到1微秒延时2 j+ D! _, y4 b$ G$ O- n& n, R
  7. }
复制代码
5 Y% D1 B& ^- @. u( e' J  q
        2)在ICore添加key目录,并添加key.h/key.c源文件
; Q8 @+ j4 R9 [/ @5 Y, F
) F, M! u+ Q  V4 q( o! {        key.h
1 @4 P0 j2 H$ y4 e' ?
  1. #ifndef KEY_KEY_H_
    + ?5 C  m% N. ^& B
  2. #define KEY_KEY_H_
    $ e9 g7 @4 t; d. Q4 ^
  3. * x/ e! |4 u5 H0 J
  4. #include "stm32f1xx_hal.h" //HAL库文件声明
    1 e/ a/ O/ x& L
  5. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用
    3 ~. e' \, E( x8 V  u* p
  6. #include "../delay/delay.h"
    8 K6 I7 S. Z% {( r
  7. 3 ^- \& B7 |. V# G# m
  8. uint8_t KEY_1(void);//按键1
    7 I" |! z% y) Y0 R8 w9 W
  9. uint8_t KEY_2(void);//按键24 i6 ~# \, a4 G: I

  10. & g3 R% N0 I( m1 |$ p3 U
  11. #endif /* KEY_KEY_H_ */
复制代码

$ T; A" d' X0 t- A. N, q, ?        key.c
* ~* K+ s$ K1 [% e0 i0 J& t6 O  i7 W
  1. #include "key.h"
    ) Q8 A3 M6 o/ z
  2. $ G/ y( d8 F- v! m
  3. uint8_t KEY_1(void)) r3 e5 V( }9 o" Q% x" M6 ^  ?
  4. {
    - o6 }, V+ @6 ~! E  l; F
  5.         uint8_t a;
    7 e: e0 i7 }# _7 u. f. E
  6.         a=0;//如果未进入按键处理,则返回0: m4 M4 n2 W: S2 i' Q1 t( X
  7.         if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平
    % I6 I8 R7 d/ i2 A: ?# C5 B
  8. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数): w- i8 J7 }- v( r: ]8 L
  9.                 delay_us(20000);//延时去抖动( m- e5 K& w0 M5 L. {
  10.                 if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
    5 B0 ?! _) W) o4 m$ f2 Y
  11.                         a=1;//进入按键处理,返回1
    ; w% u( _0 {0 a$ N1 `
  12.                 }6 G# |1 f( f+ E" ~2 L( g4 |' k
  13.         }
    / }0 t$ E9 k& z, y' `9 G! g6 f% l
  14.         while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开0 ?" D) |" T, C
  15.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)
    6 o: d) q% W! k7 K* ^) Z
  16.         return a;2 ?) ^% l7 m6 ~9 i6 p1 C& O. z! ]
  17. }& h! ~- ^5 ~' \8 ]6 Y" t  f

  18. " j# b- U7 F9 l3 s( e0 l
  19. uint8_t KEY_2(void)8 L# G. \/ n9 T$ B( T
  20. {
    3 D: h7 z. l& l) U- a* H
  21.         uint8_t a;, X& k# x- L. M  ~
  22.         a=0;//如果未进入按键处理,则返回0( k9 U. m7 F1 r$ ^! Y0 w
  23.         if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
    " _# H. [; h/ Q( {" M, n1 Z
  24. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
    1 h0 Z' }+ N5 D& ?% S
  25.                 delay_us(20000);//延时去抖动, I/ L- ~/ t' \& r& w/ p7 @$ C* a
  26.                 if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
    ! |% ^+ g+ U" M, m
  27.                         a=1;//进入按键处理,返回1; t6 C6 X( z8 p* x% X: I4 |
  28.                 }
    4 G4 o6 K* z2 I0 i3 a' g$ z
  29.         }; q( }( T% v0 F0 A
  30.         while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
    3 x( W2 P' C" i" i: B6 f
  31.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)
    + \5 J  t% U. `$ F5 H3 \
  32.         return a;# a+ L, R: z' M7 k8 U" q
  33. }
复制代码

/ j: a& ~2 m! F. y        3)在ICore添加led目录,并添加led.h/led.c源文件
& C& z: J! G  E7 ?" s% R: Q
; @! @3 l7 Z6 d) Z8 {        key.h7 d. g2 l; P5 V  O1 s+ @
  1. #ifndef LED_LED_H_
    : W( X3 q2 _/ b& V
  2. #define LED_LED_H_
    / v  d4 t! I3 C4 x/ Y
  3. 9 l' D+ [- R4 {) M
  4. #include "stm32f1xx_hal.h" //HAL库文件声明
    2 r$ T4 @; W; k! g7 u" u
  5. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用' f! A# @" J3 L0 ]- H& Z. b- A& \

  6. ' p  ], F# C5 l( E
  7. void LED_1(uint8_t a);//LED1独立控制函数(0为熄灭,其他值为点亮)/ ^" z+ l/ t" Q5 [
  8. void LED_2(uint8_t a);//LED2独立控制函数(0为熄灭,其他值为点亮)
    + q% \  B1 \( i- V$ G* s
  9. void LED_ALL(uint8_t a);//LED1~4整组操作函数(低4位的1/0状态对应4个LED亮灭,最低位对应LED1)6 u0 b! B0 j, w% _4 Q4 R
  10. void LED_1_Contrary(void);//LED1状态取反
    " B6 @' ]$ R. s" ]4 m
  11. void LED_2_Contrary(void);//LED2状态取反/ D, q& I4 T! F- _

  12. % [- J5 _* d, Q- X5 d# F) K3 B6 s
  13. #endif /* LED_LED_H_ */
复制代码
6 w7 m8 L. X& g0 c; |5 F
        key.c
2 H0 V( A3 H, s" I% e0 [! x
  1. #include "led.h"
    - g( K  H0 A8 @

  2. ) f8 I8 Q7 M+ ~
  3. void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)! g7 Z' y4 ~: p2 b4 c4 B( u0 k( R, J
  4. {
    ; V4 c5 P, w. N# s. }! G5 v, v
  5.         if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);( Q/ S5 ?" Q: s9 Z2 Q8 E3 T, A. p
  6.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
      @5 ?# Z' z6 e
  7. }9 W6 b' Y( s. r, g
  8. void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)" g* F, O. \# i$ c8 `
  9. {
    + c# d3 w3 ?. |( _
  10.         if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
    7 u1 |$ \3 I+ c: e  S. a4 t8 v
  11.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
    9 e& Z- A4 k: F$ z* j
  12. }& O: J# q, S( o5 e6 e
  13. void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1)/ q. a2 Z) |' D
  14. {) Y* G) J9 p+ B& S) ^5 q
  15.         if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);% U2 H' \4 Y& r# |  A9 @4 h: Y
  16.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
    5 ^- o: l  @9 ?/ A) K9 T' j: f
  17.         if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);) H1 R+ X  g% C4 l- s) V
  18.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);( f& j% l/ B& q
  19. }9 B) N" w0 b" ]9 s2 j5 C# M* h. |# v
  20. void LED_1_Contrary(void){3 j% z+ D1 V1 P0 z6 V3 j
  21.         HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));
    ( P) z: t% X7 E4 f2 F
  22. }# h* Z% J9 j" g7 s8 t2 a: W- C
  23. void LED_2_Contrary(void){$ }# ~+ [( R4 `, B4 F
  24.         HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));' |/ e% z, W9 S! m+ i
  25. }
复制代码

! B' i7 N* d% _1 p  M0 F        【3】创建串口驱动程序,主要是复写串口回调功能9 v; ]% p- }  t4 A% C
        1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能
- a/ N2 l4 u) A0 M  i4 x, V/ V. i/ s8 b# k# ?- @
        usart.h$ g$ ~1 s8 F  T1 m% I% a
  1. #ifndef INC_USART_H_4 X; [3 j7 `! `: Z* i
  2. #define INC_USART_H_8 k' b# M$ z6 N* n8 t. A
  3.   Q2 J" ~5 ?3 p* F" o
  4. #include "stm32f1xx_hal.h" //HAL库文件声明- g% [3 k8 H, F7 B6 l4 D* N
  5. #include <string.h>//用于字符串处理的库9 |  V; Y3 w6 T& M- O
  6. #include "../print/print.h"//用于printf函数串口重映射
    . u1 F" X1 c1 {' I

  7. / M# X* ?1 Z& {1 m% x: o; y" t% }" {
  8. extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体/ I) Z7 r7 q5 P4 _1 b* D% Q
  9. extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体  @+ G1 }& h+ r7 w7 O% q- j& u
  10. 2 W6 N2 P( O$ V
  11. #define USART1_REC_LEN  200//定义USART1最大接收字节数5 l5 F+ W9 ]7 Q1 \3 W$ e$ s
  12. #define USART2_REC_LEN  200//定义USART1最大接收字节数6 a2 k2 e" z4 w- @8 s" r

  13. " Z" t9 h. O, O7 u. u" W- A) ?
  14. extern uint8_t  USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符1 x+ A% `. E! m) c( R: [& b# o
  15. extern uint16_t USART1_RX_STA;//接收状态标记+ T( S: d; D- c  D0 _
  16. extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存5 U+ H: |8 K4 ~9 u  Z

  17. " p. ]  d# n# K, _) Y7 [2 ~( X! f
  18. extern uint8_t  USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    ( f3 G3 a! r( n, q' z
  19. extern uint16_t USART2_RX_STA;//接收状态标记
    : W7 ]( ]9 k( F) t( k; H3 R' s
  20. extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存
      L) ?; x3 H5 x1 [8 B8 C9 y! N

  21. ) q! e- b7 o4 u6 `

  22. + F9 e2 Q3 z- b0 Y% }
  23. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明' ^% v0 h$ i" O4 Y7 T# J( ]9 E
  24. # ?. i" e: F' i. S+ q
  25. #endif /* INC_USART_H_ */
复制代码

5 `2 B  A, |  R: P        usart.c& y# X( g2 F1 Y
  1. #include "usart.h"1 W+ ^) U! Y! u, F" n

  2. / F6 Z# f! b+ |* f
  3. uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
    8 B3 D4 \0 C6 ~- B  ]9 _1 g
  4. /*
    0 a$ M- y, N) n# m
  5. * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;
    : {) Z+ j9 P4 Q4 W
  6. * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;3 Q3 N9 E( ]. M1 \! C3 A
  7. * bit13:预留8 F+ i% ^: C1 S: V0 L
  8. * bit12:预留- z' X6 ]- g; g& |( F) J, |
  9. * bit11~0:接收到的有效字节数目(0~4095)7 i  ~+ b4 t$ V
  10. */5 x* F* @# x9 R% n! Y  n
  11. uint16_t USART1_RX_STA=0;& @7 L3 ?/ M0 _: i. k4 [3 t' d) ]
  12. uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存
    & D) i! D7 H# y, O5 H) I+ U
  13. ( H: o$ X  c; u& k
  14. uint8_t USART2_RX_BUF[USART2_REC_LEN];8 L- T( h7 Y# w2 d
  15. uint16_t USART2_RX_STA=0;: q1 W3 y# q: j: A
  16. uint8_t USART2_NewData;
    1 x3 f% d. q7 @$ b& Q; F4 V

  17. 3 Q( ]# F) {, w1 {+ x5 l: r
  18. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
    3 I" y8 {8 z, o& e6 B- e  D7 L
  19. {
    ! K6 C1 x# T9 ~& ?
  20.         if(huart ==&huart1)//判断中断来源(串口1:USB转串口)
    8 }# c7 U: u- X1 S/ |3 Q3 \* ~7 s# _) E
  21.     {% O1 f# I* o* X. u2 j
  22. //                printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
    ) G, R# U$ O% ?! E8 N6 d
  23.                 if(USART1_NewData==0x0d){//回车标记$ n# s* N1 Y0 L! o6 W
  24.                         USART1_RX_STA|=0x8000;//标记接到回车7 T- [* w4 P, [9 l5 g
  25.                 }else{
    3 X: D* j2 Y, V; ?6 ~
  26.                         if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){
    7 v: g' c' s! I4 Y: g
  27.                                 USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组
    5 X0 J  |. U$ d' b5 a3 u( n+ L  U
  28.                                 USART1_RX_STA++;  //数据长度计数加1
    ) \* ^$ P" F3 H
  29.                         }else{% h; g% a. T8 _% `; X
  30.                                 USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出# l; l4 G* L* `9 A9 ~, d: o7 E: y
  31.                         }" o, e7 X# ?3 n: p5 U7 T5 r# q4 f
  32.         }
    3 v& t" y$ K- L0 r) [4 k+ j
  33.        HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断* e# l0 w- U" |* L+ w$ _7 \. C
  34.     }  h8 i7 L8 E1 @  m
  35.         if(huart ==&huart2)//判断中断来源(串口2:BT模块)' w$ U# F8 D' E' {% }
  36.         {* m; }; t2 G- v) i* S6 H5 L) D5 k
  37. //                printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
    ' r) m8 X$ a7 b8 J- U  V. H
  38.                 if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)4 u3 f7 h  B* }
  39.                         USART2_RX_STA|=0x8000;//标记接到回车: Y: F' N/ F) |3 D
  40.                 }else{
    * J% J) A) r. u3 u% Y8 T" r
  41.                         if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){6 F* D: P6 p+ `3 N. s3 e
  42.                                 USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组/ B5 g+ v0 M1 m; j' o
  43.                                 USART2_RX_STA++;  //数据长度计数加1( }; u9 A# n0 ?
  44.                         }else{
    : Q7 E/ @# P) H! ?& p/ f
  45.                                 USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出4 G' W& s  d, i) ~9 l3 _9 r
  46.                         }
    * d' h+ h+ ^8 C1 z# l
  47.         }
    2 T; ^1 }" b" r! w$ |) \
  48.                 HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断, {( r0 o/ ~4 s
  49.         }
    * |6 {* f9 `" j
  50. }
复制代码
$ i$ h& X  {1 G. Z0 J
        【4】创建蓝牙驱动
, p3 b. B) X7 D  w, g        该驱动主要实现通过usart2向蓝牙模块写入数据,(读取数据主要通过串口usart2回调,在usart.c中实现)。在ICore添加bt目录,并添加bt.h/bt.c源文件,实现蓝牙驱动功能5 N$ V8 w: Y- w/ J: r3 }9 v. d

- t. t) h* k( j& p0 N: d, N        bt.h( |1 i7 ~# @' x- B2 S& m0 {
  1. #ifndef BT_BT_H_. Z. S: `1 b; x+ U
  2. #define BT_BT_H_+ q, K# b; p: [+ r4 b3 z; i2 z

  3. : c+ S) s2 u! F8 m5 H0 Z) m: C) v2 w
  4. #include "stm32f1xx_hal.h" //HAL库文件声明
    ; g# ]) V) p  N0 c$ I
  5. #include "main.h"
    & `4 R* }7 j2 A* c, I
  6. #include "../usart/usart.h"
    " N- e! j- l3 @: ^( C( h' g
  7. #include "../delay/delay.h"
    8 c% g" v* l. _4 M. g
  8. #include <string.h>//用于字符串处理的库
    3 J6 P3 W7 c2 J/ l: d1 x  Y7 M
  9. #include <stdarg.h>" ~* D/ g7 r5 [1 f3 g  ~
  10. #include <stdlib.h>+ u; z: v7 K" ^1 g5 u8 {
  11. #include "stdio.h"( R2 x& j1 R# F$ D% a3 {
  12. / a: G$ Y3 y2 `' \% a5 u
  13. extern UART_HandleTypeDef huart2;//声明UART2的HAL库结构体
      W9 m5 f  M1 F3 g5 P8 [
  14. void BT_WEEKUP (void);//蓝牙模块唤醒函数
    / |, x. w- a+ I2 c3 K3 }
  15. void BT_printf (char *fmt, ...); //BT蓝牙模块发送& G. b( \7 r- L1 V  z" }  `
  16. 4 ]& s4 c5 T  B$ ?, x% I+ a5 O
  17. #endif /* BT_BT_H_ */
复制代码

1 o# ]5 `" _8 q, k% }        bt.c
% \0 D7 f- q* j# l( l/ ]
  1. #include "bt.h"; i2 G- d' Q6 W3 z+ u; {' k. W
  2. ' y# L7 @, h6 w3 j; S, T
  3. //蓝牙模块唤醒函数
    + \& @( L! X- K" R8 R/ u
  4. //对蓝牙模块上的PWRC(P00)接口一个低电平脉冲,如不使用睡眠模式可忽略此函数
    ! v' e+ _1 R* _2 i3 @/ [
  5. void BT_WEEKUP (void)
    ' w2 [" ^1 G% ^0 S$ p) c* W9 @
  6. {9 x$ n2 t# I; y1 Z9 h$ H
  7.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_RESET);//PWRC接口控制8 s' ~& E# h. w3 r; A  j
  8.         delay_us(100);
    : k  F, y* x3 |* ]/ m9 B
  9.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_SET);//PWRC接口控制
    ' u" {. C9 V. V$ ^6 B
  10. }! P+ v/ o/ A1 l! W- k6 S7 q
  11. //蓝牙模块通信,使用UART2,这是BT蓝牙的printf函数
    $ |8 u( a% K$ g- g5 ?' s& g1 g8 _
  12. //调用方法:BT_printf("123"); //向UART2发送字符123
    - R) n0 ~7 U, n
  13. void BT_printf (char *fmt, ...)
    / T/ g/ I3 v0 v# P. ~  j' h
  14. {
    ! x6 `: ]" I8 K4 X7 W
  15.     char buff[USART2_REC_LEN+1];  //用于存放转换后的数据 [长度]6 m1 B1 I7 N* Z+ ?
  16.     uint16_t i=0;
    2 E6 y: s% [, M3 B
  17.     va_list arg_ptr;( y- ]% C* k: f' N" U! C. ^
  18.     va_start(arg_ptr, fmt);
    5 P6 ?. J4 e9 ^- ?, G7 R
  19.     vsnprintf(buff, USART2_REC_LEN+1, fmt,  arg_ptr);//数据转换
    4 m8 B4 k5 c0 |5 \. Z% y# y
  20.     i=strlen(buff);//得出数据长度
    8 L. m' ~% \. r) J3 ?/ a  X
  21.     if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)$ k: `1 _% H: g  b) \1 T
  22.     HAL_UART_Transmit(&huart2,(uint8_t  *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)
    9 g  ]: I- k* s5 P: o4 j
  23.     va_end(arg_ptr);, g9 L7 Z( v) d/ y/ L$ l+ n% C
  24. }
    2 N0 G2 [' `3 p  ~- ]) h5 _4 |7 b
  25. //所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在USART.C文件中。
复制代码
4 G2 i$ J$ g1 A% n
五、编译及测试
( e' F# [$ d! \: z        【1】功能调用及编译
9 P4 a5 ~4 a' N2 X& n        1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:
: [% Z& {5 H! ~$ T
  1. /* USER CODE END Header */
    ) h9 l* ~! m. N. y; g& L" H1 B
  2. /* Includes ------------------------------------------------------------------*/1 R2 w# f2 @) N! l2 \+ r1 w/ O$ C/ T& E
  3. #include "main.h"
    0 c' c# S" T" x- |* `$ ^

  4. 6 X: i/ \! g5 O
  5. /* Private includes ----------------------------------------------------------*/
    + F# Y5 ]( o/ R. i* [1 A! P* o
  6. /* USER CODE BEGIN Includes */
    ) c9 X7 Z1 O* m% s; I
  7. #include "../../ICore/led/led.h"
    ! p. q# F$ g0 M, s
  8. #include "../../ICore/key/key.h"
    , ]. u7 ]/ g" B! R5 ~
  9. #include "../../ICore/delay/delay.h"* L0 W) L+ I, _, a: H
  10. #include "../../ICore/print/print.h"//用于printf函数串口重映射
    % D( R" l3 r& ~4 |- }+ v
  11. #include "../../ICore/bt/bt.h"6 e" _! q9 \4 h% P- S
  12. /* USER CODE END Includes */0 [' y9 z" q4 r) m. e- g
  13. ' R, C; _' y# `. Y5 t$ i" [
  14. /* Private typedef -----------------------------------------------------------*// |1 V" \" c& u) \& v8 Q
  15. /* USER CODE BEGIN PTD */% g* U/ ]2 c4 B4 }: _9 z  r
  16. / b! }( [; U' ^
  17. /* USER CODE END PTD */9 D5 }+ P. s' Y! K
  18. * j3 P- B" C0 ~6 g
  19. /* Private define ------------------------------------------------------------*/
    , Z( O" V$ u: ^+ a; ?8 ^; e
  20. /* USER CODE BEGIN PD */, a9 x8 L# I9 v* J( ?8 U
  21. /* USER CODE END PD */
    . y3 l+ @/ [( |# b$ I  U* ]/ I0 N
  22. ! i  x! K5 e# p
  23. /* Private macro -------------------------------------------------------------*/$ X6 h4 j. I2 q/ j  X8 F4 U
  24. /* USER CODE BEGIN PM */
    . x- S) `, c2 G: P; A, m

  25. ! p9 o/ o! k7 A) Q
  26. /* USER CODE END PM */9 d/ ^, @4 l6 ?. h2 x& q% H8 V

  27. : l; i1 e* {% @
  28. /* Private variables ---------------------------------------------------------*/+ c; W& W& [4 M6 u
  29. UART_HandleTypeDef huart1;) x2 N4 T1 N! u- r$ g' C
  30. UART_HandleTypeDef huart2;, `, W/ U" \/ n3 i9 W

  31. 5 J- p2 \( j5 E2 N3 v
  32. /* USER CODE BEGIN PV */
    $ G1 I# {' r4 Z  @' Z; Z$ v

  33.   e  o$ P7 u/ X
  34. /* USER CODE END PV */& q/ w' E- ]! N" Z6 e
  35. * ^8 ]" d/ G, V* }& W
  36. /* Private function prototypes -----------------------------------------------*/
    + P5 q7 M# ?+ {6 ?+ m
  37. void SystemClock_Config(void);) l) Y: N# }( W: G- q
  38. static void MX_GPIO_Init(void);; u* t  h- R5 _  |/ o! V) G
  39. static void MX_USART1_UART_Init(void);* v( e1 u( F/ q
  40. static void MX_USART2_UART_Init(void);
    & k, J" U& X7 S1 E- R1 g. m
  41. /* USER CODE BEGIN PFP */9 e4 r( s+ Z* }# E2 V4 p6 V

  42. 0 l; A0 y* a5 f' x: N1 M
  43. /* USER CODE END PFP */
    ' Q, @1 X" m8 d' i

  44. 6 K- P' G3 M1 d0 q# `8 b& V
  45. /* Private user code ---------------------------------------------------------*/8 @8 J! J2 Z2 o  b9 ~* }
  46. /* USER CODE BEGIN 0 */
    / W) y+ j4 u( ~* I$ l; h) l& ?

  47. 9 R1 u% ~2 \8 p9 E
  48. /* USER CODE END 0 */
    ! \; i2 V% o! V
  49. + ^8 L6 Y! c- _  W8 }4 \# s; E
  50. /**
    5 W/ ^- H, M" Z* |
  51.   * @brief  The application entry point.
    . s; L* `$ Q% F3 b# R* a6 s
  52.   * @retval int3 q, e3 [6 G& K! r3 H7 J+ @! ~
  53.   */3 c7 `& O/ c. C* y1 n: C
  54. int main(void)$ u/ @" v& A4 s) ^" t
  55. {3 \' N0 K  \  o' _" ^
  56.   /* USER CODE BEGIN 1 */
    0 ?6 Y7 r/ m5 L& Z. e7 a2 K

  57. , L2 Z# V: U) ?) E% w& G( W0 _
  58.   /* USER CODE END 1 */
    1 w% P! ?( i* |/ E5 D

  59. 1 |& H. Y7 x$ ?6 N" E
  60.   /* MCU Configuration--------------------------------------------------------*/  g, t- Q: s7 a$ x
  61. ) _; u" o% I8 P1 |# B7 a' y
  62.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    , j4 L2 u0 ^2 f5 r
  63.   HAL_Init();3 N  r; I& P1 x
  64. 0 t. A# `9 a8 H  ?# C3 g8 U
  65.   /* USER CODE BEGIN Init */
    ; Y0 G3 j4 `6 W; V$ k  g4 Z" J6 C! ?
  66. ; |: J; G( u$ X. j: i
  67.   /* USER CODE END Init */
    1 k6 c; {4 H6 ~2 T& K

  68. 7 M  q+ q6 m# `: ^3 @7 H* r
  69.   /* Configure the system clock */
    % V( I6 ]& U' N, Z! N  E
  70.   SystemClock_Config();% l/ x  u" P! b, D) \; M

  71. 5 p7 }" T) z: ]$ ?
  72.   /* USER CODE BEGIN SysInit */
    ( L, h( V6 W) Q! |+ K7 X

  73. ( |6 N' @: n8 M  s+ K- f7 Z8 P
  74.   /* USER CODE END SysInit */
    - C1 X# ^: F$ n/ P4 W/ p7 J. b
  75. 5 c& e. Q$ ^7 b. g
  76.   /* Initialize all configured peripherals */! H( H, |" ~3 c, g6 j! X
  77.   MX_GPIO_Init();
    , n; [# G  K: _* p7 w& W  \) t
  78.   MX_USART1_UART_Init();1 t! F! s+ y4 ~% I% ^
  79.   MX_USART2_UART_Init();
    , e$ e9 T* e: O) K
  80.   /* USER CODE BEGIN 2 */* M& A! E/ B) L- N+ b. D
  81.   ResetPrintInit(&huart1);//将printf()函数映射到UART1串口上, _2 g3 \' W3 j, y7 C
  82.   HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);//开启串口1接收中断
      B& \, S5 G2 V* a+ C
  83.   HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启串口3接收中断* ]+ Y% y. U2 B0 h) L
  84.   /* USER CODE END 2 */
    , x. k9 w  C: P

  85. " U/ Z, @# b! u) t, }
  86.   /* Infinite loop *// x8 N8 @1 b1 N# H
  87.   /* USER CODE BEGIN WHILE */( x7 S* x  ?7 P0 @- n8 u  _9 M
  88.   while (1)- i/ }; v- q3 j  O. }+ @* ~
  89.   {
    7 w/ z8 r9 c; R! G
  90.           //demo 蓝牙024 M$ p9 }( }7 }! s
  91.       if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)
    - ]9 b/ p; K4 g% o6 D, U! Q
  92.              BT_printf("%c",USART2_RX_STA);# x7 x. o6 P* q/ p7 j
  93.              if((USART2_RX_STA&0x7FFF) == 1)        //判断接收数量1个(手机控制程序)* f# g/ o  R5 p" M  ~/ r2 k# x
  94.              {+ ~7 [6 M! \: y) _: w
  95.                      BT_printf("%c",USART2_RX_BUF[0]);
    : `  Z+ _# m& E4 Y& n7 k$ I
  96.                      switch (USART2_RX_BUF[0]){//判断接收数据的内容
    6 A4 R0 y% M7 v5 `. N3 J
  97.                                 case 0x41:1 Y" H" ]& q: v4 o0 ?) }6 C
  98.                                         LED_1(1);//LED1控制
    7 O; e! n  [( o
  99.                                         BT_printf("Relay ON");//返回数据内容,在手机APP上显示
    8 b+ Q3 T" \% o- D1 ~9 N
  100.                                         break;" |* I. Y* [  w$ U2 o
  101.                                 case 0x44:( N5 F7 N# Y: E: }3 I7 [3 J# `
  102.                                         LED_1(0);//LED1控制
    6 _% i+ E, r' J8 T4 A
  103.                                         BT_printf("Relay OFF");//返回数据内容,在手机APP上显示8 I8 N9 y) k- l( J9 ?
  104.                                         break;
    1 N' v5 o4 G) \. p$ f4 k
  105.                                 case 0x42:; T$ g2 x, @/ z5 N/ b5 v+ ~. A% z
  106.                                         LED_2(1);//LED1控制" ~5 o- c' f4 j2 A+ N4 {+ z
  107.                                         BT_printf("LED1 ON");//返回数据内容,在手机APP上显示
    7 O: ?& R0 ?4 H) E
  108.                                         break;# \! h" `5 n# ~; I# L9 _4 ~8 ?
  109.                                 case 0x45:
    8 i0 n0 o8 s( ^2 q
  110.                                         LED_2(0);//LED1控制, w0 |8 B" P' H- l4 ^' i  Z
  111.                                         BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示, v$ a+ r0 z4 ]: I$ R
  112.                                         break;* @  s$ H0 b: O4 M8 @* o/ K  a
  113.                                 case 0x43:9 b4 R) t- [' q+ x0 \
  114.                                         LED_1(0);//LED1控制1 {  |# i3 f8 q4 e7 s* t, [
  115.                                         LED_2(0);//LED1控制( q2 X' D, b9 j" s9 ]* ]
  116.                                         BT_printf("BEEP");//返回数据内容,在手机APP上显示% U, H) l: S) P
  117.                                         break;
    3 E8 @8 W5 v. w" D; y
  118.                                 case 0x46:: v% @5 [6 R5 @" P, l
  119.                                         BT_printf("CPU Reset");//返回数据内容,在手机APP上显示
    % l6 @6 y" r2 ]7 G( k  X4 z
  120.                                         HAL_Delay(1000);//延时
      n* N  G+ u% E: l. b  |' p4 f
  121.                                         NVIC_SystemReset();//系统软件复位函数" V9 ]8 [* X& ~
  122.                                         break;7 R1 V' a* p, d7 F' X  \
  123.                                 default:. A1 o7 `. E2 _$ p" {+ e+ s& ^
  124.                                         //冗余语句
    , ?" W( `4 r( V) d
  125.                                         break;
    1 }- T: W& U! b% X$ U
  126.                           }3 X" C/ q8 w, O6 d/ ~/ ?- l% a
  127.                  }
    1 \/ T0 |0 v+ d: E( x' ^
  128.                 printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1
    2 p# D# M* n  p7 m5 J$ I/ L. r5 L
  129.          USART2_RX_STA=0;//标志位清0,准备下次接收# {% n9 L$ {, [& N
  130.       }
    " [+ W! X5 ~( E3 k: F
  131.       //接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块5 S; h2 L5 j# R, T' u
  132.       if(USART1_RX_STA&0xC000){//结束标记
    $ H  W2 u" k' Y1 o; o5 Q  G& f
  133.               BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);3 k$ F% ?& }5 n' b' x& P
  134.               USART1_RX_STA=0;//接收重新开始
    , h  W7 @2 F" j
  135.               HAL_Delay(100);//等待
    4 e) C' ^: }& I5 u
  136.       }; D- L8 w8 t( b6 m3 d% d
  137.           if(KEY_1())//按下KEY1判断. Y, t( Z+ |# d4 I
  138.           {
    ; C. T8 D: d& J1 s7 r
  139.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
    $ |# C/ ]5 V1 t( Q1 e) e' y5 Q( ^
  140.                   LED_2(0);//LED2控制
    ! A: a, _& F8 s5 v8 w! V% ^
  141.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)5 o- X' h4 s0 o* y
  142.           }/ z( e$ e0 e- @# B
  143.           if(KEY_2())//按下KEY2判断
    1 j! \. a1 u1 v; h/ d
  144.           {- O- C# T  E! [! Q8 Y
  145.                   LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
    ' q( U; A  T  F6 N% v1 Y0 Z$ d
  146.                   LED_2(1);//LED2控制
    8 C4 D( O/ v* F, o" r. t/ [5 k+ \
  147.                   BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)
    8 D7 O1 R  [- K! ~% v! V
  148.           }( s6 K$ O3 {! l3 c; c( H* v
  149.     /* USER CODE END WHILE */
    6 p0 N+ e$ g: ~  }

  150. $ m& [, c$ Z1 L6 @; {- j  J
  151.     /* USER CODE BEGIN 3 */3 ?2 {! M2 Q: g
  152.   }
    # E% U9 y6 G, M& U" v! Q, {
  153.   /* USER CODE END 3 */
    . `+ w" j! U% {) m. }0 e" {5 H" c
  154. }
复制代码

  m7 K! r! z# M, z' ~       2)设置编译输出支持,右键工程进入项目属性设置页面:8 ?6 x4 M. F# O$ w2 e3 H1 O4 c
  ?; Q: y% h3 Y  t7 a
b959f3b4bbc34e9a933d8fa45890c6ba.png
3 j9 F' i  c5 }$ P9 G! Q  g% Z, _$ i# E4 N% V
          3)点击编译按钮,完成编译(整个工程需要源码修改或添加的源文件如下):
  z& H. y, L" \  R: H9 F2 D# t1 V: F; ^$ h0 m
288d14c992b3413ab8b2e3c42e0994ed.png
" [' E+ ~' V1 z8 d9 ^5 X7 d2 e- l; x  L6 R( S
        【2】程序测试, U8 n( F+ m4 e8 v1 ]
        1)测试过程需要三个工具文件支持,读者可以自网上搜索最新版本或采用其他同功能工具替代测试:% _: X: w+ `- K6 |) t( D* Z5 |
        FlyMCU加载工具,将生成的.hex程序文件加载到板子上4 M' `6 P1 Y- G8 s
        SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入
/ [! z/ V& ^8 `5 e% h- r; ]        蓝牙调试器工具,本文用的是1.9安卓版本。) h$ F, T9 \& [. `& Y7 k0 q
4 T7 t3 p5 E3 t& P/ T& Y
616ca3780a8b4077ba5ba5f13ad76834.png
! ]4 Y5 k6 g1 z8 _/ T( V+ @9 ~& s( @
& b; G$ v; E0 m
/ W3 ]* f3 o0 n/ b& q( q( r/ D        2)加载程序,选择串口,选择程序(.hex),点击开始编程按钮:+ H7 }! m0 g( d8 y" @& k7 R
1 {" b8 C- ~2 o
5da0d56a3c4e4c45a74e90e7fbf4b989.png 7 M% U/ R* x2 N" k5 ^
0 i! j" F8 t; I
         3)手机打开蓝牙调试器(别忘了开启手机蓝牙功能),进入界面,搜索蓝牙,点击蓝牙边上“+”按钮连接蓝牙模块,采用SSCOM串口工具连接到usart1上,就可以通过蓝牙通信实现手机(蓝牙调试器)与电脑(串口工具)的通信了,在蓝牙调试器发送数据时,十六进制时需要加上“0A”作为结尾,如果十进制发送时,注意加上换行再发送:8 t& A7 J' F& E, ^/ J
0 D$ ?& W. x3 k. p, [
df172bc6aaa94e678d2c06fb92dbe6a9.png a573139985cc47b79688e2ee52359e8e.png , B: f2 x9 E) y2 W1 l' \: a1 q  i' X, t

5 j. g: U* j; X        注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:
+ F2 A# i; `: Z7 U4 G: Y% E
  1. if(KEY_1())//按下KEY1判断
    - t- i4 ~( y: y8 w" B, T. X
  2.           {
    . K5 i/ {" a/ `/ P
  3.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位% b! O( I1 ?8 n6 I  w$ S  R/ b
  4.                   LED_2(0);//LED2控制
    $ l6 Z" w" q; R& z& H& `3 Y' u' g2 a4 G
  5.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)5 J3 e$ f. M+ {1 D$ o: Y  I$ Q& J+ {
  6.           }
复制代码
# U! Z/ ^0 ~+ c- Z* O( O' A' Q4 _
        串口发送数据:, m+ v* Y7 w4 _& \" m! ^$ i4 [4 ?) N

  {7 P1 I4 ^( F
399927e9b5474fd4bafe8534255fab31.png
, S4 i) W) I2 Z. `5 Y2 i
5 w. B5 s6 {# i1 P7 F& X5 A1 N6 C! i
# x% h1 J5 [# V; C, C, [+ D
        可以进入按钮控制页面进行指令定制设置) I  _( C: g; y0 s# W2 k, v8 b

3 k. F. c. s! g% j( a8 E
56473e9c27a04fafaa96bc2f0dab5f08.png 9ac0cde743b143e08e391b2d9e793b56.png ; a/ |3 K  U$ J6 o' U

  D- ^1 @3 |) G$ P9 h2 i         至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。4 j* E8 n$ @$ ~) Q+ I' n; c8 @5 m
————————————————. _$ y  Q' b! K( A$ [
版权声明:py_free-物联智能, M; T" w! v% q+ {* F' K
如有侵权请联系删除
0 s2 s! s7 {% R8 U
% ^& F. Z7 ~* `0 v( b4 t3 [1 T& b) Q9 x; I/ }
9 b' @& r! {3 U" u8 I
收藏 评论0 发布时间:2023-4-7 15:54

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版