cubeIDE开发, 物联网应用之stm32的蓝牙通信设计

news2025/7/14 3:13:11

一、蓝牙通信技术

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

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

二、MCU及蓝牙模块

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

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

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

        TICC2541 芯片 引脚:

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

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

 三、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

         2)为工程命名完成创建

         【2】CubeMX配置

        1)开启sys mode接口

         2)开启RCC

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

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

         5)串口引脚参数配置

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

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

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

 四、代码设计

        【1】首先创建usart1接口的调试输出支持

        1)禁用syscalls.c,右键选择该文件进入属性页面设置。

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

        print.h

#ifndef INC_RETARGET_H_
#define INC_RETARGET_H_

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

void ResetPrintInit(UART_HandleTypeDef  *huart);

int _isatty(int fd);
int _write(int fd, char* ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char* ptr, int len);
int _fstat(int fd, struct stat* st);

#endif /* INC_RETARGET_H_ */

        print.c

#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>

#include "print.h"

#if !defined(OS_USE_SEMIHOSTING)
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

UART_HandleTypeDef *gHuart;

void ResetPrintInit(UART_HandleTypeDef *huart)  {
  gHuart = huart;
  /* Disable I/O buffering for STDOUT  stream, so that
   * chars are sent out as soon as they are  printed. */
  setvbuf(stdout, NULL, _IONBF, 0);
}
int _isatty(int fd) {
  if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
    return 1;
  errno = EBADF;
  return 0;
}
int _write(int fd, char* ptr, int len) {
  HAL_StatusTypeDef hstatus;
  if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {
    hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return len;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}
int _close(int fd) {
  if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
    return 0;
  errno = EBADF;
  return -1;
}
int _lseek(int fd, int ptr, int dir) {
  (void) fd;
  (void) ptr;
  (void) dir;
  errno = EBADF;
  return -1;
}
int _read(int fd, char* ptr, int len) {
  HAL_StatusTypeDef hstatus;
  if (fd == STDIN_FILENO) {
    hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return 1;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}
int _fstat(int fd, struct stat* st) {
  if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {
    st->st_mode = S_IFCHR;
    return 0;
  }
  errno = EBADF;
  return 0;
}

#endif //#if !defined(OS_USE_SEMIHOSTING)

        【2】创建按键驱动、LED驱动、延时函数功能的支持

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

        delay.h

#ifndef DELAY_DELAY_H_
#define DELAY_DELAY_H_

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

#endif /* DELAY_DELAY_H_ */

        delay.c

#include "delay.h"

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

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

        key.h

#ifndef KEY_KEY_H_
#define KEY_KEY_H_

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

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

#endif /* KEY_KEY_H_ */

        key.c

#include "key.h"

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

uint8_t KEY_2(void)
{
	uint8_t a;
	a=0;//如果未进入按键处理,则返回0
	if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
//		HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)
		delay_us(20000);//延时去抖动
		if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
			a=1;//进入按键处理,返回1
		}
	}
	while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
	delay_us(20000);//延时去抖动(避开按键放开时的抖动)
	return a;
}

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

        key.h

#ifndef LED_LED_H_
#define LED_LED_H_

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

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

#endif /* LED_LED_H_ */

        key.c

#include "led.h"

void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)
{
	if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
	else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
}
void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)
{
	if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
	else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
}
void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1)
{
	if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
	else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
	if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);
	else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
}
void LED_1_Contrary(void){
	HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));
}
void LED_2_Contrary(void){
	HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));
}

        【3】创建串口驱动程序,主要是复写串口回调功能

        1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能

        usart.h

#ifndef INC_USART_H_
#define INC_USART_H_

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

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

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

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

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


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

#endif /* INC_USART_H_ */

        usart.c

#include "usart.h"

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

uint8_t USART2_RX_BUF[USART2_REC_LEN];
uint16_t USART2_RX_STA=0;
uint8_t USART2_NewData;

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
{
	if(huart ==&huart1)//判断中断来源(串口1:USB转串口)
    {
//		printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
		if(USART1_NewData==0x0d){//回车标记
			USART1_RX_STA|=0x8000;//标记接到回车
		}else{
			if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){
				USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组
				USART1_RX_STA++;  //数据长度计数加1
			}else{
				USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
			}
        }
       HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断
    }
	if(huart ==&huart2)//判断中断来源(串口2:BT模块)
	{
//		printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑
		if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)
			USART2_RX_STA|=0x8000;//标记接到回车
		}else{
			if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){
				USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组
				USART2_RX_STA++;  //数据长度计数加1
			}else{
				USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
			}
        }
		HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断
	}
}

        【4】创建蓝牙驱动

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

        bt.h

#ifndef BT_BT_H_
#define BT_BT_H_

#include "stm32f1xx_hal.h" //HAL库文件声明
#include "main.h"
#include "../usart/usart.h"
#include "../delay/delay.h"
#include <string.h>//用于字符串处理的库
#include <stdarg.h>
#include <stdlib.h>
#include "stdio.h"

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

#endif /* BT_BT_H_ */

        bt.c

#include "bt.h"

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

五、编译及测试

        【1】功能调用及编译

        1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../../ICore/led/led.h"
#include "../../ICore/key/key.h"
#include "../../ICore/delay/delay.h"
#include "../../ICore/print/print.h"//用于printf函数串口重映射
#include "../../ICore/bt/bt.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

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

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  //demo 蓝牙02
      if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)
    	 BT_printf("%c",USART2_RX_STA);
    	 if((USART2_RX_STA&0x7FFF) == 1)	//判断接收数量1个(手机控制程序)
    	 {
    		 BT_printf("%c",USART2_RX_BUF[0]);
    		 switch (USART2_RX_BUF[0]){//判断接收数据的内容
				case 0x41:
					LED_1(1);//LED1控制
					BT_printf("Relay ON");//返回数据内容,在手机APP上显示
					break;
				case 0x44:
					LED_1(0);//LED1控制
					BT_printf("Relay OFF");//返回数据内容,在手机APP上显示
					break;
				case 0x42:
					LED_2(1);//LED1控制
					BT_printf("LED1 ON");//返回数据内容,在手机APP上显示
					break;
				case 0x45:
					LED_2(0);//LED1控制
					BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示
					break;
				case 0x43:
					LED_1(0);//LED1控制
					LED_2(0);//LED1控制
					BT_printf("BEEP");//返回数据内容,在手机APP上显示
					break;
				case 0x46:
					BT_printf("CPU Reset");//返回数据内容,在手机APP上显示
					HAL_Delay(1000);//延时
					NVIC_SystemReset();//系统软件复位函数
					break;
				default:
					//冗余语句
					break;
			  }
		 }
		printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1
         USART2_RX_STA=0;//标志位清0,准备下次接收
      }
      //接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块
      if(USART1_RX_STA&0xC000){//结束标记
    	  BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);
    	  USART1_RX_STA=0;//接收重新开始
    	  HAL_Delay(100);//等待
      }
	  if(KEY_1())//按下KEY1判断
	  {
		  LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
		  LED_2(0);//LED2控制
		  BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
	  }
	  if(KEY_2())//按下KEY2判断
	  {
		  LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
		  LED_2(1);//LED2控制
		  BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

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

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

        【2】程序测试

        1)测试过程需要三个工具文件支持:

        FlyMCU加载工具,将生成的.hex程序文件加载到板子上

        SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入

        蓝牙调试器工具,本文用的是1.9安卓版本。

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

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

        注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:

if(KEY_1())//按下KEY1判断
	  {
		  LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位
		  LED_2(0);//LED2控制
		  BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)
	  }

        串口发送数据:

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

         至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十二、CANdelaStudio入门-Security

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的Security概念,欢迎各位朋友订阅、评论,…

【GamePlay】Unity手机屏幕UI适配问题

前言 关于UI不同分辨率适配问题和摄像机视口的注意事项 画布大小与锚点 首先要了解这两个东西 对于画布大小&#xff0c;主要理解match的含义&#xff0c;滑到Width时&#xff0c;表示以宽度为基准&#xff0c;Width不变&#xff0c;Height根据真机分辨率改变。 比如自己设…

pytest测试框架搭建

文章目录一、pytest是什么&#xff1f;二、pytest的特点三、pytest下载安装四、pytest的配置五、pytest约束规则六、编写脚本七、pytest的运行方式1、主函数模式2、命令行模式3、通过读取pytest ini配置文件运行 &#xff08;最主要运用的方式&#xff09;一、pytest是什么&…

【Unity】按Text文本内容自适应背景大小

按照文本内容自动调节背景框大小是十分方便的&#xff0c;本文章记录一下通过无代码方式实现该效果。&#xff08;版本Unity2018.4&#xff09; 目录 一、Text组件操作 二、Image组件操作 三、效果展示 一、Text组件操作 创建新的Text组件&#xff0c;然后进行下面操作&am…

LabVIEW避免在使用functional global时内存中有多个大数组的拷贝

LabVIEW避免在使用functional global时内存中有多个大数组的拷贝 有一个非常大的数组,但想保证在内存中只有一个拷贝.知道可以用移位寄存器,并用"ReplaceArray Subset" VI 保证只有一个拷贝。然而&#xff0c;想使之成为一个functionalglobal。因为&#xff0c;不能…

Ceph对象存储

目录 一、环境准备 二、什么是对象存储 三、部署对象存储服务 1、启动RGW服务 2、更改RGW服务端口 3、客户端测试 一、环境准备 Ceph集群搭建参照&#xff1a;Ceph集群部署_桂安俊kylinOS的博客-CSDN博客 以下Ceph存储实验环境均基于上述Ceph集群环境搭建。 二、什么是…

理解中国经济的五层思维-中国视角下的宏观经济

理解中国经济的五层思维 – 潘登同学的宏观经济学笔记 文章目录理解中国经济的五层思维 -- 潘登同学的宏观经济学笔记思想的力量理解中国经济的五层思维第一层思维&#xff1a;唯GDP论第二层思维&#xff1a;天真的市场派(新-新古典综合世界观对中国经济的影响)第三层思维&…

20221126给Chrome浏览器安装扩展程序——猫抓

20221126给Chrome浏览器安装扩展程序——猫抓 2022/11/26 21:43 百度&#xff1a;chrome 猫爪 https://www.onlinedown.net/soft/1232149.htm 猫抓 1.0.17 最新版 设置→ 01 百度搜索 QQ图片20221126214334.png 02 猫抓 QQ图片20221126214407.png 03 设置.png 04扩展程序.…

HTTP介绍报文格式构造

HTTP 一. 简单介绍一下: 二. 学习报文格式: 三. HTTP中的细节介绍 四, 如何构造一个HTTP请求 一. 简单介绍一下: 是应用层的典型协议客户端发送一个HTTP请求, 服务器返回一个HTTP响应(一问(请求)一答(响应)的)HTTP是文本格式的协议二. 学习报文格式: 1)先简单看一看HTTP的…

有监督学习神经网络的回归拟合——基于红外光谱的汽油辛烷值预测(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

2022年11月26日NaiveBayes

参考 ​ 朴素贝叶斯算法的核心思想是通过考虑特征概率来预测分类&#xff0c;即对于给出的待分类样本&#xff0c;求解在此样本出现的条件下各个类别出现的概率&#xff0c;哪个最大&#xff0c;就认为此待分类样本属于哪个类别。 ​ 我的理解是已知结果然后计算所有导致结果原…

[BJDCTF2020]EzPHP

前言 这个题目考的php知识真的比较多&#xff0c;也比较经典。由于我php基础不是很好&#xff0c;总会遇到一些问题。花时间弄懂这道题后也能更加巩固所学的知识。所以这道题还是有必要记录下来的。 题目 打开题目&#xff0c;在前端代码注释有这么一行编码。 受固化思想的影…

[CVPR2022] Cross-Model Pseudo-Labeling for Semi-Supervised Action Recognition

Cross-Model Pseudo-Labeling for Semi-Supervised Action Recognition 要点&#xff1a; 1、半监督动作识别&#xff0c;使用伪标记分配未标记数据&#xff0c;然后在训练中用作附加的监督 2、最近研究&#xff1a;伪标签通过在标记数据上训练模型获取&#xff0c;然后使用来…

重装系统电脑黑屏开不了机如何处理

​电脑使用时间久了难免就出现各种故障&#xff0c;比如卡顿、黑屏甚至崩溃直接开不了机。那么电脑黑屏开不了机怎么办呢?其实还是有解决的办法的&#xff0c;接下来看看小编是如何解决的吧! 工具/原料&#xff1a; 系统版本&#xff1a;windows 10系统 品牌型号&#xff1…

求余数联系和赋值运算

算术和赋值运算符 算术运算符&#xff1a; (加)、 -(减)、 *(乘)、 /(除)、 %(求余) 赋值运算符&#xff1a;、 、 -、 *、 /、 % 加法运算代码及效果 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title&…

Wlan三层组网+三层漫游

目录 wlan漫游配置(三层漫游)拓扑图和配置如下 思路: wlan配置不指定漫游组服务器的ac间漫游,实现笔记本之间在wlan覆盖范围内移动时业务不中断 要求:请大家参考教材196页完成AC间三层漫游配置&#xff0c;提交拓扑截图&#xff0c;ap上线截图&#xff0c;sta获取IP截图&#…

cpu设计和实现(协处理器hi和lo)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多同学可能不了解mips处理器&#xff0c;如果个人想补充一点mips cpu的知识&#xff0c;可以找些书籍资料来读一下&#xff0c;比如《See Mips R…

Springboot中集成mongodb,mysql(密码从密码服务中获取并且动态更新)

一.密码服务&#xff1a;公司统一进行数据库密码管理&#xff0c;为了防止密码泄露&#xff0c;会不定时更换密码&#xff0c;服务端就需要获取密码&#xff0c;类似key,value账号类型&#xff0c;首先根据数据库名去密码服务注册一个账号&#xff0c;后面通过这个注册的这个账…

【python】-详解进程与线程

文章目录进程1、多任务2、进程介绍3、多进程1 进程的创建步骤2 通过进程类创建进程对象3 进程的创建与启动代码4、进程执行带有参数的任务1 进程执行带有参数的任务2 args 参数的使用3 kwargs 参数的使用4 代码实现5 获取进程编号1 os.getpid()的使用2 os.getppid()的使用3 代码…

PLC中ST编程的定时器

定义通电延时功能块TON的变量&#xff0c;掉电延时功能块TOF的变量&#xff1b; 通过实例名来使用定时器&#xff1b; IN: 和 PT: 是输入引脚&#xff0c;Q> 和 ET> 是输出引脚&#xff1b; 定时器的通过IN输入引脚来触发的&#xff1b;定时器尽量不要在IF内调用&#…