Discover the secret life of plants! FLORANIUM FDRM-KL25Z Shield An experimental Polygraph for green plants. www.floranion.de

Dependencies:   FastPWM SPI_TFT_ILI9341 TFT_fonts

SOME BELIEVE PLANTS CAN FEEL OUR PRESENCE...

The FLORANIUM PROJECT is an innovative plant life indicator, similar to a humans polygraph, that allow you to visualize activities of living plants, caused by movement, touch, changes in climate, environment and many other elements of life. It's a whole new way to interact with green plants!

Please visit http://www.floranium.com or http://www.floranion.de for more information.

/media/uploads/lasmahei/screenshot_2018-02-14_13-35-22.png/media/uploads/lasmahei/floranium.png

main.cpp

Committer:
lasmahei
Date:
21 months ago
Revision:
2:de08bea849b8
Parent:
1:f95f37892056

File content as of revision 2:de08bea849b8:

/*******************************************************************************************
    FLORANION Scientific SHIELD for FRDM KL25Z REV2.00
    Discover the secret life of plants!
    (c) Martin Heine - Light Art Vision 2018 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
********************************************************************************************/
#include <mbed.h>
#include <FastPWM.h>
#include <SDBlockDevice.h>
#include <FATFileSystem.h>
#include "SPI_TFT_ILI9341.h"
#include "Arial12x12.h"
#include "Arial24x23.h"
#include "Arial28x28.h"
#include "font_big.h"

#define firmware 1.00       // Firmware Version
#define RGBmask 0xFF        // RGB Color resolution (0xFF = 8 Bit = 256 Colors)
#define dacMask 0xFFF       // DAC Voltage resoltion
#define samples 100         // Measuring samples 
#define baudrate 115000     // Baudrate for serial monitor over USB

#define datalogger true     // SD Card Data Recording (Datalogger)
#define dac true            // Outputs the analog Voltage of the RGB Color Wheel via DAC at J18 Pin 1 (To watch plant signal with an Oscilloscope)
#define extRGB true         // RGB PWM at J19 Pins 1, 2, 3
#define onBoardRGB true     // On Board RGB LED
#define QVGA true           // TFT QVGA Display support

/************************************** Inits ***************************************/
// I/Os
AnalogIn ain(PTB0);  // Amplified and filtered Plant-Signal 
AnalogIn ain0(PTB1); // Non amplified absolute voltage level / skin resistance level.

//LED Bar for Plants absolute voltage level / skin resistance level.
DigitalOut barDot3(PTC9);  
DigitalOut barDot2(PTC8); 
DigitalOut barDot1(PTA5);
DigitalOut barDot0(PTA4);
DigitalOut barDot7(PTA12);
DigitalOut barDot6(PTD4);
DigitalOut barDot5(PTC17);
DigitalOut barDot4(PTC16);
DigitalIn Record(PTB8);             // SD Card Data Record Switch
//FastPWM pwmAnalogOut(PTA13);      // Optional PWM out for Analog Voltage. all RGB PWMs must be disabled!
AnalogOut aout(PTE30);              // Analog Out (DAC)

//Using FastPWM for higher speed and resolution. Otherwise, the RGB LED will flicker  

//RGB LED on the FRDM KL25Z board 
FastPWM r(LED_RED);
FastPWM g(LED_GREEN);
FastPWM b(LED_BLUE);

//External RGB LEDs
FastPWM extRed(PTE20);
FastPWM extGreen(PTE21);
FastPWM extBlue(PTE29);

// SD-Card Pins
SDBlockDevice sd(PTE1, PTE3, PTE2, PTE4);   // mosi,miso,sck,cs
FATFileSystem fs("sd");

// QVGA 2.2 TFT SPI 240x320 Color Display
SPI_TFT_ILI9341 TFT(PTC6, PTC7, PTC5, PTC4, PTC0, PTC3, "TFT"); // mosi, miso, sclk, cs, reset, DC/RS
DigitalOut LCD_LED(PTC12);       // the display has a backlight switch on board 

Serial pc(USBTX, USBRX);

Thread thread;

/************************************* Global Variables ******************************/
long int plant, plant0, tmp, dacOut;;
short int plantRGB;
double pwmNormVal;
float colorRange = 255;
float Volt;
int i; float bl; unsigned int upDown = 0;
bool plantConnected, fileOpen, newFile = 1;
bool rec = false;
bool noLogo;
bool SDOK;
//char filename[64];    
int n = 0;
short unsigned y=16, yStart=16, yold = y, plantRGBold, plantBit4, plantBit4old, msg=0;
float dacRange = 4095;

/**************************************** Functions **********************************/
void barDot(short unsigned level)
{
    barDot0 = 0;
    barDot1 = 0;
    barDot2 = 0;
    barDot3 = 0;
    barDot4 = 0;
    barDot5 = 0;
    barDot6 = 0;    
    barDot7 = 0;   
    
    switch (level) 
    {
        case 0: barDot0 = 1; break; 
        case 1: barDot1 = 1; break;
        case 2: barDot2 = 1; break;
        case 3: barDot3 = 1; break;
        case 4: barDot4 = 1; break;
        case 5: barDot5 = 1; break;
        case 6: barDot6 = 1; break; 
        case 7: barDot7 = 1; break; 
    }
}

void initPWMs()
{
    r.period_ms(10);                // RGB LED PWM Frequency
    g.period_ms(10);
    b.period_ms(10);
    
    extRed.period_ms(10);           // RGB extern PWM Frequency
    extGreen.period_ms(10);
    extBlue.period_ms(10);
    
   //pwmAnalogOut.period_us(20);     //50kHz PWM out for Analog Voltage. RGB PWMs need to be disabled!
} 

void fadeBlue()
{
    r=1;
    g=1;
    if (!upDown) i++; else i--;
    bl = (1/colorRange)*i;
    b=1-bl;
    if (i >=256) upDown = 1;
    if ((i == 0) && (upDown == 1)) upDown = 0;
}

void TFTinit()
{
    TFT.claim(stdout);          // send stdout to the TFT display
    TFT.set_orientation(1);
    TFT.background(Black);      // set background to black
    TFT.foreground(White);      // set chars to white
    TFT.cls();                  // clear the screen
    LCD_LED = 1;                // backlite on
}

void TFTwelcome()
{
    TFT.foreground(Cyan);
    TFT.set_font((unsigned char*) Arial24x23);
    TFT.locate(80,100);
    TFT.printf("Welcome to");
    TFT.locate(85,125);
    TFT.printf("Floranium");
    wait(2);
    TFT.foreground(White);
    TFT.set_font((unsigned char*) Arial12x12);
    TFT.locate(20,200);
    TFT.printf("FLORANIUM Firmware Version %f",firmware);
    wait(1);
    TFT.cls();                // clear the screen
    TFT.rect(15,0,320,225,LightGrey);    
    TFT.foreground(White);
}

void data2TFT() 
{
    if (msg == 1) 
    {
        TFT.cls();
        TFT.rect(15,0,320,225,LightGrey); 
        yold = yStart;
        y = yStart;
        msg = 0;
    }
             
    plantBit4 = (plant & 0xFF00);    // Avoid line at rollover from 255 -> 1 and 1 > 255
    TFT.line(y+1,1,y+1,224,Cyan);    // traveling blue line
    TFT.line(y,1,y,224,Black);
    if (y == 319) TFT.line(y,1,y,224,DarkGrey);
    if (plantBit4 - plantBit4old == 0) TFT.line(yold,plantRGBold/1.13,y,(RGBmask-plantRGB)/1.13,GreenYellow);  // x-y to x-y
        
    plantRGBold = RGBmask-plantRGB; //invert so curve on display goes up when plantRGB increases
    yold = y;
    y++;
    plantBit4old = plantBit4;       // to avoid line on display when upper or lower border reached.
        
    // Circle Bar on left side for overall voltage level
    TFT.fillcircle(6,6,5,DarkGrey);
    TFT.fillcircle(6,219,5,DarkGrey);
    TFT.fillrect(0,6,12,219,DarkGrey);
    TFT.fillcircle(6,219-(plant/310),5,GreenYellow);
        
    // bottom ADC and voltage values
    TFT.foreground(White);   
    // TFT.locate(0,228);
    // TFT.printf("ADC %5d", plant);
    if (!Record) 
    {
        if (SDOK) 
        {
            TFT.fillcircle(6,230,5,Red);    // Red Dot for recording
        }
        else
        { 
            TFT.fillcircle(6,230,5,Yellow); // Yello Dot SD Card failure (not present)
        }
    } 
    else
    {    
        TFT.fillcircle(6,230,5,DarkGrey);
    }
    TFT.locate(16,228);
    TFT.printf("Udisp %6.4fV", Volt);
    TFT.locate(130,228);
    TFT.printf("RGB %3d", plantRGB);
    TFT.locate(225,228);
    TFT.printf("Uin %6.4fV", (plant0/65535.0)*3.3);
    
    // when curve reaches end of display, start from the beginning
    if (y >= 319) 
    {
        yold = yStart;
        y = yStart;
        TFT.rect(15,0,320,225,LightGrey);
    }
}

void adc2rgb_thread() 
{
    unsigned short i;
    long long sample, sample0;
    float color,red,green,blue;  
    
    while (1) 
    {
        barDot(plant0/8192);                 // LED Bargraph    
      
        for (i=1; i<=samples; i++) 
        {
            sample += ain.read_u16();       // read filtered and amplified plant signal ADC Value 
            sample0 += ain0.read_u16();     // read plant DC level ADC Value
            wait_us(100);
        }  
        
        plant=sample/samples;               // Averaging
        plant0 = sample0/samples;
        
        sample = 0;
        sample0= 0;
        pwmNormVal = (plant/65535.0);
        Volt = pwmNormVal*3.3;
        
        if (Volt <= 3.2)    // Only if a green plant is connected!
        {
            plantConnected = true;
            plantRGB = (plant & RGBmask);       // mask LSB Bit 0-4 for RGB LED Display
          
            // ********************* RGB LED Color mixing
            color = (1/colorRange)*plantRGB;
            if(plantRGB >= 0 && plantRGB <= 85 ) { red = 1-(color*3); green = color*3; blue = 0; }
            if(plantRGB > 85 && plantRGB <= 170) { red = 0; green = 2-(color*3); blue = (color*3)-1; }
            if(plantRGB > 170 && plantRGB <= 255) { red = (color*3)-2; green = 0; blue = (1-color)*3; }
    
            //FRDM-KL25Z RGB LED
            if (onBoardRGB)
            {
                r=1-red;
                g=1-green; 
                b=1-blue;
            }
            else
            {
                r=1;
                g=1; 
                b=1;
            }
        
            //PWM Output RGB EXT (Shield Connector J19)
            if (extRGB)
            {
                extRed=1-red;
                extGreen=1-green;
                extBlue=1-blue;
            }
            
            if (dac) aout = (1/colorRange)*plantRGB; // DAC Analog Out (J18)
            //pwmAnalogOut = pwmNormVal; // PWM out for Analog Voltage (PWM: J15 and DC J12) Please Comment out RGB Color Display above if this PWM or/and Analog Output is used. 
        } 
        else 
        { 
            fadeBlue(); // fade blue LED slowly up and down if no plant is connected
            plantConnected = false;
        }
    }
}

void data2serial()
{    
    short unsigned bar,j;
    pc.printf("%5d %6.5f %3d ", plant, Volt, plantRGB);
    bar = (plant & 0xFF)/8;
    for (j=1; j<=bar; j++) pc.printf(" ");
    pc.printf("*\n\r");
}

bool data2SDCard()
{
    char filename[64];
    
    if (newFile)
    {
        mkdir("/sd/data", 0777);
        while(1) 
        {
            sprintf(filename, "/sd/data/flrm%04d.csv", n);    // construct the filename fileNNN.csv
            FILE *fp = fopen(filename, "r");                  // try and open it
            if(fp == NULL) 
            {                       
                break;              // if not found, we're done!
            }
            fclose(fp);             // close the file
            n++;                    // and try the next one
        }
        pc.printf("Data are logged to file: %s...\n\r", filename);
        newFile = 0;
    }
    FILE *fp = fopen(filename, "a");
    if(fp == NULL) 
    {
        pc.printf("Could not open File for write. SD Card present?\n\r");
        return 0;
    }
    fprintf(fp,"%5d,%6.4f,%3d\n\r", plant, Volt, plantRGB);
    fclose(fp);
    return 1;
}

/************************************ Main Program **********************************/
int main()
{
    bool SDmounted;
 
    pc.baud(baudrate);
    initPWMs();
    pc.printf("Welcome to \033[32mFLORANIUM \033[0m Firmware Vers. %3.2f (c)Light Art Vision 2018\n\n\r", firmware);
    if (QVGA) TFTinit();
    if (QVGA) TFTwelcome();

    thread.start(adc2rgb_thread);
    while(1)
    {
        data2serial();
        if (QVGA) data2TFT();
        if ((!Record) && (datalogger))
        {
            if (!SDmounted) // Mount SD-Card if not already mounted  
            {
                sd.init();
                fs.mount(&sd);
                SDmounted = true;
                pc.printf("SD Card mounted\n\r");
                
            }
            SDOK = data2SDCard();
        }
        else        
        {
            if (SDmounted)  // Unmount SD-Card if not already unmounted
            {
                fs.unmount();
                sd.deinit();
                SDmounted = false;
                pc.printf("SD Card unmounted. You can remove it safely!\n\r");
                newFile = 1;
            }
        }
        if (!QVGA) wait(0.5);
    }
}