/**比特树创造力【BIT.SH1003多功能智能风扇板卡全功能验证】
  1、能够根据接收到的红外遥控器数字按键值0-3改变风速,同时在数码管上显示0-3数字风速档位;
  2、能够根据接收到的红外遥控器按键值(齿轮键0xFFA857)或实体按键1(D4)在不同的工作模式切换;
  3、工作模式1蜂鸣器响1声为红外遥控模式;
  4、工作模式2蜂鸣器响2声为超声波测距模式,距离越远,风速越快,(<5cm=0档、<30cm=1档、<60cm=2档、>60cm=3档)数码管显示相应档位;
  5、工作模式3蜂鸣器响3声为温湿度自动调速模式,当温湿度越高风速越大;
  5、工作模式4蜂鸣器响4声为手动调速模式,结合A3引脚电位器映射风扇转速;
  6、实体按键SW1和SW2按下有不同声音;
  7、所有操作能够通过A1引脚的蜂鸣器不同声音次数反馈;
  bit-tree.com  by liking [2025-07-25]
**/
#include <IRremote.h>    // 红外遥控库
#include <Wire.h>       // IIC通信库,用于AHT20温湿度传感器

// ======================================
// 硬件引脚与参数定义区
// ======================================

/** 引脚定义 **/
#define BEEPER        A1    // 有源蜂鸣器控制引脚
#define IR_RECEIVE_PIN 7    // 红外接收模块引脚
#define TRIG_PIN       2    // 超声波传感器触发引脚
#define ECHO_PIN       3    // 超声波传感器回声引脚
#define FAN_NEG        6    // 风扇电机负极控制引脚
#define FAN_POS        5    // 风扇电机正极PWM控制引脚
#define SW1            4    // 实体按键1(模式切换)
#define SW2           A2    // 实体按键2(保留音效)
#define POT           A3    // 手动调速模式电位器引脚

/** 数码管引脚定义 **/
#define SEG_A         A0    // 数码管A段
#define SEG_B          8    // 数码管B段
#define SEG_C          9    // 数码管C段
#define SEG_D         10    // 数码管D段
#define SEG_E         11    // 数码管E段
#define SEG_F         12    // 数码管F段
#define SEG_G         13    // 数码管G段

/** 红外遥控器按键码定义 **/
#define FAN_0        0xFF6897  // 0档风速对应红外码
#define FAN_1        0xFF30CF  // 1档风速对应红外码
#define FAN_2        0xFF18E7  // 2档风速对应红外码
#define FAN_3        0xFF7A85  // 3档风速对应红外码
#define MODE_SWITCH  0xFFA857  // 模式切换按键(齿轮键)对应红外码

/** 工作模式定义 **/
#define MODE_IR        1  // 模式1:红外遥控模式(蜂鸣器响1声)
#define MODE_ULTRASONIC 2  // 模式2:超声波测距模式(蜂鸣器响2声)
#define MODE_TEMP_HUM   3  // 模式3:温湿度自动模式(蜂鸣器响3声)
#define MODE_MANUAL     4  // 模式4:手动调速模式(蜂鸣器响4声)

/** AHT20温湿度传感器参数 **/
#define AHT20_ADDR   0x38  // AHT20的IIC通信地址
#define AHT20_INIT_CMD 0xBE  // AHT20初始化命令
#define AHT20_MEASURE_CMD 0xAC  // AHT20测量命令

/** 蜂鸣器音效参数 **/
#define BEEP_DURATION 100  // 单声持续时间(毫秒)
#define BEEP_GAP      100  // 声音之间的间隔(毫秒)

// ======================================
// 全局变量定义区
// ======================================

int currentMode = MODE_IR;  // 当前工作模式(初始化为红外遥控模式)
int modeSpeeds[5] = {0};    // 各模式独立保存的风速档位
unsigned long modeTimers[5] = {0};  // 各模式定时计数器
unsigned long debounceDelay = 200;  // 按键去抖延迟(毫秒)
float humidity = 0.0;       // 湿度值(百分比)
float temperature = 0.0;    // 温度值(摄氏度)
bool isPlaying = false;     // 蜂鸣器播放状态标志

// 红外接收对象
IRrecv irrecv(IR_RECEIVE_PIN);
decode_results results;

// 数码管段码表(共阴极,0-3)
const byte digitPatterns[4][7] = {
  {1, 1, 1, 1, 1, 1, 0}, // 0
  {0, 1, 1, 0, 0, 0, 0}, // 1
  {1, 1, 0, 1, 1, 0, 1}, // 2
  {1, 1, 1, 1, 0, 0, 1} // 3
};

// ======================================
// 蜂鸣器控制函数区
// ======================================

/**
   控制有源蜂鸣器开关
   @param on  true=发声,false=停止
*/
void setBuzzer(bool on) {
  digitalWrite(BEEPER, on ? HIGH : LOW);
}

/**
   播放指定次数的提示音
   @param count 发声次数
*/
void playBeepSequence(int count) {
  if (isPlaying || count < 1) return;
  isPlaying = true;

  for (int i = 0; i < count; i++) {
    setBuzzer(true);
    delay(BEEP_DURATION);
    setBuzzer(false);
    if (i < count - 1) delay(BEEP_GAP);
  }

  isPlaying = false;
}

/**
   播放模式切换提示音
   @param mode 模式编号(1-4),响对应次数
*/
void playModeTone(int mode) {
  playBeepSequence(mode);
}

/**
   按键2(SW2)的音效
   播放1声短音
*/
void playButton2Sound() {
  if (isPlaying) return;
  isPlaying = true;

  setBuzzer(true);
  delay(BEEP_DURATION);
  setBuzzer(false);

  isPlaying = false;
}

/**
   红外操作反馈音
   播放短提示音
*/
void playIRFeedback() {
  if (isPlaying) return;
  isPlaying = true;

  setBuzzer(true);
  delay(BEEP_DURATION / 2);
  setBuzzer(false);

  isPlaying = false;
}

// ======================================
// 传感器控制函数区
// ======================================

/**
   初始化AHT20温湿度传感器
   @return 成功返回true,失败返回false
*/
bool initAHT20() {
  Wire.beginTransmission(AHT20_ADDR);
  Wire.write(AHT20_INIT_CMD);
  Wire.write(0x08);
  Wire.write(0x00);
  if (Wire.endTransmission() != 0) return false;

  delay(100);
  return true;
}

/**
   读取AHT20温湿度数据
*/
void readAHT20() {
  Wire.beginTransmission(AHT20_ADDR);
  Wire.write(AHT20_MEASURE_CMD);
  Wire.write(0x33);
  Wire.write(0x00);
  Wire.endTransmission();

  delay(80);

  if (Wire.requestFrom(AHT20_ADDR, 6) != 6) return;

  byte status = Wire.read();
  if ((status & 0x80) == 0) {
    byte hum1 = Wire.read();
    byte hum2 = Wire.read();
    byte hum3 = Wire.read();
    byte temp1 = Wire.read();
    byte temp2 = Wire.read();
    byte temp3 = Wire.read();

    unsigned long humValue = ((unsigned long)hum1 << 12) |
                             ((unsigned long)hum2 << 4) |
                             (hum3 >> 4);
    humidity = humValue * 100.0 / 0x100000;

    unsigned long tempValue = ((unsigned long)(hum3 & 0x0F) << 16) |
                              ((unsigned long)temp1 << 8) |
                              temp2;
    temperature = tempValue * 200.0 / 0x100000 - 50;
  }
}

/**
   超声波测距
   @return 距离(厘米)
*/
long getDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH);
  return constrain(duration * 0.0343 / 2, 0, 150);
}

// ======================================
// 模式控制函数区
// ======================================

/**
   红外遥控模式逻辑
*/
void runIRMode() {}

/**
   超声波模式逻辑(每500ms更新)
*/
void runUltrasonicMode() {
  if (millis() - modeTimers[MODE_ULTRASONIC] < 500) return;

  long distance = getDistance();
  int newSpeed = distance < 5 ? 0 :
                 (distance < 30 ? 1 :
                  (distance < 60 ? 2 : 3));

  if (newSpeed != modeSpeeds[MODE_ULTRASONIC]) {
    modeSpeeds[MODE_ULTRASONIC] = newSpeed;
    setFanSpeed(newSpeed);
  }

  modeTimers[MODE_ULTRASONIC] = millis();
}

/**
   温湿度模式逻辑(每2000ms更新)
*/
void runTempHumMode() {
  if (millis() - modeTimers[MODE_TEMP_HUM] < 2000) return;

  readAHT20();

  float tempIndex = constrain((temperature - 20) / 20, 0, 1);
  float humIndex = constrain(humidity / 100, 0, 1);
  float index = (tempIndex * 0.6 + humIndex * 0.4) * 100;

  int newSpeed = index < 25 ? 0 : (index < 50 ? 1 : (index < 75 ? 2 : 3));

  if (newSpeed != modeSpeeds[MODE_TEMP_HUM]) {
    modeSpeeds[MODE_TEMP_HUM] = newSpeed;
    setFanSpeed(newSpeed);
  }

  modeTimers[MODE_TEMP_HUM] = millis();
}

/**
   手动模式逻辑(每200ms更新)
*/
void runManualMode() {
  if (millis() - modeTimers[MODE_MANUAL] < 200) return;

  int newSpeed = map(analogRead(POT), 0, 1023, 0, 3);

  if (newSpeed != modeSpeeds[MODE_MANUAL]) {
    modeSpeeds[MODE_MANUAL] = newSpeed;
    setFanSpeed(newSpeed);
  }

  modeTimers[MODE_MANUAL] = millis();
}

// ======================================
// 设备控制函数区
// ======================================

/**
   设置风扇风速
   @param speed 风速档位(0-3)
*/
void setFanSpeed(int speed) {
  if (speed < 0 || speed > 3) return;

  int pwmValue = speed * 85;  // 0→0, 1→85, 2→170, 3→255

  digitalWrite(FAN_NEG, LOW);
  analogWrite(FAN_POS, pwmValue);
}

/**
   数码管显示数字
   @param digit 数字(0-3)
*/
void displayDigit(int digit) {
  if (digit < 0 || digit > 3) return;

  digitalWrite(SEG_A, digitPatterns[digit][0]);
  digitalWrite(SEG_B, digitPatterns[digit][1]);
  digitalWrite(SEG_C, digitPatterns[digit][2]);
  digitalWrite(SEG_D, digitPatterns[digit][3]);
  digitalWrite(SEG_E, digitPatterns[digit][4]);
  digitalWrite(SEG_F, digitPatterns[digit][5]);
  digitalWrite(SEG_G, digitPatterns[digit][6]);
}

// ======================================
// 事件处理函数区
// ======================================

/**
   处理红外命令
   @param cmd 红外码值
*/
void processIRCommand(unsigned long cmd) {
  switch (cmd) {
    case FAN_0:
      modeSpeeds[currentMode] = 0;
      setFanSpeed(0);
      playIRFeedback();
      break;
    case FAN_1:
      modeSpeeds[currentMode] = 1;
      setFanSpeed(1);
      playIRFeedback();
      break;
    case FAN_2:
      modeSpeeds[currentMode] = 2;
      setFanSpeed(2);
      playIRFeedback();
      break;
    case FAN_3:
      modeSpeeds[currentMode] = 3;
      setFanSpeed(3);
      playIRFeedback();
      break;
    case MODE_SWITCH:
      switchMode();  // 红外模式切换
      break;
  }
}

/**
   模式切换函数(循环切换)
*/
void switchMode() {
  currentMode = (currentMode % 4) + 1;  // 1→2→3→4→1

  setFanSpeed(modeSpeeds[currentMode]);
  playModeTone(currentMode);  // 播放模式提示音
}

/**
   检查按键状态
   SW1改为模式切换,SW2保留音效
*/
void checkButtons() {
  static unsigned long lastDebounce = 0;
  unsigned long now = millis();

  // SW1按键:模式切换(带防抖)
  if (digitalRead(SW1) == LOW && now - lastDebounce > debounceDelay) {
    switchMode();  // 执行模式切换
    lastDebounce = now;
  }

  // SW2按键:保留原有音效
  if (digitalRead(SW2) == LOW && now - lastDebounce > debounceDelay) {
    playButton2Sound();
    lastDebounce = now;
  }
}

// ======================================
// 初始化与主循环区
// ======================================

void setup() {
  // 初始化引脚
  pinMode(BEEPER, OUTPUT);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(FAN_POS, OUTPUT);
  pinMode(FAN_NEG, OUTPUT);
  pinMode(SW1, INPUT_PULLUP);  // 模式切换按键
  pinMode(SW2, INPUT_PULLUP);  // 音效按键
  pinMode(POT, INPUT);

  // 初始化数码管
  pinMode(SEG_A, OUTPUT);
  pinMode(SEG_B, OUTPUT);
  pinMode(SEG_C, OUTPUT);
  pinMode(SEG_D, OUTPUT);
  pinMode(SEG_E, OUTPUT);
  pinMode(SEG_F, OUTPUT);
  pinMode(SEG_G, OUTPUT);

  // 初始化通信
  Serial.begin(9600);
  Wire.begin();
  irrecv.enableIRIn();

  // 初始化AHT20
  if (!initAHT20()) {
    Serial.println("AHT20初始化失败!");
    while (1);
  }

  // 初始化定时器
  for (int i = 1; i <= 4; i++) modeTimers[i] = millis();

  // 初始状态
  setBuzzer(false);
  setFanSpeed(0);
  displayDigit(0);
  playModeTone(MODE_IR);  // 启动提示
}

void loop() {
  // 处理红外信号
  if (irrecv.decode(&results) && !isPlaying) {
    processIRCommand(results.value);
    irrecv.resume();
  }

  // 检查按键(SW1模式切换,SW2音效)
  checkButtons();

  // 执行当前模式逻辑
  if (!isPlaying) {
    switch (currentMode) {
      case MODE_IR:         runIRMode(); break;
      case MODE_ULTRASONIC: runUltrasonicMode(); break;
      case MODE_TEMP_HUM:   runTempHumMode(); break;
      case MODE_MANUAL:     runManualMode(); break;
    }
    displayDigit(modeSpeeds[currentMode]);
  }

  delay(50);
}