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

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

[复制链接]
攻城狮Melo 发布时间:2023-4-7 15:54
一、蓝牙通信技术7 U- \5 Z; t% b5 z  E1 Z5 X9 l
        蓝牙技术是一种点对点点对面的网络构架,他可以在限制的范围内以很快的速度传输网络数据,在物联网应用中,支持网状网络的物联网短距离无线通信。目前它还被广泛用于智能可穿戴设备、智能门锁、智能医疗设备、智能照明设备、智能家电等消费电子、工业采集、汽车电子、智能建筑等所有的物联网智能产品中。
; L& m7 S" F5 q3 X4 j! ?

; g7 j2 f2 A+ Q/ K( M5 _6 |        蓝牙是无线个人局域网,最初由爱立信制作,后来由蓝牙技术联盟制定了技术标准。蓝牙产品包括小型蓝牙模块,以及支持连接的蓝牙无线电和软件。 如果两台蓝牙设备想相互交流,则需要进行配对,一台设备将成为主设备,所有其他设备都将成为从设备。 通信时,主站侧需要进行检索并开始配对,如果构建链成功,则双方需要能够发送接收数据。在通信状态下,主侧和从侧的设备都开始切断,可以切断蓝牙链接。蓝牙通信本质上就是无线电传输技术,蓝牙的工作波段为2400–2483.5MHz(包括防护频带)。这是全球范围内无需取得执照(但并非无管制的)的工业、科学和医疗用(ISM)波段的 2.4 GHz 短距离无线电频段。
5 w& ?3 p- T* g2 v4 I" g
" U+ p% a; k4 }% f! _4 j( }

  X. S# i+ B0 i9 e, L二、MCU及蓝牙模块
* X9 q5 O( \& z/ T, n        本文采用STM32F103C8T6的芯片及JDY-08 蓝牙透传模块,相关引脚如下:
5 v6 z) m% m' q5 Q  C# N( c1 @+ G3 R1 b- m$ Q) F9 W3 y
        MCU引脚设定:PA9、PA10作为USART1引脚,用于下载程序、调试显示,PA2、PA3作为USART2引脚,并与蓝牙模块进行通信,PA8作为GPIO_OUTPUT模式,用来控制蓝牙模块上的PWRC。& y$ H9 ?$ }" }( ~* V9 u' f
4 h" ]8 P9 x$ v
2d927f8850734dd683cfc95f270f3604.png
4 o- T, s( r2 B( R- H7 d" t- I$ }* ~2 g# o3 Q5 G+ h& D; N
         蓝牙模块为JDY-08 蓝牙透传模块,基于蓝牙 4.0 协议标准,工作频段为 2.4GHZ 范围,调制 方式为 GFSK,最大发射功率为 0db,最大发射距离 80 米,采用 TICC2541 芯片设计,支持用户通过 AT 命令修改设备名、服务 UUID、发射功率、配对密码等指令。3 V2 R# N! ~9 B3 R

- ~' @8 P2 B) y) W, E        TICC2541 芯片 引脚:: G+ U, {  `2 [! @  D1 i
9 {/ z. G9 P6 @8 z$ d
87b66d3312cc4c23b64182bd2c2496c9.png ! K7 l/ p5 n1 d3 V( W9 v2 m
! O5 e+ [" E* k2 {
         引脚功能定义,在使用串口发送命令时,请将模块的 PWRC 引脚接地,并接上模块的电源(VCC、GND),电源电压为3~ 3.3V:0 J( J" c# L; l4 B
2 O$ s- W0 \8 ~. @% l9 u+ g
50c5510d3d8b4234879cc66e8e1a6988.png / e( ?5 o& B1 O  v3 g
' p2 f, Z, S  A# n  V7 x
         以及本文用到两个AT指令:
. M8 j. J- `: j) @
7 h1 P& j- W- h5 W5 d$ P  w
d5bc46612e09498c922ad506da5679f4.png * e1 ]) M9 H# i6 [
* t+ G6 V% Y% H: X) Y& V
三、cubeMX配置MCU及蓝牙接口
) F6 J# G5 z" [) z        本工程设计功能如下:9 i) {- A2 k0 g( ~
/ F6 B9 `, m  f
        MCU(STM32F103C8T6)的引脚PA2、PA3的与蓝牙模块(TICC2541 )的11、12引脚连接,实现数据通信;MCU的PA8引脚与蓝牙模块的22引脚连接实现,实现蓝牙模块唤醒。
* \, x; b8 N! }4 D. \2 q& ^$ V" x5 ?
( M: z% y8 F& W9 a
        通信逻辑:电脑(com4)<->(Usart1)MCU(Usart2)<->蓝牙模块->手机(蓝牙调试器,需要开启手机蓝牙功能)。) Q% d7 {2 {0 ~5 d9 G, Z3 }
  @5 `1 U( M9 G! K
        功能:& D0 y% k) l7 C# ]9 L8 x! z# ~7 {1 U( g
        按键功能,用于按键时向蓝牙模块发送AT指令;
+ D) m2 g9 S5 {% w        LED功能,用于接收蓝牙模块数据时做出闪灯响应;) V) a" ~, F" O3 o( }
        蓝牙功能,接收来自MCU端的串口通信,接收手机端的无线传输(即蓝牙通信);/ V1 K. z0 n- a* ?: t+ m! Y  }
        串口调试功能,MCU执行程序可以向Usart1发送信息到电脑端,既可实现日志输出,也可以实现指令转发到蓝牙模块。
/ \5 Y) M9 U% n2 g' J
        【1】创建工程
. T' m, H; Q$ |7 C3 R5 t        1)新建stm32工程,选择芯片STM32F103C8T6
- r8 |% s- X+ X* V' r0 G  O% ^* f3 v/ s3 x# {) U$ O
a4d9946142d542f3a8ade81b66e0a552.png 6 Q9 j# Y( ~# w. G# M* Y4 C5 U+ [' U% V

; h0 Y4 p  }* J: J  e& V) @         2)为工程命名完成创建: {. d; n2 q4 g! T3 m+ u

$ N2 t2 y1 J& J" B- y" b1 J
8177bd2fea6b478e8c172a4b4604aa43.png
, r  m. N6 M  ^5 ~7 P
4 g* M5 G; _% S7 x' q
         【2】CubeMX配置2 Y6 H9 c4 H  w8 w
        1)开启sys mode接口
* A* u- W, Q. W( ^3 g3 S2 H  n5 i4 R( o* n- T
6945e8635a7a466b83c22611ad53d9c5.png   b+ |) A% ?" h6 p2 o  Y2 r
1 m! v% |: \) `) Y
         2)开启RCC
$ X% h. k& W) ]* i/ M9 Y' e/ B6 P8 F' s* ^$ f* Q
eb9677e954f14340b91608f89a899e85.png # p$ H  Q% _& }7 [2 v
, m4 {- u. f* s& l  @7 M8 _
         3)开启USART1(下载、调试)、USART2(连接蓝牙模块)。4 D( f6 t0 j  }6 l4 n. m
3 i. r* ]; f1 q! ^; a
8a56a450ae704a66afcd75f588cd2e64.png
; o* V3 t) b. @& M
% Q. I5 p8 a1 G5 W# O3 T4 m$ t         4)开启串口USART1、USART2中断功能
5 N( E* b# N" N( Z7 N/ N. V8 \! a& j9 y+ \
1a51fe61e16c48fd95cd3c1841c6cf9f.png 6 q: |, o4 H5 J& [

+ t8 y+ g5 \, V  n' |* @/ T) D. U2 E         5)串口引脚参数配置
6 b3 f+ `- z) q4 [% V: i* ^- G: b( y
3c5015317b1643e1b7e9a55510e02cfc.png
, N! G: M' P, ~/ u! V2 ~! E
' B+ ~+ Q: {0 m
         6)蓝牙测试辅助接口及按键、LED灯GPIO引脚添加:
" ]8 r% n5 g9 L' h+ b! @& H$ {1 U% R& j
70a978fd9ca34aa18d434351ceb7bb5b.png   N" g) n. f' F2 i
" `- g0 e  l2 o/ W" V( }
        7)系统 时钟配置,直接拉满STM32F103C8T6能支持到的72MHz。6 L; q2 U5 {* |  o/ k" M

) b4 e2 b2 u( t0 U+ F
cd5e618b97e54ef1886818cc2b4c1956.png
4 K% T+ t2 K3 B! [

' q4 @! M" x/ X% T  r1 _, n          8)本工程配置页面保持默认,没有为每个外围设备驱动创建独立源文件,点击保持或生成代码按钮输出代码。
' [/ H+ Q' T- t+ s0 u' ~8 A
+ H1 f  ?9 p. q: C
31870054f08c4b95bfb5f485f13480d6.png   U. m" `8 g8 d& l, f, o* |
$ `; ]( C( H; I# p

# d0 q8 ?, f* I/ X9 B 四、代码设计( c/ i* u! `+ t1 f9 v* d
        【1】首先创建usart1接口的调试输出支持
7 M. G/ e7 |7 C& V+ a# A        1)禁用syscalls.c,右键选择该文件进入属性页面设置。8 t8 j; l6 @+ }4 `7 p0 l- g
4 I0 M3 }" L/ _% Q: C7 d, y5 Q# T; r0 S0 y
aec3533e953447e39024f449845c2564.png
" {# {0 x# _& G4 q& b

0 n* h6 Z/ N% y         2)在工程目录下创建源码目录ICore,添加文件夹print及print.h/print.c,实现对系统printf函数的映射到usart1输出显示功能。
0 B0 V' U6 C2 t5 z7 P
7 T& n. |/ M& l. h  K% v        print.h
2 Q& x, _# k# A! Y; Z8 c& d
  1. #ifndef INC_RETARGET_H_
    . g  s/ l# f1 a. h
  2. #define INC_RETARGET_H_) {: E/ e* ]/ N3 ]  ~$ O4 n

  3. 2 z) E: l5 s$ b7 X+ j& A: H# g
  4. #include "stm32f1xx_hal.h"
    - l* j( `' E5 Q
  5. #include "stdio.h"//用于printf函数串口重映射
    ) O  V8 ^* \) |: z) D5 A! E& J- S
  6. #include <sys/stat.h>. P- @( ~% U* Z2 y9 q

  7. 0 R& t7 q( z( Z& l3 m+ O7 D( |, U
  8. void ResetPrintInit(UART_HandleTypeDef  *huart);
    8 S( A: o, v$ `- T8 r
  9. * z% _5 O5 Z6 H
  10. int _isatty(int fd);
    * [$ {) a- L- R3 |# m6 L- O
  11. int _write(int fd, char* ptr, int len);
    + {" t7 l: _9 f* ~  F' P( K
  12. int _close(int fd);
    1 X* K3 }0 b, P6 X
  13. int _lseek(int fd, int ptr, int dir);
    7 t# ~+ L, [2 l* l
  14. int _read(int fd, char* ptr, int len);
    2 o4 h  B2 \9 {/ m( Q) N( t
  15. int _fstat(int fd, struct stat* st);  M2 Z2 y- \& Z2 i2 D; G

  16. % J/ D4 X1 Y+ S
  17. #endif /* INC_RETARGET_H_ */
复制代码
' c/ ]' Q. y% W: H# a/ A+ }
        print.c
* j% {* R/ ~1 ]# h! V, e" k; w' A3 x2 `( v
  1. #include <_ansi.h>
    ) r  j- o2 F5 t9 f, k7 R
  2. #include <_syslist.h>) ?+ A7 x/ T5 @9 R
  3. #include <errno.h>
    1 G# r  K; x/ _7 I* d/ g
  4. #include <sys/time.h>
    9 U/ ]5 q, A. V. r
  5. #include <sys/times.h>% w) k$ h0 ^* m- H% u
  6. #include <limits.h>
    ) l# y( |7 {3 O& H
  7. #include <signal.h>
    4 t) h8 B- Q& _+ H  e5 v0 G
  8. #include <stdint.h>
    8 S4 e# s2 k7 \  I) M3 i: t
  9. #include <stdio.h>
    : c, N& E& D- N, u
  10. + w, S0 U; }8 C) I/ ~/ {
  11. #include "print.h"
    2 E: }0 \- y  y
  12. * J4 S& g, f4 ?# j; P& z
  13. #if !defined(OS_USE_SEMIHOSTING)
    , Z$ @+ r0 K0 o2 t7 L
  14. #define STDIN_FILENO  0
    9 F9 `+ H# n$ T2 o2 j7 I
  15. #define STDOUT_FILENO 11 U. h( Z; G2 b7 R. w3 j
  16. #define STDERR_FILENO 2' V: z, t: s- a5 s

  17. 2 _' V8 f- u3 x' C4 B- _
  18. UART_HandleTypeDef *gHuart;: e* n. M/ G* z/ o7 t7 u

  19. ! {0 R8 ~8 G/ I* K  E: I
  20. void ResetPrintInit(UART_HandleTypeDef *huart)  {
    : ^1 N& q' l! N, n; M9 d
  21.   gHuart = huart;
    4 b1 @3 E/ B# g
  22.   /* Disable I/O buffering for STDOUT  stream, so that
    3 n3 S8 Z0 c( n) t  {; t+ b& p
  23.    * chars are sent out as soon as they are  printed. */
    . _' w; m- S( u9 k& ~
  24.   setvbuf(stdout, NULL, _IONBF, 0);6 O6 i! l8 w5 n0 V! h; ]. o* ~
  25. }+ Q5 b4 u. J5 N5 i4 g! |+ W2 m) M
  26. int _isatty(int fd) {
    5 }  ~/ F4 l8 M8 G0 z# o5 O1 y; G+ q: D
  27.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
    & U" w# b( c6 \/ \) W. Y
  28.     return 1;
    7 a% B" r! [% e1 a/ u# ~
  29.   errno = EBADF;
    ' F: u4 }; R( k. V3 S
  30.   return 0;" S  b7 a4 m: _8 @) g
  31. }$ s6 ?* q8 c5 G) W2 {2 N
  32. int _write(int fd, char* ptr, int len) {2 @  R7 X, Z6 D- w; Q+ O
  33.   HAL_StatusTypeDef hstatus;" n: {7 G" R! |
  34.   if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {/ e' H8 X' t- D9 l
  35.     hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);" |4 @; b) E% x8 ]% e1 q
  36.     if (hstatus == HAL_OK)
    , H2 Q6 o- s( C; b; M
  37.       return len;
    % ^& y. U9 {7 o8 B* w
  38.     else5 a8 _0 E% x3 t9 @
  39.       return EIO;" q- x" D) y8 {( X$ `: G
  40.   }' g6 r/ G* m7 v
  41.   errno = EBADF;% D9 o6 Z. v( g: L0 `; @0 y) |
  42.   return -1;/ z4 [. |" ^. {: ]( }  V" b; _5 K2 I
  43. }+ N/ r( R4 \# k  r& w
  44. int _close(int fd) {
    " c$ Y& S* ~. ~9 S( D8 \, m2 l- D$ t
  45.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
    6 N( t( m% ?% E+ @
  46.     return 0;
    , ?; }  `, r- u- q0 t  k9 `
  47.   errno = EBADF;
    $ g  {1 x8 W1 I/ R
  48.   return -1;+ E2 ^) U. c- g2 q: j+ s* [$ L: D' B6 S
  49. }/ P; k: |) W* i" x$ ~7 [) U
  50. int _lseek(int fd, int ptr, int dir) {
    0 T( N7 L0 e/ O
  51.   (void) fd;
    1 T/ f! Z) |' \( V1 X2 [; C
  52.   (void) ptr;, c0 H9 W2 b& n3 f5 `1 M1 V0 Q
  53.   (void) dir;0 D: q% r8 L/ F  ^, ^% T
  54.   errno = EBADF;  U9 I9 S: ]: Q
  55.   return -1;* K0 E% R1 Q, r; b8 Q% J4 w
  56. }' ^$ N) U8 Q2 i  i
  57. int _read(int fd, char* ptr, int len) {
    3 [5 q3 f! v  F
  58.   HAL_StatusTypeDef hstatus;0 r7 G- a. F, T) R, Z1 B% C
  59.   if (fd == STDIN_FILENO) {
    : ?2 h) e3 d3 [, j$ I5 c/ c7 Y
  60.     hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);
    . p+ |+ o3 ?6 {, ]8 I5 J1 |, y& R
  61.     if (hstatus == HAL_OK)
    ! _9 X2 y9 K. ?$ `" v! m' I
  62.       return 1;
    ! b  v# w7 h8 Z
  63.     else
    * L) ~7 @6 p, W% d
  64.       return EIO;
    4 [# B8 e# c& J9 h# }
  65.   }
    # ?4 |, F$ |) i0 Q
  66.   errno = EBADF;
    # {6 e, x; n1 c3 C/ f
  67.   return -1;
    5 p% ?6 F. i: ^6 p$ E7 b% n: G
  68. }
    + n* F( H7 T5 r
  69. int _fstat(int fd, struct stat* st) {
    6 D) B# ~  h( G0 R9 J7 W  `( f
  70.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {* f2 a( L3 v2 `5 V: d
  71.     st->st_mode = S_IFCHR;$ H/ ?! ^# n3 u$ e
  72.     return 0;
    6 \- ^- d  q0 u# r0 U+ E
  73.   }9 B. j; h+ k8 }. ~9 e/ ?4 a
  74.   errno = EBADF;
    / C5 p# ]6 H6 R1 [5 L
  75.   return 0;
    : M# ?2 x+ z) Y' i2 F5 l( D- B
  76. }+ d& [& ^- k) r( X* e' k
  77. ( a9 p* T) h8 G; P
  78. #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码
' X0 G/ n# V- ]$ S2 m* f: d4 f1 D7 S
        【2】创建按键驱动、LED驱动、延时函数功能的支持
+ ?8 Z) r) c+ S7 \1 R3 V& w         1)在ICore添加delay目录,并添加delay.h/delay.c源文件- I; m' W. ]2 r& A- U. G- F( w
        delay.h* a9 @, f. r# W  p
  1. #ifndef DELAY_DELAY_H_5 E  E( v' c3 `* |: v4 P; `
  2. #define DELAY_DELAY_H_
    ) b6 h; z) X- h( Z3 E0 u7 t
  3. ) \5 Q! l( D: M' h$ l! ?: s
  4. #include "stm32f1xx_hal.h" //HAL库文件声明4 G$ M; `5 X  c& W; e
  5. void delay_us(uint32_t us); //C文件中的函数声明
    $ o/ {, G" g5 g) `# W9 d* z

  6. 2 P: T7 s' b7 i
  7. #endif /* DELAY_DELAY_H_ */
复制代码

4 X( \4 H% g# s$ y' N8 v        delay.c
* R2 c. m$ B; {' T
  1. #include "delay.h"" ]5 J; O, J, W3 s) V* m: p8 y, u
  2. 9 |/ j; F9 z8 K* `) q: W
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
    ( r5 X: N' D0 o$ ~2 ^
  4. {/ I: ~; l, \& G8 n
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数7 z" m8 |- c6 g6 F4 l! u
  6.     while (delay--); //循环delay次,达到1微秒延时1 ^3 U9 x7 c- k. I$ p- d1 F: p* l
  7. }
复制代码
8 I, v! T  }& g8 F. o$ L+ W; J
        2)在ICore添加key目录,并添加key.h/key.c源文件
9 ~' v$ i" @2 T1 Y1 y4 K' U  W8 X# [1 I1 j* b/ d4 X
        key.h3 Z) p* M9 R* K& H3 A( {; v
  1. #ifndef KEY_KEY_H_) H! q1 |5 q3 R( j1 y
  2. #define KEY_KEY_H_
    9 |+ t# \# n: f6 S3 d7 h

  3. 2 u- L$ l4 u, }
  4. #include "stm32f1xx_hal.h" //HAL库文件声明
    - P" a+ {/ z/ b( q9 \9 P
  5. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用
    9 l% b8 J2 ~! x% S
  6. #include "../delay/delay.h"
    ( w' `" q' Q7 F0 ?
  7. / \0 t1 {/ c" O" w1 d# g: v/ L; r
  8. uint8_t KEY_1(void);//按键1' A+ y7 L% W) l* }2 z& P4 N6 S. `
  9. uint8_t KEY_2(void);//按键2
    4 T# K; k0 @3 @! f$ K3 z: F

  10. 9 Q: m# q2 X( m3 |+ j0 D# Q/ i
  11. #endif /* KEY_KEY_H_ */
复制代码
; F  ^- x6 [4 S, S) Y# X
        key.c
; d6 [0 E0 a0 C) X0 P
  1. #include "key.h"
    ( ?4 ?" W) I% j% |# p, k, b
  2. # K* P/ @, B) K& H
  3. uint8_t KEY_1(void)
    ( w6 ~/ Z/ l" ~
  4. {2 ?3 J; T2 f6 H/ b7 h* b2 E- z7 t1 O
  5.         uint8_t a;
    # y1 j) @) d: ?- P; t+ ~& }
  6.         a=0;//如果未进入按键处理,则返回0
    9 Q0 M# Z" M. g3 N9 j# _
  7.         if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平' ^6 ^; N' a7 L+ K
  8. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
    3 U$ R/ ]) _9 T0 {1 V& n* u
  9.                 delay_us(20000);//延时去抖动
    / N; Y3 k# r4 I, Y9 ^5 K( ~' G
  10.                 if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
    / d7 s1 [2 @5 J5 a
  11.                         a=1;//进入按键处理,返回1* p7 f0 N6 A) R, K6 ]6 O
  12.                 }& Q" P9 K$ Q3 n# Q4 |7 }* X% f3 l- B
  13.         }
      j  J7 W+ C0 X  l  K
  14.         while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开, d7 s7 P: H% a1 f. X$ R& W( f3 j+ f* e
  15.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)1 W' v5 L* P% r3 a* n4 J
  16.         return a;' l4 ]2 y7 V- r) C1 y3 f/ `
  17. }
    0 a& ~% B+ a5 g

  18. ( L- w% ?, p5 I$ F- |6 V6 O
  19. uint8_t KEY_2(void)
    1 U5 ^8 I6 W: |0 C/ I" a7 X( E  B
  20. {
    7 g2 W2 C  d* P* D8 d4 _1 E
  21.         uint8_t a;
    ' U3 }3 N, k' L) p9 B$ t. D. u
  22.         a=0;//如果未进入按键处理,则返回08 l4 M+ n/ a4 c8 a
  23.         if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平* ?+ O' ?+ _! l! w
  24. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)3 |8 n2 I0 i4 K7 E9 N/ F  g. X
  25.                 delay_us(20000);//延时去抖动  p& F3 l1 P! r# g
  26.                 if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平/ |3 M: ]- B  r, |/ }/ t  s
  27.                         a=1;//进入按键处理,返回12 w' |% ~/ V6 E% w& g, ^% ]0 c
  28.                 }
    & I& v7 y: S. T8 _6 @
  29.         }
    % q3 @' {4 ?, z3 J+ o" @
  30.         while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
      O6 F/ O3 l$ F- g% o* u9 p) _
  31.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)! {0 E6 x( V7 y: k# ]& c  {6 T
  32.         return a;
    ( v% a) C$ Q! Q( ]5 B
  33. }
复制代码

: s6 }, E6 ~$ B3 j5 }/ U6 l        3)在ICore添加led目录,并添加led.h/led.c源文件* Y: ?. g/ q" j( ~/ |7 L

1 C- {' D" u" i" i) @1 }  F        key.h
- M+ K& ?' L  w/ W# Q, `  U/ y5 P5 ^1 z
  1. #ifndef LED_LED_H_8 Q4 q% ^. x. F, s+ O. H2 {
  2. #define LED_LED_H_
    , ~' e; u2 x& B% t
  3. 0 D) t: J3 m" |) M3 w
  4. #include "stm32f1xx_hal.h" //HAL库文件声明' s. s+ q$ {2 c( Q& w" G2 b, X
  5. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用9 H; d( P4 S" o+ `: D' h  v

  6. 6 p, U+ u. j1 @' k6 t+ }- ?
  7. void LED_1(uint8_t a);//LED1独立控制函数(0为熄灭,其他值为点亮): @1 J. @; H+ y( }5 Q
  8. void LED_2(uint8_t a);//LED2独立控制函数(0为熄灭,其他值为点亮)
    & e6 {# p8 x& u# N: E% K
  9. void LED_ALL(uint8_t a);//LED1~4整组操作函数(低4位的1/0状态对应4个LED亮灭,最低位对应LED1)
    . R! v6 v: S& k3 P
  10. void LED_1_Contrary(void);//LED1状态取反
    6 j6 A! ~8 h1 x# j& X
  11. void LED_2_Contrary(void);//LED2状态取反1 c# t' P  s4 Q0 S
  12. 2 e. W! k  m' b7 C! r) C. j- D
  13. #endif /* LED_LED_H_ */
复制代码

; B4 c* w" Z+ g        key.c5 Y  t* i) |! n( e* N
  1. #include "led.h"( \! _+ l  z. v/ k0 B, x1 g6 U
  2. ' t8 c( ]  x+ o+ R3 Y8 m
  3. void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)
    , Y; s: i* J; P5 M, N/ I
  4. {
    8 h- z( R! t) B1 e7 m- q
  5.         if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
    / h% k' D" {. B( r3 V- Q4 n% `
  6.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
    , e( X+ g  x- b2 L) Y
  7. }2 c! @. C( B# d$ R
  8. void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)1 f+ K" t7 Q( x" B1 c4 }1 P7 U
  9. {0 t' Y5 V* A9 D& W# ^( O
  10.         if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
    * h, V( f! m* }, `/ v
  11.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
    , y6 X' V! R9 Q% K! F
  12. }1 ?! ^, O! k- N
  13. void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1)" D" [/ h" n! ^
  14. {
    ) _( s- ]8 L; p6 m
  15.         if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
    ! l& y2 ]- i; O4 g+ K
  16.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);$ R/ l( J3 h8 v/ H: r( S) X
  17.         if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);9 W2 f$ d% m0 r# \5 F# V" J6 u
  18.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
    1 K4 B2 F4 p# C$ Q6 g/ ^) y
  19. }
    % [3 b6 l: z6 R5 S6 H
  20. void LED_1_Contrary(void){
    ; k# j" l# W+ w. A; l; `
  21.         HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));+ G( ]! n& d) c- k2 X4 i
  22. }
      @# Q- Y" ]  `% }- A
  23. void LED_2_Contrary(void){1 L+ |8 i8 I  E9 V& p# ]& i6 w
  24.         HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));; H( o1 s% l- W' X/ |
  25. }
复制代码

, X5 M5 R. j  v- \) l2 A% _        【3】创建串口驱动程序,主要是复写串口回调功能
& A5 }, a9 j- B: X5 C        1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能  g; F  f' E0 b) Z$ b

/ q5 x% ~; R& k( B        usart.h: q# b4 Q5 ?/ I5 v. H, R
  1. #ifndef INC_USART_H_
    ' C2 v4 Z, A8 v, ~  z2 o3 f
  2. #define INC_USART_H_) r* z. y+ w9 F% U" F1 v

  3. ' Q; H' K) j' q( x. O
  4. #include "stm32f1xx_hal.h" //HAL库文件声明5 z/ i9 ^& ~/ ?3 \' ~) V  U
  5. #include <string.h>//用于字符串处理的库
    2 d+ n$ \. q/ I9 R! B: K
  6. #include "../print/print.h"//用于printf函数串口重映射
    $ ^1 r0 V7 s2 g" m! o- D6 g& z1 T  c

  7. - g/ {# B/ E. b3 @; f" t
  8. extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体# y6 q( E0 \* s6 A
  9. extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体: ]) S2 e! P( A7 N* |5 o

  10. - [6 @" N6 e. Y
  11. #define USART1_REC_LEN  200//定义USART1最大接收字节数) Z7 Y0 J" z2 A! U
  12. #define USART2_REC_LEN  200//定义USART1最大接收字节数
    5 n* q7 ~- k8 w

  13. & N7 c) {/ d' a8 J* {7 Z
  14. extern uint8_t  USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符; E4 {2 r/ j& j
  15. extern uint16_t USART1_RX_STA;//接收状态标记% e/ F$ _+ e* W+ B, }2 d) E0 f
  16. extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存2 ?, A- I1 O6 M/ \3 m
  17. , I, ^4 H/ ~/ z. P. v
  18. extern uint8_t  USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符6 l! ]" {: p0 k% N8 K3 u
  19. extern uint16_t USART2_RX_STA;//接收状态标记$ n; i( k. c- o7 x7 A* {
  20. extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存$ E7 ~7 J  G8 e. @3 n4 e

  21. % m" S- ^; S1 ]- d8 G) t" @# `4 K8 h6 ~+ o

  22. ; P3 l. N* o' }; j; p. f
  23. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明
    / ?) n' Y, `( f* w; H. t) l/ }

  24. : k1 I5 W8 r+ @$ Q- q9 T2 O* a; E
  25. #endif /* INC_USART_H_ */
复制代码

6 a0 ?$ Z- r5 m) \; H" q  |: S- \        usart.c
8 P5 G* \1 h2 }* @, q* g/ A$ V
  1. #include "usart.h"* d. v) H! B/ }% u1 F
  2. # x) n9 Y7 u8 d! w3 Z
  3. uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
    . V  Y0 U* r+ w) p
  4. /*
    * a: p3 U. L. J7 n0 L5 [
  5. * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;9 T- v& X; v8 G4 g% @$ a6 J" K
  6. * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
    8 L. \& i1 _* u; V
  7. * bit13:预留; t+ e, p; E. k9 |" B, [. W$ d
  8. * bit12:预留
    ; P5 _2 y0 M; G7 C+ ^' d; [& R
  9. * bit11~0:接收到的有效字节数目(0~4095)
    # N5 i" q6 m7 A. H: E: ?, \- c& T
  10. */
    + D; H# u) t$ g; O! \& u; ?
  11. uint16_t USART1_RX_STA=0;$ K" b5 P6 O; _3 A/ T$ t
  12. uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存: T8 t, f& F. i/ P# k2 E( H
  13. 6 ~% i5 P1 V( X
  14. uint8_t USART2_RX_BUF[USART2_REC_LEN];
    / @) D% d/ `+ _; n
  15. uint16_t USART2_RX_STA=0;
    # h' p+ O1 b6 S! G. J& {
  16. uint8_t USART2_NewData;
    - J) C. q( ?1 X! O1 p
  17. ' N2 X- ~% a+ T, g; T  U2 V6 f' F
  18. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
    ) y; ^( n$ i# v
  19. {
    1 w* E1 Q& A4 X* o5 A, ], ?2 M
  20.         if(huart ==&huart1)//判断中断来源(串口1:USB转串口)
    1 b( }" a5 N: u% l) j) b$ d
  21.     {% O2 e: U7 {: u( T& a9 Z# a
  22. //                printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑6 h" S, v- G9 d/ R" N
  23.                 if(USART1_NewData==0x0d){//回车标记0 z; ]4 V) A# h" T3 j2 O* ^" [4 ?% r' T
  24.                         USART1_RX_STA|=0x8000;//标记接到回车
    $ s+ F: K$ t8 a, ^. O
  25.                 }else{, f( z3 D3 {  r" q. ~
  26.                         if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){1 V3 U& P2 ]9 z8 ]& y8 l" P+ F  c
  27.                                 USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组
    $ f; ]' T  Q$ F% U! K6 d" ]9 y
  28.                                 USART1_RX_STA++;  //数据长度计数加1
    0 _+ |  F2 p* x) Q3 r7 d. G( N
  29.                         }else{
    8 u0 M. Q( g4 e8 e3 ^- w
  30.                                 USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
    4 o2 ?- s5 b6 }( \* i
  31.                         }
    ) l' D5 {- E& O) R
  32.         }% X( R0 c% U) m
  33.        HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断8 M7 C3 t8 M) s7 ]. m
  34.     }" M, V0 i# t. F. b( z5 C, Q# d) Y
  35.         if(huart ==&huart2)//判断中断来源(串口2:BT模块)
    9 Q" |3 r; q$ \5 a5 e
  36.         {
    ! M& _/ X$ f# g5 C6 z& ]7 X
  37. //                printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
    4 s. T0 l4 x9 X' q( B6 Z+ T
  38.                 if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)
    7 B! l2 a) O2 T9 b& ~! f
  39.                         USART2_RX_STA|=0x8000;//标记接到回车
    , _0 R. h* e% K* I  {4 b+ ]
  40.                 }else{8 Y% y, h; [! c! t
  41.                         if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){1 b6 W* ~1 Q% ?* Q# `+ I5 Q/ \/ b
  42.                                 USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组
    5 d3 S5 F! l4 K) o+ t1 E) @& K, l% h9 e
  43.                                 USART2_RX_STA++;  //数据长度计数加1) I8 s# _- B: G# F7 O* S8 C
  44.                         }else{" f0 o! T7 D- x! T6 w, Q
  45.                                 USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
    2 ?4 R/ ?6 n. U
  46.                         }
    " w7 e8 U5 C+ ]' X9 D' v
  47.         }) Z! i5 C  V; _; @( l' c& R" M
  48.                 HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断
    8 M5 S' ^2 c3 `/ X  R
  49.         }, x& `8 S' i' N* I5 A& i8 |
  50. }
复制代码
8 s, i% ~8 h) V3 }9 t+ l; h
        【4】创建蓝牙驱动
9 g: g$ A, x  |) ~$ F        该驱动主要实现通过usart2向蓝牙模块写入数据,(读取数据主要通过串口usart2回调,在usart.c中实现)。在ICore添加bt目录,并添加bt.h/bt.c源文件,实现蓝牙驱动功能6 f9 \) o; U6 \5 u/ p7 w
* a1 i) z8 F9 x  e
        bt.h# y! v1 h9 p: Q3 _+ O$ v" C
  1. #ifndef BT_BT_H_
    ' r# r; m3 z$ {$ K
  2. #define BT_BT_H_
    1 R3 W6 l- i9 h  d! w
  3. 9 h2 _" z* @5 L: ]' _
  4. #include "stm32f1xx_hal.h" //HAL库文件声明* k! x6 @2 W* f: g  W, V
  5. #include "main.h"  f; R& e) M% z/ s0 _! q
  6. #include "../usart/usart.h"
    3 q4 ?, e! T9 T. [, Y3 g2 R
  7. #include "../delay/delay.h"
    % d1 j8 C2 m7 {5 T
  8. #include <string.h>//用于字符串处理的库
    - R! e1 f  l$ }& z& f9 t- n
  9. #include <stdarg.h>
    / }" Y0 _, {" u) v
  10. #include <stdlib.h>
    # W$ @% p# _2 X
  11. #include "stdio.h"
    . @$ K! p% |- C& V! \6 v& S, N+ X1 E
  12. 6 S( i8 a5 W5 K0 i; H  @
  13. extern UART_HandleTypeDef huart2;//声明UART2的HAL库结构体- {( \. ~% l, B; k( i; b2 J. z$ J
  14. void BT_WEEKUP (void);//蓝牙模块唤醒函数& H- o3 A4 h' \1 U7 j/ E. Z: P$ M
  15. void BT_printf (char *fmt, ...); //BT蓝牙模块发送
    " {! n6 {& @8 o
  16. - N& J9 E- z' p  T/ a; H; W4 \
  17. #endif /* BT_BT_H_ */
复制代码
' i; [; }! r( P% \. @
        bt.c4 z: E' T" _* ~& a+ H# x
  1. #include "bt.h"
    0 c4 m3 u: G8 i9 D2 J1 v4 ~" s
  2. 3 y  X" ?8 V- W
  3. //蓝牙模块唤醒函数
    - d- ^1 x5 Q$ S( H; z! c9 m
  4. //对蓝牙模块上的PWRC(P00)接口一个低电平脉冲,如不使用睡眠模式可忽略此函数# k7 }% o( I% Q
  5. void BT_WEEKUP (void)2 e) f: {- r, t# e
  6. {
    : F( ^: X+ H' e- o' M( S+ I( }2 X: O
  7.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_RESET);//PWRC接口控制) Q0 j6 a4 Y  q' \5 t( }
  8.         delay_us(100);
    4 n$ M. J" P, U5 F, k$ E0 G1 |
  9.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_SET);//PWRC接口控制
    ! R& O6 j7 T/ |% `! m; i
  10. }
    " s7 v) `1 x* A% S1 J
  11. //蓝牙模块通信,使用UART2,这是BT蓝牙的printf函数
    / }6 J( A2 B5 P% o' K% M- u, v1 ^9 A
  12. //调用方法:BT_printf("123"); //向UART2发送字符123
    ; R4 K! c6 R7 m! E6 o" |' M
  13. void BT_printf (char *fmt, ...)
    * n' j; R6 `* T  e* E
  14. {
      a5 N( F: T: j9 [# d  u
  15.     char buff[USART2_REC_LEN+1];  //用于存放转换后的数据 [长度]7 n; O8 N3 J2 |* ?2 ]* P7 y
  16.     uint16_t i=0;5 k) L! J0 K" k
  17.     va_list arg_ptr;
    + j  N  b" A' P% F( S+ G
  18.     va_start(arg_ptr, fmt);
    " F1 y# T6 z) f& h- H
  19.     vsnprintf(buff, USART2_REC_LEN+1, fmt,  arg_ptr);//数据转换. z& k- T6 A+ r6 b/ E
  20.     i=strlen(buff);//得出数据长度
    3 N! [* O9 o5 z
  21.     if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
    & T) t- d, h( Q
  22.     HAL_UART_Transmit(&huart2,(uint8_t  *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)
    * ~. X# h' B* v5 C
  23.     va_end(arg_ptr);: b( {8 z3 g- Y1 D" t
  24. }
    / Y: f; p, x/ a
  25. //所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在USART.C文件中。
复制代码
! X. G. T: t# U/ |; X4 C" e5 Q3 `
五、编译及测试
% q9 {' Y% O' N2 Y+ {        【1】功能调用及编译* U4 [* u3 {$ [
        1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:
2 s7 c0 z( j2 p+ ^
  1. /* USER CODE END Header */
    ( [7 [$ `- @, [" q6 T) Y/ d& X$ u5 h
  2. /* Includes ------------------------------------------------------------------*/
    : H5 t, J# o* H/ T7 k7 K' b: F
  3. #include "main.h"& ^+ i6 Y9 y! b# s0 i

  4. 4 `) u/ O: s0 `5 O
  5. /* Private includes ----------------------------------------------------------*/! I" u; v( e7 x8 D& `
  6. /* USER CODE BEGIN Includes */
    5 g9 X5 t# G  @# c0 m) o
  7. #include "../../ICore/led/led.h"- G* J' v) X) v3 W4 I4 v, _& ?8 o
  8. #include "../../ICore/key/key.h"
    1 X1 C$ n' I' G, A& D
  9. #include "../../ICore/delay/delay.h"8 `* P6 K  W( q6 S
  10. #include "../../ICore/print/print.h"//用于printf函数串口重映射
    2 i( p$ [+ p, l1 P$ ^$ e
  11. #include "../../ICore/bt/bt.h"
    0 c% G; }3 y% Y/ _7 e
  12. /* USER CODE END Includes */# e8 Q" p. D3 r5 u2 _) t

  13. . y4 O2 p1 K' i1 j: X
  14. /* Private typedef -----------------------------------------------------------*/* m  W: U8 {; }; i
  15. /* USER CODE BEGIN PTD */1 L$ ?2 m( i9 j$ _) K# t9 J
  16. # M* y4 i( P! q, V6 X  h
  17. /* USER CODE END PTD */
    1 P: A1 ~2 @$ t$ W: A

  18. # T9 _0 n0 [, I% c, s* J/ {
  19. /* Private define ------------------------------------------------------------*/  I' s7 ]- L1 R# q% [
  20. /* USER CODE BEGIN PD */$ k& p$ b) b/ X& l7 x
  21. /* USER CODE END PD */
    $ U# t% k, q8 Z6 `0 y1 e# J

  22. 4 Q5 @4 k- c  P% v1 c/ ]/ Z% {& B
  23. /* Private macro -------------------------------------------------------------*/+ O3 m* ?* Z6 `) R. ^
  24. /* USER CODE BEGIN PM */7 B8 Y  Z" p9 z# D

  25. 9 B2 Z9 m  M& R" _7 e
  26. /* USER CODE END PM */3 w$ @% j3 X$ S2 {5 @

  27. 1 e2 o  a* o" N2 a
  28. /* Private variables ---------------------------------------------------------*/% S  b  \  `* B8 U$ F
  29. UART_HandleTypeDef huart1;
    1 T2 P2 h7 q2 H% w, y
  30. UART_HandleTypeDef huart2;/ G! r8 ~0 o  w1 \) ?8 h
  31. ! M& {1 U  u0 @% |
  32. /* USER CODE BEGIN PV */+ U) B- w+ O1 N# X. s4 t3 {
  33. ) D% r' v; d  q; o" M0 y
  34. /* USER CODE END PV */
    ( w+ r9 y/ f5 U5 i, |5 u9 S3 V
  35. ) \8 [! Q4 w1 [( m* z( g
  36. /* Private function prototypes -----------------------------------------------*/
    : C1 f% V+ ?( X. u( T, H
  37. void SystemClock_Config(void);5 j- k# {* b! y8 j( P! k- Z
  38. static void MX_GPIO_Init(void);! T- _5 Q% w0 p" A
  39. static void MX_USART1_UART_Init(void);
    ( {* W- Q4 D7 y% j' g/ x
  40. static void MX_USART2_UART_Init(void);
    ' V+ g. \! v7 A% a' i  |( a
  41. /* USER CODE BEGIN PFP */
    # `6 O; h9 [/ N+ B! L, Q2 ^0 `

  42. # Y. x! \6 A& e( b) A; Q
  43. /* USER CODE END PFP */
    $ @0 |" \9 M2 g, v& ^
  44. : ~: x+ o/ \2 }
  45. /* Private user code ---------------------------------------------------------*/- |' I  j) l1 ^  M5 L5 C& u
  46. /* USER CODE BEGIN 0 */( A. M7 e: b2 }2 G- o9 X5 d

  47. & U. S, E0 P; E) S# e: V
  48. /* USER CODE END 0 */
    # z+ Y& w4 u- `- n8 ]9 r# u; w" x
  49. - I" Q' w7 W; A. h0 h! x
  50. /**& ~+ ^* p( ?0 D8 m4 i2 N/ v
  51.   * @brief  The application entry point.
    . o5 e/ g2 u- `, O3 P) n- T
  52.   * @retval int: i# `5 J( w6 Y$ e+ a9 Q" x
  53.   */
    + a3 c5 O0 w9 h" n3 f/ D
  54. int main(void)
    1 r. ]6 Q& n6 N' ^
  55. {
    ; J4 E8 w7 Z/ f% r
  56.   /* USER CODE BEGIN 1 */
    7 V! Y; d* S9 ~# _0 [

  57. / ^+ W7 r% C! e6 n1 d5 _
  58.   /* USER CODE END 1 */
    % W# e) I) w8 W5 f- b  T

  59.   D; {' I- X7 E6 ~) @
  60.   /* MCU Configuration--------------------------------------------------------*/
      x/ |! R8 b5 [3 \, S

  61. / ~  D+ L+ E% [- G3 r% e6 J
  62.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */  O. w4 c, A% e
  63.   HAL_Init();
    / s& j4 P9 j/ |! }3 W: l

  64. 0 E5 h5 f; X. G4 i1 R
  65.   /* USER CODE BEGIN Init */
    4 ~- ]  |" l, y: x

  66. 2 j0 p, @( `7 {6 |
  67.   /* USER CODE END Init */1 A& c! p; c: p% o' z$ s9 ~
  68. , p9 A* N" P( o7 M
  69.   /* Configure the system clock */
    0 ~! x# O2 a9 `6 S
  70.   SystemClock_Config();
    2 T" Z3 W6 ~: ]$ r4 j" M0 |

  71.   B0 I% @% J+ u& T& L2 T2 ?! O
  72.   /* USER CODE BEGIN SysInit */
    " U( e; L6 R+ [7 t% W2 O' ~

  73. 9 M$ ?4 a; h0 c, L
  74.   /* USER CODE END SysInit */. D4 l1 W- I9 _5 m0 `. q7 s

  75. : o6 L3 b- I/ K+ p1 N1 c( W& Q
  76.   /* Initialize all configured peripherals */
    0 M4 M& _# W3 R: M1 X
  77.   MX_GPIO_Init();
    . o, l" W  A( z. j  T0 V9 E
  78.   MX_USART1_UART_Init();
    4 t+ @+ z* X- l
  79.   MX_USART2_UART_Init();* Q8 R+ G0 G* x, }
  80.   /* USER CODE BEGIN 2 */# h# o! D; j8 |( w$ V$ b
  81.   ResetPrintInit(&huart1);//将printf()函数映射到UART1串口上+ C: g: `+ K3 O8 A  |1 o3 O, t
  82.   HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);//开启串口1接收中断9 X0 B; [- t* O3 G6 @6 a
  83.   HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启串口3接收中断
    $ B& z# @* t7 f7 H
  84.   /* USER CODE END 2 */3 m3 V2 o5 u% B5 z6 P

  85. 1 o$ j& Y+ T! G! M6 U4 m; i
  86.   /* Infinite loop */
    0 l) T+ M8 S( [% [  c8 x; N1 F! B
  87.   /* USER CODE BEGIN WHILE */
    $ R# @, s3 m. E5 [$ n- i
  88.   while (1)( y1 ]9 I+ [: v; {( X) Z
  89.   {
    : g* Y) Q: K- N6 t: h
  90.           //demo 蓝牙02
    : e9 e$ B0 z4 L3 ]+ N
  91.       if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)
    ) f0 M! r* _9 y
  92.              BT_printf("%c",USART2_RX_STA);* ~" m, d& |8 ^/ m1 Z. [6 e
  93.              if((USART2_RX_STA&0x7FFF) == 1)        //判断接收数量1个(手机控制程序)
    4 ?- r: ~" M# i6 T! j
  94.              {* s# H/ e# s* a: e4 h# s9 c
  95.                      BT_printf("%c",USART2_RX_BUF[0]);
    & |+ l- i5 c  N/ }) l( f% }8 }& k* c
  96.                      switch (USART2_RX_BUF[0]){//判断接收数据的内容
    ) A/ f1 U, ~7 G* s) }% S7 W
  97.                                 case 0x41:
    . J2 }- v! g$ w. G% G6 X7 m$ Q
  98.                                         LED_1(1);//LED1控制
    , ?/ l4 U8 @, V; x# p
  99.                                         BT_printf("Relay ON");//返回数据内容,在手机APP上显示
    : n6 W. z! t" K+ z4 A
  100.                                         break;* Y/ n+ v8 l) X% O+ `
  101.                                 case 0x44:
    4 S6 K0 Z6 D: W% J' k5 J  P8 n# c
  102.                                         LED_1(0);//LED1控制" b* W+ s  s. m7 [
  103.                                         BT_printf("Relay OFF");//返回数据内容,在手机APP上显示
    3 P  \0 U% s9 {* e
  104.                                         break;
    ; }/ W+ W% ^. q: ^) [7 R' p
  105.                                 case 0x42:
    ) p# j+ Q# k1 u, @6 @
  106.                                         LED_2(1);//LED1控制: a$ |7 H2 E# c1 b
  107.                                         BT_printf("LED1 ON");//返回数据内容,在手机APP上显示, R  k3 O: w6 G7 \, G
  108.                                         break;
    ( P$ P9 w2 ]% {1 e
  109.                                 case 0x45:$ ~* ?5 D, x6 ^8 v& X6 N( u/ h
  110.                                         LED_2(0);//LED1控制$ K1 m- b" u3 s8 }
  111.                                         BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示
    - y! r1 S. p2 {2 q6 F9 i
  112.                                         break;& p2 S, K  @6 z4 f3 N' X2 i1 U
  113.                                 case 0x43:
    - Y- r( K. Y5 }+ R
  114.                                         LED_1(0);//LED1控制
      j7 E2 U+ w  w% h
  115.                                         LED_2(0);//LED1控制3 d! W% s# ?, ~! @2 ~& k
  116.                                         BT_printf("BEEP");//返回数据内容,在手机APP上显示- Q: G8 q$ E3 _$ E! V6 X
  117.                                         break;3 B5 \( p! L4 \) [# o: [
  118.                                 case 0x46:, B8 {6 S- d' `3 c9 V* W+ `
  119.                                         BT_printf("CPU Reset");//返回数据内容,在手机APP上显示
    3 l, S9 ~& w, w+ d8 u* i3 c- _
  120.                                         HAL_Delay(1000);//延时
    & A, {2 f& S, V' ]' X# w
  121.                                         NVIC_SystemReset();//系统软件复位函数
    - Z  S% U' C* x9 a+ q  a
  122.                                         break;
    + j/ i, n4 l' s- n5 x1 y- d/ K
  123.                                 default:# z6 y. n/ B) f( I" q
  124.                                         //冗余语句9 ]1 F+ Y. [* j3 V2 u6 \+ G
  125.                                         break;6 l1 w9 o( q/ t: I8 Y+ k
  126.                           }* A4 y1 W0 A  c  m5 X1 n
  127.                  }
    ( I/ N! p- u% E8 T
  128.                 printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1
    * L3 _2 j# B( k. x# R! K
  129.          USART2_RX_STA=0;//标志位清0,准备下次接收. Y4 O# q, A! o  }' W7 Y5 s8 l% F* |
  130.       }! t6 L3 Q: i* O; m* R4 h# g
  131.       //接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块
    2 i6 C5 p* n5 b6 L, h+ N: m
  132.       if(USART1_RX_STA&0xC000){//结束标记
    9 y' |: C+ E" q% E1 ]% q7 s  b
  133.               BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);
    2 H! |3 y8 s) S/ K5 Q$ I& Y
  134.               USART1_RX_STA=0;//接收重新开始
    8 h* d2 h9 X: i; p: O  y& ~
  135.               HAL_Delay(100);//等待: a" l3 X' O: G2 o! W( J
  136.       }
    # ?# X& u1 A4 O( F' W  {
  137.           if(KEY_1())//按下KEY1判断) }! N5 U& Z- E" z
  138.           {
    1 h% R% k+ J8 F% m' t3 L: V
  139.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
    + y8 S; {5 G, h. \
  140.                   LED_2(0);//LED2控制
    & V9 X0 {% V1 K, Q$ l' e# U
  141.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
    4 \0 S  C5 n8 @- F
  142.           }
      a( |$ {% |3 I: ^6 i
  143.           if(KEY_2())//按下KEY2判断# m3 W+ C' [* ?8 F  h7 f
  144.           {/ k: o6 F8 f4 `" A9 ]4 ]3 R
  145.                   LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位3 e$ o% Y: s- q5 {+ P' C
  146.                   LED_2(1);//LED2控制+ f9 \( I  M2 G- _" T
  147.                   BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)! I/ }: ?- a$ `9 ?( a
  148.           }$ n2 w" F% F3 g1 F9 U  w7 m7 f2 Y
  149.     /* USER CODE END WHILE */
    2 A, n) ?% C# a+ R, l* M, @

  150. . y, k' D2 k; u% Q7 t2 ]' u
  151.     /* USER CODE BEGIN 3 */7 n2 k/ j3 S- q- a! n* G; J
  152.   }  ~* e/ S/ ?. w6 Y9 G. d# i
  153.   /* USER CODE END 3 */1 n/ r- o: B& d, I$ ~- R
  154. }
复制代码
3 |" R8 h$ \6 n4 Z: j- V% g- b
       2)设置编译输出支持,右键工程进入项目属性设置页面:5 g8 m# ^/ |1 X/ @2 I/ {
6 i8 I  f1 J* ?
b959f3b4bbc34e9a933d8fa45890c6ba.png
7 W( j% N" k$ p5 R2 j0 v
- z: D3 {, F; L1 B* [+ ^; K1 H  K7 M          3)点击编译按钮,完成编译(整个工程需要源码修改或添加的源文件如下):, ?+ E( s2 ?4 W& ]2 R2 Z# N- u* [4 W

8 S) O9 r1 l3 A
288d14c992b3413ab8b2e3c42e0994ed.png
3 L0 a0 d2 F5 n) e$ ^" g4 [2 d" G: R. _
        【2】程序测试
# d4 e9 q% P. f# @( I8 i4 g& J8 ]        1)测试过程需要三个工具文件支持,读者可以自网上搜索最新版本或采用其他同功能工具替代测试:* ?) P( H4 t. |
        FlyMCU加载工具,将生成的.hex程序文件加载到板子上
2 R$ f4 a2 i; {        SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入
1 V2 v4 M; R5 E) ^2 \        蓝牙调试器工具,本文用的是1.9安卓版本。
: d! k8 t( v& X5 v3 G
8 p# [) f$ k7 w/ n2 ~8 h
616ca3780a8b4077ba5ba5f13ad76834.png
3 {0 U+ t" q' T# V8 F0 L/ k& e9 ^+ ^
# f( b% t0 M$ k; ^# d% ?
- m2 ~$ P! b7 o9 z1 A9 r        2)加载程序,选择串口,选择程序(.hex),点击开始编程按钮:
. h) _6 o9 i; D) S7 Y$ Z
. Q$ P# Q' I- O( Y3 ?
5da0d56a3c4e4c45a74e90e7fbf4b989.png
& X. I4 F7 C9 {8 D1 |$ s% S2 a' f* f$ W& n/ v) m
         3)手机打开蓝牙调试器(别忘了开启手机蓝牙功能),进入界面,搜索蓝牙,点击蓝牙边上“+”按钮连接蓝牙模块,采用SSCOM串口工具连接到usart1上,就可以通过蓝牙通信实现手机(蓝牙调试器)与电脑(串口工具)的通信了,在蓝牙调试器发送数据时,十六进制时需要加上“0A”作为结尾,如果十进制发送时,注意加上换行再发送:3 M# }8 h/ m: K3 s* j

# f- r+ s2 Q: B
df172bc6aaa94e678d2c06fb92dbe6a9.png a573139985cc47b79688e2ee52359e8e.png 8 n. N( h" E" O1 C6 f

+ L6 q5 C& m1 E  @* |        注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:1 [( |4 z7 X  Y, `" E
  1. if(KEY_1())//按下KEY1判断+ S) b7 `9 |6 p/ k( K4 P$ i& b
  2.           {
    3 ?$ V. B" P  E* g, |3 S8 r" q
  3.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
    : m* G  Y! l* {  {8 p2 a* M5 w
  4.                   LED_2(0);//LED2控制
    4 t. y9 U# e3 s3 t" Z; R! j
  5.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)  z/ ]$ S$ b2 L. E+ m9 y) n
  6.           }
复制代码

: A  K/ ^' a& p( h. u        串口发送数据:0 B1 |' E2 [" n) h

3 F- x8 D6 |3 v0 H
399927e9b5474fd4bafe8534255fab31.png
% y/ F' k& O# `: y$ I
- h- X3 q( V: C
8 t% k# a- Z* {( u& O
        可以进入按钮控制页面进行指令定制设置
9 w* e; O: g; R, B) U) e& v8 V- V" I" Y  ?3 J6 p: a) b
56473e9c27a04fafaa96bc2f0dab5f08.png 9ac0cde743b143e08e391b2d9e793b56.png / _+ g& W/ {- j* l% C- w4 B; A" y; W

. ~' j* \5 c& H1 ]5 B6 Y         至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。& ?* B$ i  A9 F* I/ c& k8 A
————————————————7 p7 Q( `/ b6 P
版权声明:py_free-物联智能
  s+ R' ?( l) P% F如有侵权请联系删除
1 g* I1 M2 k5 F- K; L9 J; v8 Q' V/ v
# t1 u% k# {; o0 `) q" T  p
4 `( c1 m- `3 r, g' Z: ~# D' x5 b8 j. a
收藏 评论0 发布时间:2023-4-7 15:54

举报

0个回答

所属标签

相似技术帖

官网相关资源

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