瀚文机械键盘固件开发详解:HWKeyboard.cpp文件解析与应用

news2025/6/9 16:23:57

🔥 机械键盘固件开发从入门到精通:HWKeyboard模块全解析

作为一名嵌入式开发老司机,今天带大家拆解一个完整的机械键盘固件代码。即使你是单片机小白,看完这篇教程也能轻松理解机械键盘的工作原理,甚至自己动手复刻一个!

🚀 项目整体概览

这个hw_keyboard.cpp模块实现了一个完整的机械键盘固件,基于STM32单片机开发,主要功能包括:

  • 按键矩阵扫描与状态读取
  • 机械按键消抖处理
  • 键位映射与HID协议数据生成
  • RGB灯效控制(支持WS2812B灯带)
  • 特殊功能键(Fn键、触控条)处理

整个固件就像一个智能中转站,把物理按键的按下抬起动作,转换成电脑能理解的键盘信号,同时控制炫酷的RGB灯光效果。

🧩 核心模块拆解

一、延时函数:精确掌控时间

inline void DelayUs(uint32_t _us)
{
    for (int i = 0; i < _us; i++)              // 外层循环,每次循环代表1微秒
        for (int j = 0; j < 8; j++)            // 内层循环,调整延时时长(不同芯片需调整)
            __NOP();                           // 空操作,单纯耗时
}
白话解析:
  • 这是一个微秒级的延时函数,精确控制程序暂停的时间
  • 双重循环结构,外层控制延迟多少微秒,内层循环次数需要根据芯片主频调整
  • __NOP()是"No Operation"的缩写,就是让CPU空转一个周期
  • 为什么需要它?键盘需要精确的时间控制,比如消抖、LED控制都需要

二、按键扫描模块:监听键盘上的每一次敲击

uint8_t* HWKeyboard::ScanKeyStates()
{
    memset(spiBuffer, 0xFF, IO_NUMBER / 8 + 1);    // 将spiBuffer缓冲区全部置为0xFF,准备接收数据
    PL_GPIO_Port->BSRR = PL_Pin;                   // 设置锁存引脚为高电平,锁存当前按键状态

    spiHandle->pRxBuffPtr = (uint8_t*) spiBuffer;  // 设置SPI接收缓冲区指针
    spiHandle->RxXferCount = IO_NUMBER / 8 + 1;    // 设置SPI接收字节数
    __HAL_SPI_ENABLE(spiHandle);                   // 使能SPI外设
    while (spiHandle->RxXferCount > 0U)            // 循环直到所有数据接收完毕
    {
        if (__HAL_SPI_GET_FLAG(spiHandle, SPI_FLAG_RXNE)) // 检查SPI接收缓冲区非空标志
        {
            (*(uint8_t*) spiHandle->pRxBuffPtr) = *(__IO uint8_t*) &spiHandle->Instance->DR; // 从SPI数据寄存器读取数据到缓冲区
            spiHandle->pRxBuffPtr += sizeof(uint8_t); // 指针后移
            spiHandle->RxXferCount--;                 // 剩余接收字节数减一
        }
    }
    __HAL_SPI_DISABLE(spiHandle);                     // 禁用SPI外设

    PL_GPIO_Port->BRR = PL_Pin;                       // 设置锁存引脚为低电平,完成采样
    return scanBuffer;                                // 返回扫描缓冲区指针
}
白话解析:
  • 这个函数就像键盘的"耳朵",不断监听按键是否被按下
  • PL_Pin是一个特殊引脚,拉高时会把所有按键的状态"拍照"保存
  • SPI通信就像快递系统:
    • spiBuffer是装数据的袋子
    • pRxBuffPtr是指向袋子的手指
    • RxXferCount是需要接收的数据数量
  • 数据接收完成后,返回的scanBuffer里存着所有按键的当前状态(1表示未按下,0表示按下)

三、按键消抖模块:解决机械按键的"手抖"问题

void HWKeyboard::ApplyDebounceFilter(uint32_t _filterTimeUs)
{
    memcpy(debounceBuffer, spiBuffer, IO_NUMBER / 8 + 1); // 备份当前SPI缓冲区到消抖缓冲区

    DelayUs(_filterTimeUs); // 延时一段时间,等待抖动消除
    ScanKeyStates();        // 再次扫描按键状态

    uint8_t mask;
    for (int i = 0; i < IO_NUMBER / 8 + 1; i++) // 遍历所有字节
    {
        mask = debounceBuffer[i] ^ spiBuffer[i]; // 计算两次扫描的不同位
        spiBuffer[i] |= mask;                    // 将有变化的位强制置为1(消除抖动影响)
    }
}
白话解析:
  • 机械按键按下时会像"手抖"一样产生短暂的多次通断,这就是抖动
  • 消抖处理就像拍照时的防抖功能:
    1. 先保存第一次拍的照片(按键状态)
    2. 等一小会儿(_filterTimeUs微秒)
    3. 再拍一张照片(再次扫描按键)
    4. 比较两张照片,如果有不同,就认为是"抖动",修正这些差异
  • 这个过程很重要,否则键盘会误判你按了多次键

四、键位映射模块:把物理按键变成电脑认识的键

uint8_t* HWKeyboard::Remap(uint8_t _layer)
{
    int16_t index, bitIndex; // 定义索引变量

    memset(remapBuffer, 0, IO_NUMBER / 8); // 清空重映射缓冲区
    for (int16_t i = 0; i < IO_NUMBER / 8; i++) // 遍历每个字节
    {
        for (int16_t j = 0; j < 8; j++) // 遍历每个bit
        {
            index = (int16_t) (keyMap[0][i * 8 + j] / 8);         // 计算当前物理按键在scanBuffer中的字节索引
            bitIndex = (int16_t) (keyMap[0][i * 8 + j] % 8);      // 计算当前物理按键在该字节中的位索引
            if (scanBuffer[index] & (0x80 >> bitIndex))           // 检查该物理按键是否被按下(高电平为未按下,低电平为按下)
                remapBuffer[i] |= 0x80 >> j;                      // 如果按下,则在remapBuffer中对应位置标记为1
        }
        remapBuffer[i] = ~remapBuffer[i];                         // 取反,转换为"按下为1,未按下为0"
    }

    memset(hidBuffer, 0, KEY_REPORT_SIZE);                        // 清空HID报告缓冲区

    int i = 0, j = 0;
    while (8 * i + j < IO_NUMBER - 6)                             // 遍历所有可用按键(排除最后6个保留位)
    {
        for (j = 0; j < 8; j++)
        {
            index = (int16_t) (keyMap[_layer][i * 8 + j] / 8 + 1); // 计算映射后按键在hidBuffer中的字节索引(+1跳过修饰键)
            bitIndex = (int16_t) (keyMap[_layer][i * 8 + j] % 8);  // 计算映射后按键在该字节中的位索引
            if (bitIndex < 0)
            {
                index -= 1;                                        // 位索引为负时,向前借一字节
                bitIndex += 8;
            } else if (index > 100)
                continue;                                          // 越界保护

            if (remapBuffer[i] & (0x80 >> j))                      // 如果该按键被按下
                hidBuffer[index + 1] |= 1 << (bitIndex);           // 在hidBuffer中对应位置标记为1(+1跳过Report-ID)
        }
        i++;
        j = 0;
    }

    return hidBuffer;                                              // 返回HID报告缓冲区
}
白话解析:
  • 这个模块就像一个"翻译官",把物理按键的位置翻译成电脑认识的键码
  • 过程分两大步:
    1. 第一步:把原始扫描结果(scanBuffer)转换成中间格式(remapBuffer
      • 这一步是把"物理按键位置"变成"逻辑按键位置"
      • 使用keyMap[0]查表,找到每个物理按键对应的逻辑位置
    2. 第二步:把中间格式(remapBuffer)转换成USB-HID标准格式(hidBuffer
      • 这一步是把"逻辑按键位置"变成"标准键码"
      • 使用keyMap[_layer]查表,支持多层键位映射(比如Fn组合键)
  • 最终生成的hidBuffer就是可以直接发送给电脑的USB-HID报告

五、RGB灯效控制模块:让键盘"发光发热"

void HWKeyboard::SetRgbBufferByID(uint8_t _keyId, HWKeyboard::Color_t _color, float _brightness)
{
    // 防止全0导致ws2812b协议错误
    if (_color.b < 1)_color.b = 1;                                 // 蓝色分量最小为1,避免全0

    for (int i = 0; i < 8; i++)                                   // 遍历8位
    {
        rgbBuffer[_keyId][0][i] =
            ((uint8_t) ((float) _color.g * _brightness) >> brightnessPreDiv) & (0x80 >> i) ? WS_HIGH : WS_LOW; // 绿色分量
        rgbBuffer[_keyId][1][i] =
            ((uint8_t) ((float) _color.r * _brightness) >> brightnessPreDiv) & (0x80 >> i) ? WS_HIGH : WS_LOW; // 红色分量
        rgbBuffer[_keyId][2][i] =
            ((uint8_t) ((float) _color.b * _brightness) >> brightnessPreDiv) & (0x80 >> i) ? WS_HIGH : WS_LOW; // 蓝色分量
    }
}

void HWKeyboard::SyncLights()
{
    while (isRgbTxBusy);                                           // 等待上一次DMA传输完成
    isRgbTxBusy = true;                                            // 标记DMA忙
    HAL_SPI_Transmit_DMA(&hspi2, (uint8_t*) rgbBuffer, LED_NUMBER * 3 * 8); // 通过DMA发送RGB数据
    while (isRgbTxBusy);                                           // 等待DMA完成
    isRgbTxBusy = true;                                            // 再次标记DMA忙
    HAL_SPI_Transmit_DMA(&hspi2, wsCommit, 64);                    // 发送ws2812b协议结尾信号
}
白话解析:
  • 这个模块负责控制键盘上的RGB灯,让键盘变得炫酷
  • SetRgbBufferByID函数像是一支神奇的画笔:
    • _keyId:选择要涂色的灯珠
    • _color:选择RGB颜色(红、绿、蓝三原色)
    • _brightness:控制颜色的亮度(0.0-1.0)
  • WS2812B是一种智能LED灯珠,需要特殊的信号格式:
    • 每个灯珠需要24位数据(8位绿+8位红+8位蓝)
    • WS_HIGHWS_LOW是两种不同的电平时序,用来表示1和0
    • 所有灯珠串联在一起,数据像多米诺骨牌一样传递
  • SyncLights函数使用DMA(直接内存访问)技术快速发送数据:
    • DMA可以在不占用CPU的情况下传输数据
    • 发送完所有LED数据后,还要发送一个结束信号(wsCommit

六、特殊功能键处理模块:Fn键和触控条

bool HWKeyboard::FnPressed()
{
    return remapBuffer[9] & 0x02;                                  // 检查remapBuffer第9字节的第2位(Fn键状态)
}

uint8_t HWKeyboard::GetTouchBarState(uint8_t _id)
{
    uint8_t tmp = (remapBuffer[10] & 0b00000001) << 5 |            // 取remapBuffer第10字节的各个位,重新排列组合
              (remapBuffer[10] & 0b00000010) << 3 |
              (remapBuffer[10] & 0b00000100) << 1 |
              (remapBuffer[10] & 0b00001000) >> 1 |
              (remapBuffer[10] & 0b00010000) >> 3 |
              (remapBuffer[10] & 0b00100000) >> 5;
    return _id == 0 ? tmp : (tmp & (1 << (_id - 1)));              // 返回全部状态或指定触控条状态
}
白话解析:
  • 这部分处理键盘上的特殊功能键:Fn键和触控条
  • FnPressed函数检查Fn键是否按下:
    • 简单查看remapBuffer中的特定位,1表示按下,0表示未按下
    • Fn键在这个键盘中位于第9字节的第2位(从0开始计数)
  • GetTouchBarState函数读取触控条状态:
    • 触控条有多个触摸点,每个点对应remapBuffer[10]的一位
    • 函数进行位重排,使触摸点按从左到右的顺序排列
    • 参数_id为0时返回所有触摸点状态,否则返回特定触摸点状态

七、HID报告处理模块:电脑与键盘的"对话"

uint8_t* HWKeyboard::GetHidReportBuffer(uint8_t _reportId)
{
    switch (_reportId)
    {
        case 1:
            hidBuffer[0] = 1;                                      // 设置报告ID为1
            return hidBuffer;                                      // 返回主报告缓冲区
        case 2:
            hidBuffer[KEY_REPORT_SIZE] = 2;                        // 设置报告ID为2
            return hidBuffer + KEY_REPORT_SIZE;                    // 返回备用报告缓冲区
        default:
            return hidBuffer;                                      // 默认返回主报告缓冲区
    }
}

bool HWKeyboard::KeyPressed(KeyCode_t _key)
{
    int index, bitIndex;

    if (_key < RESERVED)                                           // 判断是否为保留键
    {
        index = _key / 8;                                          // 计算字节索引
        bitIndex = (_key + 8) % 8;                                 // 计算位索引
    } else
    {
        index = _key / 8 + 1;                                      // 计算字节索引(跳过修饰键)
        bitIndex = _key % 8;                                       // 计算位索引
    }

    return hidBuffer[index + 1] & (1 << bitIndex);                 // 检查对应位是否为1(按下)
}

void HWKeyboard::Press(HWKeyboard::KeyCode_t _key)
{
    int index, bitIndex;

    if (_key < RESERVED)
    {
        index = _key / 8;
        bitIndex = (_key + 8) % 8;
    } else
    {
        index = _key / 8 + 1;
        bitIndex = _key % 8;
    }

    hidBuffer[index + 1] |= (1 << bitIndex);                       // 设置对应位为1(按下)
}

void HWKeyboard::Release(HWKeyboard::KeyCode_t _key)
{
    int index, bitIndex;

    if (_key < RESERVED)
    {
        index = _key / 8;
        bitIndex = (_key + 8) % 8;
    } else
    {
        index = _key / 8 + 1;
        bitIndex = _key % 8;
    }

    hidBuffer[index + 1] &= ~(1 << bitIndex);                      // 清除对应位(释放)
}
白话解析:
  • 这部分处理键盘的HID报告,这是键盘与电脑通信的"官方语言"
  • GetHidReportBuffer函数准备不同类型的HID报告:
    • 报告ID 1:标准键盘报告
    • 报告ID 2:扩展功能报告(如多媒体键、自定义功能键)
  • KeyPressed函数检查某个键是否被按下:
    • 通过计算键码在HID报告中的位置(字节索引和位索引)
    • 特殊处理小于RESERVED的键(可能是修饰键如Ctrl、Shift等)
  • PressRelease函数模拟按键按下和释放:
    • 直接修改HID报告缓冲区中对应键的状态位
    • 这允许程序在不实际按键的情况下发送按键信号

📊 完整工作流程

一个按键从按下到被电脑识别的全过程:

  1. 硬件初始化

    • 设置SPI通信参数
    • 配置GPIO引脚
    • 初始化RGB灯为熄灭状态
  2. 按键扫描循环

    while(1) {
        ScanKeyStates();              // 扫描按键矩阵,读取原始状态
        ApplyDebounceFilter(5000);    // 应用5ms消抖滤波
        uint8_t layer = FnPressed() ? 1 : 0;  // 根据Fn键状态选择映射层
        Remap(layer);                 // 重映射键位,生成HID报告
        
        // 发送HID报告给电脑
        uint8_t* report = GetHidReportBuffer(1);
        USB_SendData(report, KEY_REPORT_SIZE);
        
        // 更新RGB灯效
        UpdateRgbEffects();
        SyncLights();
        
        HAL_Delay(10);  // 10ms扫描周期
    }
    
  3. 关键环节解析

    • 按键扫描:使用SPI读取74HC165移位寄存器中的按键状态
    • 消抖处理:比较两次扫描结果,忽略抖动引起的差异
    • 重映射处理:物理按键位置→逻辑按键位置→标准HID键码
    • RGB控制:设置每个LED的RGB值,通过DMA高速传输数据
    • USB通信:定期发送HID报告给电脑,告知当前按键状态

💡 小白开发指南

开发环境搭建

  1. 硬件准备

    • STM32F1/F4系列单片机(如STM32F103C8T6)
    • 74HC165移位寄存器(扩展输入IO)
    • WS2812B RGB灯珠
    • 机械键盘轴体和轴座
    • PCB电路板
  2. 软件工具

    • STM32CubeIDE或Keil MDK(代码编写和编译)
    • STM32CubeMX(单片机外设配置)
    • PCB设计软件(如立创EDA、Altium Designer)

从零开始的实现步骤

  1. 项目结构设计

    - main.c         // 主程序入口
    - hw_keyboard.h  // HWKeyboard类声明
    - hw_keyboard.cpp // HWKeyboard类实现
    - usb_device.c   // USB设备配置
    - key_map.h      // 键位映射表
    
  2. 关键硬件连接

    STM32 SPI1_MISO <- 74HC165 QH (串行数据输出)
    STM32 SPI1_CLK -> 74HC165 CLK (时钟信号)
    STM32 GPIO_PL -> 74HC165 PL (锁存信号)
    
    STM32 SPI2 -> WS2812B数据线(通过电平转换)
    
  3. 代码实现步骤

    • 实现ScanKeyStates函数,通过SPI读取按键状态
    • 添加ApplyDebounceFilter消抖处理
    • 实现Remap函数,完成键位映射
    • 添加RGB灯效控制函数
    • 最后实现USB通信部分
  4. 测试调试方法

    • 分阶段测试:先测试按键扫描,再测试灯效控制
    • 使用串口打印中间变量进行调试
    • 使用示波器观察SPI和WS2812B信号波形

📚 进阶知识点

1. 如何定制键位映射

键位映射是通过keyMap二维数组实现的:

// 示例键位映射表(简化版)
const uint16_t keyMap[2][64] = {
    // Layer 0: 标准层
    {
        KEY_ESC, KEY_1, KEY_2, KEY_3, /* 更多键... */
    },
    // Layer 1: Fn层
    {
        KEY_GRAVE, KEY_F1, KEY_F2, KEY_F3, /* 更多键... */
    }
};

定制步骤:

  1. 测量物理按键矩阵位置
  2. 确定每个位置对应的标准键码(参考USB HID标准)
  3. 填写到keyMap数组中

2. RGB灯效编程技巧

// 彩虹灯效示例
void RainbowEffect() {
    static uint8_t hue = 0;
    for(int i = 0; i < LED_NUMBER; i++) {
        // 创建彩虹色相滚动效果
        Color_t color = HsvToRgb(hue + i * 255 / LED_NUMBER, 255, 255);
        keyboard.SetRgbBufferByID(i, color, 0.5f); // 亮度50%
    }
    keyboard.SyncLights();
    hue++; // 颜色循环移动
}

// HSV转RGB颜色转换
Color_t HsvToRgb(uint8_t h, uint8_t s, uint8_t v) {
    Color_t rgb = {0, 0, 0};
    // 转换算法实现
    // ...
    return rgb;
}

3. 性能优化技巧

  1. 扫描频率优化

    • 降低扫描频率可节省CPU资源
    • 但过低会导致输入延迟
    • 推荐扫描频率:100Hz(10ms周期)
  2. DMA使用

    • 使用DMA传输RGB数据,释放CPU资源
    • 使用中断而非轮询等待DMA完成
  3. 内存优化

    • 使用位操作减少内存使用
    • 共用缓冲区减少RAM占用

🎯 实战项目:DIY全彩RGB机械键盘

完成这个教程后,你可以尝试以下项目:

  1. 简易版:61键迷你键盘

    • 标准QWERTY布局
    • 单色背光
    • 两层键位映射
  2. 进阶版:64键配置RGB

    • 增加方向键
    • 全RGB背光
    • 多种灯效模式
  3. 大师版:分体式人体工学键盘

    • 左右分离设计
    • 每键RGB可寻址
    • 支持无线蓝牙连接

通过本教程的学习,你已经掌握了机械键盘固件开发的核心技术。从简单的按键扫描到复杂的RGB控制,从底层硬件操作到高层次的用户体验,一步步揭开了机械键盘的神秘面纱。希望这份教程能帮助你开启DIY键盘的奇妙旅程!

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

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

相关文章

AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月8日第102弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀4-5个和值&#xff0c;可以做到100-300注左右。 (1)定…

【第九篇】 SpringBoot测试补充篇

简介 本文介绍了SpringBoot测试中的五项关键技术&#xff1a;测试类专用属性加载、 测试类专用Bean配置、 表现层测试方法、测试类事务回滚控制、配置文件随机数据设置&#xff09;。这些技术可以有效隔离测试环境&#xff0c;确保测试数据不影响生产环境&#xff0c;同时提供了…

springcloud SpringAmqp消息队列 简单使用

这期只是针对springBoot/Cloud 在使用SpringAmqp消息队列的时候遇到的坑。 前提 如果没有安装RabbitMQ是无法连接成功的&#xff01;所以前提是你要安装好RabbitMQ。 docker 安装命令 # 拉取docker镜像 docker pull rabbitmq:management# 创建容器 docker run -id --namera…

Framework开发之IMS逻辑浅析1--关键线程及作用

关键线程:EventHub,InputReader,InputDispatcher EventHub: 由于Android继承Linux,Linux的思想是一切皆文件,而输入的类型不止一种(触碰&#xff0c;写字笔&#xff0c;键盘等)&#xff0c;每种类型都对应一种驱动设备&#xff0c;而每个硬件驱动设备又对应Linux的一个目录文件…

系统思考:跳出症状看全局

明天将为华为全球采购认证管理部的伙伴们带来一场关于系统思考的深度课程&#xff01;通过经典的啤酒游戏经营决策沙盘&#xff0c;一起沉浸式体验如何从全局视角看待问题&#xff0c;发现单点最优并不等于全局最优。 这不仅是一次简单的课程&#xff0c;更是一次洞察系统背后…

DeepSeek R1 V2 深度探索:开源AI编码新利器,效能与创意并进

最近&#xff0c;AI界迎来了一位神秘的“突袭者”——DeepSeek团队悄无声息地发布了其推理模型DeepSeek R1的重磅升级版V2&#xff08;具体型号R1-0528&#xff09;。这款基于MIT许可的开源模型&#xff0c;在原版R1的基础上进行了多项令人瞩目的改进&#xff0c;正以其强大的潜…

surfer15安装

安装文件 安装包和破解文件 安装 破解及汉化 打开软件

Python训练营---DAY48

DAY 48 随机函数与广播机制 知识点回顾&#xff1a; 随机张量的生成&#xff1a;torch.randn函数卷积和池化的计算公式&#xff08;可以不掌握&#xff0c;会自动计算的&#xff09;pytorch的广播机制&#xff1a;加法和乘法的广播机制 ps&#xff1a;numpy运算也有类似的广播机…

debian12拒绝海外ip连接

确保 nftables 已安装&#xff1a; Debian 12 默认使用 nftables 作为防火墙框架。检查是否安装&#xff1a; sudo apt update sudo apt install nftables启用并启动 nftables 服务 sudo systemctl enable nftables sudo systemctl start nftables下载maxmind数据库 将文件解…

70年使用权的IntelliJ IDEA Ultimate安装教程

安装Java环境 下载Java Development Kit (JDK) 从Oracle官网或OpenJDK。推荐选择JDK 11或更高版本。 运行下载的安装程序&#xff0c;按照提示完成安装。注意记录JDK的安装路径&#xff08;如C:\Program Files\Java\jdk-11.0.15&#xff09;。 配置环境变量&#xff1a; 右键…

MySQL的日志

就相当于人的日记本&#xff0c;记录每天发生的事&#xff0c;可以对数据进行追踪 一、错误日志 也就是存放错误信息的 二、二进制日志-binlog 在低版本的MySQL中&#xff0c;二进制日志是不会默认开启的 存放除了查询语句的其他语句 三、查询日志 查询日志会记录客户端的所…

低功耗高安全:蓝牙模块在安防系统中的应用方案

随着物联网(IoT)和智能家居的快速发展&#xff0c;安防行业正迎来前所未有的技术革新。蓝牙模块作为一种低功耗、高稳定性的无线通信技术&#xff0c;凭借其低成本、易部署和智能化管理等优势&#xff0c;在安防领域发挥着越来越重要的作用。本文将探讨蓝牙模块在安防系统中的应…

C++定长内存块的实现

内存池 内存池是指程序预先从操作系统 申请一块足够大内存 &#xff0c;此后&#xff0c;当程序中需要申请内存的时候&#xff0c;不是直接向操作系统申请&#xff0c;而是 直接从内存池中获取 &#xff1b; 同理&#xff0c;当 **程序释放内存 **的时候&#xff0c;并不真正将…

Unity使用代码分析Roslyn Analyzers

一、创建项目&#xff08;注意这里不要选netstandard2.1会有报错&#xff09; 二、NuGet上安装Microsoft.CodeAnalysis.CSharp 三、实现[Partial]特性标注的类&#xff0c;结构体&#xff0c;record必须要partial关键字修饰 需要继承DiagnosticAnalyzer 注意一定要加特性Diagn…

大数据CSV导入MySQL

CSV Import MySQL 源码主要特性技术栈快速开始1. 环境要求2. 构建项目3. 使用方式交互式模式命令行模式编程方式使用 核心组件1. CsvService2. DatabaseService3. CsvImportService 数据类型映射性能优化1. 连接池优化2. 批量操作优化3. MySQL配置优化 配置说明application.yml…

MySQL 索引优化(Explain执行计划) 详细讲解

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 MySQL 索引优化&#xff08;Explain执行计划…

Cad 反应器 cad c#二次开发

在 AutoCAD C# 二次开发中&#xff0c;DocumentCollectionEventHandler 是一个委托&#xff08;delegate&#xff09;&#xff0c;用于处理与 AutoCAD 文档集合&#xff08;DocumentCollection&#xff09;相关的事件。它属于 AutoCAD .NET API 的事件处理机制&#xff0c;本质…

【websocket】安装与使用

websocket安装与使用 1. 介绍2. 安装3. websocketpp常用接口4. Websocketpp使用4.1 服务端4.2 客户端 1. 介绍 WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的 消息推送机制。 传统的 web 程序都是属于 “一问一答” 的形式&#xff0c;即客户端给服务器发送…

【大模型】LogRAG:基于检索增强生成的半监督日志异常检测

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构D 实验设计D.1 数据集/评估指标D.2 SOTAD.3 实验结果 E 个人总结E.1 优点E.2 不足 A 论文出处 论文题目&#xff1a;LogRAG: Semi-Supervised Log-based Anomaly Detection with Retrieval-Augmented …

基于SpringBoot实现的大创管理系统设计与实现【源码+文档】

基于SpringBootVue实现的大创管理系统采用前后端分离架构方式&#xff0c;系统设计了管理员、学生、指导老师、院系管理员两种角色&#xff0c;系统实现了用户登录与注册、个人中心、学生管理、指导老师管理、院系管理员管理、优秀项目管理、项目类型管理、项目信息管理、项目申…