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

【手把手教程】从零开始的机械键盘固件开发:HWKeyboard.h详解

前言

大家好,我是键盘DIY爱好者Despacito0o!今天想和大家分享我开发的机械键盘固件核心头文件HWKeyboard.h的设计思路和技术要点。这个项目是我多年来对键盘固件研究的心血结晶,希望能帮助更多对单片机开发和键盘DIY感兴趣的小伙伴入门!

本文将按模块详解每部分代码的具体作用和设计目的,让完全没有键盘开发经验的朋友也能一看就懂。后续文章会继续分享.cpp文件的实现细节,形成一个完整系列。

一、为什么要自己开发键盘固件?

在开始代码解析前,先聊聊为什么要自己写键盘固件:

  1. 学习目的:深入理解单片机编程和嵌入式系统
  2. 个性化需求:市面上的键盘功能很难完全满足个人需求
  3. DIY乐趣:自己设计的键盘、自己写的固件,用起来格外有成就感
  4. 开发能力提升:涉及SPI通信、USB协议、RGB驱动等多种技术

二、整体架构设计目的

我设计这个键盘固件的主要目标是:

  1. 模块化设计:核心功能独立封装,便于扩展和维护
  2. 高效率:采用SPI批量读取按键状态,降低扫描延迟
  3. 丰富功能:支持RGB灯效、多层按键映射、触控条等
  4. 可定制性:预留足够扩展接口,方便用户个性化配置

下面就正式开始代码详解!

三、HWKeyboard类定义与初始化

#ifndef HELLO_WORD_KEYBOARD_FW_HW_KEYBOARD_H
#define HELLO_WORD_KEYBOARD_FW_HW_KEYBOARD_H#include "spi.h" // 引入SPI相关头文件,用于与74HC165和WS2812B通信// 硬件键盘类定义 - 整合键盘所有硬件控制功能
class HWKeyboard
{
public:// 构造函数,传入已初始化的SPI句柄explicit HWKeyboard(SPI_HandleTypeDef* _spi) :spiHandle(_spi) // 将SPI句柄存储到类成员变量{scanBuffer = &spiBuffer[1]; // scanBuffer指向spiBuffer的第2个字节,第1个字节用于SPI命令// 使能74HC165芯片(拉低CE引脚激活芯片)HAL_GPIO_WritePin(CE_GPIO_Port,CE_Pin,GPIO_PIN_RESET);// 初始化所有RGB灯为关闭状态for (uint8_t i = 0; i < HWKeyboard::LED_NUMBER; i++)SetRgbBufferByID(i, HWKeyboard::Color_t{0, 0, 0});}

模块设计目的

  • 构造函数设计初衷是简化键盘初始化流程,只需传入一个SPI句柄,就能完成所有硬件初始化
  • SPI句柄传递意在将底层硬件控制与键盘逻辑分离,提高代码可移植性
  • scanBuffer偏移设计是因为SPI传输需要命令字节,实际有效数据从第2个字节开始
  • CE引脚控制用于激活74HC165移位寄存器,是扫描电路的核心控制信号
  • RGB灯初始化为关闭是一个安全设计,避免上电瞬间灯光异常

四、常量定义模块

    // 常量定义区 - 配置键盘硬件参数static const uint8_t IO_NUMBER = 11 * 8;    // IO总数:11片74HC165,每片8位,共88个IO点static const uint8_t KEY_NUMBER = 82;       // 按键总数:82个物理按键static const uint8_t TOUCHPAD_NUMBER = 6;   // 触控条数量:6个电容触摸点static const uint8_t LED_NUMBER = 104;      // RGB灯数量:104颗WS2812B可编程灯珠static const uint16_t KEY_REPORT_SIZE = 1 + 16; // 键盘HID报告长度:1字节报告ID + 16字节键盘数据static const uint16_t RAW_REPORT_SIZE = 1 + 32; // 原始报告长度:1字节报告ID + 32字节原始扫描数据static const uint16_t HID_REPORT_SIZE = KEY_REPORT_SIZE + RAW_REPORT_SIZE; // 完整HID报告总长度

模块设计目的

  • 使用静态常量明确定义硬件规格,方便后续修改适配不同的键盘布局
  • IO_NUMBER设为88是为了预留足够的IO口,实际使用82个物理按键
  • 分离KEY_NUMBER和IO_NUMBER是考虑到部分IO可能用于特殊功能而非按键
  • TOUCHPAD_NUMBER定义触控点数量,用于后续触控条功能的实现
  • HID报告大小严格按照USB标准制定,确保与操作系统兼容

五、键码枚举模块

    // 键码枚举定义 - 遵循USB HID标准,方便进行按键映射enum KeyCode_t : int16_t{/*------------------------- HID报告数据定义 -------------------------*/LEFT_CTRL = -8,LEFT_SHIFT = -7,LEFT_ALT = -6,LEFT_GUI = -5, // 左侧修饰键(负值方便识别)RIGHT_CTRL = -4,RIGHT_SHIFT = -3,RIGHT_ALT = -2,RIGHT_GUI = -1, // 右侧修饰键(Windows/Command键)RESERVED = 0,ERROR_ROLL_OVER,POST_FAIL,ERROR_UNDEFINED, // 保留键值和错误码(0-3)A,B,C,D,E,F,G,H,I,J,K,L,M, // 字母键A-M(4-16)N,O,P,Q,R,S,T,U,V,W,X,Y,Z, // 字母键N-Z(17-29)NUM_1/*1!*/,NUM_2/*2@*/,NUM_3/*3#*/,NUM_4/*4$*/,NUM_5/*5%*/, // 数字键1-5(30-34)NUM_6/*6^*/,NUM_7/*7&*/,NUM_8/*8**/,NUM_9/*9(*/,NUM_0/*0)*/, // 数字键6-0(35-39)ENTER,ESC,BACKSPACE,TAB,SPACE, // 常用功能键(40-44)MINUS/*-_*/,EQUAL/*=+*/,LEFT_U_BRACE/*[{*/,RIGHT_U_BRACE/*]}*/, // 符号键(45-48)BACKSLASH/*\|*/,NONE_US/**/,SEMI_COLON/*;:*/,QUOTE/*'"*/, // 符号键(49-52)GRAVE_ACCENT/*`~*/,COMMA/*,<*/,PERIOD/*.>*/,SLASH/*/?*/, // 符号键(53-56)// ...(省略部分键码定义以简化显示)FN = 1000 // Fn功能键,使用1000作为特殊值(超出标准HID范围)/*------------------------- HID报告数据定义结束 -------------------------*/};

模块设计目的

  • 用枚举类型定义所有键码,使代码更易读,避免直接使用数字常量
  • 修饰键使用负值,普通键使用正值,便于程序判断键的类型
  • 严格遵循USB HID标准键码顺序,确保与操作系统完全兼容
  • FN键使用1000这个特殊值,因为它是自定义功能键,不属于标准USB HID键码
  • 注释中标明每个键的实际符号,提高代码可读性

六、颜色结构体与WS2812B协议定义

    // RGB颜色结构体定义 - 存储单个灯珠的RGB值struct Color_t{uint8_t r; // 红色分量 (0-255)uint8_t g; // 绿色分量 (0-255)uint8_t b; // 蓝色分量 (0-255)};// WS2812B协议字节定义 - SPI模拟WS2812B时序关键enum SpiWs2812Byte_t : uint8_t{WS_HIGH = 0xFE, // 表示WS2812B协议中的"1"位 (二进制: 11111110)WS_LOW = 0xE0   // 表示WS2812B协议中的"0"位 (二进制: 11100000)};

模块设计目的

  • Color_t结构体简化RGB颜色处理,使设置灯光效果代码更加直观
  • SpiWs2812Byte_t枚举是本固件的一个创新点,用SPI模拟WS2812B协议
  • 0xFE和0xE0这两个特殊值经过精确计算,在特定SPI时钟频率下恰好满足WS2812B的时序要求
  • 使用枚举而非直接使用数值,增强代码可读性和可维护性

技术拓展:为什么选择0xFE和0xE0作为WS2812B协议的高低位表示?

WS2812B要求"1"位的高电平持续时间约为800ns,低电平约为450ns;"0"位的高电平约为400ns,低电平约为850ns。按8MHz SPI时钟计算,一位传输需要125ns,因此0xFE(11111110)提供了7位高电平(875ns)和1位低电平(125ns),而0xE0(11100000)提供了3位高电平(375ns)和5位低电平(625ns),非常接近WS2812B的时序要求。

七、功能函数声明模块

    // 功能函数声明区 - 键盘核心功能接口uint8_t* ScanKeyStates();                        // 扫描按键状态,通过SPI读取74HC165数据void ApplyDebounceFilter(uint32_t _filterTimeUs = 100); // 应用按键消抖,消除机械开关抖动uint8_t* Remap(uint8_t _layer = 1);              // 按键重映射,将物理按键转换为逻辑键码void SyncLights();                              // 同步RGB灯光,通过SPI将数据发送到WS2812Bbool FnPressed();                               // 检测Fn键是否按下,用于层切换bool KeyPressed(KeyCode_t _key);                // 检测指定键码是否按下,用于组合键判断void Press(KeyCode_t _key);                     // 模拟按下某键,用于宏功能void Release(KeyCode_t _key);                   // 模拟释放某键,配合Press使用uint8_t* GetHidReportBuffer(uint8_t _reportId); // 获取HID报告缓冲区,用于USB通信uint8_t GetTouchBarState(uint8_t _id = 0);      // 获取触控条状态,实现触控功能void SetRgbBufferByID(uint8_t _keyId, Color_t _color, float _brightness = 1); // 设置RGB灯颜色和亮度

模块设计目的

  • 提供完整的功能接口集,将复杂的底层操作封装成简单易用的函数
  • 遵循单一职责原则,每个函数只负责一个明确的功能,便于调试和维护
  • 参数默认值设计,如默认消抖时间100μs、默认使用第1层按键映射等,简化调用
  • 函数命名清晰表达功能,如ScanKeyStatesApplyDebounceFilter等,提高代码可读性

八、按键映射表模块

    // 按键映射表(多层)- 核心功能:实现按键多层定义int16_t keyMap[5][IO_NUMBER] = {// 物理按键到逻辑键的映射(0层,物理布局,标识PCB上按键的实际位置索引){67,61,60,58,59,52,55,51,50,49,48,47,46,3,80,81,64,57,62,63,53,54,45,44,40,31,26,18,2,19,70,71,66,65,56,36,37,38,39,43,42,41,28,1,15,74,73,72,68,69,29,30,35,34,33,32,24,0,14,76,77,78,79,16,20,21,22,23,27,25,17,4,13,12,8,75,9,10,7,11,6,5,86,84,82,87,85,83}, // TouchBar索引位置(最后6个值)// 第一层映射(标准QWERTY键盘布局,日常使用的基础层){ESC,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,PAUSE,GRAVE_ACCENT,NUM_1,NUM_2,NUM_3,NUM_4,NUM_5,NUM_6,NUM_7,NUM_8,NUM_9,NUM_0,MINUS,EQUAL,BACKSPACE,INSERT,TAB,Q,W,E,R,T,Y,U,I,O,P,LEFT_U_BRACE,RIGHT_U_BRACE,BACKSLASH,DELETE,CAP_LOCK,A,S,D,F,G,H,J,K,L,SEMI_COLON,QUOTE,ENTER,PAGE_UP,LEFT_SHIFT,Z,X,C,V,B,N,M,COMMA,PERIOD,SLASH,RIGHT_SHIFT,UP_ARROW,PAGE_DOWN,LEFT_CTRL,LEFT_GUI,LEFT_ALT,SPACE,RIGHT_ALT,FN,RIGHT_CTRL,LEFT_ARROW,DOWN_ARROW,RIGHT_ARROW},// 第二层映射(自定义功能层,按下Fn键时激活){ESC,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,PAUSE,GRAVE_ACCENT,NUM_1,NUM_2,NUM_3,NUM_4,NUM_5,NUM_6,NUM_7,NUM_8,NUM_9,NUM_0,MINUS,EQUAL,BACKSPACE,INSERT,TAB,A,B,C,D,E,F,G,H,I,J,LEFT_U_BRACE,RIGHT_U_BRACE,BACKSLASH,DELETE,CAP_LOCK,K,L,M,N,O,P,Q,R,S,SEMI_COLON,QUOTE,ENTER,PAGE_UP,LEFT_SHIFT,T,U,V,W,X,Y,Z,COMMA,PERIOD,SLASH,RIGHT_SHIFT,A,PAGE_DOWN,LEFT_CTRL,LEFT_GUI,LEFT_ALT,SPACE,RIGHT_ALT,FN,RIGHT_CTRL,LEFT_ARROW,DOWN_ARROW,RIGHT_ARROW}};

模块设计目的

  • 设计多层按键映射机制,实现一键多功能,大大提高键盘的可用性
  • 第0层(物理层)存储每个按键在电路中的实际位置索引,不是功能映射
  • 第1层是标准QWERTY键盘布局,作为默认使用层
  • 第2层是演示用的自定义层,将字母区重新排列为ABCDEF顺序
  • 预留5层空间(keyMap[5][IO_NUMBER]),为将来扩展更多功能层提供可能
  • 使用前面定义的键码枚举值,使映射表更加清晰易读

知识拓展:多层按键映射的实际应用

多层按键映射是现代机械键盘的重要功能,允许在不增加物理按键的情况下实现更多功能:

  • 媒体控制层:在Fn+F1~F12可以映射为音量控制、播放/暂停等多媒体功能
  • 鼠标控制层:将WASD键映射为鼠标移动,实现无鼠标操作
  • 宏功能层:将常用的按键组合映射到单个按键,提高工作效率
  • 游戏专用层:为不同游戏定制专用按键布局

九、状态标志与私有成员变量

    volatile bool isRgbTxBusy;    // RGB灯DMA传输忙标志,用于中断同步bool isCapsLocked = false;    // 大写锁定状态标志,用于CapsLock LED控制private:SPI_HandleTypeDef* spiHandle; // SPI句柄指针,用于底层硬件通信uint8_t spiBuffer[IO_NUMBER / 8 + 1]{}; // SPI接收缓冲区(每8个IO点占用1字节,外加1字节命令)uint8_t* scanBuffer;          // 扫描缓冲区指针,指向spiBuffer中的有效数据部分uint8_t debounceBuffer[IO_NUMBER / 8 + 1]{}; // 按键消抖缓冲区,存储上一次稳定的按键状态uint8_t hidBuffer[HID_REPORT_SIZE]{};        // HID报告缓冲区,用于USB通信uint8_t remapBuffer[IO_NUMBER / 8]{};        // 按键重映射缓冲区,存储逻辑按键状态uint8_t rgbBuffer[LED_NUMBER][3][8]{};       // RGB灯数据缓冲区,3色各8位,存储WS2812B时序数据uint8_t wsCommit[64] = {0};                  // WS2812B协议复位信号缓冲区(至少50µs低电平)uint8_t brightnessPreDiv = 2;                // RGB亮度预分频(值为2表示亮度为1/4)
};#endif

模块设计目的

  • 公有标志变量:提供给外部访问的状态标志
    • isRgbTxBusy设计为volatile是因为它会在中断中被修改,避免编译器优化导致的问题
    • isCapsLocked用于跟踪大写锁定状态,便于实现CapsLock LED指示
  • 私有成员变量:封装内部数据结构,防止外部直接访问
    • 缓冲区设计遵循数据处理流程:spiBufferdebounceBufferremapBufferhidBuffer
    • rgbBuffer特殊设计为三维数组,精确映射WS2812B的时序要求
    • wsCommit是WS2812B协议结束信号,确保所有LED能正确锁存数据

十、实际应用详解

下面通过一个具体例子,演示这个键盘类的完整工作流程:

// 1. 包含必要头文件
#include "hw_keyboard.h"
#include "spi.h"  // STM32 HAL库
#include "usbd_hid.h" // USB设备HID库// 2. 全局变量定义
extern SPI_HandleTypeDef hspi1;  // 假设在CubeMX中已配置SPI1
extern USBD_HandleTypeDef hUsbDeviceFS; // USB设备句柄
HWKeyboard myKeyboard(&hspi1);  // 创建键盘对象// 3. 自定义RGB灯效 - 呼吸灯效果
void breathingEffect(HWKeyboard &kb, uint32_t timeMs) {// 计算亮度值(0-255之间呼吸变化)uint8_t brightness = (sin(timeMs * 0.001f) + 1.0f) * 127.5f;// 设置所有按键为相同颜色,但亮度随时间变化for (uint8_t i = 0; i < HWKeyboard::LED_NUMBER; i++) {// 使用蓝色作为基础颜色,亮度随时间变化kb.SetRgbBufferByID(i, HWKeyboard::Color_t{0, 0, brightness});}// 同步灯光数据到WS2812Bkb.SyncLights();
}// 4. 主程序循环
void mainLoop() {uint32_t currentTime = HAL_GetTick(); // 获取当前时间(毫秒)static uint32_t lastReportTime = 0;   // 上次发送HID报告的时间static uint32_t lastLightTime = 0;    // 上次更新灯光的时间// 4.1 按键扫描和处理(1ms周期)if (currentTime - lastReportTime >= 1) {// 扫描按键状态myKeyboard.ScanKeyStates();// 应用消抖滤波myKeyboard.ApplyDebounceFilter();// 检测Fn键状态,确定当前使用的映射层uint8_t currentLayer = myKeyboard.FnPressed() ? 2 : 1;// 执行按键重映射,生成逻辑按键状态myKeyboard.Remap(currentLayer);// 获取键盘HID报告并通过USB发送uint8_t* keyReport = myKeyboard.GetHidReportBuffer(1);USBD_HID_SendReport(&hUsbDeviceFS, keyReport, HWKeyboard::KEY_REPORT_SIZE);// 更新上次发送时间lastReportTime = currentTime;}// 4.2 灯光效果更新(20ms周期,避免频繁更新造成闪烁)if (currentTime - lastLightTime >= 20 && !myKeyboard.isRgbTxBusy) {// 调用呼吸灯效果函数breathingEffect(myKeyboard, currentTime);// 更新上次灯光更新时间lastLightTime = currentTime;}
}

实现要点解析

  1. 初始化流程

    • 创建键盘对象时只需传入SPI句柄,简化初始化
    • 构造函数自动完成硬件初始化,无需额外代码
  2. 按键处理流水线

    • 扫描原始按键状态 → 消抖处理 → 层选择 → 重映射 → 生成HID报告 → 发送USB数据
    • 整个流程清晰,每步对应一个函数调用
  3. 灯光效果实现

    • 示例中实现了简单的呼吸灯效果,适合入门学习
    • 使用isRgbTxBusy避免在DMA传输过程中修改灯光数据
    • 灯光更新频率比按键扫描低,避免过度占用CPU资源
  4. 并行任务处理

    • 按键扫描和灯光控制使用不同的更新周期,实现并行处理
    • 时间戳机制确保任务按照预定间隔执行

十一、开发中的技术难点与解决方案

在开发这个键盘固件的过程中,我遇到了几个关键技术难点:

1. 按键抖动处理

难点:机械开关按下或释放时会产生数毫秒的抖动,导致一次按键被识别为多次。

解决方案

  • 实现了时间窗口消抖算法,记录状态变化点并延迟确认
  • ApplyDebounceFilter()中,通过比较当前状态与上次稳定状态来判断变化
  • 当检测到变化时,等待指定时间(默认100μs)后再次确认,确保状态稳定

2. SPI模拟WS2812B时序

难点:WS2812B要求严格的时序,传统方法需要精确的延时控制,难以实现。

解决方案

  • 创新地使用SPI接口发送特定字节模式来模拟WS2812B时序
  • WS_HIGHWS_LOW两种字节模式在特定SPI频率下恰好满足时序要求
  • 通过DMA传输大量数据,避免CPU干预,实现稳定可靠的灯光控制

3. 多层按键映射实现

难点:如何高效地实现按键层切换,同时保证响应速度。

解决方案

  • 使用二维数组存储多层映射关系,第一维是层索引,第二维是按键索引
  • 通过判断Fn键状态动态选择当前激活层
  • Remap()函数实现从物理按键到逻辑按键的转换映射

十二、拓展知识:自制键盘的完整流程

想要完全自制一把机械键盘,整体流程大致如下:

  1. 设计键盘布局

    • 选择键盘尺寸(60%、75%、TKL、全尺寸等)
    • 设计键位布局(ANSI、ISO或自定义)
  2. 设计硬件电路

    • 选择单片机(本项目使用STM32F103)
    • 设计键盘矩阵电路(本项目使用74HC165方案)
    • 规划RGB灯珠布局(WS2812B)
  3. PCB设计与制作

    • 使用KiCad或Altium Designer设计PCB
    • 发送至PCB厂商制作
  4. 固件开发(本文重点)

    • 编写按键扫描代码
    • 实现消抖算法
    • 开发多层按键映射功能
    • 实现RGB灯效控制
    • 开发USB通信模块
  5. 外壳设计与3D打印

    • 使用Fusion 360等软件设计键盘外壳
    • 3D打印或CNC加工外壳
  6. 组装与调试

    • 焊接元器件
    • 安装轴体与键帽
    • 烧录固件并调试

总结

本文详细介绍了一个完整的机械键盘固件头文件设计,从硬件接口到功能实现,逐模块进行了解析。这个.h文件为后续.cpp文件的实现奠定了基础,定义了清晰的接口和数据结构。

通过这个项目,我们不仅实现了基本的键盘功能,还加入了RGB灯效、多层按键映射、触控条等高级特性。希望这篇教程能帮助更多对键盘DIY感兴趣的朋友入门,为你的定制键盘之旅提供参考。

在下一篇文章中,我将分享.cpp文件的实现细节,敬请期待!


关键词:机械键盘固件、单片机编程、SPI通信、WS2812B驱动、多层按键映射、HID协议、DIY机械键盘、STM32开发

本文作者:Despacito0o | 出处:CSDN | 原创文章,欢迎转载,请注明出处

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

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

相关文章

2048游戏的技术实现分析-完全Java和Processing版

目录 简介Processing库基础项目构建指南项目结构核心数据结构游戏核心机制图形界面实现性能优化代码详解设计模式分析测试策略总结与展望简介 2048是一款由Gabriele Cirulli开发的经典益智游戏。本文将深入分析其Java实现版本的技术细节。该实现使用了Processing库来创建图形界…

Spring Boot + Elasticsearch + HBase 构建海量数据搜索系统

Spring Boot Elasticsearch HBase 构建海量数据搜索系统 &#x1f4d6; 目录 1. 系统需求分析2. 系统架构设计3. Elasticsearch 与 HBase 集成方案4. Spring Boot 项目实现5. 大规模搜索系统最佳实践 项目概述 本文档提供了基于 Spring Boot、Elasticsearch 和 HBase 构建…

【iOS】YYModel源码解析

YYModel源码解析 文章目录 YYModel源码解析前言YYModel性能优势YYModel简介YYClassInfo解析YYClassIvarInfo && objc_ivarYYClassMethodInfo && objc_methodYYClassPropertyInfo && property_tYYClassInfo && objc_class YYClassInfo的初始化细…

宇树科技更名“股份有限公司”深度解析:机器人企业IPO前奏与资本化路径

从技术落地到资本跃迁&#xff0c;拆解股改背后的上市逻辑与行业启示 核心事件&#xff1a;股改释放的上市信号 2025年5月28日&#xff0c;杭州宇树科技有限公司正式更名“杭州宇树科技股份有限公司”&#xff0c;市场主体类型变更为“股份有限公司”。尽管官方称为常规运营调…

Android Native 内存泄漏检测全解析:从原理到工具的深度实践

引言 Android应用的内存泄漏不仅发生在Java/Kotlin层&#xff0c;Native&#xff08;C/C&#xff09;层的泄漏同样普遍且隐蔽。由于Native内存不受Java虚拟机&#xff08;JVM&#xff09;管理&#xff0c;泄漏的内存无法通过GC自动回收&#xff0c;长期积累会导致应用内存占用…

Vortex GPGPU的github流程跑通与功能模块波形探索(四)

文章目录 前言一、demo的输入文件二、trace_csv三、2个值得注意的点3.1 csv指令表格里面的tmask&#xff1f;3.2 rtlsim和simx的log文件&#xff1f; 总结 前言 跟着前面那篇最后留下的几个问题接着把输出波形文件和csv文件的输入、输出搞明白&#xff01; 一、demo的输入文件…

UnityPSD文件转UI插件Psd2UnityuGUIPro3.4.0u2017.4.2介绍:Unity UI设计的高效助手

UnityPSD文件转UI插件Psd2UnityuGUIPro3.4.0u2017.4.2介绍&#xff1a;Unity UI设计的高效助手 【下载地址】UnityPSD文件转UI插件Psd2UnityuGUIPro3.4.0u2017.4.2介绍 这款开源插件将PSD文件无缝转换为Unity的UI元素&#xff0c;极大提升开发效率。它支持一键转换&#xff0c;…

力扣100题之128. 最长连续序列

方法1 使用了hash 方法思路 使用哈希集合&#xff1a;首先将数组中的所有数字存入一个哈希集合中&#xff0c;这样可以在 O(1) 时间内检查某个数字是否存在。 寻找连续序列&#xff1a;遍历数组中的每一个数字&#xff0c;对于每一个数字&#xff0c; 检查它是否是某个连续序列…

Java爬虫技术详解:原理、实现与优势

一、什么是网络爬虫&#xff1f; 网络爬虫&#xff08;Web Crawler&#xff09;&#xff0c;又称网络蜘蛛或网络机器人&#xff0c;是一种自动化程序&#xff0c;能够按照一定的规则自动浏览和抓取互联网上的信息。爬虫技术是大数据时代获取网络数据的重要手段&#xff0c;广泛…

神经网络与深度学习 网络优化与正则化

1.网络优化存在的难点 &#xff08;1&#xff09;结构差异大&#xff1a;没有通用的优化算法&#xff1b;超参数多 &#xff08;2&#xff09;非凸优化问题&#xff1a;参数初始化&#xff0c;逃离局部最优 &#xff08;3&#xff09;梯度消失&#xff08;爆炸&#xff09; …

【汇编逆向系列】二、函数调用包含单个参数之整型-ECX寄存器,LEA指令

目录 一. 汇编源码 二. 汇编分析 1. ECX寄存器 2. 栈位置计算​ 3. 特殊指令深度解析 三、 汇编转化 一. 汇编源码 single_int_param:0000000000000040: 89 4C 24 08 mov dword ptr [rsp8],ecx0000000000000044: 57 push rdi0000…

Linux进程替换以及exec六大函数运用

文章目录 1.进程替换2.替换过程3.替换函数exec3.1命名解释 4.细说6个exe函数execl函数execvexeclp、execvpexecle、execve 1.进程替换 fork&#xff08;&#xff09;函数在创建子进程后&#xff0c;子进程如果想要执行一个新的程序&#xff0c;就可以使用进程的程序替换来完成…

Selenium操作指南(全)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 大家好&#xff0c;今天带大家一起系统的学习下模拟浏览器运行库Selenium&#xff0c;它是一个用于Web自动化测试及爬虫应用的重要工具。 Selenium测试直接运行在…

结构性设计模式之Facade(外观)设计模式

结构性设计模式之Facade&#xff08;外观&#xff09;设计模式 前言&#xff1a; 外观模式&#xff1a;用自己的话理解就是用户看到是一个总体页面&#xff0c;比如xx报名系统页面。里面有历年真题模块、报名模块、教程模块、首页模块… 做了一个各个模块的合并&#xff0c;对…

RabbitMQ实用技巧

RabbitMQ是一个流行的开源消息中间件&#xff0c;广泛用于实现消息传递、任务分发和负载均衡。通过合理使用RabbitMQ的功能&#xff0c;可以显著提升系统的性能、可靠性和可维护性。本文将介绍一些RabbitMQ的实用技巧&#xff0c;包括基础配置、高级功能及常见问题的解决方案。…

Linux(10)——第二个小程序(自制shell)

目录 ​编辑 一、引言与动机 &#x1f4dd;背景 &#x1f4dd;主要内容概括 二、全局数据 三、环境变量的初始化 ✅ 代码实现 四、构造动态提示符 ✅ 打印提示符函数 ✅ 提示符生成函数 ✅获取用户名函数 ✅获取主机名函数 ✅获取当前目录名函数 五、命令的读取与…

环境变量深度解析:从配置到内核的全链路指南

文章目录 一、基础概念与核心作用二、常见环境变量三、操作指南&#xff1a;从查看、修改到调试3.1 快速查询3.2 PATH 原理与配置实践3.2.1 命令执行机制3.2.2 路径管理策略 四、编程接口与内存模型4.1 环境变量的内存结构4.2 C 语言访问方式4.2.1 直接访问&#xff08;main 参…

结合Jenkins、Docker和Kubernetes等主流工具,部署Spring Boot自动化实战指南

基于最佳实践的Spring Boot自动化部署实战指南,结合Jenkins、Docker和Kubernetes等主流工具,提供从环境搭建到生产部署的完整流程: 一、环境准备与工具选型​​ ​​1.基础设施​​ ​​Jenkins服务器​​:安装Jenkins LTS版本,配置JDK(推荐JDK 11+)及Maven/Gradle插…

动态规划---股票问题

1.在推状态转移方程的途中&#xff0c;箭头的起始点表示前一天的状态&#xff0c;箭头的终点是当天的状态 2.当动态规划中涉及到多状态&#xff0c;且状态之间可以相互转换&#xff0c;要画图去分析 1.买卖股票的最佳时机含冷冻期 题目链接&#xff1a;309. 买卖股票的最佳时机…

ObjectMapper 在 Spring 统一响应处理中的作用详解

ObjectMapper 是 Jackson 库的核心类&#xff0c;专门用于处理 JSON 数据的序列化&#xff08;Java 对象 → JSON&#xff09;和反序列化&#xff08;JSON → Java 对象&#xff09;。在你提供的代码中&#xff0c;它解决了字符串响应特殊处理的关键问题。 一、为什么需要 Obj…