STM32开发之HC05基础驱动编写

2024-02-24 09:20

本文主要是介绍STM32开发之HC05基础驱动编写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

驱动文件

头文件

//
// Created by shchl on 2024/2/22.
//#ifndef F4_PROJECT_BLE_HC05_H
#define F4_PROJECT_BLE_HC05_H#include "bsp.h"
#include "bsp_uart.h"typedef enum {hc05_resp_ok_status, /*接收正确*/hc05_resp_timeout_status, /*超时*/hc05_resp_fail_status /*失败*/
} hc05_resp_status; /*hc05响应状态*/void hc05_device_init(void);/*-----------------------------底层驱动需要实现的接口----------------------------------------*/extern void hc05_device_send(const char *cmd);extern char *hc05_device_wait_resp(void); /*等待设备响应数据*/
extern void hc05_device_enter_at_mode(void); /*进入AT模式*/
extern void hc05_device_quit_at_mode(void); /*退出AT模式*/
/*** 接收来自远端的数据(非阻塞)* @param dst* @return*/
extern uint16_t hc05_device_rec_remote_data(uint8_t *dst);
extern uint16_t hc05_device_send_remote_data(uint8_t *dst,uint16_t len);
/*---------------------------------------------------------------------*/void hc05_set_delay_cb(void (*delay_ms_call)(uint32_t));hc05_resp_status hc05_set_cmd(const char *cmd);char *hc05_query_cmd(const char *cmd);void hc05_delay_ms(uint32_t ms);hc05_resp_status hc05_check(uint8_t tryCnt);hc05_resp_status hc05_read_version(char *dst);hc05_resp_status hc05_read_work_stat(char *dst);hc05_resp_status hc05_read_addr(char *dst);hc05_resp_status hc05_read_name(char *dst);hc05_resp_status hc05_read_role(char *dst);hc05_resp_status hc05_read_pwd(char *dst);hc05_resp_status hc05_read_uart_cnf(char *dst);#endif //F4_PROJECT_BLE_HC05_H

源文件

//
// Created by shchl on 2024/2/22.
//#include "ble_hc05.h"static bool hc05_sub_str(char *dst, const char *src, char *prefix_str, char *suffix_str);static void (*hc05_delay_call)(uint32_t) =NULL;void hc05_set_delay_cb(void (*delay_ms_call)(uint32_t)) {hc05_delay_call = delay_ms_call;
}void hc05_delay_ms(uint32_t ms) {if (hc05_delay_call) {hc05_delay_call(ms);}
}/*** 设置指令* @param cmd*/
hc05_resp_status hc05_set_cmd(const char *cmd) {char *result = hc05_query_cmd(cmd);if (strstr(result, "OK")) {return hc05_resp_ok_status;} else if (strstr(result, "FAIL")) {return hc05_resp_fail_status;}return hc05_resp_timeout_status;}/*** 查询指令,并返回查询数据结果* @param cmd* @return*/
char *hc05_query_cmd(const char *cmd) {/*进入 AT模式*/hc05_device_enter_at_mode();hc05_delay_ms(10);hc05_device_send(cmd);//发送并接收/*退出 AT模式*/hc05_device_quit_at_mode();return hc05_device_wait_resp();}/*** @brief 蓝牙设备模块检测* @return*/
hc05_resp_status hc05_check(uint8_t tryCnt) {for (uint8_t i = 0; i < tryCnt; ++i) {if (hc05_set_cmd("AT\r\n") == hc05_resp_ok_status) {return hc05_resp_ok_status;}}return hc05_resp_timeout_status;
}/*** 获取蓝牙设备版本号* @param dst 保存位置* @return*/
hc05_resp_status hc05_read_version(char *dst) {char *ptr = hc05_query_cmd("AT+VERSION?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "VERSION:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}
hc05_resp_status hc05_read_work_stat(char *dst){char *ptr = hc05_query_cmd("AT+STATE?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "STATE:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}hc05_resp_status hc05_read_addr(char *dst){char *ptr = hc05_query_cmd("AT+ADDR?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "ADDR:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}hc05_resp_status hc05_read_name(char *dst){char *ptr = hc05_query_cmd("AT+NAME?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "NAME:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}hc05_resp_status hc05_read_role(char *dst){char *ptr = hc05_query_cmd("AT+ROLE?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "ROLE:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}hc05_resp_status hc05_read_pwd(char *dst){char *ptr = hc05_query_cmd("AT+PSWD?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "PSWD:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}hc05_resp_status hc05_read_uart_cnf(char *dst){char *ptr = hc05_query_cmd("AT+UART?\r\n"); /**/if (ptr) {if (hc05_sub_str(dst, ptr, "UART:", "\r\n")) {return hc05_resp_ok_status;}return hc05_resp_fail_status;}return hc05_resp_timeout_status;
}/*** @brief 提取字符串到指定位置* @param dst 保存子串* @param src 原始字符串* @param prefix_str 前缀(可以为NULL)* @param suffix_str 后缀(可以为NULL)* @return 是否提取成功*/
static bool hc05_sub_str(char *dst, const char *src, char *prefix_str, char *suffix_str) {const char *ptr_src = src;size_t sub_len; /*字串长度*/if (!ptr_src) return true;if (prefix_str != NULL) {ptr_src = strstr(ptr_src, prefix_str); /*查找前缀位置*/if (!ptr_src) return false;ptr_src += strlen(prefix_str); /**/}if (suffix_str) {char *endPtr = strstr(ptr_src, suffix_str);if (!endPtr) return false;sub_len = endPtr - ptr_src;} else {sub_len = strlen(ptr_src);}memcpy(dst, ptr_src, sub_len);dst[sub_len] = '\0'; /*添加结束符*/return true;
}

接口文件(对应硬件)

//
// Created by shchl on 2024/2/22.
//
#include "ble_hc05.h"#define HC05_AT_GPIO_PIN GPIO_PIN_9
#define HC05_AT_GPIO_PORT GPIOC
#define HC05_AT_GPIO_CLK_EN() __HAL_RCC_GPIOC_CLK_ENABLE()
#define hc05_uart_dev uart1_dev
static bool isCmdDatResp = false; /*是发送 指令数据标志位*/static void hc05_device_start_rec(void);static uint8_t hc05_rx_buf[UART1_RX_BUF_LEN];void hc05_device_init(void) {/*设置对应的延迟函数回调*/hc05_set_delay_cb(HAL_Delay);/*对应GPIO硬件初始化*/HC05_AT_GPIO_CLK_EN();GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = HC05_AT_GPIO_PIN;GPIO_Init.Mode = GPIO_MODE_OUTPUT_PP;GPIO_Init.Pull = GPIO_PULLDOWN;GPIO_Init.Speed = GPIO_SPEED_MEDIUM;HAL_GPIO_Init(HC05_AT_GPIO_PORT, &GPIO_Init);/*对应串口硬件初始化*/uart1_dev_init(115200);hc05_device_start_rec();/*退出at模式*/hc05_device_quit_at_mode();}__weak void hc05_device_send(const char *cmd) {HAL_UART_Transmit(&hc05_uart_dev.uart_handle, (uint8_t *) cmd, strlen(cmd), 20);
}__weak char *hc05_device_wait_resp(void) {for (int i = 0; i < 10; ++i) {hc05_delay_ms(10);uint32_t len = CacheBuffer_Read_Data(hc05_uart_dev.rx_cache_ptr, hc05_rx_buf);if (len > 0) {hc05_rx_buf[len] = '\0';
//            printf("HC05_Rec_Str len:%lu,data:%s\r\n", len, hc05_rx_buf);return (char *) hc05_rx_buf;}}return NULL;
}__weak uint16_t hc05_device_rec_remote_data(uint8_t *dst) {hc05_device_quit_at_mode();return CacheBuffer_Read_Data(hc05_uart_dev.rx_cache_ptr, dst);
}uint16_t hc05_device_send_remote_data(uint8_t *dst,uint16_t len){hc05_device_quit_at_mode();HAL_UART_Transmit(&hc05_uart_dev.uart_handle, dst, len, 20);return len;
}
__weak void hc05_device_enter_at_mode(void) {HAL_GPIO_WritePin(HC05_AT_GPIO_PORT, HC05_AT_GPIO_PIN, GPIO_PIN_SET);
}__weak void hc05_device_quit_at_mode(void) {HAL_GPIO_WritePin(HC05_AT_GPIO_PORT, HC05_AT_GPIO_PIN, GPIO_PIN_RESET);
}/*** 串口函数回调中使用* @param Size*/
void HAL_UARTEx_RxEventCallback_HC05(uint16_t Size) {CacheBuffer_Update_Data_Len(hc05_uart_dev.rx_cache_ptr, Size);/*重新接收数据*/hc05_device_start_rec();
}static void hc05_device_start_rec(void) {HAL_UARTEx_ReceiveToIdle_DMA(&hc05_uart_dev.uart_handle,hc05_uart_dev.rx_cache_ptr->List[hc05_uart_dev.rx_cache_ptr->InIndex].start,CACHE_BUFFER_ONE_DATA_MAX_LEN);
}

串口驱动文件(针对stm32f4芯片,根据需要修改)

bsp_uart.h

//
// Created by shchl on 2024/2/21.
//#ifndef BSP_UART_H
#define BSP_UART_H#include "bsp.h"#include "cachebuffer.h"#define UART_PRINTF_DEV uart2_dev.uart_handle
/*-----------------------------------串口1配置----------------------------------------*/
#define UART1_DEV_RX_CACHE_ENABLE               1        /*串口1设备接收缓冲区使能*/
#define UART1_DEV_TX_CACHE_ENABLE               0         /*串口1设备发送缓冲区使能*/
#define UART1_IT_ENABLE                         1                   /*串口1中断*/#define UART1_RX_BUF_LEN                        1024
#define UART1_TX_BUF_LEN                        1024
/*-----------------------------------串口2配置----------------------------------------*/
#define UART2_DEV_RX_CACHE_ENABLE               0       /*串口2设备接收缓冲区使能*/
#define UART2_DEV_TX_CACHE_ENABLE               0       /*串口2设备发送缓冲区使能*/
#define UART2_IT_ENABLE                         0       /*串口2中断*/
#define UART2_RX_BUF_LEN                        1024
#define UART2_TX_BUF_LEN                        1024
typedef struct {CacheBuffer_t *rx_cache_ptr; /*接收缓存*/CacheBuffer_t *tx_cache_ptr; /*发送缓存*/UART_HandleTypeDef uart_handle;
} uart_dev_t; /*串口设备*/
extern uart_dev_t uart1_dev;
extern uart_dev_t uart2_dev;
void uart1_dev_init(uint32_t baud);void uart2_dev_init(uint32_t baud);#endif //BSP_UART_H

bsp_uart.c

//
// Created by shchl on 2024/2/21.
//#include "bsp_uart.h"static void uart_conf_init(UART_HandleTypeDef *uart_handle, uint32_t baud);uart_dev_t uart1_dev = {.uart_handle.Instance=USART1};
#if UART1_DEV_RX_CACHE_ENABLE
static CacheBuffer_t uart1_rx_cache;
static uint8_t uart1_rx_buf[UART1_RX_BUF_LEN] = {0};
#endif
#if UART1_DEV_TX_CACHE_ENABLE
static CacheBuffer_t uart1_tx_cache;
static uint8_t uart1_tx_buf[UART1_TX_BUF_LEN] = {0};
#endif/*** 重写串口printf* @param file* @param ptr* @param len* @return*/
int _write(int file, char *ptr, int len)
{(void)file;HAL_UART_Transmit(&UART_PRINTF_DEV, (const uint8_t *) ptr, len, 200);return len;
}
void uart1_dev_init(uint32_t baud) {
#if UART1_DEV_RX_CACHE_ENABLEuart1_dev.rx_cache_ptr = &uart1_rx_cache;CacheBuffer_Init(uart1_dev.rx_cache_ptr, uart1_rx_buf, UART1_RX_BUF_LEN);#endif#if UART1_DEV_TX_CACHE_ENABLEuart1_dev.tx_cache_ptr = &uart1_tx_cache;CacheBuffer_Init(uart1_dev.tx_cache_ptr, uart1_tx_buf, UART1_TX_BUF_LEN);
#endifuart_conf_init(&uart1_dev.uart_handle, baud);
}uart_dev_t uart2_dev = {.uart_handle.Instance=USART2};
#if UART2_DEV_RX_CACHE_ENABLE
static CacheBuffer_t uart2_rx_cache;
static uint8_t uart2_rx_buf[UART2_RX_BUF_LEN] = {0};
#endif
#if UART2_DEV_TX_CACHE_ENABLE
static CacheBuffer_t uart2_tx_cache;
static uint8_t uart2_tx_buf[UART2_TX_BUF_LEN] = {0};
#endif/*** @brief 串口2设备 初始化* @param baud*/
void uart2_dev_init(uint32_t baud) {
#if UART2_DEV_RX_CACHE_ENABLEuart2_dev.rx_cache_ptr = &uart2_rx_cache;CacheBuffer_Init(uart2_dev.rx_cache_ptr, uart2_rx_buf, UART2_RX_BUF_LEN);#endif#if UART2_DEV_TX_CACHE_ENABLEuart2_dev.tx_cache_ptr = &uart2_tx_cache;CacheBuffer_Init(uart2_dev.tx_cache_ptr, uart2_tx_buf, UART2_TX_BUF_LEN);
#endifuart_conf_init(&uart2_dev.uart_handle, baud);
}static void uart_conf_init(UART_HandleTypeDef *uart_handle, uint32_t baud) {uart_handle->Init.BaudRate = baud;uart_handle->Init.WordLength = UART_WORDLENGTH_8B;uart_handle->Init.StopBits = UART_STOPBITS_1;uart_handle->Init.Parity = UART_PARITY_NONE;uart_handle->Init.Mode = UART_MODE_TX_RX;uart_handle->Init.HwFlowCtl = UART_HWCONTROL_NONE;uart_handle->Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(uart_handle) != HAL_OK) {Error_Handler();}
}

缓冲区文件(通用)

cachebuffer.h

//
// Created by shchl on 2024/2/21.
//#ifndef F4_DEMO_CACHEBUFFER_H
#define F4_DEMO_CACHEBUFFER_H#include <stdbool.h>
#include "stdio.h"
#include "string.h"#define CACHE_BUFFER_PARM_ASSERT(x)
#define CACHE_BUFFER_LIST_LEN 10 /*默认可以缓存10条数据,根据需要进行修改*/
#define CACHE_BUFFER_ONE_DATA_MAX_LEN 256 /*一条数据最大长度*/#define CACHE_BUFFER_MEMCPY memcpy
typedef struct {uint8_t *start;  /*起始位置*/uint8_t *end;   /*结束位置*/
} CacheIndexPtr_t; /*缓冲索引指针结构体*/typedef struct {uint32_t Count; /*累积缓存字节数*/uint16_t InIndex: 8; /*数据写入索引位置*/uint16_t OutIndex: 8; /*数据读出索引位置*/uint8_t *pBuf; /*实际数据指针存放位置*/uint32_t pBufCapacity; /*实际存放位置的容量*/CacheIndexPtr_t List[CACHE_BUFFER_LIST_LEN]; /*缓冲索引指针结构体集合*/
} CacheBuffer_t; /*缓冲Buffer结构体*/void CacheBuffer_Init(CacheBuffer_t *cacheBuffer, uint8_t *pool, int16_t size);void CacheBuffer_Update_Data_Len(CacheBuffer_t *cacheBuffer, uint32_t len);void CacheBuffer_Write_Data(CacheBuffer_t *cacheBuffer, uint8_t *pData, uint32_t len);uint32_t CacheBuffer_Read_Data(CacheBuffer_t *cacheBuffer, uint8_t *dst);#endif //F4_DEMO_CACHEBUFFER_H

cachebuffer.c

//
// Created by shchl on 2024/2/21.
//#include "cachebuffer.h"void CacheBuffer_Init(CacheBuffer_t *cacheBuffer, uint8_t *pool, int16_t size) {CACHE_BUFFER_PARM_ASSERT(cacheBuffer != NULL);CACHE_BUFFER_PARM_ASSERT(pool != NULL);cacheBuffer->pBufCapacity = size;cacheBuffer->InIndex = 0;cacheBuffer->OutIndex = 0;cacheBuffer->Count = 0;cacheBuffer->pBuf = pool;cacheBuffer->List[cacheBuffer->InIndex].start = pool;
}/*** @brief 缓存区更新数据长度,适用于缓冲区数据长度已更新,而数据长度未更新* @param cacheBuffer* @param len*/
void CacheBuffer_Update_Data_Len(CacheBuffer_t *cacheBuffer, uint32_t len) {cacheBuffer->Count += len;cacheBuffer->List[cacheBuffer->InIndex].end = cacheBuffer->pBuf + cacheBuffer->Count - 1;cacheBuffer->InIndex++;if (cacheBuffer->InIndex == CACHE_BUFFER_LIST_LEN) {/*判断是否已经到了最后的位置*/cacheBuffer->InIndex = 0;}/*判断是否需要覆盖数据*/if (cacheBuffer->pBufCapacity - cacheBuffer->Count < CACHE_BUFFER_ONE_DATA_MAX_LEN) {cacheBuffer->Count = 0;cacheBuffer->List[cacheBuffer->InIndex].start = cacheBuffer->pBuf;} else {cacheBuffer->List[cacheBuffer->InIndex].start = cacheBuffer->pBuf + cacheBuffer->Count;}
}void CacheBuffer_Write_Data(CacheBuffer_t *cacheBuffer, uint8_t *pData, uint32_t len) {/*确定写入数据位置*/if (cacheBuffer->pBufCapacity - cacheBuffer->Count < len) {/*判断写入数据是否大于剩下空间*/cacheBuffer->Count = 0;cacheBuffer->List[cacheBuffer->InIndex].start = cacheBuffer->pBuf;} else {cacheBuffer->List[cacheBuffer->InIndex].start = cacheBuffer->pBuf + cacheBuffer->Count;}CACHE_BUFFER_MEMCPY(cacheBuffer->List[cacheBuffer->InIndex].start, pData, len);cacheBuffer->Count += len;cacheBuffer->List[cacheBuffer->InIndex].end = cacheBuffer->pBuf + cacheBuffer->Count - 1;cacheBuffer->InIndex++;if (cacheBuffer->InIndex == CACHE_BUFFER_LIST_LEN) {/*判断是否已经到了最后的位置*/cacheBuffer->InIndex = 0;}
}uint32_t CacheBuffer_Read_Data(CacheBuffer_t *cacheBuffer, uint8_t *dst) {//判断是否有数据CacheIndexPtr_t *ptr;uint32_t len = 0;if (cacheBuffer->OutIndex != cacheBuffer->InIndex) {// 有数据ptr = &cacheBuffer->List[cacheBuffer->OutIndex];len = ptr->end - ptr->start + 1;CACHE_BUFFER_MEMCPY(dst, ptr->start, len);cacheBuffer->OutIndex++;if (cacheBuffer->OutIndex == CACHE_BUFFER_LIST_LEN) {cacheBuffer->OutIndex = 0; /*标记到最后位置*/}}return len;
}

这篇关于STM32开发之HC05基础驱动编写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741657

相关文章

一文教你如何解决Python开发总是import出错的问题

《一文教你如何解决Python开发总是import出错的问题》经常朋友碰到Python开发的过程中import包报错的问题,所以本文将和大家介绍一下可编辑安装(EditableInstall)模式,可... 目录摘要1. 可编辑安装(Editable Install)模式到底在解决什么问题?2. 原理3.

使用Java编写一个字符脱敏工具类

《使用Java编写一个字符脱敏工具类》这篇文章主要为大家详细介绍了如何使用Java编写一个字符脱敏工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、字符脱敏工具类2、测试工具类3、测试结果1、字符脱敏工具类import lombok.extern.slf4j.Slf4j

MySQL复合查询从基础到多表关联与高级技巧全解析

《MySQL复合查询从基础到多表关联与高级技巧全解析》本文主要讲解了在MySQL中的复合查询,下面是关于本文章所需要数据的建表语句,感兴趣的朋友跟随小编一起看看吧... 目录前言:1.基本查询回顾:1.1.查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J1.2.按照部门

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服