เอาโค้ด Gps กับ SGP30 มารวมกันเเล้วติดปัญหาครับ

image อันนี้ gps รันเเยกนะครับค่าก็โชว์ปกติ

image อันนี้ของ SGP30 นะครับรันแยกค่าปกติ

อันนี้คือเอามารวมกันขึ้นแค่ GPS start เเล้วก็ขึ้นค่าของ Sensor SGP30 อย่างเดียว

1 Like

โค้ดที่เอามารวมกันนะครับ

#include "TinyGPS++.h"
#include "SoftwareSerial.h"

#include "SparkFun_SGP30_Arduino_Library.h" // 0x58 Click here to get the library: http://librarymanager/All#SparkFun_SGP30
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4);   //Module IIC/I2C Interface บางรุ่นอาจจะใช้ 0x3f
SGP30 mySensor; //create an object of the SGP30 class

SoftwareSerial serial_connection(16, 17); //RX=pin 10, TX=pin 11
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data

void setup() {
  
  lcd.begin();
  lcd.backlight(); 
  Serial.begin(9600);
  Wire.begin();
  serial_connection.begin(9600);//This opens up communications to the GPS
  Serial.println("GPS Start");//Just show to the monitor that the sketch has started

  
  //Initialize sensor
  if (mySensor.begin() == false) {
    Serial.println("No SGP30 Detected. Check connections.");
    while (1);
  }
  //Initializes sensor for air quality readings
  //measureAirQuality should be called in one second increments after a call to initAirQuality
  mySensor.initAirQuality();
}

void loop() {

  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  if(gps.location.isUpdated())//This will pretty much be fired all the time anyway but will at least reduce it to only after a package of NMEA data comes in
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    Serial.println("Satellite Count:");
    Serial.println(gps.satellites.value());
    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);
    Serial.println("Speed MPH:");
    Serial.println(gps.speed.mph());
    Serial.println("Altitude Feet:");
    Serial.println(gps.altitude.feet());
    Serial.println("");
  }

  
  //First fifteen readings will be
  //CO2: 400 ppm  TVOC: 0 ppb
  //measure CO2 and TVOC levels
  
  mySensor.measureAirQuality();
  Serial.print("CO2: ");
  Serial.print(mySensor.CO2);
  Serial.print(" ppm\tTVOC: ");
  Serial.print(mySensor.TVOC);
  Serial.println(" ppb"); 
  lcd.setCursor(0,0);
  lcd.print("CO2: ");
  lcd.print(mySensor.CO2);
  lcd.print("ppm");
  lcd.setCursor(0,1);
  lcd.print("TVOC: ");
  lcd.print(mySensor.TVOC);
  lcd.println("ppb");
  lcd.setCursor(0,2);
  lcd.print("Longitude:"); lcd.print(gps.location.lng(), 6);
  lcd.setCursor(0,3);lcd.println("Longitude:");lcd.print(gps.location.lng(), 6);
  delay(1000); //Wait 1 secondd

โค้ดของ SGP30

#include "SparkFun_SGP30_Arduino_Library.h" // 0x58 Click here to get the library: http://librarymanager/All#SparkFun_SGP30
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4);   //Module IIC/I2C Interface บางรุ่นอาจจะใช้ 0x3f
SGP30 mySensor; //create an object of the SGP30 class



void setup() {
  
  lcd.begin();
  lcd.backlight(); 
  Serial.begin(9600);
  Wire.begin();
  

  
  //Initialize sensor
  if (mySensor.begin() == false) {
    Serial.println("No SGP30 Detected. Check connections.");
    while (1);
  }
  //Initializes sensor for air quality readings
  //measureAirQuality should be called in one second increments after a call to initAirQuality
  mySensor.initAirQuality();
}

void loop() {

  //First fifteen readings will be
  //CO2: 400 ppm  TVOC: 0 ppb
  //measure CO2 and TVOC levels
  
  mySensor.measureAirQuality();
  Serial.print("CO2: ");
  Serial.print(mySensor.CO2);
  Serial.print(" ppm\tTVOC: ");
  Serial.print(mySensor.TVOC);
  Serial.println(" ppb"); 
  lcd.setCursor(0,0);
  lcd.print("CO2: ");
  lcd.print(mySensor.CO2);
  lcd.print("ppm");
  lcd.setCursor(0,1);
  lcd.print("TVOC: ");
  lcd.print(mySensor.TVOC);
  lcd.println("ppb");
 
  delay(1000); //Wait 1 secondd

}

โค้ดของ GPS

#include "TinyGPS++.h"
#include "SoftwareSerial.h"

SoftwareSerial serial_connection(16, 17); //RX=pin 10, TX=pin 11
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data
void setup()
{
  Serial.begin(9600);//This opens up communications to the Serial monitor in the Arduino IDE
  serial_connection.begin(9600);//This opens up communications to the GPS
  Serial.println("GPS Start");//Just show to the monitor that the sketch has started
}

void loop()
{
  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  if(gps.location.isUpdated())//This will pretty much be fired all the time anyway but will at least reduce it to only after a package of NMEA data comes in
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    Serial.println("Satellite Count:");
    Serial.println(gps.satellites.value());
    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);
    Serial.println("Speed MPH:");
    Serial.println(gps.speed.mph());
    Serial.println("Altitude Feet:");
    Serial.println(gps.altitude.feet());
    Serial.println("");
  }
}

อัพเดทครับ ในส่วนของโค้ดที่เอามารวมกันพอลบ delay(); ออกในส่วนท้ายสามารถถทำงานได้ครับ เเต่ค่าที่สแดงใน จอ Lcd มันรัวมากๆเลยครับคงเพราะเนื่องจากไม่มี delay เเต่พอมี delay โปรแกรมกับไม่ทำงานในส่วนของ gps

ผลหน้าจอตอนไม่มี delayนะครับ ค่าใน Serial monitor ก็แสดงค่า sensor 2ตัวพร้อมกันครับ แต่ถ้ามี delay ค่า gps จะขึ้นเป็น 0.0000,0.00000บนจอlcd ส่วนใน serial monitorก็ตามภาพประกอบด้านบนภาพที่3เลยครับ

เช็คให้ดีครับว่าเอาโค้ตมาครบไหม เห็นว่าปีกกามันหายไป

วีดีโอไม่ขึ้นครับ

อัพเดทตรงนี้ให้ครบหน่อยครับ ไม่งั้นจะวิเคราะห์ไม่ได้ ตรงที่ขีดเส้นใต้ถ้าไม่มีปีกกา มัน verify ไม่ผ่านแน่นอน

อ้อใส่ไปเเล้วครับ เหมือนเดิมเลยครับ

หมายถึงวางให้ผมดูง่ะครับ โค้ตล่าสุด

นี่ครับ

#include "TinyGPS++.h"
#include "SoftwareSerial.h"

#include "SparkFun_SGP30_Arduino_Library.h" // 0x58 Click here to get the library: http://librarymanager/All#SparkFun_SGP30
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4);   //Module IIC/I2C Interface บางรุ่นอาจจะใช้ 0x3f
SGP30 mySensor; //create an object of the SGP30 class

SoftwareSerial serial_connection(16, 17); //RX=pin 10, TX=pin 11
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data

void setup() {
  
  lcd.begin();
  lcd.backlight(); 
  Serial.begin(9600);
  Wire.begin();
  serial_connection.begin(9600);//This opens up communications to the GPS
  Serial.println("GPS Start");//Just show to the monitor that the sketch has started

  
  //Initialize sensor
  if (mySensor.begin() == false) {
    Serial.println("No SGP30 Detected. Check connections.");
    while (1);
  }
  //Initializes sensor for air quality readings
  //measureAirQuality should be called in one second increments after a call to initAirQuality
  mySensor.initAirQuality();
}

void loop() {

  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  if(gps.location.isUpdated())//This will pretty much be fired all the time anyway but will at least reduce it to only after a package of NMEA data comes in
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    Serial.println("Satellite Count:");
    Serial.println(gps.satellites.value());
    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);
    Serial.println("Speed MPH:");
    Serial.println(gps.speed.mph());
    Serial.println("Altitude Feet:");
    Serial.println(gps.altitude.feet());
    Serial.println("");
  }

  
  //First fifteen readings will be
  //CO2: 400 ppm  TVOC: 0 ppb
  //measure CO2 and TVOC levels
  
  mySensor.measureAirQuality();
  Serial.print("CO2: ");
  Serial.print(mySensor.CO2);
  Serial.print(" ppm\tTVOC: ");
  Serial.print(mySensor.TVOC);
  Serial.println(" ppb"); 
  lcd.setCursor(0,0);
  lcd.print("CO2: ");
  lcd.print(mySensor.CO2);
  lcd.print("ppm");
  lcd.setCursor(0,1);
  lcd.print("TVOC: ");
  lcd.print(mySensor.TVOC);
  lcd.println("ppb");
  lcd.setCursor(0,2);
  lcd.print("Longitude:"); lcd.print(gps.location.lng(), 6);
  lcd.setCursor(0,3);lcd.println("Longitude:");lcd.print(gps.location.lng(), 6);
  //delay(1000); //Wait 1 secondd

}

ปัญหาหลักๆ เลยก็คือการทำงานมันเหลื่อมกันครับ ฟังก์ชันแรกทำงานได้ แต่ฟังก์ชันที่ 2 มันทำงานไม่ทัน มันจะได้อันใดอันหนึ่งเสมอ

วิธีแก้ไขให้ใช้หลักการ ตั้งเวลาให้มันทำงานไปพร้อมกันขนาดกันไป กรณีนี้ควรจับโค้ตเซนเซอร์มาตั้งเวลาทำงานซะ ทุกๆ 2 วินาทีก็ได้ ให้มันทำงานไปพร้อมกับ GPS โค้ต GPS ก็เอาไว้ที่เดิมก็ไม่มีปัญหาอะไร ตัวอย่างการทำงาน

#include "SimpleTimer.h"
SimpleTimer timer; // ประกาศให้ฟังก์ชัน ทำงาน

void readSensor() {
  Serial.print("Read sensor....");
  mySensor.measureAirQuality();
  Serial.print("CO2: ");
  Serial.print(mySensor.CO2);
  Serial.print(" ppm\tTVOC: ");
  Serial.print(mySensor.TVOC);
  Serial.println(" ppb"); 
  lcd.setCursor(0,0);
  lcd.print("CO2: ");
  lcd.print(mySensor.CO2);
  lcd.print("ppm");
  lcd.setCursor(0,1);
  lcd.print("TVOC: ");
  lcd.print(mySensor.TVOC);
  lcd.println("ppb");
  lcd.setCursor(0,2);
  lcd.print("Longitude:"); lcd.print(gps.location.lng(), 6);
  lcd.setCursor(0,3);lcd.println("Longitude:");lcd.print(gps.location.lng(), 6);
  //delay(1000); //Wait 1 secondd
}

void setup() {

  Serial.begin(9600);
  timer.setInterval(3000, readSensor); // ตั้งเวลาให้อ่านทุก 3 วิ

}

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

นำไปใส่เพิ่มในโค้ตหลักครับ

อันนี้เป็นคู่มือที่ผมเขียนไว้

อย่าลืม ลง library เพิ่มด้วย

ทำงานได้เลยครับขอบคุณมากๆครับ เเต่ผมเอาโค้ดส่วนนี้มาไว้ใน void loop

while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  if(gps.location.isUpdated())//This will pretty much be fired all the time anyway but will at least reduce it to only after a package of NMEA data comes in
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    Serial.println("Satellite Count:");
    Serial.println(gps.satellites.value());
    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);
    Serial.println("Speed MPH:");
    Serial.println(gps.speed.mph());
    Serial.println("Altitude Feet:");
    Serial.println(gps.altitude.feet());
    Serial.println("");
  }

ก็สามารถทำงานได้เเต่อยากถามว่า ควรเอาไปใส่ใน void readSensor() ตามโค้ดที่พี่ให้มามากกว่าหรือหรือเปล่าครับ หรือเอาไว้ใน void loop ดีเเล้วครับ

ขอดูโค้ตล่าสุดหน่อยครับ

นี่เลยครับ

#include "TinyGPS++.h"
#include "SoftwareSerial.h"
#include "SimpleTimer.h"

#include "SparkFun_SGP30_Arduino_Library.h" // 0x58 Click here to get the library: http://librarymanager/All#SparkFun_SGP30
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4);   //Module IIC/I2C Interface บางรุ่นอาจจะใช้ 0x3f
SGP30 mySensor; //create an object of the SGP30 class

SoftwareSerial serial_connection(16, 17); //RX=pin 10, TX=pin 11
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data
SimpleTimer timer; // ประกาศให้ฟังก์ชัน ทำงาน
void setup() {
   timer.setInterval(3000, readSensor); // ตั้งเวลาให้อ่านทุก 3 วิ
  lcd.begin();
  lcd.backlight(); 
  Serial.begin(9600);
  Wire.begin();
  serial_connection.begin(9600);//This opens up communications to the GPS
  Serial.println("GPS Start");//Just show to the monitor that the sketch has started

  
  //Initialize sensor
  if (mySensor.begin() == false) {
    Serial.println("No SGP30 Detected. Check connections.");
    while (1);
  }
  //Initializes sensor for air quality readings
  //measureAirQuality should be called in one second increments after a call to initAirQuality
  mySensor.initAirQuality();
}

void readSensor() {

  
  //First fifteen readings will be
  //CO2: 400 ppm  TVOC: 0 ppb
  //measure CO2 and TVOC levels
  
  mySensor.measureAirQuality();
  Serial.print("CO2: ");
  Serial.print(mySensor.CO2);
  Serial.print(" ppm\tTVOC: ");
  Serial.print(mySensor.TVOC);
  Serial.println(" ppb"); 
  lcd.setCursor(0,0);
  lcd.print("CO2: ");
  lcd.print(mySensor.CO2);
  lcd.print("ppm");
  lcd.setCursor(0,1);
  lcd.print("TVOC: ");
  lcd.print(mySensor.TVOC);
  lcd.println("ppb");
  lcd.setCursor(0,2);
  lcd.print("Longitude:"); lcd.print(gps.location.lng(), 6);
  lcd.setCursor(0,3);lcd.println("Longitude:");lcd.print(gps.location.lng(), 6);
  //delay(1000); //Wait 1 secondd

}
void loop(){
  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  if(gps.location.isUpdated())//This will pretty much be fired all the time anyway but will at least reduce it to only after a package of NMEA data comes in
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    Serial.println("Satellite Count:");
    Serial.println(gps.satellites.value());
    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);
    Serial.println("Speed MPH:");
    Serial.println(gps.speed.mph());
    Serial.println("Altitude Feet:");
    Serial.println(gps.altitude.feet());
    Serial.println("");
  }

  timer.run();
  }

อย่างที่ผมบอกไปนั้นแหละครับ ตรง GPS มันทำงานโดยใช้ while() หมายถึงมันต้องทำงานอยู่ตลอดจนกว่าจะได้รับ พิกัด ผมจึงเลือกให้มันอยู่ใน loop เหมือนเดิมนั้นแหละ ส่วนการอ่านเซนเซอร์เราไม่จำเป็นต้องอ่าน ตลอดเวลา ให้มันอ่านเว้นระยะก็ได้ เลยเหมาะที่จะตั้งเวลา

สรุปคือต้องดูความเหมาะสมของโค้ตเราด้วยครับว่าต้องการทำงานแบบไหน

ขอบคุณมากๆเลยครับพี่ ตัวฟังชั่น timer เหมือนการทำงาน millis หรือเปล่าครับ

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

ผมเขียนคู่มือไว้ลองอ่านเพื่อเติมได้