- 初学Arduino,就要完成一次大作业,任务是用Arduino制作智能家居,这“戳实”很艰辛。。。还好,过程很艰辛,结局还算圆满。
特别感谢一起完成该制作的YuanSnowing同学!
一、任务灵感
基于Arduino的便携灵活,容易上手的特性,以及课堂上听课所得的知识,我们打算设计一款带有轮子,并且集风扇与台灯于一体的智能移动风扇灯。
制作只是雏形,未来的设想是实现落地灯和风扇于一体,并且能移动,方便人们移动与使用落地灯和落地风扇。
二、功能要求
- 通过按钮实现一键开关灯及风扇;
- 通过指示灯显示当前调整的功能(风扇或灯);
- 通过光敏电阻实现自动调节灯光亮度;
- 通过开关控制是否自动调节灯光亮度;
- 通过遥控控制显示屏显示风力和亮度级别大小;
- 通过遥控器调节风力或亮度;
- 通过遥控实现车子的移动;
- 通过温湿度传感器显示温湿度;
- 利用测距器和蜂鸣器做警报器,若装置距其他物品过近则发出警报;
三、设计框架
四、材料准备
- Arduino Mega 2560
- 杜邦线若干
- 电阻若干
- 发光二极管
- 白色:30个;红色:1个;黄色:1个
- 面包板若干
- 直流电机一个(驱动风扇)
- 二轮小车一个
- 按钮一个
- LCD显示屏
- 按钮一个
- 超声波测距器
- L298N模块
- ULN2003模块
- 3V外接电源
- 光敏电阻
- 测温湿度传感器
- 遥控器
- 红外接收器
- 蜂鸣器
- 电位器
……
五、外观图片
六、功能实现成果展示
开机时画面:显示“Nice to meet you” ;
待机状态:正常显示温度湿度及操作提示;
待机状态按下“1”:正常显示当前操作状态,此时按下“0”进入菜单,按下“1”快速返回待机状态,或等待一秒,自动返回待机状态;
待机状态按下“0”:正常进入菜单,显示屏显示操作提示。此时按下“1”进入灯光控制模式,按下“2”进入风扇控制模式,按下“3”进入小车移动控制模式;
灯光控制模式下:显示屏正常显示操作提示。此时按下“1”进入人工控制模式,显示屏正常显示操作提示,根据提示可通过遥控器实现对灯光强度的三档调节及关闭灯光;按下“2”进入自动控制模式,当外部光强较大时,灯光变暗,当外部光强较小时,灯光变亮。若在自动控制模式启动时再次启动自动控制模式,可关闭灯光。
风扇控制模式下:显示屏正常显示操作提示。按下“0”,关闭风扇;按下“1”、“2”、“3”,调节不同风力。
小车控制状态下:显示屏正常显示操作提示。按住“2”、“4”、“6”、“8”,正常控制小车移动,按下“5”,退出。当小车前方有障碍物,蜂鸣器会发出警报,并且小车将无法向前移动。
在非灯光风扇控制模式中,按下按键:若灯光或风扇开启,则全部关闭;若灯光和风扇均关闭,则一键打开。灯光打开至自动控制模式,风扇打开至中档。
七、遇到的问题
1. LED灯管额定电压220V,配套的硬件中发光二极管不足以当作光源
- 解决方式:在网上采集了30个白色的发光二极管,并将其并联在小面包板上形成方形,从而达到了作为光源的目的。
2. 实现“长按按键则小车移动,停止按按键则小车停止”功能困难;实现不同界面的切换及连续按键切换困难。
- 解决方式:通过不断地Debug,发现长按后的信号为“0xFFFFFF”,且被视作无法接收,每次resume后必须delay一段时间才能进行判断状态的过程;同时,若想不把上次的按键值直接被系统带到接下来的判断语句中,需写个while循环。
3. 直流电机难以持续工作或难以工作。
- 解决方式:通过网上查询,先后尝试了多种方式,如直接连接5V接口,使用继电器、使用TB6612FNG,使用盒子中的“三极管”(后经证实此为霍尔元件),最终经过尝试,选择了ULN2003模块和L298N模块作为中转。
(经发现,风扇所对应的电机对电压、电流要求较高,所以外接了3V电源作为供电。)
八、创新性说明
创造性:创造性地将台灯、风扇、温湿度显示器等家居辅助设施与移动模块相结合,使生活更简单。
智能化:进入自动模式后,可以根据外界光强自动调节亮度,保护眼睛的同时也避免了不必要的浪费;进入小车模式后,当前方一定距离内有障碍物,将不能向前移动,并发出警报音,亮出指示灯,保护小车安全,也使用户使用更为省心。
多功能:集台灯、风扇、温湿度显示于一身,可作为用户的全方位辅助。
人性化:支持一键关闭、一键开启,使使用更加便捷。多挡位随心调控,照顾用户的每一丝体验。红外遥控远距离操控,无需走动便可享受智能生活。
可外拓:本作品由于小车体积和硬件设施的局限性,概念价值大于实际价值。但可以通过合理外拓,使其成为人们日后必不可少的家居助手。
九、编程代码
/*
基于Arduino Mega 2560板子以及Arduino IDE
*/
#include <IRremote.h>//Infrared Radiation library 红外接收库
#include <LiquidCrystal.h>//LCD library LCD库
#include <dht11.h>//DHT11 library DHT11库
//The Defination of Initial pins 初始Pin值定义
int RECV_Pin = 22;
int dht11_Pin = 23;
int rs = 52,e = 50,d4 = 24,d5 = 25,d6 = 26,d7 = 27;
int LR_Pin = A13;
int light_Pin = 7;
int Fan_Pin = 8;
int LED_LP = 28,LED_FP = 29;
int Buzzer_Pin = 6;
int TrigPin = 5, EchoPin = 30;
int Button_Pin = 53;
int Car1 = 9,Car2 = 10;//LEFT
int Car3 = 11,Car4 = 12;//RIGHT
//Several functions 一些功能变量
const int t = 750;
int Intensity = 0;//The intensity of illumination
int now;//Luminance
int lightdgree = 0;//light dgree
int fandgree = 0;//fan dgree
int buttonState = 0; //Button State
int past;//Button last state
float dis;//distance
bool fan = false;//Whether fan is on
bool light = false;//Whether light is on
bool LM2 = false;//Whether Light_Mode_Auto is on
bool menu = false;//Whether menu is on
bool check = 0;//Whether check_mode is on
bool whenopen = 0;//Whether it is open
IRrecv irrecv(RECV_Pin);
dht11 DHT11;
decode_results results;
LiquidCrystal lcd(rs, e, d4, d5, d6, d7);
//Set up 初始设置
void setup()
{
Serial.begin(9600);//Baud Rate
pinMode(light_Pin, OUTPUT);
pinMode(LED_LP, OUTPUT);
pinMode(LED_FP, OUTPUT);
pinMode(Buzzer_Pin, OUTPUT);
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
pinMode(Fan_Pin, OUTPUT);
pinMode(Button_Pin, INPUT);
pinMode(Car1, OUTPUT);
pinMode(Car2, OUTPUT);
pinMode(Car3, OUTPUT);
pinMode(Car4, OUTPUT);
irrecv.enableIRIn();//Open IR
lcd.begin(16, 2);
}
// Autolight Mode 自动控制灯光模式过程
void Autolight()
{
if (!LM2) return;
Intensity = analogRead(LR_Pin);
int k = Intensity/4;
if (irrecv.decode(&results)) return;
if (k >= now) for (int i = now; i <= k; i ++) {
analogWrite(light_Pin, i);
delay(10);
}
else for (int i = now; i >= k; i --) {
analogWrite(light_Pin, i);
delay(10);
}
now = k;
}
//Button Mode 按钮控制过程
void ButtonMode()
{
past = buttonState;
delay(100);
buttonState = digitalRead(Button_Pin);
if (buttonState != past&&past != HIGH) {
if (light||fan) {
light = false;
fandgree = 0;
lightdgree = 0;
LM2 = false;
fan = false;
now = 0;
digitalWrite(Fan_Pin, LOW);
digitalWrite(light_Pin, LOW);
} else {
light = true;
LM2 = true;
fandgree = 185;
fan = true;
analogWrite(Fan_Pin, fandgree);
Autolight();
}
}
}
// Light Mode 灯光模块过程
void LightMode()
{
digitalWrite(LED_LP, HIGH);
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("1: Manual");
lcd.setCursor(1, 1);
lcd.print("2: Auto");
delay(100);
irrecv.resume();
while (!irrecv.decode(&results)) Autolight();
int k = results.value;
if (irrecv.decode(&results)) {
if (results.value == 0xFF30CF){
LM2 = false;
lcd.clear();
delay(100);
irrecv.resume();
while (!irrecv.decode(&results)){
Autolight();
lcd.setCursor(1, 0);
lcd.print("Luminance:");
lcd.setCursor(1, 1);
lcd.print("0:OFF; 1, 2, 3");
}
if (results.value != 0xFF6897){
lcd.clear();
lcd.setCursor(0, 0);
switch (results.value){
case 0xFF30CF:{lightdgree=1;lcd.print("-------ON-------");break;}
case 0xFF18E7:{lightdgree=2;lcd.print("-------ON-------");break;}
case 0xFF7A85:{lightdgree=3;lcd.print("-------ON-------");break;}
default:{lcd.print("-----ERROR!-----");break;}
}
analogWrite(light_Pin, 80 * lightdgree);
now = 80 * lightdgree;
delay(t);
light = true;
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("------OFF-------");
analogWrite(light_Pin, 0);
now = 0;
delay(t);
light = false;
}
k = 0;
}
if (results.value == 0xFF18E7&&k != 0){
LM2 = !LM2;
lightdgree = 0;
if (LM2){
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Auto Mode On");
if (!light){
analogWrite(light_Pin, now);
light = true;
}
delay(t);
} else {
light = false;
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Auto Mode Off");
analogWrite(light_Pin, 0);
now = 0;
delay(t);
}
}
menu = false;
}
irrecv.resume();
lcd.clear();
digitalWrite(LED_LP, LOW);
}
// Fan Mode 风扇模式过程
void FanMode()
{
digitalWrite(LED_FP, HIGH);
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Wind Power:");
lcd.setCursor(1, 1);
lcd.print("0:OFF; 1, 2, 3");
delay(100);
irrecv.resume();
while (!irrecv.decode(&results)) Autolight();
if (results.value != 0xFF6897){
lcd.clear();
lcd.setCursor(0, 0);
switch (results.value){
case 0xFF30CF:{fandgree = 160;lcd.print("-------ON-------");analogWrite(Fan_Pin, 160);break;}
case 0xFF18E7:{fandgree = 185;lcd.print("-------ON-------");analogWrite(Fan_Pin, 185);break;}
case 0xFF7A85:{fandgree = 225;lcd.print("-------ON-------");analogWrite(Fan_Pin, 225);break;}
default:{lcd.print("-----ERROR!-----");break;}
}
delay(t);
fan = true;
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("------OFF-------");
analogWrite(Fan_Pin, 0);
fandgree = 0;
delay(t);
fan = false;
}
lcd.clear();
irrecv.resume();
digitalWrite(LED_FP, LOW);
menu = false;
}
//Calculate the Distance in the front计算前方距离过程
float Distance()
{
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
dis=pulseIn(EchoPin, HIGH)/ 58.0;
return dis;
}
//Car Command 收到指令后的车轮控制过程
void CarCommand(int c1, int c2, int c3, int c4, bool w){
while (irrecv.decode(&results)){
if (w)
while (Distance() <= 10) {
digitalWrite(LED_LP, HIGH);
for (int i = 0; i < 100; i ++){
digitalWrite(Buzzer_Pin, HIGH);
delay(1);
digitalWrite(Buzzer_Pin, LOW);
delay(1);
}
digitalWrite(LED_LP, LOW);
return;
}
digitalWrite(Car1, c1);
digitalWrite(Car2, c2);
digitalWrite(Car3, c3);
digitalWrite(Car4, c4);
irrecv.resume();
delay(150);
}
}
//Car Mode 车辆移动函数
void CarMode()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("2:Forward 8:Back");
lcd.setCursor(0, 1);
lcd.print("4:L 6:R 5:Quit");
delay(200);
irrecv.resume();
while (!irrecv.decode(&results)){
ButtonMode();
Autolight();
}
while (results.value != 0xFF38C7){
if (irrecv.decode(&results)&&(results.value == 0xFF18E7)) CarCommand(LOW, HIGH, LOW, HIGH, 1);
if (irrecv.decode(&results)&&(results.value == 0xFF4AB5)) CarCommand(HIGH, LOW, HIGH, LOW, 0);
if (irrecv.decode(&results)&&(results.value == 0xFF10EF)) CarCommand(HIGH, LOW, LOW, HIGH, 0);
if (irrecv.decode(&results)&&(results.value == 0xFF5AA5)) CarCommand(LOW, HIGH, HIGH, LOW, 0);
ButtonMode();
digitalWrite(Car1, LOW);
digitalWrite(Car2, LOW);
digitalWrite(Car3, LOW);
digitalWrite(Car4, LOW);
irrecv.resume();
while (!irrecv.decode(&results)) {
ButtonMode();
Autolight();
}
}
lcd.clear();
menu = false;
}
//Temperature and Humidity 温度和湿度计算和显示过程
void T_H()
{
DHT11.read(dht11_Pin);
lcd.setCursor(0, 0);
lcd.print("T(oC):");
if (DHT11.temperature < 100)
lcd.print(DHT11.temperature); else
lcd.print(DHT11.temperature-100);
lcd.print(" H(%):");
lcd.print(DHT11.humidity);
lcd.setCursor(0, 1);
lcd.print("0: Menu 1: Check");
}
//Menu 菜单显示过程
void Menu()
{
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("1: LED 2: FAN");
lcd.setCursor(1, 1);
lcd.print("3: CAR CONTROL");
}
//Check 状态查询过程
void Check()
{
lcd.setCursor(0, 0);
lcd.print("L:");
if (lightdgree){
lcd.print(lightdgree);
lcd.print(" ");
} else if (LM2) lcd.print("Auto ");
else lcd.print("OFF ");
lcd.print("F:");
if (fandgree) {
switch (fandgree) {
case 160:{lcd.print("1");break;}
case 185:{lcd.print("2");break;}
case 225:{lcd.print("3");break;}
}
lcd.print(" ");
} else lcd.print("OFF ");
lcd.setCursor(0, 1);
lcd.print("0: Menu 1: Back");
}
//Open Welcome 开机欢迎画面
void OpenWelcome()
{
if (!whenopen) {
lcd.setCursor(0, 0);
char s[16] = "Nice To Meet You";
for (int i = 0; i < 16; i++){
lcd.print(s[i]);
delay(100);
}
lcd.setCursor(0, 1);
lcd.print(" ^_^ ");
delay(2000);
whenopen = true;
lcd.clear();
}
}
//Loop 主循环程序
void loop()
{
OpenWelcome();
if (check){
lcd.clear();
Check();
for (int i = 1; i <= 200; i ++){
delay(10);
buttonState = digitalRead(Button_Pin);
if (results.value == 0xFFFFFF)irrecv.resume();
if (buttonState != past) break;
if (irrecv.decode(&results)&&results.value != 0xFFFFFF) break;
}
check = 0;
}
ButtonMode();
if (!light) digitalWrite(light_Pin, LOW);
Autolight();
if (!menu&&check == 0) T_H();
if (irrecv.decode(&results)&&!menu) {
if (results.value == 0xFF6897) {
lcd.clear();
Menu();
menu = true;
}
if (results.value == 0xFF30CF) {check = 1;delay(250);}
irrecv.resume();
delay(100);
}
if (irrecv.decode(&results)&&menu) {
if (results.value == 0xFF30CF&&menu) LightMode();
if (results.value == 0xFF18E7&&menu) FanMode();
if (results.value == 0xFF7A85&&menu) CarMode();
irrecv.resume();
delay(100);
}
}
大概就是这么多吧,写了好几天,也Debug了很久,终于完成了!
十、结语
花了四天左右的时间,第一天通宵,后面几天都三点多睡,每天盯着屏幕和眼花缭乱的线,每次遇到bug都要加紧调试,元旦假期就这么过去了,也还算充实,最后几天也在认真的制作ppt和大作业文档,1月2号课堂答辩也算划下一个圆满的句点吧。
最后,
以此文记录Arduino大作业