pATAq 发表于 2019-7-2 21:24:25

【脑洞大赛】Sparrow 开发板化身电脑音量调节器 [已更新]

# Sparrow
## 前言

原创文章,转载引用务必注明链接,水平有限,如有疏漏,欢迎指正。
**之前的新浪不能用啦,这次部分图片用的sm.ms的图床,加载慢,请耐心,准备换图床。**

## 1、开箱简介
来填坑了!这次是 (https://www.dfrobot.com.cn/goods-1929.html)(以下称S板), [产品页面](https://www.dfrobot.com.cn/goods-1927.html),(https://wiki.dfrobot.com.cn/index.php?title=(SKU:DFR0589)Sparrow_%E5%BE%AE%E6%8E%A7%E5%88%B6%E5%99%A8)。
S板主控芯片使用的是与Arduino Leonardo相同的ATmega32u4主芯片,那么它和经典爆款Arduino UNO使用的ATmega328主芯片的有何不同呢?我们来瞅一瞅:
![](https://mc.dfrobot.com.cn/data/at ... g4c1r74frdd973g.png)
这只是官方提供的介绍,真正应用上的区别,可以参考这篇文章[《Arduino各开发板的比较》](https://www.arduino.cn/thread-42417-1-1.html),综合可知Leonardo的优劣势:
* **优点:** Leonardo与所有先前的板子不同之处在于ATmega32u4具有内置的USB通讯,无需使用类似UNO上的16u2辅助处理器。这允许Leonardo作为鼠标和键盘出现在连接的计算机上,以及虚拟(CDC)串口或 COM端口。
* **缺点:** 编译原理和其他arrduino的avr主控不太一样,深层开发有些麻烦。
> UNO 是使用额外的16u2芯片来实现USB 串口功能的,就是板子上那块小芯片,注意它也是可编程的,相信有很多玩家改造过了。

### 1.1 硬件规格
!
如图所示,一眼望去,供电途径很多样,板子很小,有硬件输出(四枚LED+BUILTIN LED),硬件输入(Potentiometer),感觉怪怪的,好像都不是传统的输入输出手段,可能镊子也挺好用的吧。

### 1.2 引脚定义与注意点
!(https://mc.dfrobot.com.cn/data/at ... zxxfwacif5gi4i2.png)
1. [官方wiki介绍](https://wiki.dfrobot.com.cn/index.php?title=(SKU:DFR0589)Sparrow_%E5%BE%AE%E6%8E%A7%E5%88%B6%E5%99%A8)
2. 参考官方`电位器读取`例程,发现不对,找到[原理图](https://www.dfrobot.com.cn/images ... 104172324xdtx59.pdf),最后确定如下:
    * 电位器接在A2
    * BulitIn LED接在D13引脚,板上丝印是D8,D代表二极管,可以看出这整体是有点混乱的,希望后续可以改进。
    * LED灯带接在D10引脚
    * **自锁开关**单纯用于控制供电(microUSB除外),没有接到MCU上,所以无法作为输入;红绿led用于显示锂电池充电情况。
    * microusb有串口调试功能

### 1.3 出厂程序
[下载地址](https://www.dfrobot.com.cn/images ... 104172504qazc7x.zip)
!(https://mc.dfrobot.com.cn/data/at ... 2gc5c9ucu7crm79.jpg)
需要安装Adafruit NeoPixel库,效果就是拨动电位器,四颗灯珠颜色逐渐变化。默认亮度着实瞎眼,另外大家能告诉我为啥子是菱形发散的光,摄像头(iphone6)问题?通过第1个示例可知电位器输出0-1023。
> 题外话:为啥胃酸是盐酸,而不是硫酸、醋酸啊什么的。

### 1.4 尚能饭否?
Arduino Leonardo,发布去今有好多年了,彼时物联网概念并不热门,但是随着ESP8266的出现,无线能力几乎成了标配,现在出这么一款产品,无疑限制了它的应用范围。
此外,对于S板有以下建议:
* 电池接口:我感觉用的多的是PH2.0接口,比如DF商城的锂电池、micro:bit等,默认焊接2.54的有点难受
* 板载一个按钮作为输入手段是否更好
* 丝印有待改进

!(https://mc.dfrobot.com.cn/data/at ... jg2gwzplgy2pdyj.png)
另外看到注意事项关于电源的内容有很多,这个能否傻瓜一点,我这种小白记不住boom了咋办。
那么,Sparrow究竟如何呢?我们接着往下看。

## 2、开展便民服务

### 2.1 项目设想
最近配了一台台式机(见前文),没有之前Thinkpad笔记本电脑的物理音量调节按钮,就想自己搞一个,于是看着手头的Sparrow,计上心头。
S板主要有两点优势:
1. 32u4内置USB通讯,适合模拟HID (Human Interface Device)设备
2. S板上有个电位器角度传感器,是不是很像音量调节旋钮?

原理是这么回事:现在常用的键盘属于HID设备的一种,而很多键盘上都有多媒体键,可以方便地调节音量、打开执行程序甚至自定义功能,我们利用S板模拟出键盘上的多媒体按键即可。看起来比较简单,下面动手看看如何实现。大致拆分了一下,流程拢共分两步:一是模拟成键盘;二是使用电位器调节音量。

### 2.2 环境需求
* 软件:Arduino IDE
* 硬件:MicroUSB Cable,Builtin Potentiometer

哇,引脚都不用焊接!

### 2.3 项目实施——轮子的救赎
既往没做过,先找块石头摸着过河,看看有没有人做过类似的,放狗(Google)一搜,看到这个(https://www.instructables.com/id/USB-Volume-Control/),顺蔓摸瓜找到这个(https://learn.adafruit.com/trinket-usb-volume-knob/overview),研究一下。
* 主控板使用Adafruit开发的 (https://www.adafruit.com/product/1500),采用ATtiny85主控芯片,额,没事,程序代码可以参考思路
* 使用Arduino编程语言,借助(https://github.com/adafruit/Adafruit-Trinket-USB/)库,可能需要移植或者更换

#### 2.3.1 第一部分:模拟HID
理论基础有了,我们说干就干,但是AdaFruit 的Trinket还是存在一些不同,我们直接在Arduino IDE里面搜索看看有木有现成的轮子可用,关键词HID,然后发现了这位大佬(https://github.com/NicoHood),此外还看到了大佬的IR库:[IRLremote
](https://github.com/NicoHood/IRLremote), `This library is way more efficient than the "standard" IR library from Ken Shirriff.`
我们这里用到(https://github.com/NicoHood/HID)库,直接在IDE里面的包管理工具安装即可,话说新版的IDE好像下载东西不用挂代理了。
!(https://mc.dfrobot.com.cn/data/at ... wksfwkhnthtrntf.png)
下面实现一个简单的Demo:按下按钮,使电脑切换静音。代码如下:

```c
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.

Consumer example
Press a button to play/pause music player

You may also use SingleConsumer to use a single report.

See HID Project documentation for more Consumer keys.
https://github.com/NicoHood/HID/wiki/Consumer-API
*/

#include "HID-Project.h"

const int pinLed = LED_BUILTIN;
const int pinButton = 9;

void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT_PULLUP);

// Sends a clean report to the host. This is important on any Arduino type.
Consumer.begin();
}

void loop() {
if (!digitalRead(pinButton)) {
    digitalWrite(pinLed, HIGH);

    // See HID Project documentation for more Consumer keys
    Consumer.write(MEDIA_VOLUME_MUTE);

    // Simple debounce
    delay(300);
    digitalWrite(pinLed, LOW);
}
}
```
这里修改自官方例程`Consumer`,我这里没有按钮,就直接用镊子了,最终效果就是将Sparrow通过MicroUSB线插到电脑上,短接D9和GND(相当于按下了按钮),然后在板上D8上的Builtin灯会闪一下(发白光),电脑就静音啦,再短接一次就会取消静音,如此反复。
!(https://i.loli.net/2019/07/16/5d2deafa6011649711.jpg)
由此第一步就完事了。再来看看第二步,参考下Adafruit的教程,虽然不一样但是思路总能参考吧!但是!结果!发现越发看不懂了,我们的电位器没有ABC脚!大费周章,茅塞顿开,恍然大悟,Encoder编码器和Potentiometer电位器不一样!
##### 电位器和编码器的区别
上文的Adafruit教程原本以为可以参考一下思路,然后发现我这里是电位器(**Potentiometer**,模拟信号),原文是旋转编码器(Rotary **Encoder**,数字信号),虽然外观上相似,但本质不同:
电位器:
![](https://ws.dfrobot.com.cn/FrBThtZGs3UF-ibvcsRMWJt1Eu2X)
编码器:
![](https://ws.dfrobot.com.cn/Fh12o50HHBALl32Xk_h1rmRX-mmZ)

两者的辨别:
> 电位器与编码器,有着本质的区别,最直接的分辨方法就是:旋转一下,要是旋转角度不足一圈的是电位器,要是可以360度无限旋转的是编码器。

有兴趣可以看这篇[电位器和编码器的区别](https://www.elecfans.com/d/799722.html)文章,具体还可以移步杜洋的免费公开课[《工欲善其事——电子技术探索与教学》](https://study.163.com/course/courseMain.htm?courseId=600002),里面有讲解有拆解。

#### 2.3.2 第二部分:旋钮调节音量
首先摸摸情况,夯实基础。我们手头有这些线索:
1. 电位器输出模拟值,范围0-1024,windows系统的音量控制范围是0-100(应该是百分比)。
2. 每次按下音量UP/DOWN按钮系统音量变动步进为2。我们参考(https://github.com/NicoHood/HID/wiki/Consumer-API),只有简单的步进。而且我手动测试发现步进为2,即每次按下按钮增加2,这和电脑上的多媒体键一样的,这是在哪定义的呢?我们看看(https://github.com/NicoHood/HID/wiki/API-Documentation),大佬就是大佬,这里找到usb协会的定义。原页面的链接地址失效了,新的是:
    * https://www.usb.org/sites/default/files/documents/hid1_11.pdf
    * https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
第2个是具体实现,可以看到0x1c是consumer。

下面思考的内容:
* 需要用到(https://www.arduino.cc/reference/en/language/functions/math/map/),角度0~270° -> 0-1023 -> 0-100。
    * PLAN A:电位器最大范围和音量范围对应满程,避免出现电位器到底了音量没到底。这就需要接上的时候根据电位器位置初始化音量,模拟按下指定次数。
    * PLAN B:电位器不精确对应音量,仅仅是有调整音量大小的作用。需要电位器范围尽量大于音量范围,2倍?但是此方案无论如何都会出现问题。
* 能不能实现鼠标即点即改到目标音量?试了一下笔记本上的音量控制键,一次仅增加一点,长按快速按步进增加。也就是UP/DOWN按键没这功能。
* 另外按键模拟有usb、ps/2接口,后者无论何时都有用,前者是usb hid模拟?bios有用,与系统无关。16进制代码。
* 看了`hut1_12v2.pdf`的130页,发现音量控制有两种方案,一是+/-按钮,二是Knob,也就是旋钮式控制。参考Ada的我们再瞅瞅。旋钮仅仅能转270°?不过我们看到的是df有300°,360°和3600°的。大致看了下,S板上的电位器角度传感器大概就是270度。

那么用电位器就不行了吗,当然不是,只是逻辑上有区别,我们参考[这个项目](https://www.instructables.com/id ... otentiometer-Based/)的代码进行修改。
```c
#include <HID-Project.h>                  //include HID_Project library
#include <HID-Settings.h>

#define REVERSED false                      //if your controller is reversed change it to true

int val = 0;
int previousval = 0;
int val2 = 0;

void setup() {
Consumer.begin();                         //initialize computer connection
delay(1000);                              //wait for computer to connect
for(int a = 0; a < 52; a++) {
    Consumer.write(MEDIA_VOLUME_DOWN);      //set the volume to 0
    delay(2);
}
}

void loop() {
val = analogRead(2);                      //read potentiometer value
val = map(val, 0, 1023, 0, 101);          //map it to 102 steps
if(REVERSED) {
    val = 101 - val;
}
if(abs(val - previousval) > 1) {          //check if potentiometer value has changed
    previousval = val;
    val /= 2;                               //divide it by 2 to get 51 steps
    while(val2 < val) {
      Consumer.write(MEDIA_VOLUME_UP);      //turn volume up to appropiate level
      val2++;
      delay(2);
    }
    while(val2 > val) {
      Consumer.write(MEDIA_VOLUME_DOWN);    //turn volume down to appropiate level
      val2--;
      delay(2);
    }
}
delay(301);                               //wait at least 300ms between changing volume levels
}                                           //if it will change faster Windows can sometimes
                                          //increase or decrease volume by 10 steps at once
```
简单的代码要点介绍:
* **判断电位器正接反接**(reversed),这里S板的电位器是固定的,我们不用管
* **初始化**,将音量调到0,再增大到电位器目前所在位置音量,这样才可以完整用到电位器全程。前面介绍过,每次up/down的音量步进为2,所以最多51次降到0,实测降到0后继续down无影响。
* 检测电位器值变化,每次间隔300ms+,否则可能一次变动步进为10。

效果演示及注意:
!(https://mc.dfrobot.com.cn/data/at ... v84s9skkzkkvd40.gif)
* 可以看到接上S板之后系统响了一下识别音(current 45)->系统音量降到0->增大到电位器目前位置对应音量(46)->**开始拨动电位器**调整音量,最小步进2。
* 由于板载电位器最大角度270°,加上阻尼小,所以拨动有点快,对于我这种强迫症不到整数不舒服的实在不友好,以后可以使用角度比较大的电位器,或者干脆使用旋转编码器。

这里使用以下软件
* 录制软件:(https://github.com/NickeManarin/ScreenToGif/) | 开源免费,功能强大
* 音量控制:(https://github.com/File-New-Project/EarTrumpet) | 开源免费,[介绍页面](https://www.appinn.com/eartrumpet-for-windows/)

### 更进一步
* **更多功能键**
我们[从这里](https://github.com/NicoHood/HID/ ... -APIs/ConsumerAPI.h)可以看到其他功能按键的定义,对源码稍加改动就可以做一个自定义的专属键盘了。
* **其他用法**
BadUSB之类的,有兴趣的自己搜搜。
* **USB协议分析软件**
Bus Hound/USBlyzer/USBTrace等,不过都收费,而且有段时间没更新了。

## 后记
这里实现了一个小功能,后续再把其他做的东西整理分享出来,此外micro:bit的东西也拖了好久了。

## Reference
* (https://cal-eng.com/?page_id=579)
* (https://www.arduino.cc/reference ... tions/usb/keyboard/)
* (https://github.com/NicoHood/Nico ... ega-and-HID-Project)
* (https://www.arduino.cn/thread-5107-1-1.html)

ASH腻 发表于 2019-7-5 10:09:28

啥时候fill-----前排发广告----

gada888 发表于 2019-7-6 10:03:10

鼓励一下

pATAq 发表于 2019-7-16 23:29:47

ASH腻 发表于 2019-7-5 10:09
啥时候fill

已经更新啦!
@ASH腻

pATAq 发表于 2019-7-16 23:30:10

gada888 发表于 2019-7-6 10:03
鼓励一下

感谢支持

pATAq 发表于 2019-7-16 23:31:20

本帖最后由 pATAq 于 2019-7-16 23:44 编辑

顺便 @KIKIYA

#嘉诚欧巴# 发表于 2019-7-17 20:38:53

也有想法用Leonardo做个电脑输入设备,你这个调音量物理按键角度不错!!支持一波~~{:5_155:}

江宇瀚 发表于 2019-7-26 17:41:37

ASH腻 发表于 2019-7-5 10:09
啥时候fill-----前排发广告----


韩俊 发表于 2019-8-1 13:23:05

鼓励一下

汤果 发表于 2019-8-13 16:39:14

果然 Geek 的世界就是不一样!

URvj0KkE 发表于 2019-9-6 21:18:15

加油。

岑剑伟 发表于 2019-9-9 15:07:31

发现了一个精彩的世界

岑剑伟 发表于 2019-9-9 15:07:45

为什么我现在才来呢

岑剑伟 发表于 2019-9-9 15:08:39

膜拜大神的动手能力

EmSECpn6 发表于 2019-9-15 17:23:19

jzzgb 发表于 2019-11-1 15:54:27

这创意很棒。
页: [1]
查看完整版本: 【脑洞大赛】Sparrow 开发板化身电脑音量调节器 [已更新]