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

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

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

- M% D( `+ M( C* G" D' M# v        蓝牙是无线个人局域网,最初由爱立信制作,后来由蓝牙技术联盟制定了技术标准。蓝牙产品包括小型蓝牙模块,以及支持连接的蓝牙无线电和软件。 如果两台蓝牙设备想相互交流,则需要进行配对,一台设备将成为主设备,所有其他设备都将成为从设备。 通信时,主站侧需要进行检索并开始配对,如果构建链成功,则双方需要能够发送接收数据。在通信状态下,主侧和从侧的设备都开始切断,可以切断蓝牙链接。蓝牙通信本质上就是无线电传输技术,蓝牙的工作波段为2400–2483.5MHz(包括防护频带)。这是全球范围内无需取得执照(但并非无管制的)的工业、科学和医疗用(ISM)波段的 2.4 GHz 短距离无线电频段。
) [3 |8 t8 u, P
3 {% l* Q" }" ?& Z2 z: F* D5 ^& Z
& K  U0 X. o1 V2 D
二、MCU及蓝牙模块
& ]/ l; T+ M. z' f        本文采用STM32F103C8T6的芯片及JDY-08 蓝牙透传模块,相关引脚如下:- H3 C) J) \; O& {  l
* |0 I: `& o! S9 I; X, x
        MCU引脚设定:PA9、PA10作为USART1引脚,用于下载程序、调试显示,PA2、PA3作为USART2引脚,并与蓝牙模块进行通信,PA8作为GPIO_OUTPUT模式,用来控制蓝牙模块上的PWRC。. E" K& B% C5 T1 q3 V0 s
! w$ c6 b+ c/ w" W
2d927f8850734dd683cfc95f270f3604.png 0 }( {8 K$ N$ D

4 s& M- D- p$ `2 j% @6 Y6 h         蓝牙模块为JDY-08 蓝牙透传模块,基于蓝牙 4.0 协议标准,工作频段为 2.4GHZ 范围,调制 方式为 GFSK,最大发射功率为 0db,最大发射距离 80 米,采用 TICC2541 芯片设计,支持用户通过 AT 命令修改设备名、服务 UUID、发射功率、配对密码等指令。
& Q+ _* {8 g4 l: O$ l) x) |' M2 I4 f% }% |0 V* i. _" p
        TICC2541 芯片 引脚:
- @5 }6 j( t% J, t/ n8 z1 A8 `2 m$ m( }3 a4 M9 m9 N7 [2 G4 T1 {- g, ^  {- e
87b66d3312cc4c23b64182bd2c2496c9.png
- W5 @3 L) D; V" _1 r/ _3 S
* u% o$ W0 u8 M$ j6 L         引脚功能定义,在使用串口发送命令时,请将模块的 PWRC 引脚接地,并接上模块的电源(VCC、GND),电源电压为3~ 3.3V:
* G3 a; C# y+ X6 A, M, b# X  O' ]6 L" f
50c5510d3d8b4234879cc66e8e1a6988.png ' C1 `: P. h0 G/ N

0 z! `. M9 H, X& X7 `2 V         以及本文用到两个AT指令:
4 a2 @1 s( C1 m: _* P( ]) s2 U8 `, ^0 l, M. H, T
d5bc46612e09498c922ad506da5679f4.png
8 R* l( S) F: j& P, k- Q) f& e1 E) g, C

+ j) r7 `  z1 @1 b/ G 三、cubeMX配置MCU及蓝牙接口5 [1 V: I# Y& _# H" K2 n
        本工程设计功能如下:9 v9 G: Q- ~" `( q6 g
# A2 s$ B  ?3 j, G# a8 x
        MCU(STM32F103C8T6)的引脚PA2、PA3的与蓝牙模块(TICC2541 )的11、12引脚连接,实现数据通信;MCU的PA8引脚与蓝牙模块的22引脚连接实现,实现蓝牙模块唤醒。- I1 G6 t  |9 ^" L" R) \7 ~8 j) N
& M' x; K$ t) |# R
        通信逻辑:电脑(com4)<->(Usart1)MCU(Usart2)<->蓝牙模块->手机(蓝牙调试器,需要开启手机蓝牙功能)。2 Y* u, d3 [7 ?' j( w7 b

; c2 v: R# R" w7 G        功能:; a" u/ |1 M/ I: a- I
        按键功能,用于按键时向蓝牙模块发送AT指令;& t  @, {& O$ C. x9 J: ~' ]
        LED功能,用于接收蓝牙模块数据时做出闪灯响应;/ V: z  X& C7 i- N
        蓝牙功能,接收来自MCU端的串口通信,接收手机端的无线传输(即蓝牙通信);1 v! F/ _4 [2 j+ M  ]# j9 a
        串口调试功能,MCU执行程序可以向Usart1发送信息到电脑端,既可实现日志输出,也可以实现指令转发到蓝牙模块。; E2 j% @' e" q1 J8 B
        【1】创建工程0 Z( C7 a9 s1 x5 R+ [
        1)新建stm32工程,选择芯片STM32F103C8T6
% j1 l( E: |* H% l( m4 g& d8 I& E2 {  n9 v
a4d9946142d542f3a8ade81b66e0a552.png 3 W8 l& E4 Y1 k1 Q+ d
* b  [6 N/ D7 D6 K, P
         2)为工程命名完成创建
8 P4 C1 a' r1 P9 Y3 S
( ], V' k( f9 u2 G. _1 x) s( o" ^
8177bd2fea6b478e8c172a4b4604aa43.png
, e7 D5 B2 d2 m, `: }/ e+ _
! \  w" G& p9 p: s% g
         【2】CubeMX配置
" k5 ^& K& m3 s, d4 c' M, E  f1 h        1)开启sys mode接口
" n% R; ]2 M9 c
5 N% w' }: O1 s% R
6945e8635a7a466b83c22611ad53d9c5.png " A' I- s* v/ E, e9 I# Y8 t! X

' {; S* M, X' O, F* S7 e         2)开启RCC+ f4 D" p5 |8 x6 c. f( M. B8 c" B
% c# O9 K, ?1 b6 Y: U4 Y
eb9677e954f14340b91608f89a899e85.png 8 W1 u4 T$ {6 q# \8 B9 K  c" f- O

+ h1 f- ^( ?5 u6 ~2 P         3)开启USART1(下载、调试)、USART2(连接蓝牙模块)。
1 x% m' L6 R0 n9 k$ H/ N1 x; M- S5 @0 i- u. I6 }2 S
8a56a450ae704a66afcd75f588cd2e64.png . j0 E+ I6 G3 R5 |! v
2 G! r( p+ m9 Z9 o* {
         4)开启串口USART1、USART2中断功能
# r. U8 ~' s! R: @! P% ^# ?- h
( j) Z* I  k" n  b  {" P
1a51fe61e16c48fd95cd3c1841c6cf9f.png + s, H+ r7 |! I! W

7 x8 k; o+ P9 a. \         5)串口引脚参数配置, ^, c3 X% H4 d: E) d; z6 C

* `9 x3 z9 m6 h6 D) ^3 S
3c5015317b1643e1b7e9a55510e02cfc.png ( E# e% [; q: t

  ^8 M& n2 f  M* A         6)蓝牙测试辅助接口及按键、LED灯GPIO引脚添加:: ]5 S8 l/ ~3 k0 @

* t/ d0 q7 n6 l5 v& V* p& Y
70a978fd9ca34aa18d434351ceb7bb5b.png / U$ r" C! H) n6 x

: P2 b. ~) u3 H        7)系统 时钟配置,直接拉满STM32F103C8T6能支持到的72MHz。8 p3 W1 d$ G) i: C+ f2 v
0 e9 `  B1 ^! ]6 z
cd5e618b97e54ef1886818cc2b4c1956.png
0 D* Z7 j- O, Q- t4 [
% r; w% ?5 A  s* _+ ~
          8)本工程配置页面保持默认,没有为每个外围设备驱动创建独立源文件,点击保持或生成代码按钮输出代码。
$ _/ v, h% g! H
4 q$ Y* g" o) Q  {% |. F! Q
31870054f08c4b95bfb5f485f13480d6.png
  M. b5 X. x: ~9 M+ H3 `) G% S6 S2 O& z3 i' _9 A9 }3 U
8 d4 P; v; u: V2 F% B+ a8 x) Y0 @1 H
四、代码设计
! B& |/ {- B$ S5 W        【1】首先创建usart1接口的调试输出支持
* y! K5 K, y1 q. N        1)禁用syscalls.c,右键选择该文件进入属性页面设置。
4 ?4 V  p5 z! P( p- T% ^6 I6 Y. s7 e: f# R$ w( i
aec3533e953447e39024f449845c2564.png
" x  \- u$ x# O
9 @6 }7 y; t- v
         2)在工程目录下创建源码目录ICore,添加文件夹print及print.h/print.c,实现对系统printf函数的映射到usart1输出显示功能。; \* z  x- V& J6 V8 r2 b7 {& W
# O3 d( R! J0 [5 g- O9 A% n) {
        print.h
5 Z! a) d0 v4 h" ~  w: G
  1. #ifndef INC_RETARGET_H_
    * W6 W9 k5 n: P8 T9 Z3 Q
  2. #define INC_RETARGET_H_# q" W0 {4 ?! ]8 k# o& k0 |$ Q4 t

  3. ( {# o' G1 D6 v5 O+ R) u2 [& W
  4. #include "stm32f1xx_hal.h"
    8 Q$ N/ w# T: i1 [
  5. #include "stdio.h"//用于printf函数串口重映射: _* c9 i1 P6 l# h$ S3 u' R) O  u
  6. #include <sys/stat.h>
    : B: c5 f& n; d2 s

  7. ! U' {: H. T/ [2 a" H$ U
  8. void ResetPrintInit(UART_HandleTypeDef  *huart);
    ; T, N. o: d" J8 l

  9. * U# S# F% m' V
  10. int _isatty(int fd);3 u4 T1 T9 f. k, b
  11. int _write(int fd, char* ptr, int len);: H1 |* B5 I+ F& Q
  12. int _close(int fd);5 P5 ^8 A, c% b% m% L* x' d% b8 e
  13. int _lseek(int fd, int ptr, int dir);
    6 ^2 l' \4 @) L$ j% g* J
  14. int _read(int fd, char* ptr, int len);: L# J9 r/ N$ A& g/ u7 T
  15. int _fstat(int fd, struct stat* st);
    2 p: O  _$ i" d  V. {# E7 h

  16. ! \) `! [# ~8 T$ E* B; g1 |. m2 e
  17. #endif /* INC_RETARGET_H_ */
复制代码
! R- D# _5 F* S" q
        print.c0 ?3 e% |# K! R: v
  1. #include <_ansi.h>
    ; i# J  B! x  L
  2. #include <_syslist.h>+ T( {8 c  |0 J. j
  3. #include <errno.h>" }/ \- L7 y2 t
  4. #include <sys/time.h>
    % a8 G& l8 R/ W, J# O# V, f1 ~
  5. #include <sys/times.h>5 R, \! b& {' p# h( p
  6. #include <limits.h>! w, W/ _& ~9 z
  7. #include <signal.h>7 F# `# e" e- i$ ~5 Z
  8. #include <stdint.h>
    * \; c$ p7 X" o: A! i% h
  9. #include <stdio.h>
    1 A  \4 X% b% J1 U

  10. & d" l' y4 H+ z5 ]
  11. #include "print.h"* M2 H' E, ~5 v& N+ \  \) t

  12. 1 K- r3 Z+ j$ _" D7 X- K
  13. #if !defined(OS_USE_SEMIHOSTING)
    : Q, L7 s$ e1 t- {, n( D2 |
  14. #define STDIN_FILENO  05 S" K/ A; o- ?0 L: q
  15. #define STDOUT_FILENO 1, m: v0 m5 U8 s$ B
  16. #define STDERR_FILENO 28 }5 m. A* o4 N
  17. 1 t( L  ^3 p. B9 v; G' v! P$ E
  18. UART_HandleTypeDef *gHuart;3 y3 A0 \# |4 H) q) B3 f- A1 j

  19. ! q1 s1 x6 I/ H/ K4 \, c* D
  20. void ResetPrintInit(UART_HandleTypeDef *huart)  {
    5 {, Z3 G( W" |& t: h4 O
  21.   gHuart = huart;8 @8 s5 M: s# s0 h; z1 U
  22.   /* Disable I/O buffering for STDOUT  stream, so that
    ; E$ M6 f% P! V- j& W
  23.    * chars are sent out as soon as they are  printed. */7 v7 w: G/ _* ]4 S6 F0 H
  24.   setvbuf(stdout, NULL, _IONBF, 0);
    : T7 }" a9 l9 p* V
  25. }
    ' A4 t3 f8 {8 q: u. z4 ^) O+ ?
  26. int _isatty(int fd) {
    4 D* a3 H: e: ?: U- [
  27.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO), {7 ~. @) c5 ~( |: }
  28.     return 1;4 d0 q1 O. X( o5 Z6 `! L
  29.   errno = EBADF;
    + J" L" d. o( e/ l* ^, l5 g/ @
  30.   return 0;2 L9 C% x% S) }' r( G, y' x+ W
  31. }- g% y  u6 ^) E& L
  32. int _write(int fd, char* ptr, int len) {
    6 i. l# G! }$ x' F8 B) r* o
  33.   HAL_StatusTypeDef hstatus;) C+ j7 G' k8 N$ O; d+ r9 W& C
  34.   if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {) {3 I1 l" r7 ~% w7 s0 ?! a
  35.     hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);
    ; U, J9 ?4 `$ @  s* d* t8 o- S
  36.     if (hstatus == HAL_OK): O" M5 m: z' b2 \0 O& ^3 j7 D$ }
  37.       return len;
    4 S. |: h$ n* Z5 C# |( i
  38.     else
    + a# _+ c3 J& }! b0 q. H, U& e
  39.       return EIO;
    1 Q3 A1 G/ A3 D! D; W/ D
  40.   }
    $ \2 |* Y3 j( @* c& O) y2 |
  41.   errno = EBADF;  ~- A- S1 J2 k" ?' y
  42.   return -1;
    ) n0 L3 ~5 Y& }; {2 x  u7 S3 ~: N: {
  43. }+ H  W0 w" o# `& q" \- D. t, O
  44. int _close(int fd) {0 y( W7 t. U& t  I1 r; F4 E, }* `
  45.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
    ) H- ]5 Y1 G) H  [
  46.     return 0;
    ! ]3 T; E, \7 h0 J) v2 I# w
  47.   errno = EBADF;* t5 p6 E- o8 M* W$ W
  48.   return -1;# h7 D  I, Z; ^+ ~1 x. q- K1 q
  49. }+ ?4 J" O2 B% c9 ~4 U; g
  50. int _lseek(int fd, int ptr, int dir) {3 x8 O& [. j+ p6 G+ E$ L" Z
  51.   (void) fd;
    ( W1 l( e& W& a9 f' R& j% \
  52.   (void) ptr;
    & P0 U4 h3 R* {" H: r& U9 w
  53.   (void) dir;
    , @; |. f4 F1 h) `
  54.   errno = EBADF;
    6 H' X& H5 o; t2 ]1 x
  55.   return -1;0 m2 L, Q, z/ w5 B( ^
  56. }- `: E. ?& o: j
  57. int _read(int fd, char* ptr, int len) {
    - a3 R$ l5 U( |% L
  58.   HAL_StatusTypeDef hstatus;
    ! \* [. l$ k3 g% N9 V, a6 j
  59.   if (fd == STDIN_FILENO) {! n0 T. O7 f; T
  60.     hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);1 |. W3 }4 v0 R* p* `
  61.     if (hstatus == HAL_OK)
    % k3 \& K2 U7 E! p: x
  62.       return 1;4 B6 O) {( L+ r+ z6 l5 L
  63.     else) b- I& s4 c& I9 ^3 g* ?+ x' E
  64.       return EIO;7 K9 o$ r  R& q1 }' l/ E/ I3 W" l6 u
  65.   }$ X) a9 g( C8 R1 u! \
  66.   errno = EBADF;
    " M! v* r8 H+ H: }  v8 E/ y/ e8 P9 @
  67.   return -1;( |, C6 P8 X; Z6 M/ ~; G" P
  68. }
    * N" d2 ~5 t/ b
  69. int _fstat(int fd, struct stat* st) {
    " O/ P7 K* Y) p- r' n
  70.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {
    , U0 Y$ U0 }% w! ~# o
  71.     st->st_mode = S_IFCHR;
      M  |# [5 m* `! W4 b9 {! g0 I
  72.     return 0;- ?4 |- W9 q1 Z0 U" P
  73.   }
    ( g: z9 [' c5 P; `
  74.   errno = EBADF;
    8 `" A9 P  `5 g+ r8 r
  75.   return 0;
    ! Q3 Z9 f5 I! w/ p9 f
  76. }4 R5 B0 a- e; @/ O; z' U2 T- x

  77. ; p, w. E. a. A; Z1 [. z
  78. #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码

; x; H* H. _, v2 p4 m* v' F- ]        【2】创建按键驱动、LED驱动、延时函数功能的支持/ R' j& U: H9 c. W& q6 h9 d
         1)在ICore添加delay目录,并添加delay.h/delay.c源文件% v# M& |; Z: ?! E8 k
        delay.h
+ T. q+ G5 o1 E+ x( D1 L7 P
  1. #ifndef DELAY_DELAY_H_
      R$ }7 y% o% U8 [) `
  2. #define DELAY_DELAY_H_3 D0 m7 V: O2 K7 h* l2 K

  3. / g5 W  l/ A) l: I- O: M" F
  4. #include "stm32f1xx_hal.h" //HAL库文件声明) B! }% g. R) @2 W) G* J
  5. void delay_us(uint32_t us); //C文件中的函数声明8 @. }: C- e$ Y6 E4 R

  6. 9 ?; B1 o8 T# @" E9 N, _
  7. #endif /* DELAY_DELAY_H_ */
复制代码
& y/ a- J5 o0 l# B
        delay.c
) E) P: Y; c4 }) R, g6 F: t4 r6 g+ A
  1. #include "delay.h"
    & P* A- C) s" P& Z/ u5 e( q, m  c, N

  2. + Z" e8 `% @, o7 M7 }2 |2 @
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
    0 \+ S7 v* j# K, H0 b3 m6 m+ q7 m. s
  4. {* E7 R: S3 W" b9 [
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数- Q  L' k* B( X: {
  6.     while (delay--); //循环delay次,达到1微秒延时
    5 S% k/ y  W- g  E
  7. }
复制代码

( x+ h/ K# M. q1 U- p        2)在ICore添加key目录,并添加key.h/key.c源文件
. G  @5 ~- l  Z, v2 w
" c- ~- I2 U* M% r        key.h
0 {5 }, z; `1 h) ?% ?/ d
  1. #ifndef KEY_KEY_H_
    & x( K1 r3 n0 e9 f! _9 |. f* Q# t( Q
  2. #define KEY_KEY_H_
    0 Z8 K+ t$ O- g- u2 U

  3. 2 i4 k: I7 R* v. k$ g
  4. #include "stm32f1xx_hal.h" //HAL库文件声明8 I: O& n1 `& e; h4 A, d
  5. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用
    8 h, z6 X: U8 c: q
  6. #include "../delay/delay.h"
    8 |% D( Y- I+ g7 ~

  7. " T! V4 I: T5 E# s5 j- X/ j4 l, B
  8. uint8_t KEY_1(void);//按键1
    5 z4 D0 J$ W" h. Q! V3 ]. L. Z
  9. uint8_t KEY_2(void);//按键2' W( q6 }4 }4 h9 W

  10. + \( r7 N1 x8 F# ?  _" x
  11. #endif /* KEY_KEY_H_ */
复制代码

  I3 M; C$ s' P        key.c
) \. {3 T9 ]* d- G/ p" K8 c" S0 ^
  1. #include "key.h"1 P% H( |( E) q# H6 I

  2. ' F$ ]& U1 {% g0 _. n
  3. uint8_t KEY_1(void): Z' b8 ^6 H; ]
  4. {' l6 H. D% A+ M
  5.         uint8_t a;4 k5 m0 N( y: n: D8 A
  6.         a=0;//如果未进入按键处理,则返回0
    $ y, M) v+ C3 I
  7.         if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平5 r1 ]: i6 I: y. ~. S
  8. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
    ( J# b( ~$ B1 g
  9.                 delay_us(20000);//延时去抖动( U. ^  X) i7 B! ~1 d* K
  10.                 if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平/ T- h1 e2 L! M& R
  11.                         a=1;//进入按键处理,返回1
    ' P# L  X/ c  I; }+ \' |9 y3 K$ @9 C
  12.                 }5 ?% m0 N. o7 B5 h: E6 }" V
  13.         }: B% \9 j: D+ R8 [' A/ H
  14.         while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开
    8 }# ^- F/ b. j2 E
  15.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)& C+ c) o. c! s  ]1 ?9 [
  16.         return a;
    " x7 `1 F5 K# Y: [; W) X# ~7 C. u
  17. }/ D- ]8 h: w( y) l' T6 I9 c7 A* M
  18. - G$ q- V  V( }- Z0 g
  19. uint8_t KEY_2(void)
    6 J) T) L: s4 e8 ^1 t
  20. {
      R/ c7 R2 I. S8 z
  21.         uint8_t a;
    # V9 R/ E+ c! j8 n8 d4 g' ~/ L1 U  ~5 e
  22.         a=0;//如果未进入按键处理,则返回0, [# R5 _) t% f" U$ g4 J" w. f/ N
  23.         if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
    3 n. {0 p) r% p4 [9 @
  24. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)5 T. s+ P" k$ a' N$ u% @2 ]1 F
  25.                 delay_us(20000);//延时去抖动1 w+ Q3 n  ]( t0 A
  26.                 if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平3 I3 ~. n: W7 `# _7 q1 o$ q" b/ f
  27.                         a=1;//进入按键处理,返回1& B% g, ]1 J+ I% |
  28.                 }% H6 c# q6 \2 X, d% A$ m' R
  29.         }: b9 j. _2 u; e4 f0 Q' Y
  30.         while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
    $ }" b4 \4 P% C* X9 Q
  31.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)/ E6 |  Q% R7 [+ J7 X
  32.         return a;
    3 J5 W, J& R9 I
  33. }
复制代码
) Q: R& u% d7 Q  `. S7 T
        3)在ICore添加led目录,并添加led.h/led.c源文件
- |, s1 U/ h  M6 {9 u( \
/ y" F6 E; H  W4 W( N        key.h
4 x0 j3 H0 Y) A! x3 }  R: L* Z" j
  1. #ifndef LED_LED_H_% G' C& @, q, p5 ~( ~
  2. #define LED_LED_H_1 B  i6 d9 |3 w7 a

  3. / N( K" r) z/ k/ t2 }6 ^, u: U0 d4 f
  4. #include "stm32f1xx_hal.h" //HAL库文件声明
    % O& h' ?; ^9 l4 A) @
  5. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用/ x+ ~2 `4 H* t+ O1 S6 A
  6. 1 i. O, Q( j( J) f# O4 P: n- s
  7. void LED_1(uint8_t a);//LED1独立控制函数(0为熄灭,其他值为点亮)
    & v2 T0 v! d7 Z! _
  8. void LED_2(uint8_t a);//LED2独立控制函数(0为熄灭,其他值为点亮)$ q) L# ]9 O3 L* n
  9. void LED_ALL(uint8_t a);//LED1~4整组操作函数(低4位的1/0状态对应4个LED亮灭,最低位对应LED1)& i" m! u' |) q- Z! ?8 y
  10. void LED_1_Contrary(void);//LED1状态取反- S; b0 i. ^$ @& f
  11. void LED_2_Contrary(void);//LED2状态取反
    & v0 @) c" \% V" r, L
  12. 3 ?0 W- B9 d' z- ^, ]+ d5 p
  13. #endif /* LED_LED_H_ */
复制代码

* y9 N% f% a' n3 m        key.c4 @. x; |- `$ Z6 M! p  A" _' X6 k7 ~
  1. #include "led.h"$ J& {& |+ A9 g: `4 B

  2. / `8 J: D0 Z0 L/ N- D: \
  3. void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)! _: d  Z8 w, f5 E# E6 h
  4. {
    * }* g% D# S# }! V) M9 b
  5.         if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);$ Y7 Z2 C$ q/ G4 b5 z
  6.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);& j9 i# B. I/ D* x
  7. }
    ; c; A: l3 }3 ^/ {: X
  8. void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)
    * H3 \! K- R0 O# m$ [
  9. {
    5 Q$ X) T7 ?" S1 D4 d
  10.         if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
    2 o- K* y4 c1 H+ G+ P8 w/ M
  11.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);. |  u0 S% x6 d: G! q% t" F
  12. }2 B1 Y; K% z+ }% ?' U7 P
  13. void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1); {. H: P; ^& ?; Y: n
  14. {
    ; P8 N( V+ a, K) `
  15.         if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);$ J" N! h3 s, _  i" V
  16.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
    ; y; F, J  ?9 ~* M% a5 k
  17.         if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);2 ~3 z8 U8 N' z. U1 \. T
  18.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
    7 {& k% i/ J, G* P# N
  19. }
    1 p2 `- L9 V9 T4 ~+ }
  20. void LED_1_Contrary(void){
    ' `8 e& y& Y7 i7 {; `5 o& G2 y. G
  21.         HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));+ k( N! Q( D, R: j& q) C
  22. }
    7 N' T' o" F4 K7 Y5 a
  23. void LED_2_Contrary(void){$ c! [  y+ n; O# Y
  24.         HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));
    , ~" q- H/ B  {. N! o
  25. }
复制代码

' e6 p9 D. ]  a. F, F% @' N        【3】创建串口驱动程序,主要是复写串口回调功能8 f! S" `# Z7 b$ v
        1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能3 Q9 U' O) z# v% x* A4 e; y
  p9 i# w! u0 f, _8 N
        usart.h
1 x5 o1 b; C4 G' W  t
  1. #ifndef INC_USART_H_
    # [: E( U" E5 ^% H! o
  2. #define INC_USART_H_$ k! O( w/ O* i1 |) M9 n. P; L) V1 U
  3. ) L/ r7 s  W  P% f
  4. #include "stm32f1xx_hal.h" //HAL库文件声明5 _+ k; P5 s9 Y8 P5 u( ]5 ?& q
  5. #include <string.h>//用于字符串处理的库; j8 L8 T( ?; [, T9 P
  6. #include "../print/print.h"//用于printf函数串口重映射9 t3 k8 B/ S5 u0 d0 r) w" B
  7. , u: c" F! t6 f6 H
  8. extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体9 u3 x: N$ A) U) S
  9. extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体
    6 b4 `$ V( o( _- K' s1 b
  10. " S4 m& d4 i* W. a/ m( b" M
  11. #define USART1_REC_LEN  200//定义USART1最大接收字节数3 R: t2 d# I4 C7 ^7 P5 O8 I" ~
  12. #define USART2_REC_LEN  200//定义USART1最大接收字节数
    8 {: o' X/ m) Q# a! A8 h

  13. ) o$ `) d8 ^0 I7 H, v
  14. extern uint8_t  USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符$ L# r( J7 O  B
  15. extern uint16_t USART1_RX_STA;//接收状态标记
    ( s: {1 D0 J1 G/ e5 a* T# x3 b
  16. extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存
    0 [+ l; U3 Z. g- _  d% }1 l, g# G
  17. . i! O- ?9 _8 \# D
  18. extern uint8_t  USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    + L$ z1 a* w+ p3 M. k3 T. Q
  19. extern uint16_t USART2_RX_STA;//接收状态标记2 s% f( d- x8 s* f: c! k
  20. extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存7 y9 N/ P4 c' i
  21. : c( |7 S/ X8 ?; m; _# ~  e6 a) e0 z

  22. ( U" o  f1 w3 ~: u3 a
  23. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明
    5 {9 r2 R- f# ]& K$ l2 y

  24. $ R$ C, A9 D$ ?
  25. #endif /* INC_USART_H_ */
复制代码

. m5 V) E: q, ]" j6 W3 n        usart.c
' i4 F# t% x9 B1 s% k$ A: |  W
  1. #include "usart.h"- S) j! t% U- D/ g" c0 x& D
  2.   ^! x$ F0 j4 o* E  Q
  3. uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
    " v; ^! }! I# D) D, R! b, {; j$ E
  4. /*& f' h7 r4 u4 @- O5 @
  5. * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;% F1 J1 E6 I& B6 Q0 Q& Y% H
  6. * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;4 f  l# ?& \/ p8 |( I, C
  7. * bit13:预留
    . b  x, O/ Q% _! _
  8. * bit12:预留
    - u+ y5 }% u) ?* o* T
  9. * bit11~0:接收到的有效字节数目(0~4095)
    4 q5 T- l% c8 Z* |2 `* w! {
  10. */
    4 E& C5 Y: |6 o$ u9 j' B
  11. uint16_t USART1_RX_STA=0;7 I( M- A( o$ Y5 E, V3 c7 V
  12. uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存8 e( T& X9 q* w+ V6 h8 G

  13. 8 `; ?! m+ U- {/ D0 _
  14. uint8_t USART2_RX_BUF[USART2_REC_LEN];
    2 G! v/ s8 D0 k
  15. uint16_t USART2_RX_STA=0;
    $ p: b: E2 N5 l5 c; l* J* J
  16. uint8_t USART2_NewData;# I! M0 H6 |+ b6 S/ d
  17. 8 i( k+ p1 w$ V+ i/ m
  18. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数9 W# s# N+ N' b
  19. {
      X2 n# y6 s) Y% _" V" g6 }
  20.         if(huart ==&huart1)//判断中断来源(串口1:USB转串口)
    9 d7 b4 z$ m+ @6 f
  21.     {
    6 l) M$ c- R& p% M2 d
  22. //                printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
    ! r$ O% `# k1 `- S) E( ~! D
  23.                 if(USART1_NewData==0x0d){//回车标记
    9 ?% x9 n% U* R, C) ^
  24.                         USART1_RX_STA|=0x8000;//标记接到回车- \. K' i2 p, C# q/ ~, Z3 E+ X
  25.                 }else{, N, e0 k5 r: i
  26.                         if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){2 s; _2 U, Y! Q5 R& J- f. ]
  27.                                 USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组
    : q  p; I& G3 c
  28.                                 USART1_RX_STA++;  //数据长度计数加1
    9 s6 ^8 T, D& K% w, m. m" n
  29.                         }else{
    3 e. b7 p; ?/ S2 f3 i9 ~* m
  30.                                 USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
    1 g9 ]% d" h6 h, e/ p- L
  31.                         }7 @" N! p; l) g2 f, J4 I
  32.         }0 Q  y8 x3 `4 @: \. s% H3 A2 X; E7 g
  33.        HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断6 [* R* t% u) J7 P2 W" p
  34.     }* ]' ]0 u5 K( F" z, {% r/ D3 Z7 R
  35.         if(huart ==&huart2)//判断中断来源(串口2:BT模块)! \, I3 |" ]5 {
  36.         {
    8 j8 Q8 E0 T( J9 ?: p" h( Y/ K6 j
  37. //                printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑6 @; D; p5 M# p) ~
  38.                 if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)+ b& b* W1 A! D5 g
  39.                         USART2_RX_STA|=0x8000;//标记接到回车7 S" T, X; c! ]" M0 C
  40.                 }else{
    8 k/ h7 c! r- x: [. I
  41.                         if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){* _/ T/ h4 [$ Y& v/ }; w4 T/ i8 J0 E
  42.                                 USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组
    % E* g+ ]* A, s9 O
  43.                                 USART2_RX_STA++;  //数据长度计数加1) I  R/ E# R) A: V/ E" ]
  44.                         }else{
    " c" s7 _$ M4 [
  45.                                 USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
    7 |3 w/ d* ^! p
  46.                         }
    - [8 M6 o' W- w/ `. m
  47.         }0 T5 V! t/ x1 o" I  Y3 h
  48.                 HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断
    ! y( t# ^4 O# Z: |- Z. S, V
  49.         }
    9 S1 o, B; k- I
  50. }
复制代码
* Q0 C2 w/ |* Q1 y9 p$ L
        【4】创建蓝牙驱动6 R2 o, p) ^0 i( y* y
        该驱动主要实现通过usart2向蓝牙模块写入数据,(读取数据主要通过串口usart2回调,在usart.c中实现)。在ICore添加bt目录,并添加bt.h/bt.c源文件,实现蓝牙驱动功能7 e1 b' j! t/ [+ U
" z8 L3 a. P1 _% }1 I. V
        bt.h1 k" U3 C$ N0 Z
  1. #ifndef BT_BT_H_5 q# i# u3 u5 w1 g
  2. #define BT_BT_H_
    $ I+ I6 |4 |7 t$ O4 c5 E0 B3 B. {

  3. # n# G9 ~) ]1 y# L; n
  4. #include "stm32f1xx_hal.h" //HAL库文件声明3 z" g1 ?. h" W' z, O5 O  w  W
  5. #include "main.h"+ i. q+ `2 S. z9 |; p! Q0 @
  6. #include "../usart/usart.h"
    & y- C) L  |( x4 G2 E' W: E
  7. #include "../delay/delay.h"
    6 H# k: S! b0 ~5 ~, }  j! c
  8. #include <string.h>//用于字符串处理的库1 G' _- v! o5 Q- D8 S. G2 s
  9. #include <stdarg.h>8 m5 F) ?( p" Y6 D, T) I$ n
  10. #include <stdlib.h>
    : m& e1 K0 s0 ~' c6 s
  11. #include "stdio.h"/ U3 X* H# k1 t7 I+ K( {/ n5 q6 M6 M
  12. * F: u+ y0 u! V6 ?5 r* u
  13. extern UART_HandleTypeDef huart2;//声明UART2的HAL库结构体
    ) n- ~$ u' \* s: O* ~
  14. void BT_WEEKUP (void);//蓝牙模块唤醒函数- e( B, n+ I* V4 r  |9 n
  15. void BT_printf (char *fmt, ...); //BT蓝牙模块发送
    0 M# u1 N1 G8 D4 }8 Z% Y3 b( C: F3 P2 q
  16. ( @8 H+ A5 F! X3 l1 b# e* r
  17. #endif /* BT_BT_H_ */
复制代码
& |5 _& c0 W1 v: h+ b! V6 a
        bt.c( M2 D' U  q, t% c( z
  1. #include "bt.h"+ G& V, x" }* b$ Z4 J! \

  2. ; J+ j: k0 z+ y, Y
  3. //蓝牙模块唤醒函数
    , P1 h' m3 ^* ]& A8 G1 I  w9 j, J+ V
  4. //对蓝牙模块上的PWRC(P00)接口一个低电平脉冲,如不使用睡眠模式可忽略此函数
    % a, p5 H1 O" `; |
  5. void BT_WEEKUP (void). r$ b5 |+ s0 h: U
  6. {
    ) _: X" O' }  I  k8 B# z
  7.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_RESET);//PWRC接口控制8 E1 y+ G, m) z( q1 D$ @; Q* y8 }
  8.         delay_us(100);* L, s0 m. B9 |
  9.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_SET);//PWRC接口控制
      r4 q' }$ G' {
  10. }
    8 ~9 v0 L8 L$ B" I8 U
  11. //蓝牙模块通信,使用UART2,这是BT蓝牙的printf函数
    0 ~, L+ J9 U& Q
  12. //调用方法:BT_printf("123"); //向UART2发送字符123
      b; j7 T$ p9 B8 `% a# z' @& o% l
  13. void BT_printf (char *fmt, ...)
    ) B' |; L& ?; o% V* S9 a3 ?
  14. {0 ~+ d* W  E* o
  15.     char buff[USART2_REC_LEN+1];  //用于存放转换后的数据 [长度]
    6 v8 h% }& {$ |- w) U
  16.     uint16_t i=0;
    " Q9 Y7 F8 a! O! P6 B
  17.     va_list arg_ptr;+ l" K$ v; Q. E$ P7 W7 Q
  18.     va_start(arg_ptr, fmt);
    . e- l& j" I' X0 x+ L, J2 d$ B
  19.     vsnprintf(buff, USART2_REC_LEN+1, fmt,  arg_ptr);//数据转换
    + k) O& O7 H4 _1 [, X( e
  20.     i=strlen(buff);//得出数据长度' s. x& l7 N# @, B# ~( f
  21.     if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)2 h% P: p4 T# o" k
  22.     HAL_UART_Transmit(&huart2,(uint8_t  *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)
    : ]" A9 H" ~8 j, }
  23.     va_end(arg_ptr);
    3 w: S' Z1 {3 B- h5 ]; n
  24. }
    , {8 V9 L8 y% ]% X1 {. d" X
  25. //所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在USART.C文件中。
复制代码

8 O( Y0 r' ^$ w, ~- g五、编译及测试
. ]6 m2 {! D& S. ]9 I6 a- e; M        【1】功能调用及编译$ z% g5 F0 a; d* @
        1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:+ S5 f9 c' k6 E2 g' t
  1. /* USER CODE END Header */3 e( Q2 B6 O! s0 v) I8 y& ]
  2. /* Includes ------------------------------------------------------------------*/8 j2 J' p! q) S) l9 \6 x
  3. #include "main.h"" f5 {6 g7 r0 i% z1 U% F! @& B
  4. 4 i" S  B, |  q3 F1 u- o
  5. /* Private includes ----------------------------------------------------------*/
    - w# }( u# T8 \8 o
  6. /* USER CODE BEGIN Includes */
    1 h7 V5 K# w" f8 N
  7. #include "../../ICore/led/led.h"
    ; j% A, _- B4 y" E' ^0 _  p. R' t
  8. #include "../../ICore/key/key.h"
    4 w* p' i9 l  j: L+ `5 `- s
  9. #include "../../ICore/delay/delay.h"
    , G) ^1 i. T7 I+ I
  10. #include "../../ICore/print/print.h"//用于printf函数串口重映射
    ; p8 ^# B. Z/ A" I6 P
  11. #include "../../ICore/bt/bt.h"
    / x! S3 _6 z7 V! U  Z8 m
  12. /* USER CODE END Includes */) m. C. Q2 y0 g5 ]

  13. " u) {' F" H+ m* G
  14. /* Private typedef -----------------------------------------------------------*/  C/ P: A: T* C7 K' Q8 p
  15. /* USER CODE BEGIN PTD */
    ; p, U$ S( x0 A
  16. 2 ?  \8 z! D4 V/ `
  17. /* USER CODE END PTD */4 U! E* @% G/ g9 w  L2 `; ~2 n  ^

  18. ) ?+ h( t: A# M
  19. /* Private define ------------------------------------------------------------*/
    ; d7 n6 @0 ?8 y/ g1 |' {
  20. /* USER CODE BEGIN PD */
    3 ~5 w3 s* Y- z) D8 T
  21. /* USER CODE END PD */
    " ~  D5 o" C) e- E8 n' |2 M

  22. 8 V" q' i  @0 C' n
  23. /* Private macro -------------------------------------------------------------*/
    ; v2 w# c9 V+ p% M/ C9 M
  24. /* USER CODE BEGIN PM */
    + m7 K0 H, |6 v
  25. 1 T7 a" h7 h. p2 d$ K
  26. /* USER CODE END PM */  |4 ?# _& D% u
  27. + L9 n; w- j# v  W
  28. /* Private variables ---------------------------------------------------------*/
    $ B' T: u9 }7 k" M
  29. UART_HandleTypeDef huart1;
    / k# H) \" n" r3 w6 x
  30. UART_HandleTypeDef huart2;6 Y/ \7 g$ N& I

  31. 7 [7 f3 _1 u, z2 q
  32. /* USER CODE BEGIN PV */
    ) \: x1 m' K4 ]$ ~) W  q; b% v

  33. ; d  |2 I" V& X; ~" T
  34. /* USER CODE END PV */1 K4 Q0 @! c9 D- z( Y0 A: x& |
  35. . ^% L1 j/ K$ s0 U  f' t' N1 X
  36. /* Private function prototypes -----------------------------------------------*/
    - ^8 V2 X: w+ k& e
  37. void SystemClock_Config(void);7 r7 i0 z, Q. Q: |
  38. static void MX_GPIO_Init(void);
    ) s- l  u! m( p$ v, V
  39. static void MX_USART1_UART_Init(void);5 E% I  p( b- T
  40. static void MX_USART2_UART_Init(void);
    # J0 B1 \* O# R. ^+ g# `
  41. /* USER CODE BEGIN PFP */' J3 [; U- D8 u" ^; k6 A9 v# _
  42. 5 o  Z0 l- J7 ~
  43. /* USER CODE END PFP */7 g8 E7 E; B; |& N, N" Z+ m7 U8 o( J

  44. 5 G8 p* p/ @: }8 O/ }
  45. /* Private user code ---------------------------------------------------------*/
    % {' Z7 b7 Z! ]: f2 y
  46. /* USER CODE BEGIN 0 */) D2 m$ \% I4 P6 O/ X7 A$ R
  47. ' V$ F2 n# }- q9 c
  48. /* USER CODE END 0 */
    4 _, m* n' q  f# k- P, Q, n# [

  49. + Y; e3 K3 J. P6 v, L% p( z
  50. /**
    ' }0 a" C* P5 p2 [. y$ r
  51.   * @brief  The application entry point.: V, @1 s# Q3 a
  52.   * @retval int& Z9 _' r4 @' d) ~# A# y9 N6 o' z
  53.   */
    % p3 }; v8 p- R; \2 j7 l) K+ f
  54. int main(void)+ Q9 }7 o1 @: d" f3 n$ r3 N# B5 k
  55. {
    1 d+ f+ `& |' L3 `
  56.   /* USER CODE BEGIN 1 */
    $ m; o  ~* y6 O% Z9 n( @& G
  57. ) a5 R$ T3 H7 S6 F
  58.   /* USER CODE END 1 */
    ; P" @. d4 S' H( L, t

  59. 8 p, x9 g- ~# k7 n0 ]/ k* F5 Q3 A( W5 c
  60.   /* MCU Configuration--------------------------------------------------------*/
    8 [1 w2 S) h8 \- L
  61. 5 l( K7 l5 S# g" Q' G
  62.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */8 B' Z6 W1 v& |: r- E' c* A+ X8 k
  63.   HAL_Init();" C* H5 y! U5 K! D6 n  N8 e
  64. 9 W( d/ O0 @; V0 [
  65.   /* USER CODE BEGIN Init */
    % Y# l# y  H5 r" H
  66. $ Y# I- A. Z! O0 d7 F4 E
  67.   /* USER CODE END Init */
    2 b) N2 T/ S; J3 t/ [( V# s( C

  68. 9 k! U* }! K2 {- u
  69.   /* Configure the system clock */3 R/ j, z  D. H8 `. o: P2 q8 g: V: ^) r# m
  70.   SystemClock_Config();
    ' L+ N6 F; I0 @0 t5 [

  71. ' n' m% ~/ Z7 X2 x1 B5 ]
  72.   /* USER CODE BEGIN SysInit */! E* H/ \! K  ]% G
  73. , G  o- I! c; N$ c( Z+ B$ j1 [* f3 b$ m
  74.   /* USER CODE END SysInit */
    " g3 c; b: w9 R8 S3 X2 A

  75. ) w0 P, x7 Z1 O
  76.   /* Initialize all configured peripherals */
    0 E3 _: k  y; k; x/ E: h1 K
  77.   MX_GPIO_Init();
    * s8 T6 e5 @; k' z* X
  78.   MX_USART1_UART_Init();
    & J3 \1 D2 l! v; t2 f1 V: ?6 U
  79.   MX_USART2_UART_Init();' F9 J" m& X3 V, P) N
  80.   /* USER CODE BEGIN 2 */! d( v; @5 ?& z" f2 ]% [5 v+ f: t
  81.   ResetPrintInit(&huart1);//将printf()函数映射到UART1串口上
    5 z8 n  D- \% Y( _; D
  82.   HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);//开启串口1接收中断
    " @  r6 @! o7 }+ d) O$ n; e, k0 _+ L
  83.   HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启串口3接收中断) K" c7 J, X! G  o! \/ G  t7 }
  84.   /* USER CODE END 2 */
    2 Q9 N6 z6 z- p2 e: Y0 Z1 v

  85. ' t% T/ l% S8 {( o+ f+ a6 r; n
  86.   /* Infinite loop */
    & I8 i) k: X# d/ O
  87.   /* USER CODE BEGIN WHILE */
    5 I( R5 o/ y2 I% O/ {- R; b0 J  X
  88.   while (1)" z: `0 C4 b0 `3 t2 H& d
  89.   {
    4 O  a; ?. o) P/ ^8 {
  90.           //demo 蓝牙02; d7 r* ]7 t3 d' ^! N# |
  91.       if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)
    3 t5 |$ [6 P4 {4 z& L- C* [8 k0 h
  92.              BT_printf("%c",USART2_RX_STA);
    . o. F+ X$ i0 M. i$ v/ b
  93.              if((USART2_RX_STA&0x7FFF) == 1)        //判断接收数量1个(手机控制程序)
    4 H( V$ y8 j% t, @# a9 s* o: q
  94.              {
    ( I1 w; a- U) X0 U7 S9 b" G2 e! J/ o
  95.                      BT_printf("%c",USART2_RX_BUF[0]);
    ' _. ]) n  ~6 Y$ u8 Y9 _) H
  96.                      switch (USART2_RX_BUF[0]){//判断接收数据的内容
    % K9 ?) ]2 u7 s8 T3 l5 S7 @0 _
  97.                                 case 0x41:
    ( g$ E, }; K5 X& ?4 S
  98.                                         LED_1(1);//LED1控制
    - W2 ~9 A% w! B+ X: q, X+ s
  99.                                         BT_printf("Relay ON");//返回数据内容,在手机APP上显示
    # o- E5 `# F) m/ y
  100.                                         break;5 k" e/ J8 i3 U6 G9 x) j( y+ m
  101.                                 case 0x44:$ A' a! P" D* U$ L  D
  102.                                         LED_1(0);//LED1控制6 P3 F& Z- C( [9 n
  103.                                         BT_printf("Relay OFF");//返回数据内容,在手机APP上显示0 Y0 g) ?6 h" H/ r; _$ i. [9 L& b
  104.                                         break;# f" y% k& Z0 }
  105.                                 case 0x42:
    ) `. u( Z3 ^4 W1 l6 R( B
  106.                                         LED_2(1);//LED1控制
    $ r" f' N7 C& t
  107.                                         BT_printf("LED1 ON");//返回数据内容,在手机APP上显示6 I3 f' n6 x2 w
  108.                                         break;6 H& i7 o1 R9 Q( v3 {
  109.                                 case 0x45:* Y+ M# s  I2 n% r3 d
  110.                                         LED_2(0);//LED1控制
    4 `3 b; n1 [/ U8 r" {* I& M7 H3 {2 e
  111.                                         BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示" `: s7 I* ]4 b( n+ l3 L4 m; Q) S
  112.                                         break;
    8 z! w6 d. v0 K" G/ P, P! l
  113.                                 case 0x43:0 @4 j9 X* l4 O; v4 y
  114.                                         LED_1(0);//LED1控制* S7 }9 z+ T! I4 w8 ~$ ^* M
  115.                                         LED_2(0);//LED1控制& K3 s! T7 Z* ~, V# \2 E2 W
  116.                                         BT_printf("BEEP");//返回数据内容,在手机APP上显示1 V" ?: M( ]2 ]5 R% A5 Z
  117.                                         break;; {) _) u" h% Z" \/ {4 V
  118.                                 case 0x46:2 t; G9 P4 V& n8 x8 H, }6 g5 l7 P
  119.                                         BT_printf("CPU Reset");//返回数据内容,在手机APP上显示, S2 D& k1 r" x1 q* r2 r
  120.                                         HAL_Delay(1000);//延时; A6 x9 B7 v% s* u# H& c. u
  121.                                         NVIC_SystemReset();//系统软件复位函数
    # J* g4 Q0 j% O; e0 ~0 }2 V
  122.                                         break;& ~. @/ w- ?2 @/ @8 X* B! S5 M& j2 q
  123.                                 default:) z4 n8 `' L# l8 J0 b- G" W* s6 J" Y
  124.                                         //冗余语句* ]6 L; v; A( ^# ]7 M9 P. J5 O
  125.                                         break;' c" ~8 y2 l! s
  126.                           }% v+ b! W9 R+ q) q& m% k
  127.                  }6 B+ d" G9 a. T* ]" `' Z2 S
  128.                 printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1: Q$ S. E! W7 y# }. g8 C( O
  129.          USART2_RX_STA=0;//标志位清0,准备下次接收9 y8 m: u3 C3 t- z9 E) E
  130.       }4 O' B) W- a" B8 b$ M. w% g
  131.       //接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块
    ( y6 i: k. k6 q" Z6 W
  132.       if(USART1_RX_STA&0xC000){//结束标记
    0 d3 N4 d0 ]% u: D
  133.               BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);& U7 e# N6 T  Z1 B+ H
  134.               USART1_RX_STA=0;//接收重新开始/ D1 l9 H4 r* Q& _0 _$ U; D+ @+ {" ?
  135.               HAL_Delay(100);//等待' T7 N' ~9 v  v# c
  136.       }
    5 d7 U7 ^/ I/ }/ l
  137.           if(KEY_1())//按下KEY1判断
    # P8 }5 a/ H! @, `
  138.           {
    - h9 S# N  Z2 H/ A7 x" E
  139.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
      J% S* f1 A3 E3 b5 P% I2 n0 \
  140.                   LED_2(0);//LED2控制
    7 I0 |( S1 D* R
  141.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
    . }! E8 ^# }/ R- H. F- p
  142.           }1 |4 R9 y7 C  u& o
  143.           if(KEY_2())//按下KEY2判断+ ?' Q) J5 U& L9 t4 ]
  144.           {3 z, o2 e4 @0 u, n. z; y# C: O' y
  145.                   LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
    # J- m! z/ j! E) @) d2 h* B; V
  146.                   LED_2(1);//LED2控制& q: p# e- K0 i6 u  K* a, }
  147.                   BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)
    : e4 S8 E4 ?& x4 p4 d
  148.           }
    9 x$ j7 \( S1 _
  149.     /* USER CODE END WHILE */
    4 {- a* N; @$ ~) b" i* q
  150. # H+ i3 L  b5 m# T9 u# z
  151.     /* USER CODE BEGIN 3 */0 P  s, C% m& w( z6 P* _1 z* p" H" P
  152.   }& b$ I, j. V+ Q/ c: t
  153.   /* USER CODE END 3 */: d# e' C3 o& h
  154. }
复制代码

* y/ x6 S, A7 k: L! Y       2)设置编译输出支持,右键工程进入项目属性设置页面:
1 B' U) V; O- I! d/ p5 h7 B" m9 u: g' w5 ~* w1 U2 `, \% f- q$ G; O0 D
b959f3b4bbc34e9a933d8fa45890c6ba.png 3 |* F/ S3 L, ?7 B8 H! B1 c
& C0 A% z0 u: a
          3)点击编译按钮,完成编译(整个工程需要源码修改或添加的源文件如下):# Z( g# K5 G' e2 _$ y& E( C

3 n, U' g& Q: y7 @, P- ^* k
288d14c992b3413ab8b2e3c42e0994ed.png ; `+ T5 G, g: t) g( P

" S: b; u4 L: @/ }        【2】程序测试
( ^# U5 `  W. f/ U' Z+ _3 t1 q2 u        1)测试过程需要三个工具文件支持,读者可以自网上搜索最新版本或采用其他同功能工具替代测试:0 Y0 L5 G1 U7 o
        FlyMCU加载工具,将生成的.hex程序文件加载到板子上
. Y0 B& v  O& G3 [% v3 F        SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入
1 v9 A. u) d3 d: g# |: D) `, m        蓝牙调试器工具,本文用的是1.9安卓版本。
3 x, {, ~- L4 o  K) D% S4 u3 u
, s% l( L/ Z3 N# E5 `5 m
616ca3780a8b4077ba5ba5f13ad76834.png 5 E* V( }8 `: z" k  m" Z' l. I
" \2 j7 D6 @, N% P: J' R2 i+ z( \9 j( i; z- @
2 O% a9 g: C# Q' a% x9 q
        2)加载程序,选择串口,选择程序(.hex),点击开始编程按钮:
0 H1 s+ X" ?6 h4 A, j* c  \2 @3 u9 b- A
5da0d56a3c4e4c45a74e90e7fbf4b989.png
) A: z8 U/ Q0 d) |1 B" p( M
% W) A$ l  _  g( d  p         3)手机打开蓝牙调试器(别忘了开启手机蓝牙功能),进入界面,搜索蓝牙,点击蓝牙边上“+”按钮连接蓝牙模块,采用SSCOM串口工具连接到usart1上,就可以通过蓝牙通信实现手机(蓝牙调试器)与电脑(串口工具)的通信了,在蓝牙调试器发送数据时,十六进制时需要加上“0A”作为结尾,如果十进制发送时,注意加上换行再发送:
# @/ E, O, L5 s; @) C; A' U5 w- A3 ~
df172bc6aaa94e678d2c06fb92dbe6a9.png a573139985cc47b79688e2ee52359e8e.png
# b7 F5 }$ R+ w. H2 U
- S3 q$ w' \  [! U! V
        注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:  x; P+ }; K9 u8 d' |
  1. if(KEY_1())//按下KEY1判断/ U' y! `9 Z6 F+ Z+ S. E
  2.           {
    ! T4 R# e7 a# v& b$ h. @; w9 J
  3.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位8 G) i5 _& v' n9 W
  4.                   LED_2(0);//LED2控制
    & l; ]$ q6 t1 K& r  \9 ]$ ~3 k/ J
  5.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)( _4 D( v) y( k9 i) K; v
  6.           }
复制代码
/ R2 A; g9 L3 `; I  {& _& v
        串口发送数据:
# |- V1 H* I1 U  {  m5 A
2 S& P5 }% x* r. R& f2 z8 b
399927e9b5474fd4bafe8534255fab31.png
! b/ q* U$ g) p8 P" C) z$ c
. t( D- E/ l" g/ g
6 U* p% ]  I# L# P' F* g: W
        可以进入按钮控制页面进行指令定制设置
: f9 R8 P4 @8 l# x8 \3 o  T0 \
+ h& e/ h- F0 x" L& d( W2 Q# ~
56473e9c27a04fafaa96bc2f0dab5f08.png 9ac0cde743b143e08e391b2d9e793b56.png 5 X9 p7 s6 R4 D' p
, G: @) ^2 X* b( ]
         至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。. d9 x" L, @3 W1 j1 M- ^" U+ Z
————————————————: Y  G7 Z  l8 ~' y% N, w
版权声明:py_free-物联智能+ q: m5 f4 Z1 E2 c# a8 Q. F5 E
如有侵权请联系删除
8 b) o  J0 R' ?( Q  ?
  {' h  I7 p! g/ `
* Q7 l# B7 u( h) H7 P7 ?+ t2 O2 z' K" I& q# ?( w
赞 收藏 评论0 发布时间:2023-4-7 15:54

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版