STM32入门笔记(02):USART串口通信注意事项笔记(SPL库函数版)

在这里插入图片描述

这是通过串口通信发送过来的数据,里面包括了故障码,电压,电流,频率等信息,请你用STM32f103系列单片机的串口1读取该数据并解析出电压和电流是多少?

要用STM32F103系列单片机的串口1读取并解析发电机上的逆变器发送的数据,你需要编写代码来完成以下步骤:

  1. 初始化串口:配置STM32的USART1以正确的波特率和参数读取数据。
  2. 读取数据:从串口缓冲区读取完整的数据包。
  3. 解析数据:从数据包中提取电压和电流信息。

假设数据格式如下(每个字节的数据如图所示):

  • 起始位:字节0
  • 数据长度:字节1
  • 故障码、电压、电流、频率等信息从字节2开始

根据图片中的数据:

  • 电压信息在字节2和字节3
  • 电流信息在字节4和字节5

以下是一个示例代码,用于在STM32F103系列单片机上实现上述步骤:

#include "stm32f10x.h"
#include "usart.h"  // 包含USART初始化配置文件

#define DATA_LENGTH 31  // 假设总共要读取31个字节的数据

uint8_t received_data[DATA_LENGTH];  // 接收数据的缓冲区

void USART1_IRQHandler(void) {
    static uint8_t i = 0;
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        received_data[i++] = USART_ReceiveData(USART1);
        if (i >= DATA_LENGTH) {
            i = 0;  // 重置接收计数器
        }
    }
}

void init_USART1(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置USART1 Tx (PA.09) 作为推挽复用功能
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置USART1 Rx (PA.10) 作为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // USART参数配置
    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(USART1, &USART_InitStructure);

    // 使能USART接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 配置USART1中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // 使能USART
    USART_Cmd(USART1, ENABLE);
}

int main(void) {
    uint16_t voltage = 0;
    uint16_t current = 0;

    // 初始化USART1,波特率设置为9600(根据实际情况调整)
    init_USART1(9600);

    while (1) {
        // 检查数据包是否完整接收
        if (received_data[1] == 28) {  // 确保接收的数据长度正确
            // 解析电压和电流数据
            voltage = (received_data[2] << 8) | received_data[3];
            current = (received_data[4] << 8) | received_data[5];
            
            // 在这里可以对解析出的电压和电流进行处理,例如显示或记录
            // 注意:电压和电流的单位以及是否需要转换取决于发送方的数据格式定义
        }
    }
}

注意事项:

  1. 波特率设置:根据实际设备的波特率设置USART_InitStructure.USART_BaudRate
  2. 数据长度检查:确保接收的数据长度正确。
  3. 电压和电流解析:根据具体协议,确定数据的字节顺序和单位。

进一步优化:

  1. 数据验证:增加数据包头和校验码的验证,以确保数据的准确性。
  2. 错误处理:处理接收过程中可能出现的错误,如丢包或数据损坏。

为了增加数据包头和校验码的验证,以确保数据的准确性,你可以对接收到的数据包进行更严格的检查和处理。以下是增加数据包头和校验码验证的详细步骤和示例代码。

数据包结构假设

假设你的数据包结构如下:

  • 起始位:字节0(例如,固定为0xAA)
  • 数据长度:字节1(例如,固定为28)
  • 数据内容:字节2到字节29
  • 校验码:字节30(例如,使用简单的累加和校验)

校验码计算方法

假设校验码是所有数据字节(包括起始位和数据长度)的累加和的低8位。

示例代码

以下代码展示了如何在STM32F103单片机上实现数据包头和校验码的验证:

#include "stm32f10x.h"
#include "usart.h"

#define DATA_LENGTH 31  // 数据包总长度

uint8_t received_data[DATA_LENGTH];  // 接收数据的缓冲区

// 计算校验码
uint8_t calculate_checksum(uint8_t *data, uint8_t length) {
    uint8_t checksum = 0;
    for (uint8_t i = 0; i < length; i++) {
        checksum += data[i];
    }
    return checksum;
}

// USART1中断服务程序
void USART1_IRQHandler(void) {
    static uint8_t i = 0;
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        received_data[i++] = USART_ReceiveData(USART1);
        if (i >= DATA_LENGTH) {
            i = 0;  // 重置接收计数器
        }
    }
}

void init_USART1(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置USART1 Tx (PA.09) 作为推挽复用功能
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置USART1 Rx (PA.10) 作为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // USART参数配置
    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(USART1, &USART_InitStructure);

    // 使能USART接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 配置USART1中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // 使能USART
    USART_Cmd(USART1, ENABLE);
}

int main(void) {
    uint16_t voltage = 0;
    uint16_t current = 0;

    // 初始化USART1,波特率设置为9600(根据实际情况调整)
    init_USART1(9600);

    while (1) {
        // 检查数据包是否完整接收
        if (received_data[1] == 28) {  // 确保接收的数据长度正确
            // 验证数据包头和校验码
            if (received_data[0] == 0xAA) {  // 验证起始位
                uint8_t checksum = calculate_checksum(received_data, DATA_LENGTH - 1);
                if (checksum == received_data[30]) {  // 验证校验码
                    // 解析电压和电流数据
                    voltage = (received_data[2] << 8) | received_data[3];
                    current = (received_data[4] << 8) | received_data[5];
                    
                    // 在这里可以对解析出的电压和电流进行处理,例如显示或记录
                    // 注意:电压和电流的单位以及是否需要转换取决于发送方的数据格式定义
                }
            }
        }
    }
}

代码解释

  1. 校验码计算

    • 函数calculate_checksum用于计算接收到的数据包的校验码。
  2. USART1中断服务程序

    • USART1_IRQHandler中,当接收到新字节时,将其存入接收缓冲区received_data中。
  3. 主循环

    • 检查接收的数据长度是否正确。
    • 验证起始位(假设为0xAA)。
    • 计算并验证校验码。
    • 解析并处理电压和电流数据。

注意事项

  • 波特率设置:根据实际设备的波特率调整USART_InitStructure.USART_BaudRate
  • 校验和验证:根据实际应用选择合适的校验算法,如CRC校验等。
  • 数据解析:根据实际数据格式调整解析代码。

为了处理接收过程中可能出现的错误,如丢包或数据损坏,你可以增加一些错误处理机制,包括超时处理、错误计数、数据重发请求等。以下是具体的步骤和代码示例。

增加错误处理机制

  1. 超时处理:设置接收数据的超时机制,如果在预定时间内没有接收到完整的数据包,则认为接收超时。
  2. 错误计数:记录接收错误的次数,当错误次数超过一定阈值时,采取相应的措施。
  3. 数据包头和校验码验证:在接收数据时,严格验证数据包头和校验码,确保数据完整性。
  4. 丢包重发机制:如果检测到数据包错误,可以请求发送方重新发送数据。

示例代码

以下是一个包含错误处理机制的示例代码:

#include "stm32f10x.h"
#include "usart.h"
#include <stdbool.h>
#include <string.h>

#define DATA_LENGTH 31  // 数据包总长度
#define TIMEOUT_THRESHOLD 1000  // 超时时间阈值
#define ERROR_THRESHOLD 5  // 最大允许错误次数

uint8_t received_data[DATA_LENGTH];  // 接收数据的缓冲区
uint8_t data_index = 0;  // 当前接收数据的索引
uint32_t timeout_counter = 0;  // 超时计数器
uint8_t error_count = 0;  // 错误计数器

// 计算校验码
uint8_t calculate_checksum(uint8_t *data, uint8_t length) {
    uint8_t checksum = 0;
    for (uint8_t i = 0; i < length; i++) {
        checksum += data[i];
    }
    return checksum;
}

// USART1中断服务程序
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t received_byte = USART_ReceiveData(USART1);
        received_data[data_index++] = received_byte;
        timeout_counter = 0;  // 重置超时计数器

        if (data_index >= DATA_LENGTH) {
            data_index = 0;  // 重置接收计数器
        }
    }
}

void init_USART1(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置USART1 Tx (PA.09) 作为推挽复用功能
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置USART1 Rx (PA.10) 作为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // USART参数配置
    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(USART1, &USART_InitStructure);

    // 使能USART接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 配置USART1中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // 使能USART
    USART_Cmd(USART1, ENABLE);
}

int main(void) {
    uint16_t voltage = 0;
    uint16_t current = 0;

    // 初始化USART1,波特率设置为9600(根据实际情况调整)
    init_USART1(9600);

    while (1) {
        // 超时处理
        if (timeout_counter++ > TIMEOUT_THRESHOLD) {
            timeout_counter = 0;
            data_index = 0;  // 重置接收索引
            error_count++;
            if (error_count >= ERROR_THRESHOLD) {
                // 错误处理逻辑,例如重启或告警
                // 这里简单地重置错误计数器
                error_count = 0;
            }
        }

        // 检查数据包是否完整接收
        if (data_index == DATA_LENGTH) {
            // 验证数据包头和校验码
            if (received_data[0] == 0xAA && received_data[1] == 28) {  // 验证起始位和长度
                uint8_t checksum = calculate_checksum(received_data, DATA_LENGTH - 1);
                if (checksum == received_data[30]) {  // 验证校验码
                    // 解析电压和电流数据
                    voltage = (received_data[2] << 8) | received_data[3];
                    current = (received_data[4] << 8) | received_data[5];
                    
                    // 在这里可以对解析出的电压和电流进行处理,例如显示或记录
                    // 注意:电压和电流的单位以及是否需要转换取决于发送方的数据格式定义
                    
                    // 数据处理成功,重置错误计数器
                    error_count = 0;
                } else {
                    // 校验码错误
                    error_count++;
                }
            } else {
                // 数据包头错误
                error_count++;
            }
            // 重置接收索引
            data_index = 0;
        }
    }
}

代码解释

  1. 超时处理

    • 通过timeout_counter计数器记录接收数据的超时时间。
    • 如果在预定时间内(TIMEOUT_THRESHOLD)没有接收到完整的数据包,则认为接收超时,重置接收索引并增加错误计数器。
  2. 错误计数

    • 通过error_count记录接收错误的次数,当错误次数超过ERROR_THRESHOLD时,可以采取相应的措施,比如重启或告警。
    • 在本示例中,错误计数器简单地重置。
  3. 数据包头和校验码验证

    • 检查接收到的数据包长度是否正确。
    • 验证起始位和数据长度。
    • 计算校验码并与接收到的校验码比较。
    • 如果数据包头或校验码错误,增加错误计数器。
  4. 丢包重发机制

    • 这个示例中没有具体实现丢包重发机制,但可以通过串口发送请求重新发送数据包的命令来实现。
    • 如果检测到数据包错误,可以发送请求给发电机上的逆变器,要求重新发送数据。

注意事项

  • 实际应用中,错误处理策略需要根据具体需求进行调整,例如记录错误日志、发送告警信息或重新初始化串口等。
  • 校验码计算方法可以根据实际应用进行调整,如使用CRC校验等。
  • 丢包重发机制可以通过串口发送指令来实现,需要和逆变器的通信协议相匹配。

为了提高通信的可靠性可以增加握手协议,确保双方在传输数据之前已经准备好,并且可以用于初始化一些必要的参数。

以下是一个简单的握手协议示例:

  1. 发送握手请求:STM32单片机发送握手请求到发电机上的逆变器。
  2. 等待握手响应:STM32单片机等待逆变器的握手响应。
  3. 验证握手响应:STM32单片机验证握手响应是否正确。如果正确,则继续进行数据传输;否则,重新发送握手请求或进行错误处理。

示例代码

以下是一个示例代码,展示了如何在STM32F103单片机上实现握手协议:

#include "stm32f10x.h"
#include "usart.h"
#include <stdbool.h>
#include <string.h>

#define DATA_LENGTH 31  // 数据包总长度
#define TIMEOUT_THRESHOLD 1000  // 超时时间阈值
#define ERROR_THRESHOLD 5  // 最大允许错误次数
#define HANDSHAKE_REQUEST 0x55  // 握手请求命令
#define HANDSHAKE_RESPONSE 0xAA  // 握手响应命令

uint8_t received_data[DATA_LENGTH];  // 接收数据的缓冲区
uint8_t data_index = 0;  // 当前接收数据的索引
uint32_t timeout_counter = 0;  // 超时计数器
uint8_t error_count = 0;  // 错误计数器

// 计算校验码
uint8_t calculate_checksum(uint8_t *data, uint8_t length) {
    uint8_t checksum = 0;
    for (uint8_t i = 0; i < length; i++) {
        checksum += data[i];
    }
    return checksum;
}

// USART1中断服务程序
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t received_byte = USART_ReceiveData(USART1);
        received_data[data_index++] = received_byte;
        timeout_counter = 0;  // 重置超时计数器

        if (data_index >= DATA_LENGTH) {
            data_index = 0;  // 重置接收计数器
        }
    }
}

void init_USART1(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置USART1 Tx (PA.09) 作为推挽复用功能
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置USART1 Rx (PA.10) 作为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // USART参数配置
    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(USART1, &USART_InitStructure);

    // 使能USART接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 配置USART1中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // 使能USART
    USART_Cmd(USART1, ENABLE);
}

bool handshake(void) {
    uint32_t handshake_timeout = 0;

    // 发送握手请求
    USART_SendData(USART1, HANDSHAKE_REQUEST);

    // 等待握手响应
    while (handshake_timeout++ < TIMEOUT_THRESHOLD) {
        if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
            uint8_t response = USART_ReceiveData(USART1);
            if (response == HANDSHAKE_RESPONSE) {
                return true;  // 握手成功
            }
        }
    }
    return false;  // 握手失败
}

int main(void) {
    uint16_t voltage = 0;
    uint16_t current = 0;

    // 初始化USART1,波特率设置为9600(根据实际情况调整)
    init_USART1(9600);

    // 进行握手
    while (!handshake()) {
        // 握手失败,重新尝试
    }

    while (1) {
        // 超时处理
        if (timeout_counter++ > TIMEOUT_THRESHOLD) {
            timeout_counter = 0;
            data_index = 0;  // 重置接收索引
            error_count++;
            if (error_count >= ERROR_THRESHOLD) {
                // 错误处理逻辑,例如重启或告警
                // 这里简单地重置错误计数器
                error_count = 0;
            }
        }

        // 检查数据包是否完整接收
        if (data_index == DATA_LENGTH) {
            // 验证数据包头和校验码
            if (received_data[0] == 0xAA

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一顿五元钱的午餐

在郑州喧嚣的城市一隅&#xff0c;藏着一段鲜为人知的真实的故事。 故事的主角是一位年过半百的父亲&#xff0c;一位平凡而又伟大的劳动者。岁月在他脸上刻下了深深的痕迹&#xff0c;但他眼神中闪烁着不屈与坚韧。 他今年52岁&#xff0c;为了给远在家乡的孩子们一个更好的…

MySQL 将json转为行,JSON_TABLE函数详解

MySQL 将json转为行&#xff0c;JSON_TABLE函数详解 JSON_TABLE 是 MySQL 8.0 引入的一个强大函数&#xff0c;它用于将 JSON 数据转换为关系表的格式。通过 JSON_TABLE 函数&#xff0c;可以将 JSON 文档解析为关系表的列和行&#xff0c;使得在 SQL 查询中处理 JSON 数据更加…

RocketMQ之DefaultPushConsumer

DefaultMQPushConsumer消息链路 DefaultMQpushConsumer#start方法调用DefaultMQpushConsumerImpl#start方法,接着内部调用MQClientInstance#start方法,接着调用RebalanceService#start方法。 RebalanceService#start方法开启一个线程,执行本类中的runnable#run方法。run方法…

P6【知识点】【数据结构】【树tree】C++版

树是由一个集合以及在该集合上定义的一种关系构成的&#xff0c;集合中的元素称为树的结点&#xff0c;所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构&#xff0c;在这种层次结构中有一个结点具有特殊的地位&#xff0c;这个结点称为该树的根结点。 二叉…

数据库|基于T-SQL创建数据库

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; SQL Server用于操作数据库的编程语言为Transaction-SQL,简称T-SQL。 本节学习基于T-SQL创建数据库。以下为学习笔记。 01 打开新建查询 首先连接上数据库&#xff0c;点击【新建查询】打开新建查询窗口&#xff0c; …

如何在go项目中实现发送邮箱验证码、邮箱+验证码登录

前期准备 GoLand &#xff1a;2024.1.1 下载官网&#xff1a;https://www.jetbrains.com/zh-cn/go/download/other.html Postman&#xff1a; 下载官网&#xff1a;https://www.postman.com/downloads/ 效果图(使用Postman) Google&#xff1a; QQ&#xff1a; And …

java 8--Lambda表达式,Stream流

目录 Lambda表达式 Lambda表达式的由来 Lambda表达式简介 Lambda表达式的结构 Stream流 什么是Stream流&#xff1f; 什么是流呢&#xff1f; Stream流操作 中间操作 终端操作 Lambda表达式 Lambda表达式的由来 Java是面向对象语言&#xff0c;除了部分简单数据类型…

SpringBoot——整合MyBatis

目录 MyBatis 项目总结 1、创建SQL表 2、新建一个SpringBoot项目 3、pom.xml添加依赖 4、application.properties配置文件 5、User实体类 6、UserMapper接口 7、UserMapper.xml映射文件 8、UserController控制器 9、SpringBootMyBatisApplication启动类 10、使用Po…

关于如何创建一个可配置的 SpringBoot Web 项目的全局异常处理

前情概要 这个问题其实困扰了我一周时间&#xff0c;一周都在 Google 上旅游&#xff0c;我要如何动态的设置 RestControllerAdvice 里面的 basePackages 以及 baseClasses 的值呢&#xff1f;经过一周的时间寻求无果之后打算决定放弃的我终于找到了一些关键的线索。 当然在此…

反射的基本知识

基本概念 反射是java在运行过程中的自我观察能力&#xff0c;通过class constructor field method 四个方法来获取一个类的各个组成部分。 反射是在运行状态中对于任意一个类&#xff0c;都能知道这个类的所有属性和方法&#xff1b;对于任意一个对象都能调用它的任意一个方法…

《MySQL是怎样运行的》快速查询秘籍——B+树索引

一.引出索引 前面一章我们说出了数据页的结构&#xff0c;但是如果我们要查找某一条记录的话&#xff0c;怎么办呢&#xff1f; 我们前面知道页与页之间是一个双向链表实现的&#xff0c;我们要找的话&#xff0c;是不是要按照这个链表一个一个找下去&#xff0c;然后找到&am…

数据链路层简单介绍

mac地址&#xff08;物理地址&#xff09; mac地址和ip地址&#xff0c;目的都是为了区分网络上的不同设备的&#xff0c;在最开始的时候&#xff0c;mac地址和ip地址是两伙人&#xff0c;独立各自提出的&#xff0c;ip地址是4个字节&#xff08;早都不够用了&#xff09;&…

【个人商业画布】你有思考过把自己当成一家公司来经营吗?

商业模式画布(Business Model Canvas)&#xff0c;是亚历山大奥斯特瓦德在《商业模式新生代》中提出的一种用于描述商业模式、可视化商业模式、评估商业模式以及改变商业模式的通用语言。它由9个模块构成&#xff0c;帮助创业者理清为“细分客户提供独有价值”&#xff0c;从而…

PersonalLLM——探索LLM是否能根据五大人格特质重新塑造一个新的角色?

1.概述 近年来&#xff0c;大型语言模型&#xff08;LLMs&#xff09;&#xff0c;例如ChatGPT&#xff0c;致力于构建能够辅助人类的个性化人工智能代理&#xff0c;这些代理以进行类似人类的对话为重点。在学术领域&#xff0c;尤其是社会科学中&#xff0c;一些研究报告已经…

溪谷联运SDK功能全面解析

近期&#xff0c;备受用户关注的手游联运10.0.0版本上线了&#xff0c;不少用户也选择了版本更新&#xff0c;其中也再次迎来了SDK的更新。溪谷软件和大家一起盘点一下溪谷SDK的功能都有哪些吧。 一、溪谷SDK具有完整的运营功能和高度扩展性 1.登录&#xff1a;登录是SDK最基础…

简述MyBatis中#{}引用和${}引用的区别

各位大佬光临寒舍&#xff0c;希望各位能赏脸给个三连&#xff0c;谢谢各位大佬了&#xff01;&#xff01;&#xff01; 目录 1.有无预编译 优点 缺点 2.SQL执行的快慢 3.能否被SQL注入 4.参数输入方式 5.总结 1.有无预编译 #{}是有预编译的而${}是没有预编译的&…

OceanBase集群如何进行OCP的替换

有OceanBase社区版的用户提出替换 OCP 管控平台的需求。举例来说&#xff0c;之前的OCP平台采用单节点&#xff0c;然而随着OceanBase集群的陆续上线和数量的不断增多&#xff0c;担心单节点的OCP可能面临故障风险&#xff0c;而丧失对OceanBase集群的管控能力。另此外&#xf…

创建vue工程、Vue项目的目录结构、Vue项目-启动、API风格

环境准备 介绍&#xff1a;create-vue是Vue官方提供的最新的脚手架工具&#xff0c;用于快速生成一个工程化的Vue项目create-vue提供如下功能&#xff1a; 统一的目录结构 本地调试 热部署 单元测试 集成打包依赖环境&#xff1a;NodeJS 安装NodeJS 一、 创建vue工程 npm 类…

以Linux为例了解线程

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

IO系列(八) -浅析NIO工作原理

一、简介 现在使用 NIO 的场景越来越多&#xff0c;很多网上的技术框架或多或少的使用 NIO 技术&#xff0c;譬如 Tomcat、Jetty、Netty&#xff0c;学习和掌握 NIO 技术已经不是一个 Java 攻城狮的加分技能&#xff0c;而是一个必备技能。 那什么是 NIO 呢&#xff1f; NIO…