第1节 概述
智能硬件有意思,现在市场上有很多针对普通消费者的智能硬件。例如,智能灯泡、智能插座、智能电子秤,甚至无人飞行器。抛开这些智能设备实现的功能不谈,它们的实现原理都是大同小异:通过手机的蓝牙(或者wifi网络),连接智能硬件上的蓝牙模块,向蓝牙模块发送各种控制命令,让硬件工作起来。
也许你只是个普通的软件开发者,对硬件毫无概念,也不要着急,我们向纯软件开发者推荐一个很好的智能硬件入门平台Arduino,以此为基础,逐步熟悉智能硬件开发。
万事开头难,本章将从最简单的智能LED灯开始,向大家介绍一个智能硬件是如何设计并实现的。
当本章完成之后,大家将会得到一个按钮控制开启关闭的台灯。如下图的作品,

并且可以通过手机控制LED灯的明暗强弱。
在开始以前,假设做好如下准备:
- Arduino开发板;
- 一根连接电脑和Arduino开发板的数据线;
- 一个LED显示灯;
- 一个按钮开关;
- 一个旋钮电位器;
- 若干积木零件;
- 完成基础课程中的部分内容,以及LED灯、按钮、旋钮电位器等外接传感器的基本使用方法;
1.1 功能定义
LED灯的功能很简单,
- LED灯有个实体的开关,能够打开关闭LED灯;
- LED灯上有一个旋钮,可以用它调节灯的亮度;
- LED灯的外观要简洁实用;
1.2 硬件功能
Arduino开发板有多种型号,这里我们选择Arduino UNO或者MEGA开发板作为智能硬件的控制板。

开发板外接的LED灯模块大同小异,都是3个引脚,需要将它们连接到Arduino开发板上。

如果使用的是其他类型的LED灯也没有关系,它们大同小异,观察下引脚就可以了。
开发板要外接一个按钮开关,用来控制LED灯的开关。

旋钮电位器用来调节LED灯的亮度,它可以检测旋转的角度,角度不同,输出的数值大小也不同,
为了在开发板上同时接入多个传感器器件,需要使用扩展板,

或者

1.3 硬件结构
硬件组装好以后,需要为它设计一个简洁实用的外壳,将开发板、连接线、LED灯包裹起来。
作为个人设计的智能硬件,一定是个性化的产品。开发者可以采用3D模型软件设计一个精巧的外形,然后通过3D打印机将它变成现实,再和我们之前的智能硬件组合起来。

但是3D建模也是需要花费一定时间和精力学习的。这里我们准备采用积木拼接的方式搭建一个LED灯的外部结构。积木颗粒众多,可以随意插入和拆卸,可定制性很高,各位开发者也可以根据自己的创意随意的修改外形,设计成世界上独一无二的智能LED灯。

第2节 硬件端的开发
现在,我们开始实现智能LED灯硬件相关部分的设计。
2.1 硬件连接
选择了Arduino开发板 、旋转电位器、LED灯模块和三引脚按钮开关以后,就需要把它们组合起来,为我们所用了。
因为同一个开发板要连接多个外接硬件,这时就需要Arduino扩展板出场了。
将Arduino开发板和扩展板上下插入后,引脚就扩展出来了,

LED灯模块有3个引脚需要与开发板连接。这里我们选择UNO板的D9引脚作为LED灯的PWM控制引脚(当然可以选择任何其它具有PWM功能的引脚),
| 扩展板引脚 | 连接 | LED灯模块引脚 |
|---|---|---|
| 9组5V | <—-> | + |
| 9组GND | <—-> | G |
| 9组SIG | <—-> | S |

旋转模块有3个引脚需要与开发板连接。这里我们选择UNO板的D4引脚作为调光输入的模拟引脚(当然可以选择任何其它模拟引脚),
| 扩展板引脚 | 连接 | 旋转按钮模块引脚 |
|---|---|---|
| 4组5V | <—-> | + |
| 4组GND | <—-> | G |
| 4组SIG | <—-> | S |

最后,将按钮开关接入Arduino UNO开发板的D5引脚,
| 扩展板引脚 | 连接 | 按钮模块引脚 |
|---|---|---|
| 5组5V | <—-> | 中间未标注 |
| 5组GND | <—-> | - |
| 5组SIG | <—-> | S |

全部组装好后,如下图,

2.2 代码实现
- 初始化时,在
setup()函数中,```cpp //定义按钮开关使用的引脚编号, //这里使用的是数字引脚5, const int BUTTON_PIN = 5;
//定义LED灯模块使用的引脚编号, //这里使用的是数字引脚9, //这是一个具有PWM功能的引脚 const int LED_PIN = 9;
//定义旋转电位器模块使用的引脚编号, //这里使用的是模拟引脚4, const int ROLLING_SWITCHER = 4;
//初始情况下,按钮是没有按下的,所以是HIGH电平 int oldButtonState = HIGH;
//初始情况下,灯是关闭的 bool isLightOn = false;
void setup() { Serial.begin(9600);
//设置按钮的引脚为输入 pinMode(BUTTON_PIN, INPUT); //设置旋转电位器的引脚为输入 pinMode(ROLLING_SWITCHER, INPUT); //设置LED灯的引脚为输出 pinMode(LED_PIN, OUTPUT); //设置LED灯的初始状态为关闭 isLightOn = false; }
2. 增加对按钮开关的逻辑控制,```cppvoid loop() {int buttonState = digitalRead(BUTTON_PIN);if(buttonState == LOW && oldButtonState == HIGH){// 当前被按下(LOW),之前没有被按下(HIGH),// 说明使用者按下了按钮Serial.println("button press down");oldButtonState = buttonState;}else if(buttonState == HIGH && oldButtonState == LOW){//当前没有被按下(HIGH),之前被按下(LOW),//说明使用者松开了按钮//此时需要对灯灯开关状态做设置:以前是开启状态,说明要关闭;以前是关闭状态,说明要开启Serial.println("button press up");oldButtonState = buttonState;isLightOn = !isLightOn;Serial.println(isLightOn);}if(isLightOn) {//如果灯是开启的,那么需要从电位器获取数值,设置灯的亮度int value = analogRead(ROLLING_SWITCHER);value = map(value,0,1023,0,255);analogWrite(LED_PIN, value);} else {//如果灯是关闭的,直接这是亮度为0analogWrite(LED_PIN, 0);}}
- 将程序部署到Arduino UNO/MEGA开发板上。
第3节 LED灯的外形结构
设计外形结构的时候,可以选择3D建模,然后用3D打印机打印出来的设计方式,也可以简单的使用积木拼接。我们选择用拼接积木的方式,给LED灯搭建外形。
结构设计是一个很有意思的事情。给自己开发的智能硬件做一个个性化的外形十分的令人激动。
3.1 设计软件
LEGO Digital Designer是一款操作简单的、乐高积木设计软件。我们可以用它来进行智能硬件外观的设计,设计完成后把它拼接出来。
这是一款免费的软件,可以在乐高的官网这里根据自己使用的电脑操作系统下载。
3.2 软件使用
打开软件开始,创建新文件,开始设计外形,

拖动左边区域中的零件,摆放到右边底板上,开始模型到设计,

下图就是我们给出的一个可能的设计方案。

3.3 实际效果
如果你有兴趣自己设计,那么可以将它搭建成如下灯样子,

如果你更加喜欢自己设计台灯,可以使用更多的积木组件进行搭建。
第4节 改进方向
简单的LED按钮灯就设计完了。相信大家看到这个完全由自己打造的硬件玩具一定充满了成就感。
虽然这只是个功能上还比较阳春的智能硬件原型,但是你可以根据自己在实际使用中的感受,给它加入更多实用的功能。例如,
- 给它加上红色、绿色、蓝色的灯泡,让LED灯能呈现出更多的色彩;
- 同时增加手机端控制软件的功能,设定不同的场景,让LED灯能在不同的场景下变幻不同的灯光颜色和亮度;
- 使用声控开关,用声音来控制台灯的开启;
- 用积木拼出更多形状有特点的LED灯;
附件
整个项目的连线方式:
整个项目的代码:
//定义按钮开关使用的引脚编号,//这里使用的是数字引脚5,const int BUTTON_PIN = 5;//定义LED灯模块使用的引脚编号,//这里使用的是数字引脚9,//这是一个具有PWM功能的引脚const int LED_PIN = 9;//定义旋转电位器模块使用的引脚编号,//这里使用的是模拟引脚4,const int ROLLING_SWITCHER = 4;//初始情况下,按钮是没有按下的,所以是HIGH电平int oldButtonState = HIGH;//初始情况下,灯是关闭的bool isLightOn = false;void setup() {Serial.begin(9600);//设置按钮的引脚为输入pinMode(BUTTON_PIN, INPUT);//设置旋转电位器的引脚为输入pinMode(ROLLING_SWITCHER, INPUT);//设置LED灯的引脚为输出pinMode(LED_PIN, OUTPUT);//设置LED灯的初始状态为关闭isLightOn = false;}void loop() {int buttonState = digitalRead(BUTTON_PIN);if(buttonState == LOW && oldButtonState == HIGH){// 当前被按下(LOW),之前没有被按下(HIGH),// 说明使用者按下了按钮Serial.println("button press down");oldButtonState = buttonState;}else if(buttonState == HIGH && oldButtonState == LOW){//当前没有被按下(HIGH),之前被按下(LOW),//说明使用者松开了按钮//此时需要对灯灯开关状态做设置:以前是开启状态,说明要关闭;以前是关闭状态,说明要开启Serial.println("button press up");oldButtonState = buttonState;isLightOn = !isLightOn;Serial.println(isLightOn);}if(isLightOn) {//如果灯是开启的,那么需要从电位器获取数值,设置灯的亮度int value = analogRead(ROLLING_SWITCHER);value = map(value,0,1023,0,255);analogWrite(LED_PIN, value);} else {//如果灯是关闭的,直接这是亮度为0analogWrite(LED_PIN, 0);}}
