การตั้งรอบเวลา ตั้งเวลา ให้โค้ตทำงานด้วย SimpleTimer

เห็นคงเริ่มถามกันเยอะเลยมาตั้งกระทู้ตอบแบบ ขอสั่นๆ กันก่อนนะครับ อยากที่กล่างมาคือบางที เราเขียนโค้ตในโปรอกรมบน void loop() ยาวมากๆ ทำให้โค้ตบางส่วนของเราทำงานได้ช้า เหมือนกับว่าต้องรอ ให้ถึงส่วนที่สั่งตัวเองก่อน ถึงจะทำได้ หรือในโค้ตชุดนั้นต้องมีการใส่ delay เข้ามาหน่วงเวลาถึงจะใช้งานได้ ทำให้เข้าไปกวนการทำงานของโค้ตชุดิื่นๆ ให้ประสิทธิภาพในการทำงานลดลงอีกต่างหาก

เช่น กรณีการอ่านค่าจาก เซนเซอร์ มันต้องมีการอัพเดทอยู่เรี่อยๆ เรียลๆ เขียนตรงๆ อาจจะทำให้เราอ่านค่าได้ไม่ไว้พอ ทำให้บางงานที่ระเอียดอ่อน ในด้านเงื่อนไข คลาดเคลื่อนตามไปด้วย ดั้งนั้น ผมเลยแนะนำให้ใช้ SimpleTimer library เข้ามาแก้โจทย์ข้อนี้กันครับ

อันนี้โค้ตตัวอย่าง

#include <SimpleTimer.h>

SimpleTimer timer;

// ฟังก์ชันที่จะดำเนินการเป็นระยะ ๆ
void easyTime() {
    Serial.print("Uptime (s): ");
    Serial.println(millis() / 1000);
}

void setup() {
    Serial.begin(9600);
    timer.setInterval(1000, easyTime);
}

void loop() {
    timer.run();
}

ทีนี้ผมขออธิบายหน่อยว่า ผมได้สร้าง ฟังก์ชันชื่อ easyTime ขึ้นมา แต่ผมจะไม่เอาไปไว้ใน void loop() เนื่องจากต้องการให้มันทำงานขนานไปกับ void loop ด้วยเลย โดยใช้คำสั่ง

timer.setInterval(1000, easyTime);

1000 คือ ค่าเวลาที่เราต้องการให้มันทำคำสั่งนี้ ทุกๆ กี่ วินาที 1000 เท่ากับ 1 วินาที
easyTime คือ ชื่อฟังก์ชัน ใดๆ ก็ได้ที่เราต้องการให้มันทำงาน เป็นรอบๆ

ดาวน์โหลด library => SimpleTimer-master.zip (3.9 KB)

ถ้าอย่างนั้นก็สามารถสร้าง​ ได้หลายฟังก์ชั่น​ ที่ทำงานไปพร้อมกันได้เช่น​ การแสดงเวลา​ ชม.​ นาที​ วินาที​ และฟังก์ชั่นเชคสัญญาณ​​ WiFi.​ หรือมี​ ปุ่มกด​ 8​ ตัว​ ก็​ 8​ ฟังก์ชั่นได้เลยใช่มั็ยครับ​ ต้องลองๆ​ ขอบคุณมากครับ

ใช่ครับพี่ ถ้าต้องการงานที่ไม่ต้องรอ loop หลักก็เพิ่มบรรทัดต่อมาได้เลยครับ

image

อธิบายเพิ่มเติมอีกสักนิดหนึ่ง คือ การใช้ simpleTimer ดูเหมือนเป็นการทำงานแบบแยกคอร์ หรือ แทก ออกมา แต่จริงๆ แล้ว เป็นการแบ่ง ทรัพยากรจากคอร์เดียวออกมาทำงาน ต่างหาก ครับ เพราะโดยสเปค บอร์ดโดยทั่วไปจะมีแค่ Core เดียว

จะไม่เหมือนกับ esp32 ที่พี่ @PUYIOT พึ่งตั้งเมื่อไม่นานมานี้ อันนั้น เป็นการแยก Core จากกันโดยอิสระ เพราะ สเปค esp32 เป็น Core 2 มาในตัว ถ้าเราไม่เขียนให้ฟิกว่า ให้ทำงาน คอร์ไหน บอร์ดมันก็จะจัดสรรให้เอง

Arduino: 1.8.15 (Windows 10), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), 2, v2 Lower Memory, Disabled, None, Only Sketch, 115200"





















C:\Users\Admin\AppData\Local\Temp\arduino_modified_sketch_488216\sketch_aug05b.ino: In function 'void setup()':

sketch_aug05b:91:36: error: invalid conversion from 'void (*)(float, float, float, float, float, float)' to 'timer_callback {aka void (*)()}' [-fpermissive]

   timer.setInterval(5000L, sendData);

                                    ^

In file included from C:\Users\Admin\OneDrive\�͡���\Arduino\libraries\Blynk\src/Blynk/BlynkApi.h:37:0,

                 from C:\Users\Admin\OneDrive\�͡���\Arduino\libraries\Blynk\src/BlynkApiArduino.h:14,

                 from C:\Users\Admin\OneDrive\�͡���\Arduino\libraries\Blynk\src/BlynkSimpleEsp8266.h:24,

                 from C:\Users\Admin\AppData\Local\Temp\arduino_modified_sketch_488216\sketch_aug05b.ino:5:

C:\Users\Admin\OneDrive\�͡���\Arduino\libraries\Blynk\src/Blynk/BlynkTimer.h:62:9: error:   initializing argument 2 of 'int BlynkTimer::setInterval(long unsigned int, timer_callback)' [-fpermissive]

     int setInterval(unsigned long d, timer_callback f);

         ^

Multiple libraries were found for "SimpleTimer.h"

 Used: C:\Users\Admin\OneDrive\เอกสาร\Arduino\libraries\SimpleTimer-master

 Not used: C:\Program Files (x86)\Arduino\libraries\SimpleTimer-master

exit status 1

invalid conversion from 'void (*)(float, float, float, float, float, float)' to 'timer_callback {aka void (*)()}' [-fpermissive]



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

ขึ้นแบบนี้ครับ

เอาโค้ตเต็มมาดูหน่อยครับ

ได้แล้วครับพี่ขอบคุณมากๆครับ

เราจะสามารถเลือกตั้งเวลาให้เหมาะสมยังไงได้บ้างคะ เหมือนพอเริ่มคำสั่งเยอะขึ้นค่ามันก็ไม่ไปแสดงอีกแล้วอ่ะค่ะ

ปกติก็ตั้ง 1วิ - 5วิ ครับ ถ้ามีปัญหาต้องเอารายโค้ตมาดูกันละครับ ไม่มีข้อมูลก็วิเคราะห์อะไรไม่ได้

1 Likes
#include <InfluxDbClient.h>
#include <InfluxDbCloud.h>
#define INFLUXDB_URL "https://europe-west1-1.gcp.cloud2.influxdata.com"
#define INFLUXDB_TOKEN "ys8hBxZ5HbjyvRjIsS5y_Mp8FMY1D3QT6E2XXHjfxdnKgqFSDAQfMhNct1h4JhikDatMEVirBGB5ZS-JkmoB-g=="
#define INFLUXDB_ORG "stanutty01@gmail.com"
#define INFLUXDB_BUCKET "ESP32"
InfluxDBClient client(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN, InfluxDbCloud2CACert);
Point sensor("temp_humi");
#define TZ_INFO "PKT-5"


#if defined(ESP32)
  #include <WiFiMulti.h>
  WiFiMulti wifiMulti;
  #define DEVICE "ESP32"
#elif defined(ESP8266)
  #include <ESP8266WiFiMulti.h>
  ESP8266WiFiMulti wifiMulti;
  #define DEVICE "ESP8266"
#endif

// Uncomment one of the lines below for whatever DHT sensor type you're using!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321





/* DHT */
#include "DHT.h"
#define DHTPIN D0      // what digital pin we're connected to
#define DHTTYPE DHT22 // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
/********* แสงงง *******/

/**********************/
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <TridentTD_LineNotify.h>
#define LINE_TOKEN "KUdmGZVlBd5RS0vRZSjTJlQMT2fNgGJHAEs35KH9gOk"
#include "SimpleTimer.h"
SimpleTimer timer;
// Replace with your network credentials
const char *ssid = "PCS-Office";
const char *password = "qawsedrf";

String serverName = "http://jaiangelbot.cc.pcs-plp.com/testbot/wtsensor.php";

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");

// Week Days
String weekDays[7] = {"01", "02", "03", "04", "05", "06", "07"};

// Month names
String months[12] = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};
unsigned long lastTime = 0;
unsigned long timerDelay = 5000;

#include <Ticker.h>
unsigned long previousMillis = 0;
unsigned long previousMillisAlert = 0;
int alertsec = 0, alertm = 0; //นับเวลาฉุกเฉิน หน่วง 10 นาที
int sec = 0, m = 0, h = 0;    //นับเวลาแจ้งเตือนไลน์

float setvalue[] = {300, 400, 500, 50}; //ค่า 1 2 ปกติ 3 และ 4ถ้าเริ่มน้อยแปลว่าให้เช็คเเละเริ่มแจ้งเตือนว่าเเสงน้อย (แสง)
float setvalueh[] = {60, 70}; 
Ticker ticker;
#include <SimpleTimer.h>
SimpleTimer timer;
/*void calsensoer()
{
  int lux = lightMeter.readLightLevel() + 190;
  int h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f))
  {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
  LINE.notify("Humidity: " + String(h) + "%\t");
  LINE.notify("Lux :" + String(lux) + "%");
}*/
void connectInflux(){
   sensor.addTag("device", DEVICE);
  sensor.addTag("SSID", WiFi.SSID());
  
  timeSync(TZ_INFO, "pool.ntp.org", "time.nis.gov");
  
  if (client.validateConnection()) {
    Serial.print("Connected to InfluxDB: ");
    Serial.println(client.getServerUrl());
  } else {
    Serial.print("InfluxDB connection failed: ");
    Serial.println(client.getLastErrorMessage());
  }
  
  }

void setup()
{
   timer.setInterval(1000, temp);
   timer.setInterval(3000, sendinflux);
 // LightSensor.begin();  
//  timer.setInterval(2000, calsensoer);
  Wire.begin();
  LINE.setToken(LINE_TOKEN);
  dht.begin();
  Serial.begin(115200);
 
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  connectInflux();

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, for example:
  // GMT +1 = 3600
  // GMT +8 = 28800
  // GMT -1 = -3600
  // GMT 0 = 0
  timeClient.setTimeOffset(25200);
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Timer set to 5 seconds (timerDelay variable), it will take 5 seconds before publishing the first reading.");
}
void sendinflux(){
 sensor.clearFields();
 float humidity = dht.readHumidity();
 float temperature_Celsius = dht.readTemperature();
 sensor.addField("Temperature",temperature_Celsius);
 sensor.addField("Humidity",humidity);
  
  Serial.print("Writing: ");
  Serial.println(client.pointToLineProtocol(sensor));

  // If no Wifi signal, try to reconnect it
  if (wifiMulti.run() != WL_CONNECTED) {
    Serial.println("Wifi connection lost");
  }
  // Write point
  if (!client.writePoint(sensor)) {
    Serial.print("InfluxDB write failed: ");
    Serial.println(client.getLastErrorMessage());
  }
  Serial.println("");

}
  

void temp()
{
  
 
  int h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f))
  {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  timeClient.update();
  time_t epochTime = timeClient.getEpochTime();
  String formattedTime = timeClient.getFormattedTime();
  int currentHour = timeClient.getHours();
  int currentMinute = timeClient.getMinutes();
  int currentSecond = timeClient.getSeconds();
  String weekDay = weekDays[timeClient.getDay()];
  // Get a time structure
  struct tm *ptm = gmtime((time_t *)&epochTime);
  int monthDay = ptm->tm_mday;
  int currentMonth = ptm->tm_mon + 1;
  String currentMonthName = months[currentMonth - 1];
  int currentYear = ptm->tm_year + 1900;
  String myString = String(currentYear);
  String dayee = String(currentYear)  +"0"+ String(currentMonth) + String(monthDay)+String(currentHour)+String(currentMinute)+String(currentSecond);
  
  // readtimedate();
  Serial.println(dayee);
  int yearcurrent = myString.toInt();
  int monthcurrent = currentMonthName.toInt();
  int api = (lux * h * (yearcurrent + monthcurrent + monthDay + currentHour + currentMinute + currentSecond) * 7);
  String stringapi = String(api, HEX);
  Serial.println(stringapi);
 /*alertsec = alertm = previousMillisAlert = 0;
  if (currentMillis - previousMillis >= 1000)
  {
     sec++;
      if (sec >= 60)
        m++;
        sec = 0;
      {
        else if(){*/
     
  
              // Check WiFi connection status
              if (WiFi.status() == WL_CONNECTED)
              {
                WiFiClient client;
                HTTPClient http;
                String serverPath = serverName + "?sid=1&light=" + String(lux) + "&hum=" + String(h) + "&times=" + String(myString) + String(currentMonthName) +"0"+ String(monthDay) + String(currentHour) + String(currentMinute) + String(currentSecond) + "&type=alert&key=" + String(stringapi);
                // Your Domain name with URL path or IP address with path
                http.begin(client, serverPath.c_str());
                // Send HTTP GET request
                int httpResponseCode = http.GET();
                if (httpResponseCode > 0)
                {
                  Serial.print("HTTP Response code: ");
                  Serial.println(httpResponseCode);
                  String payload = http.getString();
                  Serial.println(payload);
                }
                else
                {
                  Serial.print("Error code: ");
                  Serial.println(httpResponseCode);
                }
                // Free resources
                http.end();
              }
              else
              {
                Serial.println("WiFi Disconnected");
              }
}
void loop(){
timer.run();
           
            }
    //  } 
        // delay(60000);
  //} 

ช่วยเช็คหน่อยครับ ผมติดบรรทัดนี้
SimpleTimer timer;

ตามนั้น

#define BLYNK_PRINT Serial

#define BLYNK_TEMPLATE_ID "TMPLuJkZnfoS"
#define BLYNK_DEVICE_NAME "Autometic pump"
#define BLYNK_AUTH_TOKEN "UPG49bfoFyJP7R35B6mJAdrtnEkV6O9u"

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include<SoftwareSerial.h>
#include <TridentTD_LineNotify.h>
#include <SimpleTimer.h>

SoftwareSerial mySerial(D5,D6);

#define LINE_TOKEN "tXGab2YPoujol9Zw6K4OWwApEyCN5fdNSX3hyLlInE2"
char auth[] = "UPG49bfoFyJP7R35B6mJAdrtnEkV6O9u";
char ssid[] = "EEE";
char pass[] = "ern12112542";

SimpleTimer timer;

unsigned char data[4]={};
float distance;
int waterlevel;
const int relay = D7;
int modeSelect = 1;
bool waterPumpStatus;

WidgetLCD LCD(V0);
WidgetLED PUMP(V1);

void setup()
 {
  pinMode(relay, OUTPUT);
  Serial.begin(57600);
  mySerial.begin(9600);
  Blynk.begin(auth, ssid, pass);
  LINE.setToken(LINE_TOKEN);
  digitalWrite(relay, LOW);
  timer.setInterval(100, sensor);
 }

void sensor()
 {
  do{
     for(int i=0;i<4;i++)
     {
     data[i]=mySerial.read();
     }
    }while(mySerial.read()==0xff);

mySerial.flush();

if(data[0]==0xff)
 {
  int sum;
  sum=(data[0]+data[1]+data[2])&0x00FF;
  if(sum==data[3])
   {
    distance=(data[1]<<8)+data[2];
    if(distance>280)
     {
      Serial.print("distance=");
      Serial.print(distance/10);
      waterlevel=(400-(distance/10));
      Serial.println("cm");
     }
else
 {
  Serial.println("Below the lower limit");
 }
}
else Serial.println("ERROR");
}
Blynk.virtualWrite(V2, waterlevel);
delay(100);
}

void autoPump()
{
  sensor();
 if(waterlevel>=320)
 {
  waterPumpStatus = 1;
 }

 if(waterlevel <=190)
 {
   waterPumpStatus = 0;
 }
 }

void loop()
{
  checkPump();
  checkFunction();
  checkLevel();
  Blynk.run();
  timer.run();
}

void checkPump() 
{
  if (waterPumpStatus==1) 
  {
    digitalWrite(relay, HIGH);
    PUMP.on();
    LINE.notify("PUMP ON");
  } 
  else 
  {
    digitalWrite(relay, LOW);
    PUMP.off();
    LINE.notify("PUMP OFF");
  }
}

void checkFunction() 
{
  if (modeSelect == 2) 
  {
    autoPump();
  }
}

void closePump() 
{  
  if (waterPumpStatus  == 1)
  {
    waterPumpStatus = 0;
  }
}

BLYNK_WRITE(V4) 
{  
  if (param.asInt()) 
  {
    closePump();
    modeSelect++;
    if (modeSelect >= 3) 
    modeSelect = 1;
    modeLabel();
  }
}

BLYNK_WRITE(V3) 
{  
  if (param.asInt()) 
  {
    modeSelect = 1;
    waterPumpStatus = 1;
    modeLabel();
  } 
  else 
  {
    modeSelect = 1;
    waterPumpStatus = 0;
    modeLabel();
  }
}

void modeLabel() 
{
  if (modeSelect == 1) 
  {
    Blynk.setProperty(V4, "onLabel", "MANUAL");
    Blynk.setProperty(V4, "offLabel", "MANUAL");
    LINE.notify("MANUAL MODE");
  } 
  else if (modeSelect == 2) 
  {
    Blynk.setProperty(V4, "onLabel", "AUTO");
    Blynk.setProperty(V4, "offLabel", "AUTO");
    LINE.notify("AUTO MODE");
  } 
}

void checkLevel() 
{
  sensor();
   if(waterlevel <=320)
 {
  LCD.clear();
  LCD.print(0,0,"Level 3");
  LCD.print(0,1,"It's crisis!");
  LINE.notify("Level 3");
  LINE.notify("It's crisis!");
 }
 else if((waterlevel >=260) && waterlevel <=280)
 {
  LCD.clear();
  LCD.print(0,0,"Level 2");
  LCD.print(0,1,"Will you pump?");
  LINE.notify("Level 2");
  LINE.notify("Will you pump?");
 }
  else if((waterlevel >=200) && waterlevel <=220)
 {
  LCD.clear();
  LCD.print(3,0,"Level 1");
  LCD.print(0,1,"It's OK.");
  LINE.notify("Level 1");
  LINE.notify("slightly higher water.Will you pump? ");
 }
}

ประมาณนี้อ่ะค่ะ

ตั้งเวลาเร็วเกินไปครับ อันนี้คือเร็วกว่า 1 วิ อีก
1000 เท่ากับ 1 วินาที ควรตั้งพื้นฐานขั้นต่ำที่ 1000

timer.setInterval(1000, sensor);

พอตั้ง1000แล้วมันไม่ขึ้นอะไรเลยค่ะ

มันเกี่ยวกับที่ตัวเซนเซอร์มันต้องใช้ดีเลย์100 ไม่เกิน150 มั้ยคะ

ลองดูสักนิดครับ ว่าสาเหตุมัน่าจะมาจากการทำงานตรงจุดไหน

ในความเห็นผม คือ
1

กว่าจะมาถึง
Blynk.run();
timer.run();
ดูแล้วเค้าต้องไปเชค 3 เงื่อนไขก่อน ซึงแต่ละเงื่อนไขก็โดน ซ้อนด้วยเงื่อนไขอีก 1 ชั้น
ดังนั้นกว่าจะไปถึง
Blynk.run();
timer.run();
ก็ใช้เวลานานมันอาจจะส่งผลให้ ค่าเราไม่แสดงออกมาก็เป็นได้ครับ