How to combine a variety of coding in one Arduino code

This is a singular exception to show you how it works:
This is the english speaking forum.
You have to do the work of translating from english to chinese and from chinese to english for all future postings

函数 delay() 被阻塞
这意味着只要执行延迟,在延迟完成之前就不能做其他事情。

所以你的代码需要一个基本的重新设计才能非阻塞地工作

您希望某些操作每 3 秒只发生一次
所以你的代码需要检查 3 秒是否已经过去。
这是基于一个叫做millis()的函数完成的

作为一个易于跟踪数字的全天示例
delay() 正在阻塞。只要延迟是“延迟”,就不能执行任何其他代码。
现在有一种非阻塞计时技术。
非阻塞计时的基本原理与使用delay() **根本不同**

**您必须先了解差异**,然后再查看代码。

否则你可能会尝试在millis()代码中“看到”一个“延迟模拟事物”**它真的不是**
试图在millis() 中看到“延迟模拟的东西”使得很难理解millis()
了解了基于millis()的非阻塞计时的基本原理,就容易理解了。

想象一下烤一个磨砂披萨
封面上写着准备将烤箱加热到 200°C
然后把披萨放进去。
烘烤时间10分钟

您估计加热需要 3 分钟
你看看你的手表是 13:02(时间快照)
你开始看报纸,不时看看你的手表
手表显示 13:02。 13:02 - 13:02 = 0 分钟过去了
手表显示 13:03。 13:03 - 13:02 = 1 分钟过去了
手表显示 13:04。 13:04 - 13:02 = 2 分钟还没到

watch 显示 13:05 我什么时候开始 13:02 的? OK 13:05 - 13:02 = 3 分钟时间将披萨放入烤箱

新基时间 13:05(时间快照)
看 13:06 还没到时间
看 13:07 还没到时间
看 13:08 还没到时间(13:08 - 13:05 = 3 分钟不到 10 分钟
看 13:09 还没到时间
看 13:10 还没到时间
看 13:11 还没到时间
看 13:12 还没到时间
看 13:13 还没到时间
看 13:14 还没到时间(13:14 - 13:05 = 9 分钟不到 10 分钟
看 13:15 我什么时候开始的 13:05 OK 13:15 - 13:05 = 10 分钟吃披萨的时间(yum yum)

你做了一个反复比较已经过去了多少时间
这就是非阻塞时序的作用
  

在查看“已经过去了多少时间”的代码中完成

当前时间 - 开始时间 >= 烘焙时间

烘烤时间为10分钟

13:06 - 13:05 = 1 分钟 >= bakeTime 是假的
13:07 - 13:05 = 2 分钟 >= bakeTime 为假
...
13:14 - 13:05 = 9 分钟 >= bakeTime 是假的
13:15 - 13:05 = 10 分钟 >= bakeTime 是计时动作的正确时间!!


所以你的 loop() 正在做

空循环()
  // 做各种事情,比如看报纸
  
  if (currentTime - previousTime >= period) {
    以前的时间 = 当前时间; // 首先要做的是更新时间的快照
    // 定时动作的时间
  }
  
它必须完全以这种方式编码,因为通过这种方式它可以管理从 Max 回零的翻转
函数millis() 自动

baldengineer.com 也有关于使用函数millis() 计时的非常好的教程。

有一段明确指出了函数 delay() 和 millis() 之间的区别:

millis() 函数是 Arduino 库中最强大的函数之一。此函数返回自上次重置以来当前草图已运行的毫秒数。一开始,你可能会想,这不是每一个都有用的!但请考虑一下您在白天如何报时。实际上,您可以查看自午夜以来已经过去了多少分钟。这就是millis()背后的想法!

与使用 delay() 时“等待一段时间”不同,您可以使用 millis() 来询问“已经过去了多少时间”?

https://www.baldengineer.com/millis-tutorial.html

The function delay() is blocking
This means as long as a delay is executed no other thing can be done until the delay has finished.

So your code needs a fundamental re-design to work non-blocking

You want to have that some actions only take place once every 3 seconds
So your code needs to check if 3 seconds have passed by.
This is done based on a function called millis()

as an allday example with easy to follow numbers
delay() is blocking. As long as the delay is "delaying" nothing else of the code can be executed.
Now there is a technique of non-blocking timing.
The basic principle of non-blocking timing is fundamental different from using delay()

You have to understand the difference first and then look into the code.

otherwise you might try to "see" a "delay-analog-thing" in the millis()-code which it really isn't
Trying to see a "delay-analog-thing" in millis() makes it hard to understand millis()
Having understood the basic principle of non-blocking timing based on millis() makes it easy to understand.

imagine baking a frosted pizza
the cover says for preparation heat up oven to 200°C
then put pizza in.
Baking time 10 minutes

You are estimating heating up needs 3 minutes
You take a look onto your watch it is 13:02 (snapshot of time)
You start reading the newspaper and from time to time looking onto your watch
watch shows 13:02. 13:02 - 13:02 = 0 minutes passed by not yet time
watch shows 13:03. 13:03 - 13:02 = 1 minute passed by not yet time
watch shows 13:04. 13:04 - 13:02 = 2 minutes passed by not yet time

watch shows 13:05 when did I start 13:02? OK 13:05 - 13:02 = 3 minutes time to put pizza into the oven

New basetime 13:05 (the snapshot of time)
watch 13:06 not yet time
watch 13:07 not yet time
watch 13:08 not yet time (13:08 - 13:05 = 3 minutes is less than 10 minutes
watch 13:09 not yet time
watch 13:10 not yet time
watch 13:11 not yet time
watch 13:12 not yet time
watch 13:13 not yet time
watch 13:14 not yet time (13:14 - 13:05 = 9 minutes is less than 10 minutes
watch 13:15 when did I start 13:05 OK 13:15 - 13:05 = 10 minutes time to eat pizza (yum yum)

You did a repeated comparing how much time has passed by
This is what non-blocking timing does

In the code looking at "How much time has passed by" is done

currentTime - startTime >= bakingTime

bakingTime is 10 minutes

13:06 - 13:05 = 1 minute >= bakingTime is false
13:07 - 13:05 = 2 minutes >= bakingTime is false
...
13:14 - 13:05 = 9 minutes >= bakingTime is false
13:15 - 13:05 = 10 minutes >= bakingTime is TRUE time for timed action!!

So your loop() is doing

void loop()
// doing all kinds of stuff like reading the newspaper

if (currentTime - previousTime >= period) {
previousTime = currentTime; // first thing to do is updating the snapshot of time
// time for timed action
}

it has to be coded exactly this way because in this way it manages the rollover from Max back to zero
of the function millis() automatically

baldengineer.com has a very good tutorial about timing with function millis() too .

There is one paragraph that nails down the difference between function delay() and millis() down to the point:

The millis() function is one of the most powerful functions of the Arduino library. This function returns the number of milliseconds the current sketch has been running since the last reset. At first, you might be thinking, well that’s not every useful! But consider how you tell time during the day. Effectively, you look at how many minutes have elapsed since midnight. That’s the idea behind millis()!

Instead of “waiting a certain amount of time” like you do with delay(), you can use millis() to ask “how much time has passed”?

best regards Stefan

1 Like

Thanks a lot

See my tutorial on How to write Timers and Delays in Arduino

To add extra buffering to Serial out see Arduino Serial I/O for the Real World

The exact problem of doing multiple things simultaneously on Arduino is addressed by the project "QP-Arduino: Modern RTOS & State Machines for Arduino".

Many thanks for your help. Now, I only owe the Bluetooth part.

I have looked into this and I have watched the introductional video.
Well my comment on the introductional material is:

shows some basic steps but then leaves the user to "tinker yourself until you understand it"
Yes there is a basic example of blink and blink2 but there is no detailed explanation that would explain the translation from a description of a functionality that is given in normal words into steps what to do with using the QP-software to create QP-diagrams.

For you the creators all this is very clear because you developed it.
But as an unavoidable consequence you are suffering from what I call
The "experts blindness about beginners difficulties" and the only way to overcome this is to become an expert for beginners difficulties through reading a lot of beginners questions.

best regards Stefan

#include "IR_remote.h"
#include "keymap.h"
IRremote ir(4);
#include <Servo.h>
Servo servo_13;

#include "EM_TTP229.h"
EM_TTP229 mTTP229;
const byte SCLPin = 9, SDOPin = 8;
String Read_Key () {
  String key_name = mTTP229.GetKeyMap();
  char * result = (char *)key_name.c_str();
  return result;
}
#include <Servo.h>

String item;
volatile long time;
volatile int number;
String password[] = {"0", "0", "0"};

Servo servo_12;
unsigned long buttonPushedMillis; // when button was released
unsigned long ledTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 250; // wait to turn on
unsigned long turnOffDelay = 5000; // turn off after this time
bool ledReady = false; // flag for when button is let go
bool ledState = false; // for servo is on or not.

#include "Buzzer.h"
#include "Sounds.h"
#include "PH20Port.h"

PH20Port buzzerplay(P9);


int touch_PIN2  = 2;
Buzzer mBuzzer = Buzzer(buzzerplay.pin1());
Buzzer buzzer(buzzerplay.pin1());


#include <Wire.h>
#include "TM1650.h"

TM1650 tm_4display;
volatile int _light;
volatile int yudi;
volatile int i;

#include "SoftI2CMaster.h"
#include "LiquidCrystal_SoftI2C.h"
#include "DHT.h"

LiquidCrystal_SoftI2C mylcd(0x27, 16, 2, 7, A0);
DHT dhtA3(A3, 11);


#include <Servo.h>
Servo servo_11;

void setup() {
  Serial.begin(9600);
  item = "";
  time = 0;
  number = 0;
  mTTP229.initTTP229(SCLPin, SDOPin);

  servo_12.attach(12);
  servo_11.attach(11);
  pinMode(touch_PIN2, INPUT);

  Wire.begin();
  tm_4display.init();
  _light = 0;
  yudi = 0;
  tm_4display.clear();
  servo_13.attach(13);

  dhtA3.begin();
  mylcd.begin(16, 2);

  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(10, INPUT);
  i = 1;
  ir.begin();

}

void door() {
  unsigned long currentMillis = millis(); // grab current time
  item = Read_Key();
  if (item == "1" && number == 0) {
    Serial.println(item);
    password[(int)(0)] = item;
    number = 1;
    delay(1);

  }
  if (item == "2" && number == 1) {
    Serial.println(item);
    password[(int)(1)] = item;
    number = 2;
    delay(1);

  }
  if (item == "3" && number == 2) {
    Serial.println(item);
    password[(int)(2)] = item;
    number = 3;
    delay(1);

  }
  if (password[(int)(0)] == "1" && (password[(int)(1)] == "2" && password[(int)(2)] == "3")) {
    servo_12.write(0);
    password[(int)(0)] = "0";
    password[(int)(1)] = "0";
    password[(int)(2)] = "0";
    number = 0;
    buttonPushedMillis = currentMillis;
    ledReady = true;
  }

  // make sure this code isn't checked until after button has been let go
  if (ledReady) {
    //this is typical millis code here:
    if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
      // okay, enough time has passed since the button was let go.
      servo_12.write(90);
      // setup our next "state"
      ledState = true;
      // save when the LED turned on
      ledTurnedOnAt = currentMillis;
      // wait for next button press
      ledReady = false;
    }
  }

  // see if we are watching for the time to turn off LED
  if (ledState) {
    // okay, led on, check for now long
    if ((unsigned long)(currentMillis - ledTurnedOnAt) >= turnOffDelay) {
      ledState = false;
      servo_12.write(90);
    }
  }

}

void doorbell() {
  if (digitalRead(touch_PIN2) == HIGH) {
    mBuzzer.bendTones(1500, 2500, 1.05, 20, 8);
    mBuzzer.bendTones(2499, 1500, 1.05, 25, 8);
  } else {
    buzzer.noTone();
  }
}

void window() {
  // 将连接在A2接口的光敏传感器的模拟值赋给light变量
  _light = analogRead(A2);
  // 将连接在A1接口的雨滴传感器的返回值赋予yudi变量
  yudi = analogRead(A1);
  tm_4display.displayString(_light);
  delay(2000);
  // 判断光线模拟值是否大于100,如果是打开窗户;否则,关闭窗户
  if (_light > 100) {
    // 雨滴传感器感应都雨水时,数值会变小,否则数值变大。此处判断雨滴模拟返回值是否小于200,如果是,则关闭窗户;否则打开窗户
    if (yudi < 600) {
      servo_13.write(90);
      delay(50);

    } else {
      servo_13.write(0);
      delay(50);
    }

  } else {
    servo_13.write(90);
    delay(20);

  }
}

void TandH() {
  float t = dhtA3.readTemperature();
  float h = dhtA3.readHumidity();
  mylcd.setCursor(0, 0);
  mylcd.print("Temp: ");
  mylcd.print(dhtA3.readTemperature());
  mylcd.print("C");
  mylcd.setCursor(0, 1);
  mylcd.print("Humdity:");
  mylcd.print(dhtA3.readHumidity());
  mylcd.print("%");
  delay(10);

  if (dhtA3.readTemperature() > 35 || dhtA3.readHumidity() > 75) {
    digitalWrite(5, HIGH);
    digitalWrite(6, LOW);

  } else {
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);

  }
}

void remote() {
  // 按下1键,同时打开风扇和黄灯
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_4) {
    digitalWrite(5, HIGH);
    digitalWrite(6, LOW);

  }
  // 按下2键,同时关闭风扇和黄灯
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_5) {
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);

  }
  // 按下3键,打开门
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_7) {
    servo_12.write(90);
    delay(1);

  }
  // 按下4键,关闭门
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_6) {
    servo_12.write(0);
    delay(1);

  }
  // 按下5键,打开窗
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_9) {
    servo_13.write(90);
    delay(1);

  }
  // 按下4键,关闭窗
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_8) {
    servo_13.write(0);
    delay(1);

  }
}

void cargate() {
  // 判断连接在D4号管脚的人体传感器是否感应到有人靠近,感应到则为1,否则为0.
  if (digitalRead(10) == 1) {
    // “高”表示点亮连接在D3号管脚绿灯,时间延续5s
    digitalWrite(3, HIGH);
    servo_11.write(90);
    delay(1);

  } else {
    // “低”表示熄灭连接在D3号管脚绿灯
    digitalWrite(3, LOW);
    servo_11.write(0);

  }
}

void bluetooth() {
  if (Serial.available() > 0) {
    item = Serial.readStringUntil('.');

    if (String(item).equals(String("l"))) {
      Serial.println("turn on the light");
      digitalWrite(3, HIGH);

    } else if (String(item).equals(String("ol"))) {
      Serial.println("turn off the light");
      digitalWrite(3, LOW);
    }
    if (String(item).equals(String("f"))) {
      Serial.println("open fan");
      // 打开风扇
      digitalWrite(5, HIGH);
      digitalWrite(6, LOW);

    } else if (String(item).equals(String("of"))) {
      Serial.println("close fan");
      // 关闭风扇
      digitalWrite(5, LOW);
      digitalWrite(6, LOW);
    }
    if (String(item).equals(String("od"))) {
      Serial.println("Close door");
      servo_12.write(90);
      delay(20);

    } else if (String(item).equals(String("d"))) {
      Serial.println("open door");
      servo_12.write(0);
      delay(20);
    }
    if (String(item).equals(String("ow"))) {
      Serial.println("close window");
      servo_13.write(90);
      delay(20);

    } else if (String(item).equals(String("w"))) {
      Serial.println("open window");
      servo_13.write(0);
      delay(20);
    }
  }
}

in the following loop, it is manual mode (1) at first, but when I press 2, the automatic mode will remain for 15 seconds quickly, and then it will switch back to manual mode.
How to I press 2 with the remote control, it will switch to automatic mode, which will last a long time (~2 minutes)
Many thanks.

void loop() {
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_1) {
    i = 1;
  }
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_2) {
    i = 0;
  }
  if (i == 0 ) {
    TandH();
    doorbell();
    window();
    cargate();

  }
  else {
    remote();
    bluetooth();
    door();
  }

}

Well your QP/QM-Framework is for professionals who are experienced in embedded softwaredevelopment.

There is an introductional video that explains some basics. But does not show step by step how the developing process really works.

I was asking a very specific question about such a tutorial and got an answer that listed up all their "teaching-material" but nothing special introductional about the QP.exe working together with the arduino-IDE.

Sorry quantum leaps, you might be doing quantum-leaps but at the level at which one tries - mathematically - to unite the special theory of relativity with quantum mechanics

regards Stefan

Hi savion,

You should post code by using code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

best regards Stefan

There is the "QM Model-Based Design Tool" video tutorial that shows you step-by-step how to use the QM modeling tool to build the "blinky" state machine. That tutorial ends up running the blinky on a different embedded board than Arduino, but you should be able to easily apply all the steps from the tutorial to the "blinky" example provided for Arduino.

Sorry, i am so late.

#include "IR_remote.h"
#include "keymap.h"
IRremote ir(4);
#include <Servo.h>
Servo servo_13;

#include "EM_TTP229.h"
EM_TTP229 mTTP229;
const byte SCLPin = 9, SDOPin = 8;
String Read_Key () {
  String key_name = mTTP229.GetKeyMap();
  char * result = (char *)key_name.c_str();
  return result;
}
#include <Servo.h>

String item;
volatile long time;
volatile int number;
String password[] = {"0", "0", "0"};

Servo servo_12;
unsigned long buttonPushedMillis; // when button was released
unsigned long ledTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 250; // wait to turn on
unsigned long turnOffDelay = 5000; // turn off after this time
bool ledReady = false; // flag for when button is let go
bool ledState = false; // for servo is on or not.

#include "Buzzer.h"
#include "Sounds.h"
#include "PH20Port.h"

PH20Port buzzerplay(P9);


int touch_PIN2  = 2;
Buzzer mBuzzer = Buzzer(buzzerplay.pin1());
Buzzer buzzer(buzzerplay.pin1());


#include <Wire.h>
#include "TM1650.h"

TM1650 tm_4display;
volatile int _light;
volatile int yudi;
volatile int i;

#include "SoftI2CMaster.h"
#include "LiquidCrystal_SoftI2C.h"
#include "DHT.h"

LiquidCrystal_SoftI2C mylcd(0x27, 16, 2, 7, A0);
DHT dhtA3(A3, 11);


#include <Servo.h>
Servo servo_11;

void setup() {
  Serial.begin(9600);
  item = "";
  time = 0;
  number = 0;
  mTTP229.initTTP229(SCLPin, SDOPin);

  servo_12.attach(12);
  servo_11.attach(11);
  pinMode(touch_PIN2, INPUT);

  Wire.begin();
  tm_4display.init();
  _light = 0;
  yudi = 0;
  tm_4display.clear();
  servo_13.attach(13);

  dhtA3.begin();
  mylcd.begin(16, 2);

  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(10, INPUT);
  i = 1;
  ir.begin();

}

void door() {
  unsigned long currentMillis = millis(); // grab current time
  item = Read_Key();
  if (item == "1" && number == 0) {
    Serial.println(item);
    password[(int)(0)] = item;
    number = 1;
    delay(1);

  }
  if (item == "2" && number == 1) {
    Serial.println(item);
    password[(int)(1)] = item;
    number = 2;
    delay(1);

  }
  if (item == "3" && number == 2) {
    Serial.println(item);
    password[(int)(2)] = item;
    number = 3;
    delay(1);

  }
  if (password[(int)(0)] == "1" && (password[(int)(1)] == "2" && password[(int)(2)] == "3")) {
    servo_12.write(0);
    password[(int)(0)] = "0";
    password[(int)(1)] = "0";
    password[(int)(2)] = "0";
    number = 0;
    buttonPushedMillis = currentMillis;
    ledReady = true;
  }

  // make sure this code isn't checked until after button has been let go
  if (ledReady) {
    //this is typical millis code here:
    if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
      // okay, enough time has passed since the button was let go.
      servo_12.write(90);
      // setup our next "state"
      ledState = true;
      // save when the LED turned on
      ledTurnedOnAt = currentMillis;
      // wait for next button press
      ledReady = false;
    }
  }

  // see if we are watching for the time to turn off LED
  if (ledState) {
    // okay, led on, check for now long
    if ((unsigned long)(currentMillis - ledTurnedOnAt) >= turnOffDelay) {
      ledState = false;
      servo_12.write(90);
    }
  }

}

void doorbell() {
  if (digitalRead(touch_PIN2) == HIGH) {
    mBuzzer.bendTones(1500, 2500, 1.05, 20, 8);
    mBuzzer.bendTones(2499, 1500, 1.05, 25, 8);
  } else {
    buzzer.noTone();
  }
}

void window() {
  // 将连接在A2接口的光敏传感器的模拟值赋给light变量
  _light = analogRead(A2);
  // 将连接在A1接口的雨滴传感器的返回值赋予yudi变量
  yudi = analogRead(A1);
  tm_4display.displayString(_light);
  Serial.print(String(" light:") + String(_light));
  Serial.print(",");
  Serial.println(String("yudi:") + String(yudi));
  delay(2000);
  // 判断光线模拟值是否大于100,如果是打开窗户;否则,关闭窗户
  if (_light > 100) {
    // 雨滴传感器感应都雨水时,数值会变小,否则数值变大。此处判断雨滴模拟返回值是否小于200,如果是,则关闭窗户;否则打开窗户
    if (yudi < 600) {
      servo_13.write(90);
      delay(50);

    } else {
      servo_13.write(0);
      delay(50);
    }

  } else {
    servo_13.write(90);
    delay(20);

  }
}

void TandH() {
  float t = dhtA3.readTemperature();
  float h = dhtA3.readHumidity();
  mylcd.setCursor(0, 0);
  mylcd.print("Temp: ");
  mylcd.print(dhtA3.readTemperature());
  mylcd.print("C");
  Serial.print("Temp: ");
  Serial.print(t);
  Serial.println(" *C ");
  mylcd.setCursor(0, 1);
  mylcd.print("Humdity:");
  mylcd.print(dhtA3.readHumidity());
  mylcd.print("%");
  Serial.print("Hum: ");
  Serial.print(h);
  Serial.print(" %\t");
  delay(100);

  if (dhtA3.readTemperature() > 35 || dhtA3.readHumidity() > 75) {
    digitalWrite(5, HIGH);
    digitalWrite(6, LOW);

  } else {
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);

  }
}

void remote() {
  // 按下1键,同时打开风扇和黄灯
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_4) {
    digitalWrite(5, HIGH);
    digitalWrite(6, LOW);

  }
  // 按下2键,同时关闭风扇和黄灯
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_5) {
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);

  }
  // 按下3键,打开门
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_7) {
    servo_12.write(90);
    delay(1);

  }
  // 按下4键,关闭门
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_6) {
    servo_12.write(0);
    delay(1);

  }
  // 按下5键,打开窗
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_9) {
    servo_13.write(90);
    delay(1);

  }
  // 按下4键,关闭窗
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_8) {
    servo_13.write(0);
    delay(1);

  }
}

void cargate() {
  // 判断连接在D4号管脚的人体传感器是否感应到有人靠近,感应到则为1,否则为0.
  if (digitalRead(10) == 1) {
    // “高”表示点亮连接在D3号管脚绿灯,时间延续5s
    digitalWrite(3, HIGH);
    servo_11.write(90);
    delay(1);

  } else {
    // “低”表示熄灭连接在D3号管脚绿灯
    digitalWrite(3, LOW);
    servo_11.write(0);

  }
}

void bluetooth() {
  if (Serial.available() > 0) {
    item = Serial.readStringUntil('.');

    if (String(item).equals(String("l"))) {
      Serial.println("turn on the light");
      digitalWrite(3, HIGH);

    } else if (String(item).equals(String("ol"))) {
      Serial.println("turn off the light");
      digitalWrite(3, LOW);
    }
    if (String(item).equals(String("f"))) {
      Serial.println("open fan");
      // 打开风扇
      digitalWrite(5, HIGH);
      digitalWrite(6, LOW);

    } else if (String(item).equals(String("of"))) {
      Serial.println("close fan");
      // 关闭风扇
      digitalWrite(5, LOW);
      digitalWrite(6, LOW);
    }
    if (String(item).equals(String("od"))) {
      Serial.println("Close door");
      servo_12.write(90);
      delay(20);

    } else if (String(item).equals(String("d"))) {
      Serial.println("open door");
      servo_12.write(0);
      delay(20);
    }
    if (String(item).equals(String("ow"))) {
      Serial.println("close window");
      servo_13.write(90);
      delay(20);

    } else if (String(item).equals(String("w"))) {
      Serial.println("open window");
      servo_13.write(0);
      delay(20);
    }
  }
}

void loop() {
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_1) {
    i = 1;
  }
  if (ir.getIrKey(ir.getCode(), 2) == EM_IR_KEYCODE_2) {
    i = 0;
  }
  if (i == 0 ) {
    TandH();
    doorbell();
    window();
    cargate();

  }
  else {
    remote();
    bluetooth();
    door();
  }

}

what is your actual question?

Your DHT library may have sensor reading functions that block for several seconds. Most of them do. That will wreck any other attempts to write non-blocking code.

I did not see a several sec delay in the Adafruit DHT library but there is at least 10mS delays in the read. The 80byte read can take about ~10mS and it disables the interrupts as well.

There is 2sec 'delay' between readings but that is not a real delay. The call to read just returns immediately with the old value.

If there is an old value...

True, but still no 2sec delay, Here is the code

 uint32_t currenttime = millis();
  if (!force && ((currenttime - _lastreadtime) < MIN_INTERVAL)) {
    return _lastresult; // return last correct measurement
  }
  _lastreadtime = currenttime;

My bad, it's a 5ms delay according to the DHT22 data sheet. That delay will be incurred on the first sensor read, and on any subsequent read where MIN_INTERVAL has expired. That is long enough to create multitasking problems.

I agree. Looks like a DHT22 'task' would take 5mS or more.
It is an open question if this slow task interferes with the running of other tasks in the round robbin setup I mentioned above.
At 9600 baud it takes about 60mS to fill the RX buffer so we could live that.
The touch panel could be set to 8 keys direct output and just polled.

What often happens, someone writes a huge project like this, it has some minor built in delay like the DHT read, everything runs just fine in round robin fashion because the other tasks don't have to be serviced that fast. The designer, happy with the success, then expands the program to 5,000 lines of code. But then, decides for example, "wouldn't NeoPixels look cool with this?". Suddenly, either the DHT or the NeoPixels (or IR, or 433MHz OOK, or...) mysteriously fail, and the person tears their hair out trying to figure out why. Even a relatively empty loop() execution does take some time, so it is a good idea to monitor loop() execution time during development, and exercise any opportunities to reduce it in view of future unknown additional requirements.

I absolutely agree, That is why I coded my loopTimer class to allow easy monitoring of loop times and task times.
The loopTimer is included in the SafeString library