零知开源——基于STM32F103RBT6的智能风扇控制系统设计与实现

发布于:2025-09-06 ⋅ 阅读:(18) ⋅ 点赞:(0)

 ✔零知IDE 是一个真正属于国人自己的开源软件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知实验室,获取更多实战项目和教程资源吧!

www.lingzhilab.com

目录

一、硬件连接部分

1.1 硬件清单

1.2 接线方案

1.3 具体接线图

1.4 接线实物图

二、关键代码解析

2.1 主循环设计

2.2 红外信号处理

2.3 显示更新优化

2.4 风扇驱动控制

2.5 系统完整代码

三、项目结果演示

3.1 操作流程

3.2 界面展示

3.3 视频演示

四、JQC-3FF-S-Z工作原理

4.1 基本结构

4.2 动作机制

五、常见问题解答

Q1: 如何调整光控的灵敏度?

Q2: 如何修改定时时间?

Q3: 舵机转动不流畅怎么办?


(1)项目概述

        本项目基于STM32F103RBT6主控芯片(零知标准板),设计并实现了一个功能丰富的智能风扇控制系统。融合了红外遥控、自动光控、定时关闭、睡眠模式等多种智能控制方式。系统采用JQC-3FF-S-Z继电器作为主要控制元件,通过红外遥控器实现远程控制,同时集成了光敏传感器实现环境光线自适应控制。

(2)项目难点及解决方案

       问题描述:系统需要同时处理红外信号接收、舵机控制、传感器数据采集和显示更新等多个任务。

解决方案: 采用基于millis()的时间管理方法,避免使用delay(),确保系统响应及时

一、硬件连接部分

1.1 硬件清单

组件名称 型号/规格 数量 备注
主控板 零知标准板(STM32F103RBT6) 1 核心控制单元
继电器模块 JQC-3FF-S-Z 1 控制风扇电源
TFT显示屏 ST7789 240x240 1 用户界面显示
红外控制模块 IR Receiver红外接收模块 1 接收红外信号
舵机 SG90 1 实现风扇摇头功能
光敏电阻 光敏电阻模块 1 环境光线检测
直流电机 3.3V 1 被控对象

1.2 接线方案

        注意:JQC-3FF-S-Z的D+接5V,其他器件电源接3.3V

组件 零知标准板引脚 说明
继电器IN 6 继电器控制引脚
红外接收DATA 3 红外信号输入
舵机信号 5 舵机控制
TFT_SCL 13 显示屏时钟线
TFT_SDA 11 显示屏数据输入
TFT_CS 10 显示屏片选
TFT_DC 9 显示屏数据/命令
TFT_RST 8 显示屏复位
光敏电阻OUT 0 光线传感器信号

1.3 具体接线图

        PS:直流电机的其中一极接3.3V电源,另一极接JQC-3FF-S-Z继电器的COM公共端

1.4 接线实物图

二、关键代码解析

2.1 主循环设计

void loop() {
  // 处理红外信号
  if (irrecv.decode(&results)) {
    handleIRCommand(results.value);
    irrecv.resume();
    redrawNeeded = true;
  }
  
  // 处理舵机摆动
  handleSwing();
  
  // 处理定时器
  handleTimer();
  
  // 处理睡眠模式
  handleSleepMode();
  
  // 读取光线传感器数据
  readLightSensor();
  
  // 自动模式处理
  if (operationMode == MODE_LIGHT_AUTO) {
    handleAutoMode();
  }
  
  // 更新显示
  updateDisplay();
  
  delay(100); // 短暂延迟以减少CPU使用率
}

        主循环采用非阻塞设计,通过状态标志控制各功能的执行,确保系统响应及时。

2.2 红外信号处理

void handleIRCommand(unsigned long value) {
  Serial.print("IR Code Received: 0x");
  Serial.println(value, HEX);
  
  switch(value) {
    case BTN_POWER:
      togglePower();
      break;
    // 其他按键处理...
  }
}

        红外信号处理函数通过switch-case结构解析不同按键的功能,代码结构清晰易懂。

2.3 显示更新优化

void updateDisplay() {
  // 只在需要时重绘
  if (!redrawNeeded) {
    // 对于定时器模式,每秒更新一次时间显示
    if (operationMode == MODE_TIMER && timerActive) {
      unsigned long currentTime = millis();
      if (currentTime - lastTimerUpdate >= 1000) {
        lastTimerUpdate = currentTime;
        updateTimerDisplay();
      }
    }
    // 省略其他模式...
    return;
  }
  // 全屏刷新逻辑...
}

        显示更新函数通过redrawNeeded标志控制刷新频率,避免不必要的屏幕刷新,提高系统效率。

2.4 风扇驱动控制

void turnOffFan() {
  digitalWrite(RELAY_PIN, HIGH);
  fanState = FAN_OFF;
  swingState = SWING_OFF; // 关闭风扇时也停止摆动
  timerActive = false; // 取消定时
  sleepActive = false; // 取消睡眠模式
  Serial.println("Fan Turned OFF");
}

void turnOnFan() {
  digitalWrite(RELAY_PIN, LOW);
  fanState = FAN_ON;
  Serial.println("Fan Turned ON");
}

void handleSwing() {
  if (swingState == SWING_OFF) return;
  
  unsigned long currentTime = millis();
  if (currentTime - lastSwingTime >= swingSpeed) {
    lastSwingTime = currentTime;
    
    // 摆动范围 20-160 度
    static int direction = 1; // 1为增加角度,-1为减少角度
    
    swingAngle += direction;
    myservo.write(swingAngle);
    
    // 到达边界时改变方向
    if (swingAngle >= 160 || swingAngle <= 20) {
      direction = -direction;
    }
  }
}

        JQC-3FF-S-Z继电器模块控制风扇电源并设置标志位

2.5 系统完整代码

#include "IRremote.h"
#include "Servo.h"
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>

// 引脚定义
#define IR_RECV_PIN 3     // 红外接收 DAT 引脚
#define RELAY_PIN 6       // 继电器控制引脚
#define SERVO_PIN 5       // 舵机控制引脚
#define TFT_CS 10         // TFT显示屏片选引脚
#define TFT_DC 9          // TFT显示屏数据/命令引脚
#define TFT_RST 8         // TFT显示屏复位引脚
#define LIGHT_SENSOR A0   // 光敏电阻引脚

// 红外按键编码
enum IR_CODES {
  BTN_POWER = 0xFF30CF,   // 按键1 - 电源开关
  BTN_SWING = 0xFF18E7,   // 按键2 - 摇头开关
  BTN_TIMER_10 = 0xFF7A85, // 按键3 - 10秒定时
  BTN_TIMER_30 = 0xFF10EF, // 按键4 - 30秒定时
  BTN_MODE = 0xFF38C7,    // 按键5 - 模式切换
  BTN_SLEEP = 0xFF4AB5    // 按键8 - 睡眠模式
};

// 系统状态
enum FAN_STATE {
  FAN_OFF,
  FAN_ON
};

enum SWING_STATE {
  SWING_OFF,
  SWING_ON
};

enum OPERATION_MODE {
  MODE_NORMAL,
  MODE_LIGHT_AUTO,
  MODE_TIMER,
  MODE_SLEEP
};

// 全局变量
IRreceiver irrecv(IR_RECV_PIN);
IRdecode_results results;
Servo myservo;
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

int fanState = FAN_OFF;
int swingState = SWING_OFF;
int operationMode = MODE_NORMAL;
int swingAngle = 90;     // 舵机角度
int swingSpeed = 15;     // 舵机速度 (ms延迟,值越小越快)
unsigned long lastSwingTime = 0;
unsigned long timerStartTime = 0;
unsigned long timerDuration = 0;
bool timerActive = false;
unsigned long sleepStartTime = 0;
unsigned long sleepDuration = 5 * 1000; // 8小时睡眠模式  8 * 60 * 60 * 1000
bool sleepActive = false;
int lightLevel = 0;
int lastLightLevel = 0;
unsigned long lastTimerUpdate = 0;
bool redrawNeeded = true;

// 显示区域定义
#define STATUS_AREA 40
#define DATA_AREA 80
#define LIGHT_THRESHOLD 500 // 光线阈值

void setup() {
  Serial.begin(9600);
  
  // 初始化引脚
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH);  // 初始关闭继电器

  // 初始化红外接收和舵机
  irrecv.enableIRIn();
  myservo.attach(SERVO_PIN);
  myservo.write(swingAngle);      // 初始位置
  
  // 初始化显示屏
  tft.init(240, 240);
  tft.setRotation(1);
  tft.fillScreen(ST77XX_BLACK);
  
  // 初始化光敏电阻
  pinMode(LIGHT_SENSOR, INPUT);
  
  // 显示准备界面
  showReadyScreen();
  
  Serial.println("\nSmart Fan Control System Started");
}

void loop() {
  // 处理红外信号
  if (irrecv.decode(&results)) {
    handleIRCommand(results.value);
    irrecv.resume();
    redrawNeeded = true;
  }
  
  // 处理舵机摆动
  handleSwing();
  
  // 处理定时器
  handleTimer();
  
  // 处理睡眠模式
  handleSleepMode();
  
  // 读取光线传感器数据
  readLightSensor();
  
  // 自动模式处理
  if (operationMode == MODE_LIGHT_AUTO) {
    handleAutoMode();
  }
  
  // 更新显示
  updateDisplay();
  
  delay(100); // 短暂延迟以减少CPU使用率
}

void showReadyScreen() {
  tft.fillScreen(ST77XX_BLACK);
  
  // 显示标题
  tft.setCursor(60, 80);
  tft.setTextColor(ST77XX_CYAN);
  tft.setTextSize(3);
  tft.println("READY");
  
  // 绘制进度条
  tft.drawRect(20, 120, 200, 20, ST77XX_WHITE);
  for (int i = 0; i <= 100; i += 5) {
    tft.fillRect(20, 120, i * 2, 20, ST77XX_BLUE);
    delay(50);
  }
  
  delay(1000);
  tft.fillScreen(ST77XX_BLACK);
  redrawNeeded = true;
}

void handleIRCommand(unsigned long value) {
  Serial.print("IR Code Received: 0x");
  Serial.println(value, HEX);
  
  switch(value) {
    case BTN_POWER:
      togglePower();
      break;
      
    case BTN_SWING:
      toggleSwing();
      break;
      
    case BTN_TIMER_10:
      setTimer(10);
      break;
      
    case BTN_TIMER_30:
      setTimer(30);
      break;
      
    case BTN_MODE:
      switchMode();
      break;
      
    case BTN_SLEEP:
      toggleSleepMode();
      break;
      
    default:
      Serial.println("Unknown Command");
      break;
  }
}

void togglePower() {
  if (fanState == FAN_OFF) {
    turnOnFan();
  } else {
    turnOffFan();
  }
}

void turnOffFan() {
  digitalWrite(RELAY_PIN, HIGH);
  fanState = FAN_OFF;
  swingState = SWING_OFF; // 关闭风扇时也停止摆动
  timerActive = false; // 取消定时
  sleepActive = false; // 取消睡眠模式
  Serial.println("Fan Turned OFF");
}

void turnOnFan() {
  digitalWrite(RELAY_PIN, LOW);
  fanState = FAN_ON;
  Serial.println("Fan Turned ON");
}

void toggleSwing() {
  if (fanState == FAN_OFF) {
    Serial.println("Please Turn ON Fan First");
    return;
  }
  
  swingState = !swingState;
  Serial.print("Swing Function ");
  Serial.println(swingState ? "Enabled" : "Disabled");
}

void setTimer(int seconds) {
  if (fanState == FAN_OFF) {
    Serial.println("Please Turn ON Fan First");
    return;
  }
  
  timerDuration = seconds * 1000; // 转换为毫秒
  timerStartTime = millis();
  timerActive = true;
  operationMode = MODE_TIMER;
  redrawNeeded = true;
  Serial.print("Timer Set: ");
  Serial.print(seconds);
  Serial.println(" seconds");
}

void switchMode() {
  if (operationMode == MODE_NORMAL) {
    operationMode = MODE_LIGHT_AUTO;
  } else if (operationMode == MODE_LIGHT_AUTO) {
    operationMode = MODE_NORMAL;
  } else {
    // 如果是定时器或睡眠模式,切换到普通模式
    operationMode = MODE_NORMAL;
  }
  
  redrawNeeded = true;
  
  if (operationMode == MODE_NORMAL) {
    Serial.println("Normal Mode");
  } else if (operationMode == MODE_LIGHT_AUTO) {
    Serial.println("Light Auto Mode");
  }
}

void toggleSleepMode() {
  if (fanState == FAN_OFF) {
    Serial.println("Please Turn ON Fan First");
    return;
  }
  
  sleepActive = !sleepActive;
  
  if (sleepActive) {
    sleepStartTime = millis();
    operationMode = MODE_SLEEP;
    Serial.println("Sleep Mode Activated - Fan will turn off at 6 AM");
  } else {
    operationMode = MODE_NORMAL;
    Serial.println("Sleep Mode Deactivated");
  }
  
  redrawNeeded = true;
}

void handleSwing() {
  if (swingState == SWING_OFF) return;
  
  unsigned long currentTime = millis();
  if (currentTime - lastSwingTime >= swingSpeed) {
    lastSwingTime = currentTime;
    
    // 摆动范围 20-160 度
    static int direction = 1; // 1为增加角度,-1为减少角度
    
    swingAngle += direction;
    myservo.write(swingAngle);
    
    // 到达边界时改变方向
    if (swingAngle >= 160 || swingAngle <= 20) {
      direction = -direction;
    }
  }
}

void handleTimer() {
  if (!timerActive) return;
  
  unsigned long currentTime = millis();
  unsigned long elapsedTime = currentTime - timerStartTime;
  
  if (elapsedTime >= timerDuration) {
    turnOffFan();
    operationMode = MODE_NORMAL;
    Serial.println("Timer Finished - Fan Turned OFF");
    redrawNeeded = true;
  }
}

void handleSleepMode() {
  if (!sleepActive) return;
  
  unsigned long currentTime = millis();
  unsigned long elapsedTime = currentTime - sleepStartTime;
  
  // 模拟6点关闭(8小时睡眠时间)
  if (elapsedTime >= sleepDuration) {
    turnOffFan();
    sleepActive = false;
    operationMode = MODE_NORMAL;
    Serial.println("Sleep Mode Finished - Fan Turned OFF");
    redrawNeeded = true;
  }
}

void readLightSensor() {
  // 读取光线强度
  int newLightLevel = analogRead(LIGHT_SENSOR);
  
  // 添加一些滤波以减少噪声
  lightLevel = (lightLevel * 0.7) + (newLightLevel * 0.3);
}

void handleAutoMode() {
  if (operationMode != MODE_LIGHT_AUTO) return;
  
  if (fanState == FAN_OFF && lightLevel < LIGHT_THRESHOLD) {
    turnOnFan();
    Serial.println("Low Light - Auto ON");
    redrawNeeded = true;
  }
  
  if (fanState == FAN_ON && lightLevel >= LIGHT_THRESHOLD) {
    turnOffFan();
    Serial.println("Bright Light - Auto OFF");
    redrawNeeded = true;
  }
}

void updateDisplay() {
  // 只在需要时重绘
  if (!redrawNeeded) {
    // 对于定时器模式,每秒更新一次时间显示
    if (operationMode == MODE_TIMER && timerActive) {
      unsigned long currentTime = millis();
      if (currentTime - lastTimerUpdate >= 1000) {
        lastTimerUpdate = currentTime;
        updateTimerDisplay();
      }
    }
    // 对于睡眠模式,每分钟更新一次时间显示
    else if (operationMode == MODE_SLEEP && sleepActive) {
      unsigned long currentTime = millis();
      if (currentTime - lastTimerUpdate >= 10000) {
        lastTimerUpdate = currentTime;
        updateSleepDisplay();
      }
    }
    return;
  }
  
  lastLightLevel = lightLevel;
  
  // 清除整个屏幕
  tft.fillScreen(ST77XX_BLACK);
  
  // 绘制标题和模式指示器
  tft.setCursor(20, 10);
  tft.setTextColor(ST77XX_CYAN);
  tft.setTextSize(2);
  tft.println("SMART FAN");
  
  // 绘制模式指示器
  uint16_t modeColor;
  String modeText;
  
  switch(operationMode) {
    case MODE_NORMAL:
      modeColor = ST77XX_BLUE;
      modeText = "NORM";
      break;
    case MODE_LIGHT_AUTO:
      modeColor = ST77XX_GREEN;
      modeText = "AUTO";
      break;
    case MODE_TIMER:
      modeColor = ST77XX_YELLOW;
      modeText = "TIMER";
      break;
    case MODE_SLEEP:
      modeColor = ST77XX_MAGENTA;
      modeText = "SLEEP";
      break;
  }
  
  tft.fillRect(180, 10, 50, 20, modeColor);
  tft.setCursor(185, 15);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.println(modeText);
  
  // 绘制分隔线
  tft.drawFastHLine(10, 35, 220, ST77XX_WHITE);
  
  // 根据模式更新显示
  switch(operationMode) {
    case MODE_NORMAL:
      updateNormalModeDisplay();
      break;
    case MODE_LIGHT_AUTO:
      updateLightModeDisplay();
      break;
    case MODE_TIMER:
      updateTimerDisplay();
      break;
    case MODE_SLEEP:
      updateSleepDisplay();
      break;
  }
  
  redrawNeeded = false;
  lastTimerUpdate = millis();
}

void updateNormalModeDisplay() {
  // 清除数据区域
  tft.fillRect(10, STATUS_AREA, 220, 200, ST77XX_BLACK);
  
  // 显示风扇状态
  tft.setCursor(20, 50);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(2);
  tft.print("FAN: ");
  tft.setTextColor(fanState == FAN_ON ? ST77XX_GREEN : ST77XX_RED);
  tft.println(fanState == FAN_ON ? "ON" : "OFF");
  
  // 显示摇头状态
  tft.setCursor(20, 80);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("SWING: ");
  tft.setTextColor(swingState == SWING_ON ? ST77XX_GREEN : ST77XX_RED);
  tft.println(swingState == SWING_ON ? "ON" : "OFF");
  
  // 显示舵机速度
  tft.setCursor(20, 110);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("SPEED: ");
  tft.setTextColor(ST77XX_YELLOW);
  tft.print(swingSpeed);
  tft.println("ms");
  
  // 显示光线数据
  tft.setCursor(20, 140);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("LIGHT: ");
  tft.setTextColor(ST77XX_GREEN);
  tft.println(lightLevel);
  
  // 底部状态栏
  tft.fillRect(0, 220, 240, 20, ST77XX_BLUE);
  tft.setCursor(70, 225);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.print("NORMAL MODE");
}

void updateLightModeDisplay() {
  // 清除数据区域
  tft.fillRect(10, STATUS_AREA, 220, 200, ST77XX_BLACK);
  
  // 显示标题
  tft.setCursor(20, 50);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(2);
  tft.println("LIGHT CONTROL");
  
  // 显示光线数据
  tft.setCursor(20, 80);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("LIGHT: ");
  tft.setTextColor(ST77XX_GREEN);
  tft.println(lightLevel);
  
  // 显示阈值信息
  tft.setCursor(20, 110);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("THRESHOLD: ");
  tft.setTextColor(ST77XX_YELLOW);
  tft.println(LIGHT_THRESHOLD);
  
  // 显示控制状态
  tft.setCursor(20, 140);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("CONTROL: ");
  if (lightLevel < LIGHT_THRESHOLD) {
    tft.setTextColor(ST77XX_GREEN);
    tft.println("FAN ON");
  } else {
    tft.setTextColor(ST77XX_RED);
    tft.println("FAN OFF");
  }
  
  // 显示当前风扇状态
  tft.setCursor(20, 170);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("FAN: ");
  tft.setTextColor(fanState == FAN_ON ? ST77XX_GREEN : ST77XX_RED);
  tft.println(fanState == FAN_ON ? "ON" : "OFF");
  
  // 底部状态栏
  tft.fillRect(0, 220, 240, 20, ST77XX_GREEN);
  tft.setCursor(70, 225);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.print("AUTO LIGHT MODE");
}

void updateTimerDisplay() {
  // 清除数据区域
  tft.fillRect(10, STATUS_AREA, 220, 200, ST77XX_BLACK);
  
  // 显示标题
  tft.setCursor(20, 50);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(2);
  tft.println("TIMER MODE");
  
  // 显示剩余时间
  tft.setCursor(20, 80);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("TIME LEFT: ");
  
  if (timerActive) {
    unsigned long remaining = (timerDuration - (millis() - timerStartTime)) / 1000;
    tft.setTextColor(ST77XX_YELLOW);
    tft.print(remaining);
    tft.println("s");
  } else {
    tft.setTextColor(ST77XX_RED);
    tft.println("INACTIVE");
  }
  
  // 显示风扇状态
  tft.setCursor(20, 110);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("FAN: ");
  tft.setTextColor(fanState == FAN_ON ? ST77XX_GREEN : ST77XX_RED);
  tft.println(fanState == FAN_ON ? "ON" : "OFF");
  
  // 底部状态栏
  tft.fillRect(0, 220, 240, 20, ST77XX_YELLOW);
  tft.setCursor(90, 225);
  tft.setTextColor(ST77XX_BLACK);
  tft.setTextSize(1);
  tft.print("TIMER MODE");
}

void updateSleepDisplay() {
  // 清除数据区域
  tft.fillRect(10, STATUS_AREA, 220, 200, ST77XX_BLACK);
  
  // 显示标题
  tft.setCursor(20, 50);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(2);
  tft.println("SLEEP MODE");
  
  // 显示剩余时间
  tft.setCursor(20, 80);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("TIME LEFT: ");
  
  if (sleepActive) {
    unsigned long remaining = (sleepDuration - (millis() - sleepStartTime)) / 1000;
    unsigned long hours = remaining / 3600;
    unsigned long minutes = (remaining % 3600) / 60;
    
    tft.setTextColor(ST77XX_MAGENTA);
    tft.print(hours);
    tft.print("h ");
    tft.print(minutes);
    tft.println("m");
  } else {
    tft.setTextColor(ST77XX_RED);
    tft.println("INACTIVE");
  }
  
  // 显示关闭时间
  tft.setCursor(20, 110);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("TURNS OFF: ");
  tft.setTextColor(ST77XX_YELLOW);
  tft.println("6:00 AM");
  
  // 显示风扇状态
  tft.setCursor(20, 140);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("FAN: ");
  tft.setTextColor(fanState == FAN_ON ? ST77XX_GREEN : ST77XX_RED);
  tft.println(fanState == FAN_ON ? "ON" : "OFF");
  
  // 底部状态栏
  tft.fillRect(0, 220, 240, 20, ST77XX_MAGENTA);
  tft.setCursor(90, 225);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.print("SLEEP MODE");
}
模块名称 核心职责 关键函数
红外遥控 接收并解析红外按键指令,映射到对应功能 handleIRCommand()togglePower()
风扇动作控制 控制风扇电源(继电器)和摇头(舵机) turnOnFan()turnOffFan()等
模式控制 管理普通、光线自动、定时、睡眠 4 种工作模式 switchMode()handleAutoMode()
传感器数据 读取并滤波光敏传感器数据,为自动模式提供依据 readLightSensor()
显示驱动 控制 TFT 屏显示系统状态(定时 / 睡眠剩余时间) updateTimerDisplay()等

三、项目结果演示

3.1 操作流程

(1)系统启动

        上电后系统显示准备界面,完成自检后进入主界面

(2)系统控制

        "电源键:开关风扇、"摇头键:启用/禁用摇头功能、"模式键:切换普通/光控模式                定时功能:设置10秒 / 30秒后系统自动关闭、启用睡眠模式 8 小时自动关闭

3.2 界面展示

(1)普通模式界面

        显示风扇状态、摇头状态、舵机速度和光线值

(2)光控模式界面

        显示光线值、阈值和控制状态

(3)定时模式界面

        显示剩余时间和风扇状态

(4)睡眠模式界面

        显示剩余时间和关闭时间

3.3 视频演示

JQC-3FF-S-Z继电器驱动小风扇

红外遥控操作控制智能风扇实现自动光控功能、摇头功能、模式切换以及系统定时功能

四、JQC-3FF-S-Z工作原理

4.1 基本结构

        继电器主要由电磁线圈、铁芯、铁片(衔铁)、复位弹簧、常开触点和常闭触点等部分组成。

4.2 动作机制

        根据触点的动作形式,可分为常闭式和常开式。常闭式继电器在未通电时触点闭合,通电后断开;常开式继电器在未通电时触点断开,通电后闭合。

        电器的动作机制基于电磁感应原理。当线圈通电后,产生的磁场使铁心运动,带动与铁心相连的触点动作。

五、常见问题解答

Q1: 如何调整光控的灵敏度?

A: 修改代码中的LIGHT_THRESHOLD值:

        值越小,对光线越敏感(更容易触发)。值越大,需要更暗的环境才会触发

Q2: 如何修改定时时间?

A: 在setTimer函数中修改时间参数,或者添加更多的定时选项:

void setTimer(int seconds) {
  // 修改这里的seconds参数即可
  timerDuration = seconds * 1000;
  // ...
}

Q3: 舵机转动不流畅怎么办?

A: 调整swingSpeed参数:

        值越小,转动越快。值越大,转动越慢(建议范围5-30ms)

项目资源整合

        继电器数据手册:JQC-3FF-S-Z

        显示屏数据手册:ST7789

        通过本项目的学习,读者可以掌握STM32开发的基本技能,了解继电器控制原理,并学会如何设计用户友好的交互界面。欢迎各位读者在此基础上进行扩展和改进,创造出更多有趣的智能家居应用!


网站公告

今日签到

点亮在社区的每一天
去签到