文档章节

​黑科技:程序猿如何打造属于自己的分体键盘

腾讯Bugly
 腾讯Bugly
发布于 2016/04/29 22:05
字数 1885
阅读 5548
收藏 125

前言

之前一直想买个机械键盘,听说机械键盘敲代码和玩游戏都特别爽,也是装B神器。同时也觉得普通的键盘打字打久了手腕会有点酸酸的,因为敲键盘时都是要弯着手腕的,一点也不符合人体工程学。于是乎就想买一个分体的机械键盘,结果找了半天都没有比较中意的,找到几个人体工程学键盘,都是薄膜的,而且价格高得离谱,不就多个人体工程学光环嘛。。。

普通机械键盘

淘宝人体工程学键盘

淘宝分体键盘

为了不要这么纠结,就自己diy一个咯,正好有台3D打印机,全部外壳自己打印,控制板用Arduino Leonardo,原生支持键盘鼠标驱动,轴体淘宝,考虑成本,先买了80颗国产黑轴做实验,键帽也简单打印一下,说干就干

最终成果

准备

  • 工具
    • 3D打印机
    • 电烙铁
    • 热熔胶
    • 万用表
  • 硬件
    • Arduino Leonardo板
    • 黑轴轴体
    • 二极管+电阻+杜邦线+万能板
    • 小螺丝
  • 软件
    • SolidWorks 3D建模
    • Arduino IDE 写Arduino键盘驱动

是时候上点图了。。。

自己组装的三角洲式3D打印机

淘宝买的工具



步骤

先设计键位排布,使用SolidWorks画出简单的按键布局,先从左手开始,先完整的搞定左手能使用了,再做右手。设计好布局后制作支撑轴体的面板,然后设计电路,用飞线焊接,写代码测试按键是否都正常。电路正常后设计整个外壳,然后整体组装。这就完工啦

  • 键位设计

    • 左手
      左手
    • 右手(之所以外形扭曲,是因为3D打印机打印面积有限)
      右手
  • 电路设计

    由于Arduino板io口有限,必须使用扫描来实现按键,Arduino有6个模拟口,14个数字口。我要做的键盘不超过80个键,所以使用8个数字口进行脉冲扫描,6个模拟口加4个数字口用来接收脉冲来定位按键,这样就实现了8*10的矩阵,支持80个键。还有2个数字键是空闲的,可以用于特殊按键定制。

    • 冲突处理
      使用脉冲扫描方式就会有按键冲突问题,我使用二极管来处理冲突,如图(R是扫描口,C是接收口):
       
    • 电压动荡处理
      二极管解决了冲突问题,但是不能解决电压动荡,电压不稳定有两方面,第一就是当扫描口高电压变为低电压时,接收口电压不会立即变成低电压,所以在接收口都需要加一个下拉电阻,让电压立马降下来。第二就是按键按下时接触片碰撞时导致的电压不稳,这个最好是通过加电容去过滤波动电压,买元件时忘了买电容了,这里就简单粗暴了

    • 最终电路设计

  • 外壳设计

    • 左手
    • 右手
    • 侧面
  • 键帽设计


  • 程序设计

#include "Keyboard.h"#include "HID.h"#define scanPin_len 8int scanPin[] = {4,5,6,7,0,1,2,3}; // 扫描pin,(默认高电平,逐个输出低电平)int scanPos = 0; // 当前扫描位#define btnPinA_len 6#define btnPinD_len 4int btnPinA[] = {5,4,3,2,1,0}; // 按钮pin,模拟端口int btnPinD[] = {8,9,10,11}; // 按钮pin,数字端口#define btn_len 10byte btn[scanPin_len][btn_len]; // 按钮状态byte btnTmp[btn_len]; // 临时按钮状态#define KEY_FN KEY_RIGHT_SHIFT // FN键uint8_t keyMap[scanPin_len][btn_len] = 
{
{'y','n','7','8',KEY_F6,'h','m','u','j',' '},
{'o','.','0','9',KEY_F7,'l',',','i','k',KEY_FN},
{'p','/','-',KEY_LEFT_ARROW,KEY_F8,';',KEY_UP_ARROW,'[','\'',KEY_DOWN_ARROW},
{KEY_F10,KEY_DELETE,'=',KEY_BACKSPACE,KEY_F9,KEY_F11,KEY_RETURN,']','\\',KEY_RIGHT_ARROW},
{KEY_ESC,KEY_LEFT_GUI,'`',KEY_LEFT_CTRL,KEY_TAB,'a','q','z',KEY_CAPS_LOCK,KEY_LEFT_SHIFT},
{KEY_F1,KEY_LEFT_ALT,'1',KEY_F2,'2','s','w','x','d','c'},
{KEY_F3,' ','4',KEY_F4,'3','e','r','b','f','v'},
{KEY_F5,'6','5',0,0,0,'t','g',0,0}
}; 

void setup() {
  Keyboard.begin();
  Keyboard.releaseAll();
  Serial.begin(9600);  // 初始化扫描pin
  for(int i=0; i<scanPin_len; i++) {
    pinMode(scanPin[i], OUTPUT);
  }  // 初始化按钮pin
  for(int i=0; i<btnPinD_len; i++) {
    pinMode(btnPinD[i], INPUT);
  }  // 初始化按钮状态
  for(int i=0; i<scanPin_len; i++) {    for(int j=0; j<btn_len; j++) {
      btn[i][j] = 0;
    }
  }  for(int j=0; j<btn_len; j++) {
    btnTmp[j] = 0;
  }
}void loop() {  // 轮询设置scanPin
  for(int i=0; i<scanPin_len; i++) {    if(i == scanPos) {
      digitalWrite(scanPin[i], HIGH);
    } else {
      digitalWrite(scanPin[i], LOW);
    }
  }

  delay(5);  // 读取按键信息
  readBtn();  // 处理状态有改变的btn

  for(int i=0; i<btn_len; i++) {    if(btn[scanPos][i] != btnTmp[i]) {
      btn[scanPos][i] = btnTmp[i];//      Serial.print("["); //      Serial.print(scanPos);//      Serial.print(" : ");//      Serial.print(i);

      if(btnTmp[i] == 1) {
        Keyboard.press(keyMap[scanPos][i]);//        Serial.print("] pressed");
      } else {
        Keyboard.release(keyMap[scanPos][i]);//        Serial.print("] released");
      }//      Serial.println("");
    }
  }
 scanPos = (scanPos + 1) % scanPin_len; // 下一个}void readBtn() {  // 先读模拟口,再读数字口
  // 5 -> 0
  int index = 0;  for(int i = 0; i < btnPinA_len; i ++) {    int val = analogRead(btnPinA[i]);    if(val > 600) {
      btnTmp[index] = 1;
    } else {
      btnTmp[index] = 0;
    }    // Serial.print(btnTmp[index]);
    index ++;
  }  for(int i = 0; i < btnPinD_len; i ++) {
    btnTmp[index] = digitalRead(btnPinD[i]);    // Serial.print(btnTmp[index]);
    index ++;
  }
}

制作图集

  • 第一版键帽:

  • 新买的毛玻璃打印时受热不均,碎了。。。

  • 在打印中,加热头松动掉落,还好机器有自动保护,没有造成火灾

  • 打印过程中底座脱落,一路坎坷啊

  • 轴体安装

  • 飞线

  • ArduinoLeonardo还没到货,拿uno测试按键

  • 外壳组装效果

  • 第一版键帽(字母是用美纹纸贴上去的)

  • Leonardo到货,测试驱动

  • 右手组装成功(黑色更有感觉啊)

  • 新版键帽(白色)

  • 电路板

  • 最后效果

总结

做完整个键盘感觉非常有成就感,也非常实用,截止目前已经用了快半年时间了,已经非常习惯机械键盘的按键反馈,手腕也不再弯着,没有酸过了。最后来大致汇总下花费吧

  • 80颗国产黑轴 104元
  • 元器件 24元(邮费贵,还有很多二极管和万能板没用到)
  • Leonardo 30元
    大概材料花费在160元左右,比普通的机械键盘便宜多了,而且还是分体的,所有按键可随意自定义(驱动程序都自己写的,O(∩_∩)O哈哈~)

最后晒一下我在小黑屋的办公桌

如果你觉得内容意犹未尽,如果你想了解更多相关信息,请扫描以下二维码,关注我们的公众账号,可以获取更多技术类干货,还有精彩活动与你分享~

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!


© 著作权归作者所有

共有 人打赏支持
腾讯Bugly
粉丝 277
博文 134
码字总数 568948
作品 0
深圳
加载中

评论(40)

O
OrgXxxx
膜拜大神
魅影醉
魅影醉
献上膝盖
wangbo888
wangbo888
真心流弊
Joken0704
Joken0704
屌爆了
buglife
buglife
敬仰啊
蓝天下的星空
迪拜驻开源中国大使
迪拜驻开源中国大使
高人[79]
K '
K '
100分
帆船
帆船
Orz
ubuntuvim
ubuntuvim
必须满分!
如何伪装成一个年薪 20 万刀以上的码农?

年轻的程序猿朋友们,从东岸、中部、南加……迁徙到硅谷的你,是否希望远处的美女向你投来崇拜的目光?希望身边的朋友觉得你很酷很牛逼?今天我们来聊聊如何在硅谷装成一个牛逼(身价20万刀以...

oschina
2016/03/17
10.6K
33
【编译】VMware收购人工智能创业公司Apteligent

来源:数据猿 编译:金又南 本周一(5月15日),VMware透露其已完成了对人工智能创业公司Apteligent的收购。Apteligent是一个移动应用程序智能平台,但本次收购具体交易金额尚未透露。 VMwa...

金又南
2017/05/17
0
0
程序猿的骄傲,以及骄傲背后真实的原因。

引言      程序猿,这个字汇在近几年开始渐渐被大众所熟知。在外界看来,这一直是个特殊的群体,社会上也给程序猿贴了很多的标签,内向、屌丝、苦逼、裤衩、拖鞋等等。在他们的心中,程序...

zuoxiaolong8810
2017/03/23
0
0
程序猿的骄傲,以及骄傲背后真实的原因

引言 程序猿,这个字汇在近几年开始渐渐被大众所熟知。在外界看来,这一直是个特殊的群体,社会上也给程序猿贴了很多的标签,内向、屌丝、苦逼、裤衩、拖鞋等等。在他们的心中,程序猿是这样...

oschina
2016/04/22
5.5K
38
如何让自己成长为 IT 项目管理者

在这个快节奏发展的时代,你需要用最有效的方式,学习最有用的知识。技但碎片化的信息那么多,如何选择呢?推荐几个程序员自我提升必备的公众号,快关注、使用起来吧! TGO鲲鹏会ID:tgo-kun...

bf02jgtrs00xktcx
04/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JS三元运算示例

1. topFlag=topFlag ==0?1:0; 等于 if(topFlag=00){ topFlag=1; }else if(topFlag == 1){ topFlag=0; } 2. 5>3?alert('5大'):alert('3大'); 即 if(5>3){alert('5大')}else{alert('3大')}; 注......

森火
今天
0
0
利用Slf4j的MDC跟踪方法调用链

why? 一个web项目通常提供很多URL访问地址, 项目一般都是分层处理,例如Controller——>Service——>DAO。 如果想根据日志查看用户一次请求都走了哪些方法(多数是查错误)。 如果系统是多人...

杨春炼
今天
7
0
Maven介绍及安装

Maven介绍及安装 以下内容是本人早期学习时的笔记,可能比较详实繁琐,现在复习一下Maven,顺便将内容抛出来,供大家一起学习进步。 一、Maven简介 Maven是Apache旗下的一款项目管理工具,是...

星汉
今天
0
0
小程序Aes解密

主要步骤: 1、下载AES源码(JS版) 2、在小程序中新建一个公共的文件夹,把AES源码拷贝进去(注意:需要暴露接口 module.exports = CryptoJS;) 3、添加一个用于加密解密的公共JS,可取名为...

Mr_Tea伯奕
今天
0
0
Go实现文件传输(基本传输可用)

发送端 package mainimport ("fmt""os""net""io")func SendFile(path string, connect net.Conn){file, oerr :=os.Open(path)if oerr !=nil{fmt.Println("Open", oerr)......

CHONGCHEN
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部