使用Pro micro(ATMEGA32U4)作为主控制作的20键全宏定义键盘,具有RGB功能,单引脚控制WS2811/WS2812 RGB灯带,可以定义矩阵键盘及RGB控制IO。
具有三个不同定义的按键层,四个平行线程来分别处理按键、宏、RGB灯效以及保留功能按键。每层均可定义普通按键以及宏按键。
可以使用IIC总线与SSD1306控制的OLED显示屏通信,实现键盘状态显示。
短按MODE按键切换到键盘层设置,通过轻按对应按键选择1~20号按键层,定义可在Keydefine文件中查看。
通过FN键可以使用对应按键层的宏功能。其中第三按键层预设了一部分宏用作演示。
1 | 2 | 3 | 4 |
---|---|---|---|
Ctrl+B | Ctrl+TAB | Ctrl+T | Ctrl+W |
Ctrl+1 | Ctrl+pageup | Ctrl+pagedown | Ctrl+2 |
计算器 | 静音 | 音量减少 | 音量增加 |
Ctrl+Alt+A | Ctrl+D | Ctrl+Shift+Z | Ctrl+Z |
FN | Ctrl+C | Ctrl+V | Ctr+S |
长按MODE按键进入设置状态,按键定义如下表。
1 | 2 | 3 | 4 |
---|---|---|---|
亮度设置为0 | 亮度设置为默认 | 亮度减少 | 亮度增加 |
白光常亮灯效 | 单点亮彩虹 | 同步彩虹 | 波浪彩虹 |
设置默认按键层为1 | 设置默认按键层为2 | 设置默认按键层为3 | 全部恢复默认设置 |
- HID-Project库:键盘USB功能主要支撑以及扩展 https://github.com/NicoHood/HID
- Keypad库:为矩阵键盘识别提供一些支持 https://github.com/Chris--A/Keypad
- Adafruit_NeoPixel库:驱动WS2811芯片驱动RGB LED,并提供一部分灯效 https://github.com/adafruit/Adafruit_NeoPixel
- EEPROM库:官方库,为用户设置存储提供支持
- Wire库:IIC通信库,未直接使用,仅为OLED显示库提供支持
- SSD1306Ascii & SSD1306AsciiWire库:OLED显示驱动库,可显示字符串 https://github.com/greiman/SSD1306Ascii
- SchedulerARMAVR库:Scoop库中为AVR单片机设计的多线程任务调度器库 https://github.com/fabriceo/SCoop
- OneButton库:独立按键有限状态机识别库,为Mode按键的稳定识别提供支持 https://github.com/mathertel/OneButton
- 修改了一些并没有什么卵用的BUG
- 现在可以将一个按键定义为宏直通型按键
- 现在在使用宏的时候可以正常使用修饰键了
- 以上功能主要为新键盘服务,新键盘固件编号将继承当前编号,但是会存放在新的GitHub中
- 对代码进行了简化,重构了按键事件响应逻辑,节约了20%的程序体积
- 更改了按键编号定义方式,统一为从0开始
- 测试了增加按键数量的消耗,每增加一个矩阵按键约消耗25字节RAM,程序空间消耗由该按键对应的宏函数决定。因增加按键而增加的LED点,每个约消耗5字节RAM。
- 没别的,桌面软件写好了,上世纪的界面,代码乱的一比,我也看不懂为啥没有bug,调整了一些通信部分的bug就随便搓了个界面,用的Qt库,代码见Qt_code文件夹
- 上传编译好的桌面软件,可以直接用,我保证没有病毒
- 删除了一部分不需要存在的代码
- 修改了串口功能,增加了回报设置是否成功的功能
- 桌面通信软件核心功能实现,正在测试
- 修正了一些OLED显示的bug
- 添加了接受上位机串口信息来设置按键层的功能,错误会汇报-1,正确会汇报输入数据
- macro.cpp文件中定义了一些实例宏,不要问这些是干什么的
- 对应在OLED.cpp文件中定义了两个对应的最后一行实例显示,也别问!
- OLED.cpp文件中增加了一个按照键盘层显示不同信息的功能
- 添加了一些注释
- 按键层结构重置,现在可以部署20个不同的按键层,宏仍然可以按照按键层区分激活
- 按键层选择通过轻点mode键,随后在20个键盘按键中选择一个按键层
- 取消了上一个版本中的Setting Mode,不再可以设置默认按键层
- 取消了原来的第三层设定(即宏层),所以层均不可以不使用FN键激活宏
- 只有17号按键可以被设定为FN键,其他按键不会对设定做出响应
- 换用OneButton库识别Mode按键以提高按键识别的稳定性
- 简化了一部分代码
- 将LED setting模式变更为Setting Mode,加入了默认按键层设置功能,可以在原先的LED Setting模式(现在的Setting Mode)中设置
- 单点亮灯效加入了渐隐功能
- 部分设置功能放入Setting.h文件中
- 优化了led设置的代码来试图提高运行速度
- 修正了FN键按住时进入LED设置导致FN一直使能的问题
- 层2的17号按键可以定义为其他按键了,也可以继续作为FN使用
- 取消了HOLD文件,HOLD命名,解决了历史遗留问题
- 优化了一部分代码体积
- 添加了五分钟无动作自动关闭LED节能以及OLED保护功能
- 修正了抬起其他按键使得当前按键宏失效的问题
- 修改按键宏使能方案,17号按键在layer1&2层用作FN多功能组合键
- Layer1层按住FN键将使得下一次按下被引导进宏,宏也可以发送一个普通按键或者字符串
- Layer2层宏定义不再需要将按键定义为KEY_RESERVED,只需短按FN键即可起用
- 为FN按键状态添加OLED显示
- 添加了显示函数,可以通过简单修改一个变量值来控制最后一行显示的内容
- 添加了新的显示更新方式,当显示控制变量改变时刷新屏幕
- 修正LED灯效切换时延时的BUG
- 添加LED亮度多级调节
- 更换了灯效一和二
- 优化了用户灯光设置存储
- 小幅优化代码效率
- 删除了无效的代码,精简逻辑减少资源消耗
- 使用Scoop库设计四个合作多线程
- 可以定义死循环宏而不影响其他任务
- Layer1和layer2层按键使用数组设置方便快捷
- LED专用设置层,定义4种亮度,4种灯效,还有12个按键空余
- OLED目前可简单显示键盘状态
- Layer3专用宏定义层,可定义死循环宏
- layer2层可定义按住循环宏或单次宏
- layer1层仅可定义按键,为开机默认层
- 用户可以设置LED灯效,并且该灯效掉电可保存,具有至少100,000次更改寿命
DEBOUNCETIME 键盘消抖延时,单位ms
BRIGHTNESS 默认灯光亮度,0128取值
SLEEP_TIME 定义休眠时间,单位ms 数据后必须加上UL以使其数据长度对应于millis()函数
FADE_OUT_SPEED 单点亮灯光模式渐隐速度,建议110取值
最多可以定义20个,且必须完整定义20个键盘层,定义数组存放于keydefine.cpp,对照键值表.txt文件更改数组即可。
注意:17号位置定义的普通按键无效,因其已经被FN多功能键强制占用
注意:自V2.3以后,层2可以识别17号位置定义是否为FN键,故层2可以定义为其他按键
注意:自V3.0以后,所有层17号按键均可选定是否为FN键,其余按键不能对FN做出响应
注意:自V4.1以后,所有按键均可选定是否为FN键
按键号0~19,自左到右,自上到下,Z字型排列。
key_state值为0~2,使用mode按键自加,由RGBkeyboard.h文件中MAX_KEY_LAYER宏定义限定最大值为2。
macro_flag变量定义了宏使能标志,此值用于在键盘扫描线程和宏专用线程中传递某个按键是否应当启用宏。取值0到19,负值禁用宏,0~19使能对应按键的宏。因此同时只能激活一个宏!!
FN_flag变量定义了FN键使能标志,用于在FN键按下时改变键盘行为。
LED号0~19,与按键号同样排序。
led_state取值为true或false,指示键盘模式(false)或者灯效设置模式(true)。
led_layer取值为int,目前定义为0,1,2,3,分别代表四种灯效。
若需要定义按键宏,则需要编辑marco.cpp文件,当按键层一二中FN按键被按下时,其余对应按键按下或者按键层三对应按键按下后,程序会开始执行对用的Key_n_MARCO函数。由此可见,程序逻辑中三个按键层使用了同一个函数来执行宏功能,因此在配置宏的时候必须使用if(key_state == 层数-1)逻辑来限制宏在那一层执行
本程序在头文件中定义了RUN_ONCE语句以便于定义宏时直接设定宏的单次运行,为保证程序安全所有只执行一次的按键宏都应在宏最后或宏开始使用本语句
程序逻辑在设计时,按键事件仅作为进入宏函数的引导,尽管宏运行中可以继续识别宏按键,宏函数也必须执行一遍以后才可以重新检测宏引导标志进入新的宏函数。因此若不在每次宏结束后清空宏函数,可能会导致任务堆积和极高的键盘延时。FN键采用了与宏引导类似的设计,当FN键把按键引导进去宏后,FN键便不起效了。
同时因为上述程序设计,程序需要特别的结构来实现普通按键的按下与抬起功能,下面的例子介绍了实现方法。这个结构也带来一定的优点,使得宏具备了自动重复功能,而不必反复按下按键来激活宏。
void Key_19_MARCO(void)
{
if(key_state == 0) //第一层,ESC键按下抬起组合
{
NKROKeyboard.press(KEY_ESC);
while(macro_flag == 20)
{Scheduler.delay(50);}
NKROKeyboard.release(KEY_ESC);
}
if(key_state == 1) //第二层,当按键按下时重复发送‘e’,此时无需按住FN键
{
while(macro_flag == 20)
{
NKROKeyboard.press(KEY_E);
NKROKeyboard.release(KEY_E);
}
}
if(key_state == 2) //第三层,按下按键保存文件,单次运行
{
NKROKeyboard.press(KEY_LEFT_CTRL);
NKROKeyboard.press(KEY_S);
NKROKeyboard.releaseAll();
RUN_ONCE;
}
}