一、适用场景
适用场景:手机/平板与 MCU 的短距离无线串口通信(遥控、数据上报、参数配置)、蓝牙遥控小车/机器人、无线调试串口、低功耗传感器节点与交互原型、课堂蓝牙通信实验。

二、器材清单
HC-08 BLE 模块(常见基于 TI CC2540/CC2541 的模块) ×1
stm32f103 / 其他 STM32 开发板 ×1
若干杜邦线(公对母)×1组
三、工作原理(要点)

模式:模块既支持 AT 命令模式(用于修改名称、波特率、主/从角色等),也支持连接后进入串口透传模式进行透明数据通信。通常 AT 命令在模块未配对前或特定波特下可直接使用。

接口与性能:主接口为 UART(常见默认波特 9600,但可配置 1200–115200),模块典型发射功率约 4dBm,空旷环境下厂商宣称可达几十米至 80m 的参考距离(视天线和环境决定)。

四、接线示意(常见 4/5 引脚模块)
VCC → +5V

GND → GND

标准库

PA9→RX

PA10→TX

HAL库

PA2→RX

PA3→TX

五、示例代码(HAL / UART)
标准库

#include "stm32f10x.h"
#include "forward_direction.h"
extern char mask;
int main()
{
	pwm_init();
	usart_init();
	while(1)
	{
		
		switch(mask)
		{
			case 'f':TIM_SetCompare1(TIM3,1000);break;
			case 'b':TIM_SetCompare1(TIM3,1500);break;
			case 'r':TIM_SetCompare1(TIM3,2000);break;
			case 'l':TIM_SetCompare1(TIM3,2500);break;
			case 's':TIM_SetCompare1(TIM3,500);break;
		}

	}
//	return 0;
}
#include "forward_direction.h"


char mask=0;

void usart_init()
{
	GPIO_InitTypeDef PB;
	USART_InitTypeDef usart;
	NVIC_InitTypeDef nvic;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	
	PB.GPIO_Pin = GPIO_Pin_10;
	PB.GPIO_Mode = GPIO_Mode_AF_PP;
	PB.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&PB);
	
	PB.GPIO_Pin = GPIO_Pin_11;
	PB.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOB,&PB);
	
	usart.USART_BaudRate = 9600;
	usart.USART_WordLength = USART_WordLength_8b;
	usart.USART_StopBits = USART_StopBits_1;
	usart.USART_Parity = USART_Parity_No;
	usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART3,&usart);
	
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	nvic.NVIC_IRQChannel = USART3_IRQn;
	nvic.NVIC_IRQChannelPreemptionPriority = 1;
	nvic.NVIC_IRQChannelSubPriority = 1;
	nvic.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic);
	
	USART_Cmd(USART3,ENABLE);
	
}

void Usart_SendByte(USART_TypeDef * USARTx,uint8_t ch)
{
	USART_SendData(USARTx,ch);
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
}

void Usart_SendString(USART_TypeDef * USARTx,char * str)
{
	int k=0;
	do
	{
		Usart_SendByte(USARTx,*(str+k));
		k++;
	}while((*(str+k))!='\0');
	
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
	
}


void USART3_IRQHandler()
{
	if(USART_GetFlagStatus(USART3,USART_FLAG_RXNE) == SET)
	{
		mask = USART_ReceiveData(USART3);
		Usart_SendString(USART3,"ok");
	}
}


void pwm_init()
{	
	GPIO_InitTypeDef PA;
	TIM_TimeBaseInitTypeDef tim;
	TIM_OCInitTypeDef oc;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	PA.GPIO_Pin = GPIO_Pin_6;
	PA.GPIO_Mode = GPIO_Mode_AF_PP;
	PA.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&PA);
	
	tim.TIM_Period = (20000-1);
	tim.TIM_Prescaler = (72-1);
	tim.TIM_ClockDivision = TIM_CKD_DIV1;
	tim.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3,&tim);
	
	oc.TIM_OCMode = TIM_OCMode_PWM1;
	oc.TIM_OutputState = TIM_OutputState_Enable;
	oc.TIM_OCPolarity = TIM_OCPolarity_High;
	oc.TIM_Pulse = 500;
	TIM_OC1Init(TIM3,&oc);
	
	TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
	TIM_Cmd(TIM3,ENABLE);
}

HAL库

#include "usart.h"

/* USER CODE BEGIN 0 */
#include "string.h"


#define USART2_RX_BUFFER_MAXSIZE 256					//DMA接收的最大长度
uint8_t USART2_rx_buffer[USART2_RX_BUFFER_MAXSIZE];	//数据存放的内存

uint8_t CO2_Data[6]; 
extern Data DataSendStr;
extern uint8_t DataSend[16];	
/* USER CODE END 0 */

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart2_rx;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */




  /* USER CODE END USART1_Init 2 */

}
/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */
	if(HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t *)USART2_rx_buffer, USART2_RX_BUFFER_MAXSIZE) != HAL_OK)
	{
		Error_Handler();
	}
  /* USER CODE END USART2_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

//    /* USART1 DMA Init */
//    /* USART1_RX Init */
//    hdma_usart1_rx.Instance = DMA1_Channel5;
//    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
//    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
//    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
//    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
//    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
//    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
//    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
//    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
//    {
//      Error_Handler();
//    }

	// 中断配置
  HAL_NVIC_SetPriority(USART1_IRQn, 2, 2);
  HAL_NVIC_EnableIRQ(USART1_IRQn);
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);  // 使能接收中断
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART2 DMA Init */
    /* USART2_RX Init */
    hdma_usart2_rx.Instance = DMA1_Channel6;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx);

    /* USART2 interrupt Init */
    HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

//    /* USART1 DMA DeInit */
//    HAL_DMA_DeInit(uartHandle->hdmarx);

    /* USART1 interrupt Deinit */
//    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();

    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

    /* USART2 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);

    /* USART2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */


//void USART1_DMA_STATR(void)
//{
//	HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)USART1_rx_buffer, USART1_RX_BUFFER_MAXSIZE);
//}

//void USART1_CallBack(void)
//{
//	uint16_t len ; 
//	len = USART1_RX_BUFFER_MAXSIZE- __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
//	if(len)
//	{
//		printf("DMA接收到的数据是%s\r\n",USART1_rx_buffer);
//		memset(USART1_rx_buffer,0,len);
//	}

//}

void USART2_DMA_STATR(void)
{
	HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t*)USART2_rx_buffer, USART2_RX_BUFFER_MAXSIZE);
}
//接收ESP8266的数据
void USART2_CallBack(void)
{
	uint16_t len ; 
  char show[20]={0};
	len = USART2_RX_BUFFER_MAXSIZE- __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//获取得到的数据的长度
	if(len)
	{
		//第一个字节是AA,第16个字节是DD校验位,第二是按键1,第三是按键2,第四是按键3,第四是按键4,第五是模式
		if(USART2_rx_buffer[0] == 0xAA && USART2_rx_buffer[15] == 0xDD)
		{
			//接收到的数据放在数据结构体
			DataSendStr.MODE = USART2_rx_buffer[1];
			DataSendStr.LED1 = USART2_rx_buffer[2];
			DataSendStr.LED2 = USART2_rx_buffer[3];
			DataSendStr.XUANZE = USART2_rx_buffer[4];

		}
		memset(USART2_rx_buffer,0,16);
	}
}



void USART1_CallBack(void)
{
	uint8_t receive = (uint8_t)(huart1.Instance->DR & 0xFF);
	HAL_UART_Transmit(&huart1, "ok2\n", strlen("ok2\n"), HAL_MAX_DELAY);
}

struct __FILE
{
    int a;
};
FILE __stdout;
/*****************************************************
*function: 写字符文件函数
*param1: 输出的字符
*param2: 文件指针
*return: 输出字符的 ASCII 码
******************************************************/
int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10);
	return ch;
}

 六、讲解视频

https://www.bilibili.com/video/BV1rekDBnEnz/?spm_id_from=333.1387.upload.video_card.click&vd_source=b035825fef3be39bc47a9c50b324d086

https://www.bilibili.com/video/BV1BFkDBCEPw/?spm_id_from=333.1387.upload.video_card.click&vd_source=b035825fef3be39bc47a9c50b324d086

https://www.bilibili.com/video/BV1vNkDBgEYN/?spm_id_from=333.1387.upload.video_card.click&vd_source=b035825fef3be39bc47a9c50b324d086

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐