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

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

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

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


二、MCU及蓝牙模块
        本文采用STM32F103C8T6的芯片及JDY-08 蓝牙透传模块,相关引脚如下:

        MCU引脚设定:PA9、PA10作为USART1引脚,用于下载程序、调试显示,PA2、PA3作为USART2引脚,并与蓝牙模块进行通信,PA8作为GPIO_OUTPUT模式,用来控制蓝牙模块上的PWRC。

2d927f8850734dd683cfc95f270f3604.png

         蓝牙模块为JDY-08 蓝牙透传模块,基于蓝牙 4.0 协议标准,工作频段为 2.4GHZ 范围,调制 方式为 GFSK,最大发射功率为 0db,最大发射距离 80 米,采用 TICC2541 芯片设计,支持用户通过 AT 命令修改设备名、服务 UUID、发射功率、配对密码等指令。

        TICC2541 芯片 引脚:

87b66d3312cc4c23b64182bd2c2496c9.png

         引脚功能定义,在使用串口发送命令时,请将模块的 PWRC 引脚接地,并接上模块的电源(VCC、GND),电源电压为3~ 3.3V:

50c5510d3d8b4234879cc66e8e1a6988.png

         以及本文用到两个AT指令:

d5bc46612e09498c922ad506da5679f4.png

三、cubeMX配置MCU及蓝牙接口
        本工程设计功能如下:

        MCU(STM32F103C8T6)的引脚PA2、PA3的与蓝牙模块(TICC2541 )的11、12引脚连接,实现数据通信;MCU的PA8引脚与蓝牙模块的22引脚连接实现,实现蓝牙模块唤醒。

        通信逻辑:电脑(com4)<->(Usart1)MCU(Usart2)<->蓝牙模块->手机(蓝牙调试器,需要开启手机蓝牙功能)。

        功能:
        按键功能,用于按键时向蓝牙模块发送AT指令;
        LED功能,用于接收蓝牙模块数据时做出闪灯响应;
        蓝牙功能,接收来自MCU端的串口通信,接收手机端的无线传输(即蓝牙通信);
        串口调试功能,MCU执行程序可以向Usart1发送信息到电脑端,既可实现日志输出,也可以实现指令转发到蓝牙模块。
        【1】创建工程
        1)新建stm32工程,选择芯片STM32F103C8T6

a4d9946142d542f3a8ade81b66e0a552.png

         2)为工程命名完成创建

8177bd2fea6b478e8c172a4b4604aa43.png

         【2】CubeMX配置
        1)开启sys mode接口

6945e8635a7a466b83c22611ad53d9c5.png

         2)开启RCC

eb9677e954f14340b91608f89a899e85.png

         3)开启USART1(下载、调试)、USART2(连接蓝牙模块)。

8a56a450ae704a66afcd75f588cd2e64.png

         4)开启串口USART1、USART2中断功能

1a51fe61e16c48fd95cd3c1841c6cf9f.png

         5)串口引脚参数配置

3c5015317b1643e1b7e9a55510e02cfc.png

         6)蓝牙测试辅助接口及按键、LED灯GPIO引脚添加:

70a978fd9ca34aa18d434351ceb7bb5b.png

        7)系统 时钟配置,直接拉满STM32F103C8T6能支持到的72MHz。

cd5e618b97e54ef1886818cc2b4c1956.png

          8)本工程配置页面保持默认,没有为每个外围设备驱动创建独立源文件,点击保持或生成代码按钮输出代码。

31870054f08c4b95bfb5f485f13480d6.png


四、代码设计
        【1】首先创建usart1接口的调试输出支持
        1)禁用syscalls.c,右键选择该文件进入属性页面设置。

aec3533e953447e39024f449845c2564.png

         2)在工程目录下创建源码目录ICore,添加文件夹print及print.h/print.c,实现对系统printf函数的映射到usart1输出显示功能。

        print.h
  1. #ifndef INC_RETARGET_H_
  2. #define INC_RETARGET_H_

  3. #include "stm32f1xx_hal.h"
  4. #include "stdio.h"//用于printf函数串口重映射
  5. #include <sys/stat.h>

  6. void ResetPrintInit(UART_HandleTypeDef  *huart);

  7. int _isatty(int fd);
  8. int _write(int fd, char* ptr, int len);
  9. int _close(int fd);
  10. int _lseek(int fd, int ptr, int dir);
  11. int _read(int fd, char* ptr, int len);
  12. int _fstat(int fd, struct stat* st);

  13. #endif /* INC_RETARGET_H_ */
复制代码

        print.c
  1. #include <_ansi.h>
  2. #include <_syslist.h>
  3. #include <errno.h>
  4. #include <sys/time.h>
  5. #include <sys/times.h>
  6. #include <limits.h>
  7. #include <signal.h>
  8. #include <stdint.h>
  9. #include <stdio.h>

  10. #include "print.h"

  11. #if !defined(OS_USE_SEMIHOSTING)
  12. #define STDIN_FILENO  0
  13. #define STDOUT_FILENO 1
  14. #define STDERR_FILENO 2

  15. UART_HandleTypeDef *gHuart;

  16. void ResetPrintInit(UART_HandleTypeDef *huart)  {
  17.   gHuart = huart;
  18.   /* Disable I/O buffering for STDOUT  stream, so that
  19.    * chars are sent out as soon as they are  printed. */
  20.   setvbuf(stdout, NULL, _IONBF, 0);
  21. }
  22. int _isatty(int fd) {
  23.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
  24.     return 1;
  25.   errno = EBADF;
  26.   return 0;
  27. }
  28. int _write(int fd, char* ptr, int len) {
  29.   HAL_StatusTypeDef hstatus;
  30.   if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {
  31.     hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);
  32.     if (hstatus == HAL_OK)
  33.       return len;
  34.     else
  35.       return EIO;
  36.   }
  37.   errno = EBADF;
  38.   return -1;
  39. }
  40. int _close(int fd) {
  41.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
  42.     return 0;
  43.   errno = EBADF;
  44.   return -1;
  45. }
  46. int _lseek(int fd, int ptr, int dir) {
  47.   (void) fd;
  48.   (void) ptr;
  49.   (void) dir;
  50.   errno = EBADF;
  51.   return -1;
  52. }
  53. int _read(int fd, char* ptr, int len) {
  54.   HAL_StatusTypeDef hstatus;
  55.   if (fd == STDIN_FILENO) {
  56.     hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);
  57.     if (hstatus == HAL_OK)
  58.       return 1;
  59.     else
  60.       return EIO;
  61.   }
  62.   errno = EBADF;
  63.   return -1;
  64. }
  65. int _fstat(int fd, struct stat* st) {
  66.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {
  67.     st->st_mode = S_IFCHR;
  68.     return 0;
  69.   }
  70.   errno = EBADF;
  71.   return 0;
  72. }

  73. #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码

        【2】创建按键驱动、LED驱动、延时函数功能的支持
         1)在ICore添加delay目录,并添加delay.h/delay.c源文件
        delay.h
  1. #ifndef DELAY_DELAY_H_
  2. #define DELAY_DELAY_H_

  3. #include "stm32f1xx_hal.h" //HAL库文件声明
  4. void delay_us(uint32_t us); //C文件中的函数声明

  5. #endif /* DELAY_DELAY_H_ */
复制代码

        delay.c
  1. #include "delay.h"

  2. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
  3. {
  4.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数
  5.     while (delay--); //循环delay次,达到1微秒延时
  6. }
复制代码

        2)在ICore添加key目录,并添加key.h/key.c源文件

        key.h
  1. #ifndef KEY_KEY_H_
  2. #define KEY_KEY_H_

  3. #include "stm32f1xx_hal.h" //HAL库文件声明
  4. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用
  5. #include "../delay/delay.h"

  6. uint8_t KEY_1(void);//按键1
  7. uint8_t KEY_2(void);//按键2

  8. #endif /* KEY_KEY_H_ */
复制代码

        key.c
  1. #include "key.h"

  2. uint8_t KEY_1(void)
  3. {
  4.         uint8_t a;
  5.         a=0;//如果未进入按键处理,则返回0
  6.         if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  7. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
  8.                 delay_us(20000);//延时去抖动
  9.                 if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  10.                         a=1;//进入按键处理,返回1
  11.                 }
  12.         }
  13.         while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开
  14.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)
  15.         return a;
  16. }

  17. uint8_t KEY_2(void)
  18. {
  19.         uint8_t a;
  20.         a=0;//如果未进入按键处理,则返回0
  21.         if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  22. //                HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
  23.                 delay_us(20000);//延时去抖动
  24.                 if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  25.                         a=1;//进入按键处理,返回1
  26.                 }
  27.         }
  28.         while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
  29.         delay_us(20000);//延时去抖动(避开按键放开时的抖动)
  30.         return a;
  31. }
复制代码

        3)在ICore添加led目录,并添加led.h/led.c源文件

        key.h
  1. #ifndef LED_LED_H_
  2. #define LED_LED_H_

  3. #include "stm32f1xx_hal.h" //HAL库文件声明
  4. #include "main.h" //IO定义与初始化函数在main.c文件中,必须引用

  5. void LED_1(uint8_t a);//LED1独立控制函数(0为熄灭,其他值为点亮)
  6. void LED_2(uint8_t a);//LED2独立控制函数(0为熄灭,其他值为点亮)
  7. void LED_ALL(uint8_t a);//LED1~4整组操作函数(低4位的1/0状态对应4个LED亮灭,最低位对应LED1)
  8. void LED_1_Contrary(void);//LED1状态取反
  9. void LED_2_Contrary(void);//LED2状态取反

  10. #endif /* LED_LED_H_ */
复制代码

        key.c
  1. #include "led.h"

  2. void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)
  3. {
  4.         if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
  5.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
  6. }
  7. void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)
  8. {
  9.         if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
  10.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
  11. }
  12. void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1)
  13. {
  14.         if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
  15.         else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
  16.         if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
  17.         else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
  18. }
  19. void LED_1_Contrary(void){
  20.         HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));
  21. }
  22. void LED_2_Contrary(void){
  23.         HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));
  24. }
复制代码

        【3】创建串口驱动程序,主要是复写串口回调功能
        1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能

        usart.h
  1. #ifndef INC_USART_H_
  2. #define INC_USART_H_

  3. #include "stm32f1xx_hal.h" //HAL库文件声明
  4. #include <string.h>//用于字符串处理的库
  5. #include "../print/print.h"//用于printf函数串口重映射

  6. extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体
  7. extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体

  8. #define USART1_REC_LEN  200//定义USART1最大接收字节数
  9. #define USART2_REC_LEN  200//定义USART1最大接收字节数

  10. extern uint8_t  USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
  11. extern uint16_t USART1_RX_STA;//接收状态标记
  12. extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存

  13. extern uint8_t  USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
  14. extern uint16_t USART2_RX_STA;//接收状态标记
  15. extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存


  16. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明

  17. #endif /* INC_USART_H_ */
复制代码

        usart.c
  1. #include "usart.h"

  2. uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
  3. /*
  4. * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;
  5. * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
  6. * bit13:预留
  7. * bit12:预留
  8. * bit11~0:接收到的有效字节数目(0~4095)
  9. */
  10. uint16_t USART1_RX_STA=0;
  11. uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存

  12. uint8_t USART2_RX_BUF[USART2_REC_LEN];
  13. uint16_t USART2_RX_STA=0;
  14. uint8_t USART2_NewData;

  15. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
  16. {
  17.         if(huart ==&huart1)//判断中断来源(串口1:USB转串口)
  18.     {
  19. //                printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
  20.                 if(USART1_NewData==0x0d){//回车标记
  21.                         USART1_RX_STA|=0x8000;//标记接到回车
  22.                 }else{
  23.                         if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){
  24.                                 USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组
  25.                                 USART1_RX_STA++;  //数据长度计数加1
  26.                         }else{
  27.                                 USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
  28.                         }
  29.         }
  30.        HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断
  31.     }
  32.         if(huart ==&huart2)//判断中断来源(串口2:BT模块)
  33.         {
  34. //                printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
  35.                 if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)
  36.                         USART2_RX_STA|=0x8000;//标记接到回车
  37.                 }else{
  38.                         if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){
  39.                                 USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组
  40.                                 USART2_RX_STA++;  //数据长度计数加1
  41.                         }else{
  42.                                 USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
  43.                         }
  44.         }
  45.                 HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断
  46.         }
  47. }
复制代码

        【4】创建蓝牙驱动
        该驱动主要实现通过usart2向蓝牙模块写入数据,(读取数据主要通过串口usart2回调,在usart.c中实现)。在ICore添加bt目录,并添加bt.h/bt.c源文件,实现蓝牙驱动功能

        bt.h
  1. #ifndef BT_BT_H_
  2. #define BT_BT_H_

  3. #include "stm32f1xx_hal.h" //HAL库文件声明
  4. #include "main.h"
  5. #include "../usart/usart.h"
  6. #include "../delay/delay.h"
  7. #include <string.h>//用于字符串处理的库
  8. #include <stdarg.h>
  9. #include <stdlib.h>
  10. #include "stdio.h"

  11. extern UART_HandleTypeDef huart2;//声明UART2的HAL库结构体
  12. void BT_WEEKUP (void);//蓝牙模块唤醒函数
  13. void BT_printf (char *fmt, ...); //BT蓝牙模块发送

  14. #endif /* BT_BT_H_ */
复制代码

        bt.c
  1. #include "bt.h"

  2. //蓝牙模块唤醒函数
  3. //对蓝牙模块上的PWRC(P00)接口一个低电平脉冲,如不使用睡眠模式可忽略此函数
  4. void BT_WEEKUP (void)
  5. {
  6.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_RESET);//PWRC接口控制
  7.         delay_us(100);
  8.         HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_SET);//PWRC接口控制
  9. }
  10. //蓝牙模块通信,使用UART2,这是BT蓝牙的printf函数
  11. //调用方法:BT_printf("123"); //向UART2发送字符123
  12. void BT_printf (char *fmt, ...)
  13. {
  14.     char buff[USART2_REC_LEN+1];  //用于存放转换后的数据 [长度]
  15.     uint16_t i=0;
  16.     va_list arg_ptr;
  17.     va_start(arg_ptr, fmt);
  18.     vsnprintf(buff, USART2_REC_LEN+1, fmt,  arg_ptr);//数据转换
  19.     i=strlen(buff);//得出数据长度
  20.     if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
  21.     HAL_UART_Transmit(&huart2,(uint8_t  *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)
  22.     va_end(arg_ptr);
  23. }
  24. //所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在USART.C文件中。
复制代码

五、编译及测试
        【1】功能调用及编译
        1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:
  1. /* USER CODE END Header */
  2. /* Includes ------------------------------------------------------------------*/
  3. #include "main.h"

  4. /* Private includes ----------------------------------------------------------*/
  5. /* USER CODE BEGIN Includes */
  6. #include "../../ICore/led/led.h"
  7. #include "../../ICore/key/key.h"
  8. #include "../../ICore/delay/delay.h"
  9. #include "../../ICore/print/print.h"//用于printf函数串口重映射
  10. #include "../../ICore/bt/bt.h"
  11. /* USER CODE END Includes */

  12. /* Private typedef -----------------------------------------------------------*/
  13. /* USER CODE BEGIN PTD */

  14. /* USER CODE END PTD */

  15. /* Private define ------------------------------------------------------------*/
  16. /* USER CODE BEGIN PD */
  17. /* USER CODE END PD */

  18. /* Private macro -------------------------------------------------------------*/
  19. /* USER CODE BEGIN PM */

  20. /* USER CODE END PM */

  21. /* Private variables ---------------------------------------------------------*/
  22. UART_HandleTypeDef huart1;
  23. UART_HandleTypeDef huart2;

  24. /* USER CODE BEGIN PV */

  25. /* USER CODE END PV */

  26. /* Private function prototypes -----------------------------------------------*/
  27. void SystemClock_Config(void);
  28. static void MX_GPIO_Init(void);
  29. static void MX_USART1_UART_Init(void);
  30. static void MX_USART2_UART_Init(void);
  31. /* USER CODE BEGIN PFP */

  32. /* USER CODE END PFP */

  33. /* Private user code ---------------------------------------------------------*/
  34. /* USER CODE BEGIN 0 */

  35. /* USER CODE END 0 */

  36. /**
  37.   * @brief  The application entry point.
  38.   * @retval int
  39.   */
  40. int main(void)
  41. {
  42.   /* USER CODE BEGIN 1 */

  43.   /* USER CODE END 1 */

  44.   /* MCU Configuration--------------------------------------------------------*/

  45.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  46.   HAL_Init();

  47.   /* USER CODE BEGIN Init */

  48.   /* USER CODE END Init */

  49.   /* Configure the system clock */
  50.   SystemClock_Config();

  51.   /* USER CODE BEGIN SysInit */

  52.   /* USER CODE END SysInit */

  53.   /* Initialize all configured peripherals */
  54.   MX_GPIO_Init();
  55.   MX_USART1_UART_Init();
  56.   MX_USART2_UART_Init();
  57.   /* USER CODE BEGIN 2 */
  58.   ResetPrintInit(&huart1);//将printf()函数映射到UART1串口上
  59.   HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);//开启串口1接收中断
  60.   HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启串口3接收中断
  61.   /* USER CODE END 2 */

  62.   /* Infinite loop */
  63.   /* USER CODE BEGIN WHILE */
  64.   while (1)
  65.   {
  66.           //demo 蓝牙02
  67.       if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)
  68.              BT_printf("%c",USART2_RX_STA);
  69.              if((USART2_RX_STA&0x7FFF) == 1)        //判断接收数量1个(手机控制程序)
  70.              {
  71.                      BT_printf("%c",USART2_RX_BUF[0]);
  72.                      switch (USART2_RX_BUF[0]){//判断接收数据的内容
  73.                                 case 0x41:
  74.                                         LED_1(1);//LED1控制
  75.                                         BT_printf("Relay ON");//返回数据内容,在手机APP上显示
  76.                                         break;
  77.                                 case 0x44:
  78.                                         LED_1(0);//LED1控制
  79.                                         BT_printf("Relay OFF");//返回数据内容,在手机APP上显示
  80.                                         break;
  81.                                 case 0x42:
  82.                                         LED_2(1);//LED1控制
  83.                                         BT_printf("LED1 ON");//返回数据内容,在手机APP上显示
  84.                                         break;
  85.                                 case 0x45:
  86.                                         LED_2(0);//LED1控制
  87.                                         BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示
  88.                                         break;
  89.                                 case 0x43:
  90.                                         LED_1(0);//LED1控制
  91.                                         LED_2(0);//LED1控制
  92.                                         BT_printf("BEEP");//返回数据内容,在手机APP上显示
  93.                                         break;
  94.                                 case 0x46:
  95.                                         BT_printf("CPU Reset");//返回数据内容,在手机APP上显示
  96.                                         HAL_Delay(1000);//延时
  97.                                         NVIC_SystemReset();//系统软件复位函数
  98.                                         break;
  99.                                 default:
  100.                                         //冗余语句
  101.                                         break;
  102.                           }
  103.                  }
  104.                 printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1
  105.          USART2_RX_STA=0;//标志位清0,准备下次接收
  106.       }
  107.       //接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块
  108.       if(USART1_RX_STA&0xC000){//结束标记
  109.               BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);
  110.               USART1_RX_STA=0;//接收重新开始
  111.               HAL_Delay(100);//等待
  112.       }
  113.           if(KEY_1())//按下KEY1判断
  114.           {
  115.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
  116.                   LED_2(0);//LED2控制
  117.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
  118.           }
  119.           if(KEY_2())//按下KEY2判断
  120.           {
  121.                   LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
  122.                   LED_2(1);//LED2控制
  123.                   BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)
  124.           }
  125.     /* USER CODE END WHILE */

  126.     /* USER CODE BEGIN 3 */
  127.   }
  128.   /* USER CODE END 3 */
  129. }
复制代码

       2)设置编译输出支持,右键工程进入项目属性设置页面:

b959f3b4bbc34e9a933d8fa45890c6ba.png

          3)点击编译按钮,完成编译(整个工程需要源码修改或添加的源文件如下):

288d14c992b3413ab8b2e3c42e0994ed.png

        【2】程序测试
        1)测试过程需要三个工具文件支持,读者可以自网上搜索最新版本或采用其他同功能工具替代测试:
        FlyMCU加载工具,将生成的.hex程序文件加载到板子上
        SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入
        蓝牙调试器工具,本文用的是1.9安卓版本。

616ca3780a8b4077ba5ba5f13ad76834.png


        2)加载程序,选择串口,选择程序(.hex),点击开始编程按钮:

5da0d56a3c4e4c45a74e90e7fbf4b989.png

         3)手机打开蓝牙调试器(别忘了开启手机蓝牙功能),进入界面,搜索蓝牙,点击蓝牙边上“+”按钮连接蓝牙模块,采用SSCOM串口工具连接到usart1上,就可以通过蓝牙通信实现手机(蓝牙调试器)与电脑(串口工具)的通信了,在蓝牙调试器发送数据时,十六进制时需要加上“0A”作为结尾,如果十进制发送时,注意加上换行再发送:

df172bc6aaa94e678d2c06fb92dbe6a9.png a573139985cc47b79688e2ee52359e8e.png

        注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:
  1. if(KEY_1())//按下KEY1判断
  2.           {
  3.                   LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
  4.                   LED_2(0);//LED2控制
  5.                   BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
  6.           }
复制代码

        串口发送数据:

399927e9b5474fd4bafe8534255fab31.png


        可以进入按钮控制页面进行指令定制设置

56473e9c27a04fafaa96bc2f0dab5f08.png 9ac0cde743b143e08e391b2d9e793b56.png

         至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。
————————————————
版权声明:py_free-物联智能
如有侵权请联系删除



收藏 评论0 发布时间:2023-4-7 15:54

举报

0个回答

所属标签

相似分享

官网相关资源

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