Fully functional code for LÜTR v1.

Dependencies:   PM2_Libary Adafruit_GFX BME680

main.cpp

Committer:
pfammjur
Date:
2021-05-25
Revision:
18:5019da899a41
Parent:
17:80e441d2b10a

File content as of revision 18:5019da899a41:

/*
 *  Written by Juri Pfammatter 25/5/2021 for use in mbedOS
 *
 *  Inspired by Neal Horman - http://www.wanlink.com
            and Adafruit - http://www.adafruit.com
 */
 
#include "mbed.h"
#include "Adafruit_SSD1306.h"
#include "mbed_bme680.h"
#include "platform/mbed_thread.h"
#include "Servo.h"
#include "FastPWM.h"

/*Defines BME680*/
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define ARRAYLENGTH 60

  
using namespace std::chrono;                                                    //Namespce für printf usw...
  
  
/* BME680 */
I2C i2c(I2C_SDA, I2C_SCL);                                                      //I2C Zuweisung Used inside the BME680 Mbed Lib.
BME680 bme680(0x77 << 1);                                                       //Object erstellen (<<1 für mbed 8bit Adresse)

/* OLED */
DigitalOut myled(LED1);
/* an I2C sub-class that provides a constructed default */
class I2CPreInit : public I2C
{
public:
    I2CPreInit(PinName sda, PinName scl) : I2C(sda, scl)
    {
        frequency(400000);
        //start();
    };
};

I2CPreInit gI2C(I2C_SDA, I2C_SCL);
Adafruit_SSD1306_I2c oled(gI2C,D4,0x7A,64,128);


/* Futaba Servo S3001 20mm 3kg Analog */
// https://www.modellmarkt24.ch/pi/RC-Elektronik/Servos/Standard-Servo-20mm/futaba-servo-s3001-20mm-3kg-analog.html?gclid=CjwKCAjw3pWDBhB3EiwAV1c5rK_-x_Bt19_wIY-IcS2C-RULXKBtYfY0byxejkZLjASro-EMPBUhrxoCgaQQAvD_BwE
// create servo objects
Servo servo_S1(PB_2);
int servoPeriod_mus = 20000;                                                    //Zeitperiode
int servoMax = 580, servoMin = 350;                                             //2300: 180 ; 300: 0
//float a = -2.3, b = 810;                                                      //Gas -> Rotation
//Anpassung an defekten Sensor
float a = -23, b = 695;
float tempA = 0.8369, tempB = -0.6236;                                          //Temperaturkompensation


/* Methodendeklaration */
void servoPos(int pos,int wait1, int wait2);
void checkExtreme(float temp, float hum, int press, int voc, bool reset);
void setAverage(float temp, float hum, int press, int voc, int arraynr);
int getAverageI(int array[]);
float getAverageF(float array[]);

/* Zeitmanagement */
bool           executeMainTask = false;
Timer          power_button_timer,mode_button_timer, loop_timer;
int            Ts_ms = 500;                                                     //Durchlaufzeit -> 2Hz
int            mode = 1;                                                        //Anzeigemodus: Start auf aktuellen Werten
int            counter = 0;                                                     //Zähler für verschiedene Frequnzen

/* Arrays für Mittelwerte*/
float          tempAr[ARRAYLENGTH], humAr[ARRAYLENGTH];
int            pressAr[ARRAYLENGTH], vocAr[ARRAYLENGTH];
int            arrayNr = 0;
int            firstRound = 0;
bool           firstLap = true;

/* Sonstige Parameter */
bool maxOneTime = true;                                                         //identische Position maximal ein Mal einstellen
bool resetExtreme = true;                                                       //reset
float temp, maxTemp, minTemp, hum, maxHum, minHum;
int press, maxPress, minPress, voc, maxVoc, minVoc;


/* Buttons */
InterruptIn    power_button(D6);
InterruptIn    mode_button(D5);
void           power_button_fall();          
void           power_button_rise();
void           mode_button_fall();
void           mode_button_rise();

/* Setup */
void setup(){                                                                   //Setup wird 1 mal durchlaufen
    loop_timer.start();
    power_button.mode(PullUp);                                                  //interner PullUp
    power_button.fall(&power_button_fall);                                      //von 1 auf 0
    power_button.rise(&power_button_rise);                                      //von 0 auf 1
    mode_button.mode(PullUp);
    mode_button.fall(&mode_button_fall);
    mode_button.rise(&mode_button_rise);
    oled.clearDisplay();
    oled.splashCustomLogo();                                                    //Logo Anzeigen lassen
    oled.display();
    thread_sleep_for(1000);                                                     
    set_time(1620477341);                                                       //Set RTC time to Wed, 21. April 2021 19:28:30 https://www.epochconverter.com/
    thread_sleep_for(1000);
    oled.clearDisplay();
    if (!bme680.begin()) {                                                      //begin() startet Sensor: Vorheizen usw...
        oled.printf("BME680 Begin failed \r\n");                                //Fehlermeldung
    }else{
        bme680.performReading();                                                //Nullwerte abfangen
    }
    servoPos(servoMax,1000,1000);                                               //Endpositionen anfahren
    servoPos(servoMin,1000,1000);
    
    
}

int main()
{   
    setup();
    
    while(true)
    {
        loop_timer.reset();                                                     //Timer reset
        oled.setTextCursor(0,0);                                                //Textposition reset
        
        if(executeMainTask){
            
            /* Zeit */
            time_t seconds = time(NULL);
            char timebuffer[32];
            strftime(timebuffer, 32, "%b %d %Y  %H:%M:%S", localtime(&seconds));//Nur Stunde, Minuten, Sekunden auslesen
            oled.printf("%s", timebuffer);
            
            oled.setTextCursor(0,15);                                           //Vertikaler Abstand
            
            /* Werte auslesen */
            if (bme680.performReading()) {                          
                temp = tempA*bme680.getTemperature()+tempB;                     //Temperaturkompensation
                hum = bme680.getHumidity();
                press = static_cast<int>(bme680.getPressure()/100);
                voc = static_cast<int>(bme680.getGasResistance()/1000.0);
            }else{
                oled.printf("Failed to perform reading :(\n");
            }
            /* Mittelwerte */
            if(((counter%(24*3600/ARRAYLENGTH)==0)&& !firstLap)||((counter%(3600/ARRAYLENGTH)==0)&& firstLap)){  //erste 30min: array füllen; danach alle 30 min einen Wert eintragen
                setAverage(temp, hum, press, voc, arrayNr);
                (arrayNr==(ARRAYLENGTH-1))? arrayNr= 0: arrayNr++;
            }
            /* Extremwerte */
            checkExtreme(temp, hum, press, voc, resetExtreme);
            
            /* Anzeige */
            switch (mode){
                case 1: oled.printf("Aktuellwerte\r\n");
                        oled.printf("Temperatur:  %.2f C\r\n",temp);
                        oled.printf("Luftf.:      %.2f %%\r\n",hum);
                        oled.printf("Luftdr.:     %d hPa\r\n",press);
                        oled.printf("VOC:         %d kOhm\r\n",voc);
                        oled.display();
                        break;
                    
                case 2: oled.printf("Mittelwerte\r\n");
                        oled.printf("Temperatur:  %.2f C\r\n",getAverageF(tempAr));
                        oled.printf("Luftf.:      %.2f %%\r\n",getAverageF(humAr));
                        oled.printf("Luftdr.:     %d hPa\r\n",getAverageI(pressAr));
                        oled.printf("VOC:         %d kOhm\r\n",getAverageI(vocAr));
                        oled.display();
                        break;
                    
                case 3: oled.printf("Extremwerte\r\n");
                        oled.printf("Temp:   %.1f %.1f C\r\n",minTemp, maxTemp);
                        oled.printf("Luftf.: %.1f %.1f %%\r\n",minHum, maxHum);
                        oled.printf("Luftd.: %d  %d hPa\r\n",minPress, maxPress);
                        oled.printf("VOC:    %d  %d kOhm\r\n",minVoc, maxVoc);
                        oled.display();
                        break;
            }
            
            /* Servo */
            if(counter%10==0){                                                  //Nur alle 5s Position ändern
                int output = static_cast<int>(a*(bme680.getGasResistance()/1000.0)+b);
                if(output>=servoMin && output<=servoMax){
                    servoPos(output,250,0);
                    maxOneTime = true;
                }else if(output <= servoMin){
                    if(maxOneTime){
                        servoPos(servoMin,250,0);  
                        maxOneTime = false;
                    }
                }else{    
                    if(maxOneTime){
                        servoPos(servoMax,250,0);  
                        maxOneTime = false;
                    } 
                }
            }
            
            /* Timer */
            int T_loop_ms = duration_cast<milliseconds>(loop_timer.elapsed_time()).count();
            int dT_loop_ms = Ts_ms - T_loop_ms;
            if(dT_loop_ms>=0 && dT_loop_ms<=Ts_ms)thread_sleep_for(dT_loop_ms);
            
            oled.clearDisplay();
            
            (counter==1440000)?counter=0: counter++;                            //Zähler um 1 erhöhen und nach 720000s wiederholen
            if(counter==3600){                                                  //Erste Runde um Array zu füllen
                firstLap = false;
            }
            
        }else{
            oled.clearDisplay();
            oled.display();
            if(maxOneTime){
                servoPos(servoMax,Ts_ms,0);
                maxOneTime = false;                                             
            }
        }
    }
}

//* Methoden *//
/* Servo Position */
void servoPos(int pos,int wait1,int wait2){
    servo_S1.Enable(servoMin, servoPeriod_mus);
    servo_S1.SetPosition(pos);
    thread_sleep_for(wait1);
    servo_S1.Disable();
    thread_sleep_for(wait2);
}
/* Power-Buttons */
void power_button_fall()
{
    power_button_timer.reset();
    power_button_timer.start();
}
 
void power_button_rise()
{
    int t_button = duration_cast<milliseconds>(power_button_timer.elapsed_time()).count();
    power_button_timer.stop();
    if(t_button > 30){
        resetExtreme = true;
        executeMainTask = !executeMainTask;
    }
}
/* Mode-Buttons */
void mode_button_fall()
{
    mode_button_timer.reset();
    mode_button_timer.start();
}
 
void mode_button_rise()
{
    int t_button = duration_cast<milliseconds>(mode_button_timer.elapsed_time()).count();
    mode_button_timer.stop();
    if(t_button > 30) {
        (mode!=3) ? mode++ : mode=1;   
    }
}

/* Mittelwerte */
void setAverage(float temp, float hum, int press, int voc, int arrayNr){
    tempAr[arrayNr] = temp;
    humAr[arrayNr] = hum;
    pressAr[arrayNr] = press;
    vocAr[arrayNr] = voc;
    if(firstRound<ARRAYLENGTH)firstRound++;                                     //Arraylänge für Durchschnitt
}

int getAverageI(int array[]){                                                   //int als Rückgabewert
    int sum = 0;
    for(int j=0; j<firstRound;j++){    
        if(array[j]!=0)sum+=array[j];
    }
    return sum/firstRound;                              
}

float getAverageF(float array[]){                                               //float als Rückgabewert
    float sum = 0;
    for(int j=0; j<firstRound;j++){
        if(array[j]!=0)sum+=array[j];
    }
    return sum/firstRound;
}
    
/* Extemwerte */
void checkExtreme(float temp, float hum, int press, int voc, bool reset){
        if(reset){                                                              //reset
            minTemp = temp;
            maxTemp = temp;
            minHum = hum;
            maxHum = hum;
            minPress = press;
            maxPress = press;
            minVoc = voc;
            maxVoc = voc;
            resetExtreme = false;
        }
        if(temp >= maxTemp)maxTemp = temp;
        if(temp <= minTemp||minTemp <= 1.0)minTemp = temp;
        if(hum >= maxHum) maxHum = hum;
        if(hum <= minHum||minHum <= 1.0)minHum = hum;
        if(press >= maxPress) maxPress = press;
        if(press <= minPress||minPress <= 1)minPress = press;
        if(voc >= maxVoc) maxVoc = voc;
        if(voc <= minVoc||minVoc <= 1)minVoc = voc;
    }