基于Arduino UNO的智能温控风扇

基于Arduino UNO的智能温控风扇

本文主要介绍一个基于Arduino UNO的智能温控风扇demo,其主要实现两种切换模式,分别为自动模式以及手动模式。在自动模式下,风扇可根据DS18B20检测到的环境温度,并根据温度梯度达到不同风速,同时通过2Y0A21模块检测是否有人,若无人,则30s后关闭风扇;在手动模式下,可通过红外遥控以及按键控制风速。



前言

本文主要介绍一个基于Arduino UNO的智能温控风扇demo,其主要实现两种切换模式,分别为自动模式以及手动模式。在自动模式下,风扇可根据DS18B20检测到的环境温度,并根据温度梯度达到不同风速,同时通过2Y0A21模块检测是否有人,若无人,则30s后关闭风扇;在手动模式下,可通过红外遥控以及按键控制风速。在这两种模式下,均实现在LCD12864屏幕上。显示实时温度以及距离,还有当前所处模式。

硬件模块包含:Arduino UNO板,LCD12864,DS18B20,2Y0A21,小电机,L298N(2.1A双路电机模块),红外遥控器(含红外接收器),轻触按键,上拉电阻,面包板,若干杜邦线。

在这里插入图片描述


一、硬件模块

硬件模块包含:
在这里插入图片描述
Arduino UNO板,
在这里插入图片描述
LCD12864,
在这里插入图片描述
DS18B20,
在这里插入图片描述
2Y0A21,
在这里插入图片描述
小电机,
在这里插入图片描述
L298N(2.1A双路电机模块),
在这里插入图片描述
红外遥控器(含红外接收器),
在这里插入图片描述
轻触按键,
上拉电阻,面包板,若干杜邦线。


二、接线

硬件模块包含:Arduino UNO板,LCD12864,DS18B20,2Y0A21,小电机,L298N(2.1A双路电机模块),红外遥控器(含红外接收器),轻触按键,上拉电阻,面包板,若干杜邦线。

1.屏幕接线

接线可参考链接: arduino如何驱动LCD12864显示器?(使用U8g2库)

LCD12864模块--------------------------------Arduino UNO模块
GND、PSB、BLK引脚--------------------------GND引脚
VCC、BLA引脚-----------------------------------5V引脚
RS引脚----------------------------------------------2引脚
R/W(SID)引脚-------------------------------------3引脚
E(CLK)引脚----------------------------------------4引脚
RST引脚--------------------------------------------5引脚

2.DS18B20接线

DS18B20模块----------------------------------Arduino UNO模块
GND引脚-------------------------------------------GND引脚
VCC引脚--------------------------------------------5V引脚
信号引脚---------------------------------------------6引脚

3.2Y0A21接线

2Y0A21模块----------------------------------Arduino UNO模块
GND引脚-------------------------------------------GND引脚
VCC引脚--------------------------------------------5V引脚
信号引脚--------------------------------------------A5引脚

4.驱动模块+电机接线

接线可参考链接: 2.5A双路电机驱动模块 正反转 PWM调速 双H桥 步进电机 超L298N

电机模块-----------------驱动模块--------------------Arduino UNO模块
a引脚--------------------MOTOR-A-----------------------10引脚
b引脚--------------------MOTOR-A-----------------------11引脚
------------------------GND引脚(排针)---------------GND引脚

---------------------------2V-10V引脚--------------------外接电源5V
---------------------------GND引脚-----------------------外接电源GND

5.红外接收器接线

红外接收器模块-----------------------------Arduino UNO模块
GND引脚-------------------------------------------GND引脚
VCC引脚--------------------------------------------5V引脚
信号引脚---------------------------------------------7引脚

6.轻触按键接线

轻触按键模块-----------------------------Arduino UNO模块
1引脚-------------------------------------------GND引脚
2引脚--------------------------------------------A3引脚
2引脚----------------上拉电阻----------------5V引脚
同时2引脚接一个上拉电阻之后连到Arduino UNO模块5V引脚


三、所需库

  1. IRremote库 版本:4.3.0
  2. OneWire库 版本:2.3.7
  3. DallasTemperature库 版本3.9.0
  4. U8glib库 版本1.19.1

四、源码

1.整合代码:完整功能代码(直接接线、安装对应的库即可)

#include <IRremote.h>
// #include <U8g2lib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <U8glib.h>

#define irReceiverPin 7
#define motorPin1 10
#define motorPin2 11
#define ONE_WIRE_BUS 6
#define ds18b20TimeInterval 1000
#define pin A5
#define pushButton A3

IRrecv irrecv(irReceiverPin);
decode_results results;
//U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /*clock*/4, /*data*/3, /*cs*/2, /*reset*/5);
U8GLIB_ST7920_128X64_4X u8g(4, 3, 2);

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;

unsigned long ds18b20Times = 0;
unsigned long lastPersonDetectedTime = 0;
float ds18b20Temp = 0;

unsigned long manu_flag = 0; // 存储红外信号值

bool automaticMode = true; // 初始为自动模式

int buttonState = 0;// 按键次数

void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn();
  // u8g2.begin();
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }

  sensors.begin();
  sensors.getAddress(insideThermometer, 0);

  pinMode(pin, INPUT);
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(pushButton, INPUT);
}

void loop() {
  if (irrecv.decode(&results)) {
    if (results.value == 0xFFA25D) { // 如果按下红外遥控的 CH- 按钮
      automaticMode = true; // 切换到自动模式
    } else if (results.value == 0xFFE21D) { // 如果按下红外遥控的 CH+ 按钮
      automaticMode = false; // 切换到遥控模式
    }
    irrecv.resume(); // 准备接收下一个红外信号
  }

  if (automaticMode) {
    controlFanAutomatic();
  } else {
    controlFanManual();
  }
}

void controlFanAutomatic() {
  if (millis() - ds18b20Times >= ds18b20TimeInterval) {
    ds18b20Times = millis();
    sensors.requestTemperatures();
    ds18b20Temp = sensors.getTempC(insideThermometer);

    uint16_t value = analogRead(pin);
    uint16_t range = get_gp2d12(value);

    // u8g2.firstPage();
    u8g.firstPage(); 
    do {
      u8g.setFont(u8g_font_6x10); // 使用较小的字体
      u8g.drawStr(0, 12, "Auto");

      // 第一行显示温度
      u8g.drawStr(0, 24, "Temp:");
      u8g.setPrintPos(40, 24);
      u8g.print(ds18b20Temp);
      u8g.print(" C");

      // 第二行显示距离
      u8g.drawStr(0, 36, "Distance:");
      u8g.setPrintPos(60, 36);
      u8g.print(range);
      u8g.print(" mm");

      // 如果检测到人,则更新上次检测到人的时间
      if (range < 500) {
        lastPersonDetectedTime = millis();
        if (ds18b20Temp < 26) {
          analogWrite(motorPin1, 40);
          analogWrite(motorPin2, 0);
          u8g.drawStr(40, 12, "Mode0");
        } else if (ds18b20Temp >= 26 && ds18b20Temp < 27) {
          analogWrite(motorPin1, 50);
          analogWrite(motorPin2, 0);
          u8g.drawStr(40, 12, "Mode1");
        } else if (ds18b20Temp >= 27 && ds18b20Temp < 28) {
          analogWrite(motorPin1, 75);
          analogWrite(motorPin2, 0);
          u8g.drawStr(40, 12, "Mode2");
        } else if (ds18b20Temp >= 28 && ds18b20Temp < 29) {
          analogWrite(motorPin1, 100);
          analogWrite(motorPin2, 0);
          u8g.drawStr(40, 12, "Mode3");
        } else if (ds18b20Temp >= 29 && ds18b20Temp < 30) {
          analogWrite(motorPin1, 150);
          analogWrite(motorPin2, 0);
          u8g.drawStr(40, 12, "Mode4");
        } else if (ds18b20Temp >= 30) {
          analogWrite(motorPin1, 200);
          analogWrite(motorPin2, 0);
          u8g.drawStr(40, 12, "Mode5");
        }
      } else {
        // 如果30秒内没有检测到人,则关闭电机
        if (millis() - lastPersonDetectedTime >= 30000) {
          analogWrite(motorPin1, 0);
          analogWrite(motorPin2, 0);
        }
      }
    } while (u8g.nextPage());
  }
}

// 计算距离
uint16_t get_gp2d12(uint16_t value) {
  if (value < 30)
    value = 30;
  return ((67870.0 / (value - 3.0)) - 40.0);
}
 
void controlFanManual() {
  if (millis() - ds18b20Times >= ds18b20TimeInterval) {
    ds18b20Times = millis();
    sensors.requestTemperatures();
    ds18b20Temp = sensors.getTempC(insideThermometer);

    uint16_t value = analogRead(pin);
    uint16_t range = get_gp2d12(value);

    // u8g2.firstPage();
    u8g.firstPage(); 
    do {
      u8g.setFont(u8g_font_6x10); // 使用较小的字体
      u8g.drawStr(0, 12, "Manu");

      // 第一行显示温度
      u8g.drawStr(0, 24, "Temp:");
      u8g.setPrintPos(40, 24);
      u8g.print(ds18b20Temp);
      u8g.print(" C");

      // 第二行显示距离
      u8g.drawStr(0, 36, "Distance:");
      u8g.setPrintPos(60, 36);
      u8g.print(range);
      u8g.print(" mm");

      if (digitalRead(pushButton) == 0){
        delay(20);
        while(digitalRead(pushButton) == 0);
        delay(20);
        buttonState++;
        if (buttonState == 6){
            buttonState = 0;
        }
      }

      if (buttonState == 0) { // 按键0
        analogWrite(motorPin1, 0); // 停止电机
        analogWrite(motorPin2, 0); // 
        u8g.drawStr(40, 12, "Mode0");
        buttonState = 0;
      }
      else if (buttonState == 1) { // 按键1
        analogWrite(motorPin1, 50); //
        analogWrite(motorPin2, 0); //
        u8g.drawStr(40, 12, "Mode1");
        buttonState = 1;
      }
      else if (buttonState == 2) { // 按键2
        analogWrite(motorPin1, 75); // 
        analogWrite(motorPin2, 0); //
        u8g.drawStr(40, 12, "Mode2"); 
        buttonState = 2;
      }
      else if (buttonState == 3) { // 按键3
        analogWrite(motorPin1, 100); //
        analogWrite(motorPin2, 0); //
        u8g.drawStr(40, 12, "Mode3"); 
        buttonState = 3;
      }
      else if (buttonState == 4) { // 按键4
        analogWrite(motorPin1, 150); //
        analogWrite(motorPin2, 0); //
        u8g.drawStr(40, 12, "Mode4"); 
        buttonState = 4;
      }
      else if (buttonState == 5) { // 按键5
        analogWrite(motorPin1, 200); //
        analogWrite(motorPin2, 0); //
        u8g.drawStr(40, 12, "Mode5"); 
        buttonState = 5;
      }

      if (irrecv.decode(&results)) {
        // 打印接收到的红外信号的值和位数
        Serial.print("irCode: ");
        Serial.print(results.value, HEX);
        Serial.print(", bits: ");
        Serial.println(results.bits);
        
        manu_flag = results.value;
        // 根据不同的红外信号值来控制电机转速
        if (results.value == 0xFF6897) { // 按键0
          buttonState = 0;
        }
        else if (results.value == 0xFF30CF) { // 按键1
          buttonState = 1;
        }
        else if (results.value == 0xFF18E7) { // 按键2
          buttonState = 2;
        }
        else if (results.value == 0xFF7A85) { // 按键3
          buttonState = 3;
        }
        else if (results.value == 0xFF10EF) { // 按键4
          buttonState = 4;
        }
        else if (results.value == 0xFF38C7) { // 按键5
          buttonState = 5;
        }
        else {
        // 其他按键值不进行任何操作
        }
        delay(300);
        irrecv.resume(); // 准备接收下一个红外信号
      } 
    }while (u8g.nextPage());
  }
}

2.测试代码:自动模式代码(采用U8g2lib库显示)

#include <U8g2lib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <IRremote.h>

U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /*clock*/4, /*data*/3, /*cs*/2 , /*reset*/5);

#define ONE_WIRE_BUS 6                // DS18B20
#define ds18b20TimeInterval 1000
#define pin A5                        // 2Y0A21

// 89号引脚控制一个电机的两个引脚
const int motorPin1 = 10; // 第一个引脚连接到 8 号引脚
const int motorPin2 = 11; // 第二个引脚连接到 9 号引脚

unsigned long lastPersonDetectedTime = 0; // 上次检测到人的时间

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);  
DeviceAddress insideThermometer;

unsigned long ds18b20Times = 0;
float ds18b20Temp = 0;

void setup() {
  u8g2.begin();
  Serial.begin(9600);
  sensors.begin();
  if (!sensors.getAddress(insideThermometer, 0)) {
    Serial.println("设备未上线!");
  }
  Serial.println("设备上线!");
  pinMode(pin, INPUT);
  //电机
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
}

void loop() {
  printData();
}

void printData() {
  if (millis() - ds18b20Times >= ds18b20TimeInterval) {
    ds18b20Times = millis();
    sensors.requestTemperatures();
    ds18b20Temp = sensors.getTempC(insideThermometer);
    
    uint16_t value = analogRead(pin);
    uint16_t range = get_gp2d12(value);

    u8g2.firstPage();
    do {
      u8g2.setFont(u8g2_font_6x10_tr); // 使用较小的字体
      // 第一行显示温度
      u8g2.drawStr(0, 12, "Temp:");
      u8g2.setCursor(40, 12);
      u8g2.print(ds18b20Temp);
      u8g2.print(" C");

      // 第二行显示距离
      u8g2.drawStr(0, 24, "Distance:");
      u8g2.setCursor(60, 24);
      u8g2.print(range);
      u8g2.print(" mm");

      // 如果检测到人,则更新上次检测到人的时间
      if (range<1000){
        lastPersonDetectedTime = millis();
        if (ds18b20Temp<26){
          analogWrite(motorPin1, 0); //
          analogWrite(motorPin2, 0); //
        }
        else if (ds18b20Temp>=26 && ds18b20Temp<27){
          analogWrite(motorPin1, 50); //
          analogWrite(motorPin2, 0); //
        }
        else if (ds18b20Temp>=27 && ds18b20Temp<28){
          analogWrite(motorPin1, 75); //
          analogWrite(motorPin2, 0); //
        }
        else if (ds18b20Temp>=28 && ds18b20Temp<29){
          analogWrite(motorPin1, 100); //
          analogWrite(motorPin2, 0); //
        }
        else if(ds18b20Temp>=29 && ds18b20Temp<30){
          analogWrite(motorPin1, 150); //
          analogWrite(motorPin2, 0); //
        }
        else if(ds18b20Temp>=30){
          analogWrite(motorPin1, 200); //
          analogWrite(motorPin2, 0); //
        }
      }
      else{
        if (millis() - lastPersonDetectedTime >= 10000) {
          analogWrite(motorPin1, 0); //
          analogWrite(motorPin2, 0); //
        }
      }
    } while (u8g2.nextPage());
  }
}

// 计算距离
uint16_t get_gp2d12(uint16_t value) {
  if (value < 30)
    value = 30;
  return ((67870.0 / (value - 3.0)) - 40.0);
}

3.测试代码:遥控模式代码(未显示温度、距离)

#include <IRremote.h>
// 7号引脚接收红外信号
const int irReceiverPin = 7;
// 89号引脚控制一个电机的两个引脚
const int motorPin1 = 10; // 第一个引脚连接到 10 号引脚
const int motorPin2 = 11; // 第二个引脚连接到 11 号引脚

IRrecv irrecv(irReceiverPin);
decode_results results;

void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn();
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
}

void loop() {
  if (irrecv.decode(&results)) {
    // 打印接收到的红外信号的值和位数
    Serial.print("irCode: ");
    Serial.print(results.value, HEX);
    Serial.print(", bits: ");
    Serial.println(results.bits);
    
    // 根据不同的红外信号值来控制电机转速
    if (results.value == 0xFF6897) { // 按键0
      analogWrite(motorPin1, 0); // 停止电机
      analogWrite(motorPin2, 0); // 
    }
    else if (results.value == 0xFF30CF) { // 按键1
      analogWrite(motorPin1, 100); //
      analogWrite(motorPin2, 0); //
    }
    else if (results.value == 0xFF18E7) { // 按键2
      analogWrite(motorPin1, 150); // 
      analogWrite(motorPin2, 0); // 
    }
    else if (results.value == 0xFF7A85) { // 按键3
      analogWrite(motorPin1, 200); //
      analogWrite(motorPin2, 0); // 
    }
    else {
    // 其他按键值不进行任何操作
    }
    delay(300);
    irrecv.resume(); // 准备接收下一个红外信号
  }
}

五、遇到的一些问题

1.问题1

问题1:红外遥控测试时候会出现无论按什么键均打印FFFFFF的问题
原因分析:IRremote库版本过高
解决方法:换成低版本即可,本文所用版本的库能正常使用

参考方法链接: 【Arduino】红外遥控实验按遥控器没反应 解决

2.问题2

问题2:用Arduino UNO的5V给电机模块供电,电机转不动
原因分析:Arduino UNO上面的电源管理电流过低,不足以支撑电机转动
解决方法:外接5V电源给电机模块供电,同时注意要共地!

3.问题3

问题3:各模块代码整合的时候出现Arduino UNO的内存显示不足,例如

Sketch uses 1978 bytes (6%) of program storage space. Maximum is 32256 bytes.
Global variables use 188 bytes (9%) of dynamic memory, leaving 1860 bytes for local variables. Maximum is 2048 bytes.

原因分析:经过测试发现,本项目中原本使用的U8g2lib库严重占用内存,换成小一些的屏幕显示库U8glib即可
解决方法:换成小一些的屏幕显示库U8glib即可

参考方法链接: 解决Arduino Uno上传代码时提示内存不足的问题

好的,这里是一个基于Arduino Uno温控风扇项目的设计方案: 材料清单: - Arduino Uno主板 - DHT11温湿度传感器 - 5V直流电机(风扇) - TIP120 NPN晶体管 - 1K电阻 - 2N3904 PNP晶体管 - 10K电阻 - 9V电池或者电源适配器 - 电线 - 面包板 步骤: 1. 将DHT11连接到Arduino上,连接方式如下: - VCC -> 5V - GND -> GND - DATA -> 2 2. 将晶体管TIP120连接到Arduino上,连接方式如下: - BASE -> 9 - COLLECTOR -> 5V - EMITTER -> 风扇正极 3. 将电阻1K连接到晶体管TIP120的基极和Arduino的数字引脚9之间 4. 将PNP晶体管2N3904连接到Arduino上,连接方式如下: - EMITTER -> GND - COLLECTOR -> TIP120的基极 - BASE -> 10K电阻和Arduino的数字引脚8之间 5. 将电线连接到风扇负极和Arduino的GND之间,形成回路 6. 将电源适配器(或者9V电池)连接到Arduino的5V和GND之间 代码: 下面是基于以上硬件连接的代码,它将从DHT11传感器读取温度值,并根据温度控制风扇的转速: ``` #include <dht.h> //导入DHT库 #define DHTPIN 2 //指定DHT11连接到Arduino的2号引脚 #define DHTTYPE DHT11 //指定使用DHT11传感器 #define FAN 3 //指定风扇连接到Arduino的3号引脚 #define MIN_TEMP 25 //最低温度为25℃ #define MAX_TEMP 30 //最高温度为30℃ dht DHT; //创建DHT对象 void setup() { pinMode(FAN, OUTPUT); //将风扇引脚设为输出模式 Serial.begin(9600); //初始化串口通信 } void loop() { int chk = DHT.read11(DHTPIN); //从DHT11读取温湿度值 if (chk == DHTLIB_OK) { Serial.print("Temperature: "); //将温度值输出到串口监视器 Serial.println(DHT.temperature); if (DHT.temperature > MAX_TEMP) { //如果温度高于最高温度,则风扇转速最高 analogWrite(FAN, 255); } else if (DHT.temperature < MIN_TEMP) { //如果温度低于最低温度,则风扇停止转动 digitalWrite(FAN, LOW); } else { //否则根据温度控制风扇转速 int fanSpeed = map(DHT.temperature, MIN_TEMP, MAX_TEMP, 0, 255); analogWrite(FAN, fanSpeed); } } } ``` 以上就是基于Arduino Uno温控风扇项目的设计方案,希望能对你有所帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值