就在一个月前,我浏览了
这篇文章,讲述了踩Vim。 不久之后,经过漫长的三分钟研究,我发现该主题不再是新话题,而是非常流行。 我本人仅在紧急情况下才使用Vim(如果我必须在控制台中工作,我更喜欢Nano),但对于其他应用程序也可以这样做。
最初,我想写一篇小文章,但是我获得了有关创建该设备的完整教程,其中包含分步代码编写以及对内容和方法的解释。 为了避免给文章打气,扰流板下会有各种信息,这些信息似乎很有趣,值得新手关注Arduino,高级用户,尤其是匆忙的用户可能不会浪费时间。 文章末尾还提供了完整的源代码。
我为什么需要它?
如果您对该设备的必要性和实用性毫无疑问,则可以跳过此项目。 对于其余的内容,我首先要谈谈创建此设备的先决条件。
在任何时候,程序员和设计人员都试图创建一个方便且用户友好的界面,以便用户可以使用鼠标和键盘来处理应用程序而不会出现不必要的问题,那么为什么还要使用另一个操纵器呢? 好吧,让我们回顾一下历史,或者更确切地说,是在18世纪初,发明了诸如钢琴之类的乐器时。 如您所知,这个词的字面意思是“大声而安静”,但是很少有人认为聪明的意大利大师会收到这样的乐器,实际上是“利用”了当时存在的大键琴,这使得在某种程度上控制音量成为可能。将手从钥匙上移开。
有很多例子。 汽车上有踏板,以便在需要加油时不会扔方向盘。 架子鼓也有踏板,可以敲打低音鼓和。 踏板在使用计算机时能提供什么? 好吧,例如,您可以设置一些热键组合,甚至添加不存在的键,例如打开和关闭声音。 如果您的手忙,踏板可以提供帮助:我自己弹吉他,有时伴奏,这对我来说很方便,因为它可以在不尝试不断拉动键盘的情况下滚动背衬。 最后,控制者可以在游戏中提供完全不人道的可能性:一键点击即可建立整个基地,或者在射击游戏中以每秒十打的速度消灭敌人,这是很酷的,对吧?
总的来说,我希望我能说服您,这意味着是时候直接开始开发了。
所需资源
- 其实是踏板。 由于我想不出这种踏板的名称,因此立即出现了一些困难。 我只知道缝纫机中会用到这种东西。 通常,应电动踏板的要求,我仍然设法在Aliexpress上找到需要的东西,三思而后行,我订购了3件。
- 控制者 踏板应该模拟键盘,并且可能模拟鼠标,以便无需不必要的驱动程序即可连接到PC。 为此,Arduino Pro Micro开发板是完美的,尽管没有结论,但它要尽可能紧凑。 我们在同一个速卖通上购买了这个奇迹的中文版。
- 电线。 要在桌子下面放置3个踏板,您至少需要四根电线,且电线的长度至少为一米。 我认为,这里不应该出现问题。
- RGB LED和按钮。 第一个需要指示模式,第二个需要切换模式。
- 好吧,当然,我们需要一个Arduino IDE,一个烙铁和直臂。
设备图
甚至在包裹到达之前,我就开始创建设备图。 尽管说了很多,但是因为我只需要连接踏板,二极管和按钮。 原来是这样的:

对于踏板,我决定一次分配4个端口PB1-PB4,即左分配两个端口,右腿分配两个端口,尽管到目前为止我只有3个踏板。此外,它们都在同一组中并且位于一个位置。 在LED下,我将输出PD0,PD1和PD4置于按钮PD7下。
在这种情况下,如果使用控制器内置的上拉电阻,则不需要任何上拉电阻。 没错,那么,当您按下按钮或踏板时,输入将为低,而在释放时,输入将为高,即,按下将被反转,您不要忘记这一点。
代码编写
这个阶段是最困难的:由于指针中的几个错误,我多次擦除了引导加载程序,结果在软件级别上我几乎使板子失败了。 在下面详细描述了创建固件的所有阶段,对于那些只想获得工作代码的人,它将在本文结尾。
准备工作
首先,我们需要了解踏板在程序方面的含义。 我决定可以设置两种模式之一的踏板-实时和触发。 在这种情况下,每个踏板都有两个程序:第一个在实时按住踏板或在触发模式下按一下踏板时执行,第二个在实时释放踏板或在触发模式下均匀踩下踏板时执行。 踏板还具有端口,状态和两个变量-程序1和2中的当前位置。我得到了以下结构:
struct pedal { char port;
Arduino具有相当多的内存,并且也是8位的,因此最好尝试使用char而不是int。
我们还需要标准的键盘库才能用作键盘。
点击处理
现在我们需要创建一个解释器,该解释器将从数组中读取数据并将其以击键形式发送到计算机,并为各种内部命令选择多个值。 我们打开包含关键代码的
页面 ,然后查看单击的内容和方式。 我没有深入研究各种键盘标准,因为在我看来,这里的信息对于这样的项目来说已经足够了。 前半部分保留用于标准ASCII字符(尽管其中一些不可打印或不使用),后半部分保留用于各种修饰键。 左右键甚至有单独的代码,这非常令人愉悦,但是我看不到nampad中的数字的任何特殊代码,尽管据我所知,它们在系统中的感觉比普通数字更特殊。 也许他们的代码在范围之间的“空洞”中,但是现在不再是这个问题了。 因此,最大的键是向上键-218,这意味着219-255范围可以被认为是自由键,或者至少没有任何重要键。
void pedalAction() {
我认为,即使是对C知识不甚了解的人也不会对这里发生的事情有疑问。 首先,该功能选择所需的踏板,并根据踏板的模式和条件确定应执行哪个程序。 读取数组的每个元素时,如果它不是控制字符,则将调用Keyboard.write()函数,该函数模拟按下和释放键。 控制字符需要单独处理,并且需要使用这些字符来夹紧组合键并浏览程序。
键盘模式的一些功能基于我们不是以原始形式而是以击键形式发送数据的事实,Keyboard.write()具有一些简单但对初学者来说并不明显。 首先,很奇怪的是,如果没有其他驱动程序,计算机只能接受键盘上键盘上的字符,这意味着我们将无法发送任何0x03(中断信号)或0x1B(ESCAPE序列的开始)。 其次,我们可以调整ASCII表中的大写字母,但是机器将获得组合键Shift + <小写字母>。 如果启用了CapsLock,这将成为一个问题,并且我们会“意外”收到小写字母,而不是大写字母,反之亦然。 第三,我们不能像其他任何语言那样使用俄语。 由于诸如密钥代码之类的令人讨厌的事情,这种情况再次发生。 尽管Keyboard.write()接受它作为参数,但是与它在标准英语布局中的键相对应的代码仍通过USB发送,并且如果我们尝试发送西里尔字母,我们将一无所知。 因此,如果我们想通过Arduino与讲俄语的朋友打招呼,那么在代码中我们需要编写“ Ghbdtn”,然后在选择俄语布局后将其发送。 这样的“打招呼”在乌克兰语版式中将起作用,但在保加利亚语中,尽管事实上也有西里尔字母,但由于在完全不同的地方存在字母,因此不会有任何效果。 (我曾经听过这样的观点,对于许多美国和英语开发人员来说,甚至可能需要使用几种布局,而且还要切换它们,这是令人难以理解的。)
因此,我们有一名口译员,并对踏板与计算机的交互方式有一个大概的了解。 现在,我们需要将所有这些都恢复为完整固件的状态,并用一个踏板检查性能。 如果您创建踏板的实例并循环调用踏板动作(),则理论上我们将执行结构中指定的程序。
struct pedal *pedal1 = {15, 0, 0, 0, 0, 0, "Hello, world!\0", 0}; void prepare () { pinMode(15, 2);
顺便说一句,如果它们的长度小于数组的大小并且不是循环的,则永远不要忘记这些“程序”中的空终止符,因为Arduino不仅会尝试解释未设置的数据,而且还会以很高的速度将它们发送到机器,就像给猴子一个键盘一样。
一个踏板好,两个更好
现在该处理来自多个踏板的信号的处理以及添加切换模式了。 在本文开头,为踏板分配了4个端口,必须允许每个端口以7种模式工作。 为什么是7? 因为不使用PWM,我们的LED只能给出7种颜色,而第八种颜色为灭。 对于普通用户来说,这个数量已经足够了,但是在极端情况下,可以很容易地增加它。 因此,我们将踏板存储在7 x 4的二维数组中。为了不阻塞内存,可以在单独的数组中提取几种结构共有的值,例如端口号。 结果,我们得到这样的东西:
struct pedal { unsigned char type; unsigned char act1[16]; unsigned char act2[16]; }; struct pedal pedals[7][4] = { { { 255, {"Hello, world!\0"}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} } }; char ports[4] = {15, 16, 14, 8}; char pos1[4] = {0, 0, 0, 0}; char pos2[4] = {0, 0, 0, 0}; char state[4] = {0, 0, 0, 0}; char oldState[4] = {0, 0, 0, 0}; char mode = 0;
255号魔力您可能已经注意到,在文章中经常会出现数字255,将0放在逻辑上会更合逻辑。展望未来,我想说这对于将踏板存储在EEPROM中很方便,因为出厂时每个单元都不包含0,但是仅255,这意味着该数字将比0更方便用于表示未定义的变量,因此您不必每次都覆盖内存。
对我们而言,仅了解踏板的类型和两个程序非常重要,因此我们将仅将它们直接保留在结构中,让自动化来完成其余的工作。 现在,prepare和loop方法将如下所示:
void prepare(){ pinMode(2, 1); pinMode(3, 1); pinMode(4, 1); pinMode(6, 2); for (int i : ports) pinMode(i, 2); Keyboard.begin(); } void loop() { for (int i = 0; i < 6; i++) { int current; if ((current = digitalRead(modeButton)) != last) { if (!current) { if (++mode >= 7) mode = 0; while (pedals[mode][0].type == 255 && pedals[mode][1].type == 255 && pedals[mode][2].type == 255 && pedals[mode][3].type == 255) if (++mode >= 7) { mode = 0; break; } } last = current; digitalWrite(2, (mode + 1) & 0b001); digitalWrite(3, (mode + 1) & 0b010); digitalWrite(4, (mode + 1) & 0b100); for (int i = 0; i < 4; i++) { pos1[i] = 0; pos2[i] = 0; state[i] = 0; oldState[i] = 0; } delay(50); } curPedal = i; pedalAction } } }
如果未声明单个踏板(模式= 255),则控制器将认为该模式未使用,这意味着当踩下踏板时,它将立即进入下一个模式,但第一个模式将始终存在。 切换模式时,数组中的所有值都将为空,因为我们不需要为每种模式保存它们(对吗?),然后循环绕过所有踏板并为其调用踏板动作。
同样,在pedalAction()方法的开头,您需要添加以下行,以便它了解要处理的结构:
struct pedal *pedal1 = &pedals[mode][curPedal];
可以根据需要删除现有的pedal1结构。
所有这一切也都工作得很好,但是,我遇到了一个问题:某些程序没有时间以Arduino发送它们的速度来接收点击。 最明显的解决方案是在必要时增加在动作之间设置延迟的功能。 只有当我们坐下来为微控制器编写程序时,所有芯片(例如硬件多线程)都保留在高级计算机中的某个位置,当我们增加延迟时,整个程序将停止,直到控制器计算出正确的周期数为止。 由于我们没有多线程,因此必须创建它。
很难说是容易做
我没有发明自行车,而是拿了完整的ArduinoThread库。
在这里您可以阅读一些有关其工作原理的信息并下载。 您可以从Arduino IDE本身下载该库。 简而言之,它允许您以一定的时间间隔定期执行功能,而如果执行所需的时间超过该时间间隔,则不允许您进入无限循环。 您需要什么。 为每个踏板创建另一个带有线程的数组:
Thread pedalThreads[6] = {Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10)};
现在,我们有6个相同的虚拟线程,但同时它们是不同的对象。
让我们重写踏板旁路循环以使用新功能:
... for (int i = 0; i < 4; i++) { if (pedalThreads[i].shouldRun()) { curPedal = i; pedalThreads[i].run(); } } ...
现在,程序数组中的252值对应于“什么都不做”,将产生10毫秒的延迟(尽管实际上要多一些,因为代码的执行也需要时间)。 在解释器中添加几行代码,就可以在其中几个“量子”中设置延迟,而只花费数组的2个字节即可:
... if (wait[num]) { wait[num]--; return; } else if (prg[*pos] == 250) { wait[num] = prg[++*pos]; } ...
与其他命令不同,该指令必须精确地添加到解释器的开头,即紧接在“ while(1){”之后,因为必须在解释器继续读取程序之前处理延迟。 需要以与对端口,状态等相同的方式声明wait数组。 并在切换模式时重置其单元,以使延迟不会传递给其他程序。
现在,由于可以设置最多2.55秒的延迟,因此程序定义键的问题不应该出现。
进行中的编程
原则上,这里可以完成代码并开始组装设备,但是在这种情况下,如果有人突然想对踏板进行重新编程,他将不得不打开Arduino IDE,编辑代码并再次下载固件。 自然,此选项不是最佳选择,因此我决定增加从Arduino串行端口更改程序的功能,并将程序本身存储在EEPROM中。 要使用非易失性存储器,必须连接标准库EEPROM.h。 编程模式代码如下:
... if (!digitalRead(modeButton)) {
该代码的作用由其中包含的帮助进行了解释:为模式号,踏板号和一个命令输入了一个空格号,其中有3个字-读,写和
执行程序删除。 踏板上的所有数据以33个字节的顺序依次存储,即踏板的类型和两个程序,并且我们占用了EEPROM的1024字节的7 * 4 * 33 = 924。 我放弃了使用内存中踏板的动态大小的选项,因为在这种情况下,当对一个踏板进行重新编程时,您将必须覆盖几乎所有单元,并且重写周期是有限的,因此我们建议尽可能少地这样做。
EEPROM工作功能我还想提请注意表格的各行:
PORTD = 0b00000010 + (PORTD & 0b11101100); ... PORTD = 0b00000001 + (PORTD & 0b11101100);
从程序员的角度来看,由于有了这个库,非易失性存储器才是普通的char数组,但是,作为“ arduino”,我们需要了解到写入ROM是非常困难的操作,这需要花费控制器大约3秒钟的时间,建议不要中断该操作。过程。 这种设计可使二极管在此类操作期间发出红色光,然后返回“安全”绿色。
在程序记录模式下,输入是通过带空格的十进制数字系统中的字节值直接进行的。 结果很严重,但是您不必编写复杂的解析器。 此外,重新编程不会经常发生,在这种情况下,很有可能可以查看ASCII表。
整理好结构后,现在我们需要以某种方式从中提取数据并将其转换为“踏板”视图:
... for (int i = 0; i < 7; i++) { for (int j = 0; j < 4; j++) { struct pedal *p = &pedals[i][j]; int beginAddress = sizeof(struct pedal) * (i * 6 + j); int curAddress = beginAddress; unsigned char type = EEPROM[curAddress++]; if (type == 0 || type == 1) { p->type = type; for (int k = 0 ; k < 16; k++) { p->act1[k] = EEPROM[curAddress++]; } for (int k = 0 ; k < 16; k++) { p->act2[k] = EEPROM[curAddress++]; } } } } ...
这里也没有发生任何异常现象:控制器从内存中读取数据并用它填充现有的结构。
通过UART进行编程的优点是,我们再次不需要任何特殊的驱动程序,因此您甚至可以从电话中设置操纵器的行为。
示范
完整的源代码
他在这里 #include <Keyboard.h> #include <Thread.h> #include <EEPROM.h> #define modeButton 6 struct pedal { unsigned char type; //0 — , 1 — , 255 — unsigned char act1[16]; unsigned char act2[16]; }; struct pedal pedals[7][4] = { { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} } }; char ports[4] = {8, 16, 15, 14}; char pos1[4] = {0, 0, 0, 0}; char pos2[4] = {0, 0, 0, 0}; char state[4] = {0, 0, 0, 0}; char oldState[4] = {0, 0, 0, 0}; char wait[4] = {0, 0, 0, 0}; void pedalAction(); char mode = 0; char curPedal; Thread pedalThreads[6] = {Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10)}; void setup() { pinMode(2, 1); pinMode(3, 1); pinMode(4, 1); pinMode(modeButton, 2); if (!digitalRead(modeButton)) { // Serial.begin(9600); while (!Serial) { PORTD = 0b00000000 + (PORTD & 0b11101100); delay(250); PORTD = 0b00010000 + (PORTD & 0b11101100); delay(250); } Serial.println(F("***Programming mode***")); Serial.println(F("Write the command as <m> <p> <c>")); Serial.println(F("m - number of mode, one digit")); Serial.println(F("p - number of pedal, one digit")); Serial.println(F("c - command, it can be:")); Serial.println(F("\tr - read pedal info")); Serial.println(F("\tw - enter to writing mode and change pedal programm")); Serial.println(F("\te - erase pedal programm and delete it")); Serial.println(F("There are up to 7 modes and 6 pedals per mode can be configured")); Serial.println(F("Mode will be incative if there is no pedal configured in it")); while (1) { while (Serial.available()) { Serial.read(); delay(1); } PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(""); Serial.println(F("Enter command")); while (!Serial.available()); PORTD = 0b00000010 + (PORTD & 0b11101100); delay(3); if (Serial.available() == 3) { int curMode = Serial.read() - 48; int curPedal = Serial.read() - 48; char cmd = Serial.read(); if (curMode > 6 || curMode < 0) { Serial.print(F("Mode must be in 0-6. You entered ")); Serial.println(curMode); continue; } if (curPedal > 3 || curPedal < 0) { Serial.print(F("Pedal must be in 0-3. You entered ")); Serial.println(curPedal); continue; } Serial.println(); if (cmd == 'r') { int beginAddress = sizeof(struct pedal) * (curMode * 6 + curPedal); Serial.print("type: "); int curAddress = beginAddress; Serial.println(EEPROM[curAddress++]); Serial.print("act1: "); for (int i = curAddress ; i < curAddress + (sizeof(struct pedal) - 1) / 2; i++) { Serial.print(EEPROM[i]); Serial.print("\t"); } Serial.println(); curAddress = beginAddress + 1 + (sizeof(struct pedal) - 1) / 2; Serial.print("act2: "); for (int i = curAddress ; i < curAddress + (sizeof(struct pedal) - 1) / 2; i++) { Serial.print(EEPROM[i]); Serial.print("\t"); } Serial.println(); } else if (cmd == 'w') { Serial.println(F("Enter type:")); PORTD = 0b00000001 + (PORTD & 0b11101100); while (!Serial.available()); int beginAddress = sizeof(struct pedal) * (curMode * 6 + curPedal); int curAddress = beginAddress; PORTD = 0b00000010 + (PORTD & 0b11101100); EEPROM[curAddress++] = (char)Serial.parseInt(); PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(F("Enter act1 in DEC divided by space:")); while (Serial.available()) { Serial.read(); delay(1); } while (!Serial.available()); PORTD = 0b00000010 + (PORTD & 0b11101100); while (Serial.available()) { EEPROM[curAddress++] = (char)Serial.parseInt(); delay(1); } PORTD = 0b00000001 + (PORTD & 0b11101100); curAddress = beginAddress + 1 + (sizeof(struct pedal) - 1) / 2; Serial.println(F("Enter act2 in DEC divided by space:")); while (Serial.available()) { Serial.read(); delay(1); } while (!Serial.available()); PORTD = 0b00000010 + (PORTD & 0b11101100); while (Serial.available()) { EEPROM[curAddress++] = (char)Serial.parseInt(); delay(1); } PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(F("Finished, don't forget to verify written data!")); } else if (cmd == 'e') { int beginAddress = sizeof(struct pedal) * (curMode * 6 + curPedal); Serial.println(F("Disabling pedal...")); PORTD = 0b00000010 + (PORTD & 0b11101100); EEPROM[beginAddress] = 255; PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(F("Pedal disabled")); } } else { Serial.println(F("Incorrect command, please read help above")); } }; } for (int i : ports) pinMode(i, 2); pinMode(17, 1); for (int i = 0; i < 7; i++) { for (int j = 0; j < 4; j++) { struct pedal *p = &pedals[i][j]; int beginAddress = sizeof(struct pedal) * (i * 6 + j); int curAddress = beginAddress; unsigned char type = EEPROM[curAddress++]; if (type == 0 || type == 1) { p->type = type; for (int k = 0 ; k < 16; k++) { p->act1[k] = EEPROM[curAddress++]; } for (int k = 0 ; k < 16; k++) { p->act2[k] = EEPROM[curAddress++]; } } } } Keyboard.begin(); } int last = 0; void loop() { int current; if ((current = digitalRead(modeButton)) != last) { if (!current) { if (++mode >= 7) mode = 0; while (pedals[mode][0].type == 255 && pedals[mode][1].type == 255 && pedals[mode][2].type == 255 && pedals[mode][3].type == 255) if (++mode >= 7) { mode = 0; break; } } last = current; digitalWrite(2, (mode + 1) & 0b001); digitalWrite(3, (mode + 1) & 0b010); digitalWrite(4, (mode + 1) & 0b100); for (int i = 0; i < 4; i++) { pos1[i] = 0; pos2[i] = 0; state[i] = 0; oldState[i] = 0; wait[i] = 0; } delay(50); } for (int i = 0; i < 4; i++) { if (pedalThreads[i].shouldRun()) { curPedal = i; pedalThreads[i].run(); } } } void pedalAction() { struct pedal *pedal1 = &pedals[mode][curPedal]; if (pedal1->type == 255) return; unsigned char *prg; char *pos; if (pedal1->type) { int current; if ((current = digitalRead(ports[curPedal])) != oldState[curPedal]) { if (!current) state[curPedal] = !state[curPedal]; oldState[curPedal] = current; } if (!state[curPedal]) { //act1 pos2[curPedal] = 0; pos = &(pos1[curPedal]); prg = pedal1->act1; } else { //act2 pos1[curPedal] = 0; pos = &(pos2[curPedal]); prg = pedal1->act2; } } else { if (!digitalRead(ports[curPedal])) { //act1 pos2[curPedal] = 0; pos = &(pos1[curPedal]); prg = pedal1->act1; } else { //act2 pos1[curPedal] = 0; pos = &(pos2[curPedal]); prg = pedal1->act2; } } while (1) { if (wait[curPedal]) { wait[curPedal]--; return; } else if (prg[*pos] == 250) { wait[curPedal] = prg[++*pos]; } else if (prg[*pos] == 254) { // , *pos Keyboard.press(prg[++*pos]); } else if (prg[*pos] == 253) { // , *pos Keyboard.release(prg[++*pos]); } else if (prg[*pos] == 252) { delay(10); //" ", ++*pos; return; } else if (prg[*pos] == 251) { // *pos+1 *pos = prg[*pos + 1]; return; } else if (prg[*pos] == 255 || prg[*pos] == 0) { // , return; } else { // Keyboard.write(prg[*pos]); } // , if (++*pos >= 16) pos = 0; } }
后记
尽管起初我在踏板上是为了在弹吉他的同时滚动录音,但是我个人发现在普通任务中使用踏板很方便,主要是要对这种不寻常的操纵器有所适应。这里还有另一个问题:没有最喜欢的踏板,相反的工作变得更加困难,因为您必须记住按什么,在何处以及为什么按。如果仍然可以穿上踏板并将其连接到办公室,那么在研究所的教室里跑步已经变得更加困难。因此,将本设备用于其原始用途以外的其他用途的风险由您自己承担。组装的踏板: