STM32蓝牙模块驱动开发

STM32蓝牙模块驱动开发

1. 项目概述

本项目基于STM32F1系列微控制器,使用HAL库实现了蓝牙模块的驱动程序。该驱动程序通过UART接口与蓝牙模块通信,实现了蓝牙模块的初始化、AT指令发送、数据收发等功能。

项目源代码仓库:STM32_Sensor_Drives

2. 硬件连接

本项目使用的是通用蓝牙串口模块(如HC-05/HC-06等),通过UART接口与STM32连接。具体连接如下:

  • 蓝牙模块TX -> STM32 PB11 (USART3_RX)
  • 蓝牙模块RX -> STM32 PB10 (USART3_TX)
  • 蓝牙模块VCC -> 3.3V/5V(取决于模块类型)
  • 蓝牙模块GND -> GND

3. 代码结构

项目主要包含以下几个文件:

  • main.c:主程序,包含系统初始化和主循环
  • usart.c/h:UART配置和蓝牙通信相关函数
  • gpio.c/h:GPIO配置

4. 关键代码分析

4.1 蓝牙模块参数定义

usart.h中定义了蓝牙模块的基本参数:

c 复制代码
/******************************** Bluetooth 连接引脚定义 ***********************************/
#define      Bluetooth_NAME                                 "BT04"
#define      Bluetooth_PIN                                  "1234"
#define      Bluetooth_LADDR                                "AA:BB:CC:11:22:33"
#define      Bluetooth_USART_BAUD_RATE                       "9600"
#define      Bluetooth_USART_TX_PORT                         GPIOB   
#define      Bluetooth_USART_TX_PIN                          GPIO_Pin_10
#define      Bluetooth_USART_RX_PORT                         GPIOB
#define      Bluetooth_USART_RX_PIN                          GPIO_Pin_11
#define      Bluetooth_USARTx                                huart3

这些定义包括蓝牙模块的名称、PIN码、MAC地址、波特率以及连接的GPIO引脚。

4.2 数据结构定义

为了处理蓝牙模块的数据收发,定义了一个数据帧处理结构体:

c 复制代码
#define RX_BUF_MAX_LEN     256                                     //最大接收缓存字节数
extern struct  STRUCT_USARTx_Fram                                  //串口数据帧的处理结构体
{
    char  Data_RX_BUF [ RX_BUF_MAX_LEN ];
    union {
    __IO uint16_t InfAll;
    struct  {
          __IO uint16_t FramLength       :15;                               // 14:0 
          __IO uint16_t FramFinishFlag   :1;                                // 15 
      } InfBit;
    }Inf;
};

该结构体包含一个接收缓冲区和一个信息字段,信息字段使用位域技术,包含帧长度和帧完成标志。

4.3 UART初始化

usart.c中,实现了UART的初始化函数:

c 复制代码
void MX_USART3_UART_Init(void)
{
  huart3.Instance = USART3;
  huart3.Init.BaudRate = 115200;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler();
  }
}

这里配置了USART3,用于与蓝牙模块通信,波特率为115200,8位数据位,1位停止位,无奇偶校验。

4.4 GPIO配置

HAL_UART_MspInit函数中,配置了UART对应的GPIO引脚:

c 复制代码
else if(uartHandle->Instance==USART3)
{
  /* USART3 clock enable */
  __HAL_RCC_USART3_CLK_ENABLE();

  __HAL_RCC_GPIOB_CLK_ENABLE();
  /**USART3 GPIO Configuration
  PB10     ------> USART3_TX
  PB11     ------> USART3_RX
  */
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USART3 interrupt Init */
  HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART3_IRQn);
}

这里配置了PB10为USART3_TX,PB11为USART3_RX,并启用了USART3的中断。

4.5 标准输出重定向

为了方便调试,重定向了标准输出到UART:

c 复制代码
int fputc(int ch, FILE *f)
{
    if (f == stdout) // 仅处理标准输出
    {
        HAL_UART_Transmit(current_huart, (uint8_t *)&ch, 1, 100); // 阻塞发送
        if (ch == '\n')                                           // 发送\n时自动补充\r
            HAL_UART_Transmit(current_huart, (uint8_t *)"\r", 1, 100);
    }
    return ch;
}

同时定义了两个便捷的打印宏:

c 复制代码
#define printf_log(...) do { \
    current_huart = &huart2; \
    printf(__VA_ARGS__); \
} while(0)

#define printf_blue(...) do { \
    current_huart = &Bluetooth_USARTx; \
    printf(__VA_ARGS__); \
} while(0)

printf_log用于向调试串口(USART2)输出日志,printf_blue用于向蓝牙模块(USART3)发送数据。

4.6 蓝牙模块初始化

蓝牙模块的初始化函数如下:

c 复制代码
void bluetooth_start(void)
{
    printf_log("Start init buletooth\r\n");
    HAL_UART_Receive_IT(&Bluetooth_USARTx, &UART_TEMP_CHAR, 1);
    
    uint16_t wait_time = 5000;
    char temp_cmd[20];
    sprintf(temp_cmd, "%s", "AT+RESET\r\n");
    uint8_t flag = send_blue_cmd(temp_cmd, "OK", NULL, wait_time);
    
//    sprintf(temp_cmd, "AT+LADDR%s\r\n", Bluetooth_LADDR);
//    send_blue_cmd(temp_cmd, "OK", "LADDR", wait_time);
//    
//    sprintf(temp_cmd, "AT+NAME%s\r\n", Bluetooth_NAME);
//    send_blue_cmd(temp_cmd, "OK", "NAME", wait_time);
//    
//    sprintf(temp_cmd, "AT+PIN%s\r\n", Bluetooth_PIN);
//    send_blue_cmd(temp_cmd, "OK", "PIN", wait_time);
//    
//    sprintf(temp_cmd, "AT+BAUD%s\r\n", Bluetooth_USART_BAUD_RATE);
//    send_blue_cmd(temp_cmd, "OK", "BAUD", wait_time);
    
    printf_log("Start init success\r\n");
}

该函数首先启用UART接收中断,然后发送AT+RESET命令重置蓝牙模块。注释部分是设置蓝牙模块的MAC地址、名称、PIN码和波特率的命令,可以根据需要取消注释。

4.7 AT指令发送函数

c 复制代码
uint8_t send_blue_cmd(char* cmd, char* replay1, char* replay2, uint16_t wait_time)
{
    printf_log(cmd);
    printf_blue(cmd);
    HAL_Delay(wait_time);
    if (replay1 == NULL && replay1 == NULL) return 1;
    
    char temp_buffer[RX_BUF_MAX_LEN];
    read_uart_buffer(temp_buffer);
    if (temp_buffer != NULL) printf_log(temp_buffer);
    
    if(strstr(temp_buffer, replay1) != NULL || strstr(temp_buffer, replay2) != NULL) return 1;       
    else printf_log("FAIL: Start init buletooth_%s\n", cmd);
    return 0;
}

该函数用于发送AT指令并等待响应。它首先打印并发送命令,然后等待指定时间,读取响应缓冲区,检查是否包含预期的响应字符串。

4.8 数据发送函数

c 复制代码
void blue_send_msg(char *msg)
{
    HAL_UART_Transmit(&Bluetooth_USARTx, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}

这是一个简单的数据发送函数,用于向蓝牙模块发送数据。

4.9 数据接收缓冲区读取函数

c 复制代码
void read_uart_buffer(char* temp_buffer)
{
    if (buletooth_Fram_Record.Inf.InfBit.FramFinishFlag != 1) return;
    strcpy(temp_buffer, buletooth_Fram_Record.Data_RX_BUF);
    memset(buletooth_Fram_Record.Data_RX_BUF, 0, RX_BUF_MAX_LEN);
    buletooth_Fram_Record.Inf.InfBit.FramLength = 0;
    buletooth_Fram_Record.Inf.InfBit.FramFinishFlag = 0;
}

该函数用于读取接收缓冲区的数据。如果帧完成标志为1,则将数据复制到临时缓冲区,并清空接收缓冲区。

4.10 UART接收中断回调函数

c 复制代码
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &Bluetooth_USARTx)
    {
        if (buletooth_Fram_Record.Inf.InfBit.FramLength < (RX_BUF_MAX_LEN - 1))
                buletooth_Fram_Record.Data_RX_BUF[buletooth_Fram_Record.Inf.InfBit.FramLength++] = UART_TEMP_CHAR;

        if (HAL_UART_GetState(&Bluetooth_USARTx) == HAL_UART_STATE_READY)
        {
            if (buletooth_Fram_Record.Data_RX_BUF[buletooth_Fram_Record.Inf.InfBit.FramLength-1] == '}'){
                buletooth_Fram_Record.Data_RX_BUF[buletooth_Fram_Record.Inf.InfBit.FramLength] = '\0';
                printf_log("uart back %d: %s\r\n", buletooth_Fram_Record.Inf.InfBit.FramLength, buletooth_Fram_Record.Data_RX_BUF);
                buletooth_Fram_Record.Inf.InfBit.FramFinishFlag = 1;
            }
        }
        HAL_UART_Receive_IT(&Bluetooth_USARTx, &UART_TEMP_CHAR, 1);
    }
}

这是UART接收中断的回调函数。当接收到一个字符时,将其存入接收缓冲区。如果接收到'}'字符,则认为一帧数据接收完成,设置帧完成标志,并重新启用接收中断。

4.11 主程序

c 复制代码
int main(void)
{
  /* 省略初始化代码 */
  
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
    printf_log("\r\n/**********STARTING SYSTEM**********/\r\n");
    bluetooth_start();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

    while (1)
    {
        blue_send_msg("hello\n");
        char temp_buffer[RX_BUF_MAX_LEN] = {0};
        read_uart_buffer(temp_buffer);
        if (strlen(temp_buffer) != 0) printf_log("main %d :%s\r\n", strlen(temp_buffer), temp_buffer);
        //memset(temp_buffer, 0, sizeof(temp_buffer));

        HAL_Delay(500);
    /* USER CODE END WHILE */

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

主程序初始化GPIO和UART,启动蓝牙模块,然后在主循环中每500ms发送一次"hello"消息,并读取接收缓冲区的数据。

5. 使用方法

  1. 将蓝牙模块按照硬件连接部分所述连接到STM32
  2. 编译并下载程序到STM32
  3. 使用手机蓝牙连接到蓝牙模块(名称为BT04,PIN码为1234)
  4. 使用蓝牙串口工具发送和接收数据

6. 注意事项

  1. 本驱动程序使用的是USART3,如需更改,请修改Bluetooth_USARTx宏定义
  2. 蓝牙模块的默认波特率为115200,如需更改,请修改MX_USART3_UART_Init函数中的波特率设置
  3. 接收数据帧的结束标志为'}'字符,如需更改,请修改HAL_UART_RxCpltCallback函数
  4. 如需配置蓝牙模块的名称、PIN码等参数,请取消bluetooth_start函数中的注释

7. 扩展功能

本驱动程序可以扩展以支持更多功能,例如:

  1. 添加蓝牙连接状态检测
  2. 实现蓝牙数据的解析和处理
  3. 添加蓝牙低功耗模式支持
  4. 实现蓝牙配对和安全认证

8. 参考资料