HC-05的简介与使用

第一部分*********************!!!!!!!!蓝牙模块HC-05

蓝牙概述

蓝牙(Bluetooth)是一种用于无线通信的技术标准,允许设备在短距离内进行数据交换和通信。它是由爱立信(Ericsson)公司在1994年推出的,以取代传统的有线连接方式,使设备之间能够实现低功耗、低成本的数据传输和通信。     

蓝牙作为一种小范围无线连接技术,具有低功耗、低成本、方便快捷的特点,被广泛应用于无线耳机、智能手表、无线遥控等场景,是实现无线通信的主流技术之一。

蓝牙协议各个版本

HC-05模块简介

HC-05参数

HC-05工作模式

HC-05角色 

1. Master(主角色)——查询周围 SPP 蓝牙从设备,并主动发起连接,从而建立主、从蓝牙设备间的透明数据传输通道。

2. Slave(从角色)——被动连接;

3. Slave-Loop(回环角色)——被动连接,接收远程蓝牙主设备数据并将数据原样返回给远程蓝牙主设备;

引脚定义

怎么进入命令响应工作模式(AT指令模式) 

用手按着模块上的按键,再给蓝牙模块上电。当蓝牙模块上的灯慢闪的时候就说明进入了配置模式了。

1  按下模块上的按键(PIO11置高)

2  对HC-05重新上电,模块进入AT命令响应工作模式。

3  使用串口助手,配置成波特率38400,数据位8 位,停止位1 位,无校验位,无流控制。

4  串口助手发送字符串“AT\r\n”,正常情况下模块会给出“OK\r\n”,“\r\n”为回车换行,也叫做新行。

 HC-05工作流程

AT指令模式配置HC-05模块

重新上电模块,进入自动连接工作模块,连接从模块(也可以使用AT指令,在AT指令模式下连接从模块)。

建立蓝牙连接,LED常量,直接使用串口完成通信

电脑串口助手配置

在配置蓝牙的时候一定要将串口助手按这个要求配置:设置波特率 38400,数据位 8 位,停止位 1 位,无校验位,这是固定操作!

常见指令

常见的指令 

首先我们要明确串口通信的条件,我们需要设置8位数据位,1为停止位,无检验,波特率为38400,这样才可以与HC-05进行串口通信,当然这些配置都可以在后续的AT指令中更改。

并且要以文本模式发送指令,编码格式为 utf-8,每个指令后面也要加上换行(‘\r\n’)。

1  第一个测试指令,我们直接通过串口发送“AT”即可,然后就会给我们回复“OK”,用这个没什么意义的指令可以来测试我们是否成功进入到了AT指令模式(其实通过LED的闪烁情况也可以知道)。

2  发送复位指令之后,HC-05进入复位,如果没有按下按钮的话,会默认进入到配对模式。成功后回复“OK”。

 

恢复的默认配置同上图。发送完成后貌似是自动复位了,也可能不是,反正我的HC-05从原本的AT指令模式变成配对模式了。

而且设备名称也不是上面说的“H-C-2010-06-01”而是“HC-05”,也可能是因为我的是兼容版HC-05,具体的情况以你们自己手上的HC-05为准。

不带参数的话就是回复设备名称,加“OK”,带参数的话就是修改蓝牙名称并且回复“OK”。

默认就是从机,当然我们也可以修改为主机。

这边要注意的是,配对码(密码)需要用英文半角的双引号括起来。

LED和蓝牙模块代码对比1:

 

实验现象:

代码部分(详解)

hc05.c

#include "hc05.h"
#include "delay.h"//代码片段是一些预处理指令,用于定义宏和一些常量。
#define    HC05_DelayMs(t)                Delay_Ms(t)//当调用 HC05_DelayMs(t) 时,实际上会调用 Delay_Ms(t) 函数。
#define    HC05_GPIO_LOW                  0   //这通常用于表示某种特定状态,例如在这里,可能表示低电平或关闭状态。
#define    HC05_GPIO_HIGH                 1   //它被赋值为1。类似地,这个宏可能表示高电平或打开状态。#if defined (STM32F40_41xxx)//配置输入输出
//用于配置一个GPIO引脚为输出模式。它接受两个参数:port 表示GPIO端口,pin 表示端口上的引脚。
#define    HC05_CONFIG_IO_OUTPUT(port, pin)          {GPIO_InitTypeDef GPIO_InitStructure; \GPIO_InitStructure.GPIO_Mode     =  GPIO_Mode_OUT; \GPIO_InitStructure.GPIO_OType    = GPIO_OType_PP;\GPIO_InitStructure.GPIO_PuPd     = GPIO_PuPd_UP; \GPIO_InitStructure.GPIO_Speed    =  GPIO_Speed_50MHz; \GPIO_InitStructure.GPIO_Pin      =  pin ; \GPIO_Init(port, &GPIO_InitStructure);}
//读取一个GPIO引脚的当前值。它接受两个参数:port 和 pin,分别表示GPIO端口和引脚。
#define    HC05_CONFIG_IO_INPUT(port, pin)           {GPIO_InitTypeDef GPIO_InitStructure; \GPIO_InitStructure.GPIO_Mode     =  GPIO_Mode_IN; \GPIO_InitStructure.GPIO_PuPd     = GPIO_PuPd_UP; \GPIO_InitStructure.GPIO_Speed    =  GPIO_Speed_50MHz; \GPIO_InitStructure.GPIO_Pin      =  pin ; \GPIO_Init(port, &GPIO_InitStructure);}
//用于读取一个GPIO引脚的当前值。它接受两个参数:port 和 pin,分别表示GPIO端口和引脚。
#define    HC05_IO_GET_VALUE(port, pin)               GPIO_ReadInputDataBit(port, pin)//用于设置一个GPIO引脚的输出值。它接受三个参数:port、pin 和 value,分别表示GPIO端口、引脚和要设置的值(HC05_GPIO_HIGH 或 HC05_GPIO_LOW)。
#define    HC05_IO_SET(port, pin, value)              { if(value == HC05_GPIO_HIGH) \GPIO_SetBits(port, pin); \else \GPIO_ResetBits(port, pin);}
//时钟开启 时钟使能
#define    RCC_GPIO_CLOCK_ENABLE(GPIOX)            { if (GPIOX  == GPIOA)         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); \else if (GPIOX  == GPIOB)    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); \else if (GPIOX  == GPIOC)    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); \else if (GPIOX  == GPIOD)    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); \else if (GPIOX  == GPIOE)    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE); \else if (GPIOX  == GPIOF)    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); \else if (GPIOX  == GPIOG)    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE); \else printf("gpio clock no enable\r\n"); \}
#endif//调试模式
//如果 HC05_DEBUG_MODE 的值为1,表示处于调试模式,那么 hc05_log 会被定义为 printf 函数,用于打印格式化的日志信息。
#if (HC05_DEBUG_MODE == 1)#define hc05_log(format, ...)                     printf(format, ##__VA_ARGS__)
#else#define hc05_log(format, ...)
//如果 HC05_DEBUG_MODE 的值不为1,表示不处于调试模式,那么 hc05_log 会被定义为空,即不执行任何操作,这样就可以在不需要输出调试信息时避免编译器产生多余的代码。                                                   
#endif/******************************************************************************* @brief     发送一个字符** @param[in]  bt           :  BlueTooth_t结构体指针* @param[in]  ch           :  要发送的字符** @return     0, 表示成功, 其他值表示失败*函数的作用是通过蓝牙发送一个字符。******************************************************************************/
//函数的声明,指定了函数名 send_char,参数类型为指向 BlueTooth_t 结构的指针 bt 和一个字符 ch,返回类型为 int。
static int send_char(BlueTooth_t* bt, char ch)
{while((bt->uart->SR & 0X40) == 0);bt->uart->DR = (uint16_t)ch;//一旦蓝牙模块准备好发送字符,就会将要发送的字符 ch 写入 bt 结构体中的 uart 成员的 DR(数据寄存器)中。return 0;
}
//这是一个 while 循环,它的条件是等待蓝牙模块准备好发送下一个字符。这里使用了位运算和与操作,检查 bt 
//结构体中的 uart 成员的 SR(状态寄存器)的第六位是否为 1,如果不为 1,则表示蓝牙模块还没有准备好
//发送下一个字符,程序会一直在这里循环等待。/******************************************************************************* @brief     发送字符串** @param[in]  bt           :  BlueTooth_t结构体指针* @param[in]  str          :  字符串** @return     返回具体发送的字节数*用于向蓝牙模块发送字符串数据。******************************************************************************/
static int send_string(BlueTooth_t* bt, const char* str)
{uint32_t i = 0;uint32_t len = strlen(str);for (i = 0; i < len; i++) {send_char(bt, str[i]);}return i;
}/******************************************************************************* @brief     发送AT指令函数** @param[in]  bt           :  BlueTooth_t结构体指针* @param[in]  at_cmd       :  AT指令* @param[in]  response     :  AT指令的回响* @param[in]  timeout_ms   :  超时时间** @return     0, 表示成功, 其他值表示失败*用于发送 AT 指令并等待响应的函数。以下是对注释的解释:******************************************************************************/
static int send_at_cmd(BlueTooth_t *bt, const char *at_cmd, const char *response, uint32_t timeout_ms)
{ //用于发送 AT 指令并等待响应。它接受一个指向 BlueTooth_t 结构的指针 bt,一个表示要发送的 AT 指令的字符串 at_cmd,//一个表示期望的响应的字符串 response,以及一个表示超时时间的毫秒数 timeout_ms。它返回一个整数值,表示执行结果。bt->rx_buffer_current_cnt = 0;// 这行代码将接收缓冲区的当前计数器置为0,准备接收新的响应数据。memset(bt->rx_buffer, 0, sizeof(bt->rx_buffer));//这行代码用于将接收缓冲区中的所有元素都设置为0,以清除其中的任何残留数据。send_string(bt, at_cmd);//这行代码调用了一个名为 send_string 的函数,用于发送字符串类型的数据至蓝牙模块。send_string(bt, "\r\n");// 这行代码发送一个回车换行符,以结束当前的 AT 指令。timeout_ms = timeout_ms == 0 ? 0xFFFFFFFF : timeout_ms;  //timeout_ms为0,表示延时最长时间,0xFFFFFFFF msdo {if (strstr((const char *)bt->rx_buffer, response) != NULL) {  //回应信息正确return 0;}HC05_DelayMs(1);}while(timeout_ms--);
//循环条件为 timeout_ms 不为0。在循环内部,检查接收缓冲区中是否包含期望的响应字符串,//如果包含,则返回0表示成功;否则,等待1毫秒,直到超时。if (!timeout_ms)  //发送超时return -1;
//如果超时时间为0,即等待时间已经用尽,则返回-1表示发送超时。return -2;
}/******************************************************************************* @brief     使用AT指令对蓝牙模块配置参数,重新复位** @param[in]  bt   :  BlueTooth_t结构体指针** @return     0, 表示初始化成功, 其他值表示失败*通过发送一系列的 AT 指令给蓝牙模块,来执行重置操作,并记录每个指令的执行结果和模块的响应内容。******************************************************************************/
int bt_software_reset(struct blue_tooth *bt)
//这是一个函数定义,它接受一个指向 struct blue_tooth 结构的指针作为参数,并返回一个整数值。
{char tmp_buffer[20];int ret = 0;HC05_IO_SET(bt->port[HC05_EN], bt->pin[HC05_EN], HC05_GPIO_HIGH);//这行代码设置蓝牙模块的使能引脚为高电平,以便激活模块。Delay_Ms(1000);//暂停执行代码1秒钟。memset(tmp_buffer, 0, sizeof(tmp_buffer));//这行代码用于将 tmp_buffer 数组中的所有元素都设置为0,以清除其中的任何残留数据。sprintf(tmp_buffer, "AT");//这行代码将字符串 "AT" 格式化并存储到 tmp_buffer 中,表示发送 AT 指令给蓝牙模块。ret = send_at_cmd(bt, tmp_buffer, "OK", 1000);//这行代码调用了一个名为 send_at_cmd 的函数,该函数用于发送 AT 指令给蓝牙模块,并等待接收到 "OK" 响应,最多等待1秒钟。hc05_log("AT: %d  %s\r\n", ret, bt->rx_buffer);//这行代码记录了发送 AT 指令的结果和接收到的响应内容。memset(tmp_buffer, 0, sizeof(tmp_buffer));sprintf(tmp_buffer, "AT+NAME=HC-05");//指令的作用是设置蓝牙模块的名称为 "HC-05"。ret = send_at_cmd(bt, tmp_buffer, "OK", 1000);hc05_log("AT+NAME: %d  %s\r\n", ret, bt->rx_buffer);memset(tmp_buffer, 0, sizeof(tmp_buffer));sprintf(tmp_buffer, "AT+ROLE=0");ret = send_at_cmd(bt, tmp_buffer, "OK", 1000);
//调用 send_at_cmd 函数发送命令给蓝牙模块,并等待蓝牙模块返回 "OK"。hc05_log("AT+ROLE: %d  %s\r\n", ret, bt->rx_buffer);memset(tmp_buffer, 0, sizeof(tmp_buffer));sprintf(tmp_buffer, "AT+PSWD=\"123456\"");ret = send_at_cmd(bt, tmp_buffer, "OK", 1000);hc05_log("AT+PSWD: %d  %s\r\n", ret, bt->rx_buffer);memset(tmp_buffer, 0, sizeof(tmp_buffer));sprintf(tmp_buffer, "AT+UART=38400,0,0");hc05_log("AT+UART: %d  %s\r\n", ret, bt->rx_buffer);memset(tmp_buffer, 0, sizeof(tmp_buffer));sprintf(tmp_buffer, "AT+RESET");ret = send_at_cmd(bt, tmp_buffer, "OK", 1000);hc05_log("AT+RESET: %d  %s\r\n", ret, bt->rx_buffer);HC05_IO_SET(bt->port[HC05_EN], bt->pin[HC05_EN], HC05_GPIO_LOW);//最后一行代码将蓝牙模块的使能引脚设置为低电平,以便关闭模块。return 0;
}
//通过发送一系列的AT指令给蓝牙模块,来配置其名称、角色、密码、波特率等参数,并通过 hc05_log 函数输出每个AT指令执行的结果。/******************************************************************************* @brief     初始化HC-05模块用到的硬件资源** @param[in]  bt   :  BlueTooth_t结构体指针** @return     无*******************************************************************************/
static void bt_hw_init(BlueTooth_t* bt)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;/* 初始化用大的时钟 */RCC_GPIO_CLOCK_ENABLE(bt->port[HC05_TX]);RCC_GPIO_CLOCK_ENABLE(bt->port[HC05_RX]);RCC_GPIO_CLOCK_ENABLE(bt->port[HC05_EN]);RCC_GPIO_CLOCK_ENABLE(bt->port[HC05_STATE]);/* USART端口配置 */GPIO_InitStructure.GPIO_Mode   = GPIO_Mode_AF;              //复用功能GPIO_InitStructure.GPIO_Speed  = GPIO_Speed_50MHz;          //速度50MHzGPIO_InitStructure.GPIO_OType  = GPIO_OType_PP;             //推挽复用输出GPIO_InitStructure.GPIO_PuPd   = GPIO_PuPd_UP;              //上拉GPIO_InitStructure.GPIO_Pin = bt->pin[HC05_TX];GPIO_Init(bt->port[HC05_TX], &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = bt->pin[HC05_RX];GPIO_Init(bt->port[HC05_RX], &GPIO_InitStructure);/* 配置EN、STATUS引脚 */GPIO_InitStructure.GPIO_Mode   = GPIO_Mode_OUT;             //EN引脚配置为输出GPIO_InitStructure.GPIO_Pin = bt->pin[HC05_EN];GPIO_Init(bt->port[HC05_EN], &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode   = GPIO_Mode_IN;             //STATUS引脚配置为输入GPIO_InitStructure.GPIO_Pin = bt->pin[HC05_STATE];GPIO_Init(bt->port[HC05_STATE], &GPIO_InitStructure);/* USART 初始化设置 */USART_InitStructure.USART_BaudRate              = HC05_UART_BAUD_RATE;              //波特率设置USART_InitStructure.USART_WordLength            = USART_WordLength_8b;              //8位数据位长USART_InitStructure.USART_StopBits              = USART_StopBits_1;                 //一个停止位USART_InitStructure.USART_Parity                = USART_Parity_No;                  //无奇偶校验位USART_InitStructure.USART_HardwareFlowControl   = USART_HardwareFlowControl_None;   //无硬件数据流控制USART_InitStructure.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;    //收发模式USART_Init(bt->uart, &USART_InitStructure);                                         //初始化串口USART_Cmd(bt->uart, ENABLE);                                                        //使能串口USART_ITConfig(bt->uart, USART_IT_RXNE, ENABLE);                                    //开启串口接受中断/* 串口的NVIC配置 */NVIC_InitStructure.NVIC_IRQChannel                     = USART2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority   = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority          = 2;NVIC_InitStructure.NVIC_IRQChannelCmd                  = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/******************************************************************************* @brief     初始化HC-05模块** @param[in]  bt   :  BlueTooth_t结构体指针** @return     0, 表示初始化成功, 其他值表示失败*******************************************************************************/
int BT_Init(BlueTooth_t *bt)
{if(!bt)return -1;bt->rx_buffer_current_cnt = 0;bt->rx_buffer_total_length = HC05_RECEIVE_BUFFER_SIZE;memset(bt->rx_buffer, 0, sizeof(bt->rx_buffer));/* 初始化用到的硬件 */bt_hw_init(bt);/* 使用AT指令初始化HC-05模块 */bt_software_reset(bt);return 0;
}/******************************************************************************* @brief     获得蓝牙模块连接的状态** @param[in]  bt   :  BlueTooth_t结构体指针** @return     HC05_STATUS_CONNECT, 表示蓝牙模块已连接, *             HC05_STATUS_DISCONNECT,其他值表示失败*******************************************************************************/
BT_ConnectStatus_t BT_GetBlueToothStatus(BlueTooth_t *bt)
{uint8_t pin_status = 0;pin_status = HC05_IO_GET_VALUE(bt->port[HC05_STATE], bt->pin[HC05_STATE]);if (pin_status) {   //连接return HC05_STATUS_CONNECT;} else {return HC05_STATUS_DISCONNECT;}
}/******************************************************************************* @brief     蓝牙模块缓存区里面是否有数据** @param[in]  bt   :  BlueTooth_t结构体指针** @return     true 表示缓存区有数据, *             false 表示缓存区没有数据*******************************************************************************/
bool BT_IsReceiveData(BlueTooth_t *bt)
{if (bt->rx_buffer_current_cnt) {return true;} else {return false;}
}/******************************************************************************* @brief     读取蓝牙模块缓存区里面的数据** @param[in]  bt            :  BlueTooth_t结构体指针* @param[in]  pReadBuffer   :  读缓存区指针* @param[in]  u32ReadCount  :  读取的数据量** @return     返回读取到的数据*******************************************************************************/
int BT_ReceiveData(BlueTooth_t *bt, uint8_t *pReadBuffer, uint32_t u32ReadCount)
{if (u32ReadCount >= bt->rx_buffer_current_cnt) {memcpy(pReadBuffer, bt->rx_buffer, bt->rx_buffer_current_cnt);bt->rx_buffer_current_cnt = 0;return bt->rx_buffer_current_cnt;} else {memcpy(pReadBuffer, bt->rx_buffer, u32ReadCount);bt->rx_buffer_current_cnt = 0;return u32ReadCount;}}/******************************************************************************* @brief     向蓝牙模块发送数据** @param[in]  bt            :  BlueTooth_t结构体指针* @param[in]  pReadBuffer   :  写缓存区指针* @param[in]  u32ReadCount  :  要发送的数据量** @return     返回读取到的数据*******************************************************************************/
int BT_SendData(BlueTooth_t *bt, uint8_t *pWriteBuffer, uint32_t u32WriteCount)
{int i = 0;for (i = 0; i < u32WriteCount; i++) {send_char(bt, pWriteBuffer[i]);}return i;
}

hc05.h

#ifndef  __HC05_H
#define  __HC05_H#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>#include "delay.h"#define HC05_UART_BAUD_RATE                (38400U)
#define HC05_RECEIVE_BUFFER_SIZE           (1024U)
#define HC05_DEBUG_MODE                     0//与芯片相关的部分 换芯片只需改动此处
#if defined (STM32F40_41xxx)#include "stm32f4xx.h"typedef    GPIO_TypeDef*   GPIO_Port_t;
typedef    USART_TypeDef*  UART_t;
//与芯片相关的部分 换芯片只需改动此处#else#error hc05.h: No processor defined!#endiftypedef GPIO_Port_t gpio;//蓝牙的链接状态
typedef enum bt_status
{HC05_STATUS_DISCONNECT = 0,HC05_STATUS_CONNECT = 1,
}BT_ConnectStatus_t;//四个引脚
enum HC05Pin_t
{HC05_TX = 0,HC05_RX = 1,HC05_EN = 2,HC05_STATE = 3,HC05_COUNT             //
};//初始化蓝牙结构体
//串口资源收发 引脚
typedef struct blue_tooth{ UART_t             uart;GPIO_Port_t        port[HC05_COUNT];uint16_t           pin[HC05_COUNT];uint32_t           rx_buffer_current_cnt;uint32_t           rx_buffer_total_length;                  //缓冲区总的长度char               rx_buffer[HC05_RECEIVE_BUFFER_SIZE];       //接受AT指令的缓冲区
}BlueTooth_t;int BT_Init(BlueTooth_t *bt);
BT_ConnectStatus_t BT_GetBlueToothStatus(BlueTooth_t *bt);
bool BT_IsReceiveData(BlueTooth_t *bt);
int BT_ReceiveData(BlueTooth_t *bt, uint8_t *pReadBuffer, uint32_t u32ReadCount);
int BT_SendData(BlueTooth_t *bt, uint8_t *pBuffer, uint32_t u32WriteCount);#endif

main.c

#include "main.h"BlueTooth_t gBL;
int main(void)
{BT_ConnectStatus_t s = 0;char buffer[100];int i = 0;char rx_buffer[100];Delay_Init();Debug_Init(115200);printf("BL\r\n");/* 初始化串口2对应时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);/* 串口2对应引脚复用映射 */GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);gBL.uart = USART2;gBL.port[HC05_TX] = GPIOA;gBL.pin[HC05_TX] = GPIO_Pin_2;gBL.port[HC05_RX] = GPIOA;gBL.pin[HC05_RX] = GPIO_Pin_3;gBL.port[HC05_EN] = GPIOA;gBL.pin[HC05_EN] = GPIO_Pin_4;gBL.port[HC05_STATE] = GPIOA;gBL.pin[HC05_STATE] = GPIO_Pin_5;BT_Init(&gBL);while (1) {s = BT_GetBlueToothStatus(&gBL);    //判断蓝牙是否连接if (s) {printf("蓝牙连接\r\n");sprintf(buffer, "i: %d\r\n", i++);BT_SendData(&gBL, buffer, strlen(buffer));if (BT_IsReceiveData(&gBL)) {memset(rx_buffer, 0, sizeof(rx_buffer));BT_ReceiveData(&gBL, rx_buffer, 100);printf("rx_buffer: %s\r\n", rx_buffer);}}Delay_Ms(500);}
}void USART2_IRQHandler(void)
{uint16_t ret = 0;if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {ret= USART2->DR;gBL.rx_buffer[gBL.rx_buffer_current_cnt % sizeof(gBL.rx_buffer)] = ret;gBL.rx_buffer_current_cnt++;}}

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

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

相关文章

*****水上飞机:继承,虚函数,虚继承

一题目 请设计以下航行器、飞机、船、水上飞机等 4 个类。 CRAFT 为航行器类&#xff0c;是公共基类&#xff0c;提供航行器的基本特性。包括&#xff1a; 一个保护数据成员&#xff1a;speed(速度)。 三个公有成员函数&#xff1a;构造函数(初始化速度)、析构函数和 Show 函数…

算法学习笔记(一)-快速幂

#问题的引入-对于幂次方的求解我们怎么可以最大限度的降低时间复杂度呢 #对于一个基本的幂次运算&#xff0c;c代码如下示例 long long int myPower(int base,int power) {long long int result 1 ;for (int i 1 ; i < power ; i){result * base ;}return result ; } #…

LLMs应被视为一种文字计算器?

编者按&#xff1a;当前&#xff0c;大语言模型已经成为自然语言处理领域的热点。LLMs 是否真的“智能”&#xff1f;它们又为我们带来了哪些启发&#xff1f;针对这些问题&#xff0c;Darveen Vijayan 为我们带来了这篇引人深思的文章。 作者主要阐释了两个观点&#xff1a;第…

linux上用Jmter进行压测

在上一篇中安装好了Jmeter环境&#xff0c;在这一篇中将主要分享如何使用jmeter在linux中进行单机压测。 1.项目部署 在这里我们先简单部署一下测试环境&#xff0c;所用到的项目环境是个jar包&#xff0c;先在linux上home目录下新建app目录&#xff0c;然后通过rz命令将项目ja…

2万字干货:如何从0到1搭建一套会员体系(2)

2.用户等级 还是一样&#xff0c;我们为什么要搭建用户等级&#xff1f; 一个国家有几亿人口的时候你怎么来管理&#xff1f;老祖宗秦始皇给出了我们答案&#xff1a;郡县制。发展到现在则演进成了省-市-区县-乡镇(街道)-村(社区)5层行政治理结构。 产品同理&#xff0c;当你…

Flume 的安装和使用方法(Spark-2.1.0)

一、Flume的安装 1.下载压缩包 https://www.apache.org/dyn/closer.lua/flume/1.7.0/apache-flume-1.7.0-bin.tar.gz 2.上传到linux中 3.解压安装包 cd #进入加载压缩包目录sudo tar -zxvf apache-flume-1.7.0-bin.tar.gz -C /usr/local # 将 apache-flume-1.7.0-bin.tar.g…

文旅行业| 某景区导游培养和管理项目成功案例纪实

——整合导游资源并进行统一管理&#xff0c;构建完善的培养与管理机制&#xff0c;发挥景区导游价值 【客户行业】文旅行业&#xff1b;景区&#xff1b;文旅企业 【问题类型】人才培养&#xff1b;人员管理 【客户背景】 南方某5A级景区&#xff0c;作为国内极具代表性和特…

经常睡不好觉?试试用上华为手环9新升级的睡眠监测功能

睡眠问题是不是经常困扰着你呢&#xff1f;听说&#xff0c;华为手环9的睡眠监测功能升级了&#xff0c;无论是入睡前、睡眠中还是睡醒后&#xff0c;都能够帮助我们改善睡眠&#xff0c;让我们告别糟糕的睡眠质量&#xff01; 睡觉前&#xff0c;打开华为手环9的睡眠模式&…

寻找最大价值的矿堆 - 矩阵

系列文章目录 文章目录 系列文章目录前言一、题目描述二、输入描述三、输出描述四、Java代码五、测试用例 前言 本人最近再练习算法&#xff0c;所以会发布一些解题思路&#xff0c;希望大家多指教 一、题目描述 给你一个由’0’(空地)、‘1’(银矿)、‘2’(金矿)组成的地图…

自动化测试基础 --- Jmeter

前置环境安装 首先我们需要知道如何下载Jmeter 这里贴上下载网站Apache JMeter - Download Apache JMeter 我们直接解压,然后在bin目录下找到jemter.bat即可启动使用 成功打开之后就是这个界面 每次打开可以用这种方式切换成简体中文 或者直接修改properties文件修改对应的语言…

第七届精武杯部分wp

第一部分&#xff1a;计算机和手机取证 1.请综合分析计算机和手机检材&#xff0c;计算机最近一次登录的账户名是 答案&#xff1a;admin 创建虚拟机时直接给出了用户名 2. 请综合分析计算机和手机检材&#xff0c;计算机最近一次插入的USB存储设备串号是 答案&#xff1a…

01面向类的讲解

指针指向类成员使用 代码&#xff1a; #include<iostream> using namespace std;class Test { public:void func() { cout << "call Test::func" << endl; }static void static_func();int ma;static int mb; //不依赖对象 }; void Test::static…

探索GitHub上的GPTs项目:泄露和被破解的GPT提示

GPTs项目是一个在GitHub上由用户linexjlin发起的开源项目&#xff0c;专注于提供泄露的GPT&#xff08;生成式预训练转换器&#xff09;提示。这些提示用于指导和优化AI模型的输出&#xff0c;进而提升代码生成的质量和效率。项目页面提供了丰富的功能和资源&#xff0c;旨在帮…

全套停车场管理系统报价多少钱?停车场管理系统由哪些设备组成?

随着城市化进程的加快&#xff0c;汽车保有量的不断攀升&#xff0c;停车场的管理和运营成为城市基础设施建设的重要组成部分。一个高效、智能的停车场收费系统不仅能提升停车效率&#xff0c;还能增强用户体验&#xff0c;对城市的交通管理起到关键作用。本文将为您详细介绍全…

mac 讨厌百度网盘怎么办

一、别拦我 首先请允许我泄个愤&#xff0c;tmd百度网盘下个1g的文件下载速度竟然超不过200k&#xff0c;只要不放在所有已打开软件的最前面&#xff0c;它就给你降到10k以内&#xff0c;关键是你慢就慢了&#xff0c;我也不是很着急&#xff0c;关键是你日常下载失败并且总是…

AI代理和AgentOps生态系统的剖析

1、AI代理的构成&#xff1a;AI代理能够根据用户的一般性指令自行做出决策和采取行动。 主要包含四个部分&#xff1a; &#xff08;1&#xff09;大模型&#xff08;LLM&#xff09; &#xff08;2&#xff09;工具&#xff1a;如网络搜索、代码执行等 &#xff08;3&#x…

在Qt工具栏上实现矩阵并排的按钮效果源码

如果这个要用MFC去实现头皮都得掉一层&#xff0c;建议大家以后要写GUI方面的小工具尽量转QT或其他吧&#xff0c;MFC真不适合搞这种花里胡哨的界面. 在Qt工具栏上实现矩阵并排的按钮效果源码如下&#xff1a; #include "mainwindow.h" #include "ui_mainwind…

初识指针(4)<C语言>

前言 前面的文章&#xff0c;已经对指针的基础概念以及运用有了初步了解&#xff0c;我们可以进一步探究指针比较深入的知识&#xff0c;下文将主要介绍&#xff1a;使用指针数组模拟二维数组、字符指针变量、数组指针、二维数组传参的本质、函数指针、typedef关键字等。 目录…

RustDesk 自建服务器部署和使用教程

RustDesk 是一个强大的开源远程桌面软件&#xff0c;是中国开发者的作品&#xff0c;它使用 Rust 编程语言构建&#xff0c;提供安全、高效、跨平台的远程访问体验。可以说是目前全球最火的开源远程桌面软件了&#xff0c;GitHub 星星数量达到了惊人的 64k&#xff01; 与 Team…

洪水仿真模拟(ArcGIS),水利数字孪生新利器

这两天ArcGIS Pro的官方账号释放了一个名为“Flood Simulation in ArcGIS Pro”的洪水模拟功能视频。根据视频详情页的介绍&#xff0c;该洪水仿真模拟功能会作为新功能出现在ArcGIS Pro 3.3中。 由于我目前从事的主要应用方向都是弱GIS的领域&#xff0c;所以我已经很久没有再…