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
中定义了蓝牙模块的基本参数:
/******************************** 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 数据结构定义
为了处理蓝牙模块的数据收发,定义了一个数据帧处理结构体:
#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的初始化函数:
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引脚:
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:
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;
}
同时定义了两个便捷的打印宏:
#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 蓝牙模块初始化
蓝牙模块的初始化函数如下:
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指令发送函数
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 数据发送函数
void blue_send_msg(char *msg)
{
HAL_UART_Transmit(&Bluetooth_USARTx, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
这是一个简单的数据发送函数,用于向蓝牙模块发送数据。
4.9 数据接收缓冲区读取函数
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接收中断回调函数
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 主程序
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. 使用方法
- 将蓝牙模块按照硬件连接部分所述连接到STM32
- 编译并下载程序到STM32
- 使用手机蓝牙连接到蓝牙模块(名称为BT04,PIN码为1234)
- 使用蓝牙串口工具发送和接收数据
6. 注意事项
- 本驱动程序使用的是USART3,如需更改,请修改
Bluetooth_USARTx
宏定义 - 蓝牙模块的默认波特率为115200,如需更改,请修改
MX_USART3_UART_Init
函数中的波特率设置 - 接收数据帧的结束标志为’}'字符,如需更改,请修改
HAL_UART_RxCpltCallback
函数 - 如需配置蓝牙模块的名称、PIN码等参数,请取消
bluetooth_start
函数中的注释
7. 扩展功能
本驱动程序可以扩展以支持更多功能,例如:
- 添加蓝牙连接状态检测
- 实现蓝牙数据的解析和处理
- 添加蓝牙低功耗模式支持
- 实现蓝牙配对和安全认证