基于Arduino的制作——智能桌面移动风扇灯

  • 初学Arduino,就要完成一次大作业,任务是用Arduino制作智能家居,这“戳实”很艰辛。。。还好,过程很艰辛,结局还算圆满。

特别感谢一起完成该制作的YuanSnowing同学!

一、任务灵感

基于Arduino的便携灵活,容易上手的特性,以及课堂上听课所得的知识,我们打算设计一款带有轮子,并且集风扇与台灯于一体的智能移动风扇灯。
制作只是雏形,未来的设想是实现落地灯和风扇于一体,并且能移动,方便人们移动与使用落地灯和落地风扇。

二、功能要求

  1. 通过按钮实现一键开关灯及风扇;
  2. 通过指示灯显示当前调整的功能(风扇或灯);
  3. 通过光敏电阻实现自动调节灯光亮度;
  4. 通过开关控制是否自动调节灯光亮度;
  5. 通过遥控控制显示屏显示风力和亮度级别大小;
  6. 通过遥控器调节风力或亮度;
  7. 通过遥控实现车子的移动;
  8. 通过温湿度传感器显示温湿度;
  9. 利用测距器和蜂鸣器做警报器,若装置距其他物品过近则发出警报;

三、设计框架

设计框图1
设计框图2

四、材料准备

  • 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大作业

  • 20
    点赞
  • 137
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值