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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*******************************************************************************************
00002     FLORANION Scientific SHIELD for FRDM KL25Z REV2.00
00003     Discover the secret life of plants!
00004     (c) Martin Heine - Light Art Vision 2018 
00005 
00006     This program is free software: you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation, either version 3 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 ********************************************************************************************/
00019 #include <mbed.h>
00020 #include <FastPWM.h>
00021 #include <SDBlockDevice.h>
00022 #include <FATFileSystem.h>
00023 #include "SPI_TFT_ILI9341.h"
00024 #include "Arial12x12.h"
00025 #include "Arial24x23.h"
00026 #include "Arial28x28.h"
00027 #include "font_big.h"
00028 
00029 #define firmware 1.00       // Firmware Version
00030 #define RGBmask 0xFF        // RGB Color resolution (0xFF = 8 Bit = 256 Colors)
00031 #define dacMask 0xFFF       // DAC Voltage resoltion
00032 #define samples 100         // Measuring samples 
00033 #define baudrate 115000     // Baudrate for serial monitor over USB
00034 
00035 #define datalogger true     // SD Card Data Recording (Datalogger)
00036 #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)
00037 #define extRGB true         // RGB PWM at J19 Pins 1, 2, 3
00038 #define onBoardRGB true     // On Board RGB LED
00039 #define QVGA true           // TFT QVGA Display support
00040 
00041 /************************************** Inits ***************************************/
00042 // I/Os
00043 AnalogIn ain(PTB0);  // Amplified and filtered Plant-Signal 
00044 AnalogIn ain0(PTB1); // Non amplified absolute voltage level / skin resistance level.
00045 
00046 //LED Bar for Plants absolute voltage level / skin resistance level.
00047 DigitalOut barDot3(PTC9);  
00048 DigitalOut barDot2(PTC8); 
00049 DigitalOut barDot1(PTA5);
00050 DigitalOut barDot0(PTA4);
00051 DigitalOut barDot7(PTA12);
00052 DigitalOut barDot6(PTD4);
00053 DigitalOut barDot5(PTC17);
00054 DigitalOut barDot4(PTC16);
00055 DigitalIn Record(PTB8);             // SD Card Data Record Switch
00056 //FastPWM pwmAnalogOut(PTA13);      // Optional PWM out for Analog Voltage. all RGB PWMs must be disabled!
00057 AnalogOut aout(PTE30);              // Analog Out (DAC)
00058 
00059 //Using FastPWM for higher speed and resolution. Otherwise, the RGB LED will flicker  
00060 
00061 //RGB LED on the FRDM KL25Z board 
00062 FastPWM r(LED_RED);
00063 FastPWM g(LED_GREEN);
00064 FastPWM b(LED_BLUE);
00065 
00066 //External RGB LEDs
00067 FastPWM extRed(PTE20);
00068 FastPWM extGreen(PTE21);
00069 FastPWM extBlue(PTE29);
00070 
00071 // SD-Card Pins
00072 SDBlockDevice sd(PTE1, PTE3, PTE2, PTE4);   // mosi,miso,sck,cs
00073 FATFileSystem fs("sd");
00074 
00075 // QVGA 2.2 TFT SPI 240x320 Color Display
00076 SPI_TFT_ILI9341 TFT(PTC6, PTC7, PTC5, PTC4, PTC0, PTC3, "TFT"); // mosi, miso, sclk, cs, reset, DC/RS
00077 DigitalOut LCD_LED(PTC12);       // the display has a backlight switch on board 
00078 
00079 Serial pc(USBTX, USBRX);
00080 
00081 Thread thread;
00082 
00083 /************************************* Global Variables ******************************/
00084 long int plant, plant0, tmp, dacOut;;
00085 short int plantRGB;
00086 double pwmNormVal;
00087 float colorRange = 255;
00088 float Volt;
00089 int i; float bl; unsigned int upDown = 0;
00090 bool plantConnected, fileOpen, newFile = 1;
00091 bool rec = false;
00092 bool noLogo;
00093 bool SDOK;
00094 //char filename[64];    
00095 int n = 0;
00096 short unsigned y=16, yStart=16, yold = y, plantRGBold, plantBit4, plantBit4old, msg=0;
00097 float dacRange = 4095;
00098 
00099 /**************************************** Functions **********************************/
00100 void barDot(short unsigned level)
00101 {
00102     barDot0 = 0;
00103     barDot1 = 0;
00104     barDot2 = 0;
00105     barDot3 = 0;
00106     barDot4 = 0;
00107     barDot5 = 0;
00108     barDot6 = 0;    
00109     barDot7 = 0;   
00110     
00111     switch (level) 
00112     {
00113         case 0: barDot0 = 1; break; 
00114         case 1: barDot1 = 1; break;
00115         case 2: barDot2 = 1; break;
00116         case 3: barDot3 = 1; break;
00117         case 4: barDot4 = 1; break;
00118         case 5: barDot5 = 1; break;
00119         case 6: barDot6 = 1; break; 
00120         case 7: barDot7 = 1; break; 
00121     }
00122 }
00123 
00124 void initPWMs()
00125 {
00126     r.period_ms(10);                // RGB LED PWM Frequency
00127     g.period_ms(10);
00128     b.period_ms(10);
00129     
00130     extRed.period_ms(10);           // RGB extern PWM Frequency
00131     extGreen.period_ms(10);
00132     extBlue.period_ms(10);
00133     
00134    //pwmAnalogOut.period_us(20);     //50kHz PWM out for Analog Voltage. RGB PWMs need to be disabled!
00135 } 
00136 
00137 void fadeBlue()
00138 {
00139     r=1;
00140     g=1;
00141     if (!upDown) i++; else i--;
00142     bl = (1/colorRange)*i;
00143     b=1-bl;
00144     if (i >=256) upDown = 1;
00145     if ((i == 0) && (upDown == 1)) upDown = 0;
00146 }
00147 
00148 void TFTinit()
00149 {
00150     TFT.claim(stdout);          // send stdout to the TFT display
00151     TFT.set_orientation(1);
00152     TFT.background(Black);      // set background to black
00153     TFT.foreground(White);      // set chars to white
00154     TFT.cls();                  // clear the screen
00155     LCD_LED = 1;                // backlite on
00156 }
00157 
00158 void TFTwelcome()
00159 {
00160     TFT.foreground(Cyan);
00161     TFT.set_font((unsigned char*) Arial24x23);
00162     TFT.locate(80,100);
00163     TFT.printf("Welcome to");
00164     TFT.locate(85,125);
00165     TFT.printf("Floranium");
00166     wait(2);
00167     TFT.foreground(White);
00168     TFT.set_font((unsigned char*) Arial12x12);
00169     TFT.locate(20,200);
00170     TFT.printf("FLORANIUM Firmware Version %f",firmware);
00171     wait(1);
00172     TFT.cls();                // clear the screen
00173     TFT.rect(15,0,320,225,LightGrey);    
00174     TFT.foreground(White);
00175 }
00176 
00177 void data2TFT() 
00178 {
00179     if (msg == 1) 
00180     {
00181         TFT.cls();
00182         TFT.rect(15,0,320,225,LightGrey); 
00183         yold = yStart;
00184         y = yStart;
00185         msg = 0;
00186     }
00187              
00188     plantBit4 = (plant & 0xFF00);    // Avoid line at rollover from 255 -> 1 and 1 > 255
00189     TFT.line(y+1,1,y+1,224,Cyan);    // traveling blue line
00190     TFT.line(y,1,y,224,Black);
00191     if (y == 319) TFT.line(y,1,y,224,DarkGrey);
00192     if (plantBit4 - plantBit4old == 0) TFT.line(yold,plantRGBold/1.13,y,(RGBmask-plantRGB)/1.13,GreenYellow);  // x-y to x-y
00193         
00194     plantRGBold = RGBmask-plantRGB; //invert so curve on display goes up when plantRGB increases
00195     yold = y;
00196     y++;
00197     plantBit4old = plantBit4;       // to avoid line on display when upper or lower border reached.
00198         
00199     // Circle Bar on left side for overall voltage level
00200     TFT.fillcircle(6,6,5,DarkGrey);
00201     TFT.fillcircle(6,219,5,DarkGrey);
00202     TFT.fillrect(0,6,12,219,DarkGrey);
00203     TFT.fillcircle(6,219-(plant/310),5,GreenYellow);
00204         
00205     // bottom ADC and voltage values
00206     TFT.foreground(White);   
00207     // TFT.locate(0,228);
00208     // TFT.printf("ADC %5d", plant);
00209     if (!Record) 
00210     {
00211         if (SDOK) 
00212         {
00213             TFT.fillcircle(6,230,5,Red);    // Red Dot for recording
00214         }
00215         else
00216         { 
00217             TFT.fillcircle(6,230,5,Yellow); // Yello Dot SD Card failure (not present)
00218         }
00219     } 
00220     else
00221     {    
00222         TFT.fillcircle(6,230,5,DarkGrey);
00223     }
00224     TFT.locate(16,228);
00225     TFT.printf("Udisp %6.4fV", Volt);
00226     TFT.locate(130,228);
00227     TFT.printf("RGB %3d", plantRGB);
00228     TFT.locate(225,228);
00229     TFT.printf("Uin %6.4fV", (plant0/65535.0)*3.3);
00230     
00231     // when curve reaches end of display, start from the beginning
00232     if (y >= 319) 
00233     {
00234         yold = yStart;
00235         y = yStart;
00236         TFT.rect(15,0,320,225,LightGrey);
00237     }
00238 }
00239 
00240 void adc2rgb_thread() 
00241 {
00242     unsigned short i;
00243     long long sample, sample0;
00244     float color,red,green,blue;  
00245     
00246     while (1) 
00247     {
00248         barDot(plant0/8192);                 // LED Bargraph    
00249       
00250         for (i=1; i<=samples; i++) 
00251         {
00252             sample += ain.read_u16();       // read filtered and amplified plant signal ADC Value 
00253             sample0 += ain0.read_u16();     // read plant DC level ADC Value
00254             wait_us(100);
00255         }  
00256         
00257         plant=sample/samples;               // Averaging
00258         plant0 = sample0/samples;
00259         
00260         sample = 0;
00261         sample0= 0;
00262         pwmNormVal = (plant/65535.0);
00263         Volt = pwmNormVal*3.3;
00264         
00265         if (Volt <= 3.2)    // Only if a green plant is connected!
00266         {
00267             plantConnected = true;
00268             plantRGB = (plant & RGBmask);       // mask LSB Bit 0-4 for RGB LED Display
00269           
00270             // ********************* RGB LED Color mixing
00271             color = (1/colorRange)*plantRGB;
00272             if(plantRGB >= 0 && plantRGB <= 85 ) { red = 1-(color*3); green = color*3; blue = 0; }
00273             if(plantRGB > 85 && plantRGB <= 170) { red = 0; green = 2-(color*3); blue = (color*3)-1; }
00274             if(plantRGB > 170 && plantRGB <= 255) { red = (color*3)-2; green = 0; blue = (1-color)*3; }
00275     
00276             //FRDM-KL25Z RGB LED
00277             if (onBoardRGB)
00278             {
00279                 r=1-red;
00280                 g=1-green; 
00281                 b=1-blue;
00282             }
00283             else
00284             {
00285                 r=1;
00286                 g=1; 
00287                 b=1;
00288             }
00289         
00290             //PWM Output RGB EXT (Shield Connector J19)
00291             if (extRGB)
00292             {
00293                 extRed=1-red;
00294                 extGreen=1-green;
00295                 extBlue=1-blue;
00296             }
00297             
00298             if (dac) aout = (1/colorRange)*plantRGB; // DAC Analog Out (J18)
00299             //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. 
00300         } 
00301         else 
00302         { 
00303             fadeBlue(); // fade blue LED slowly up and down if no plant is connected
00304             plantConnected = false;
00305         }
00306     }
00307 }
00308 
00309 void data2serial()
00310 {    
00311     short unsigned bar,j;
00312     pc.printf("%5d %6.5f %3d ", plant, Volt, plantRGB);
00313     bar = (plant & 0xFF)/8;
00314     for (j=1; j<=bar; j++) pc.printf(" ");
00315     pc.printf("*\n\r");
00316 }
00317 
00318 bool data2SDCard()
00319 {
00320     char filename[64];
00321     
00322     if (newFile)
00323     {
00324         mkdir("/sd/data", 0777);
00325         while(1) 
00326         {
00327             sprintf(filename, "/sd/data/flrm%04d.csv", n);    // construct the filename fileNNN.csv
00328             FILE *fp = fopen(filename, "r");                  // try and open it
00329             if(fp == NULL) 
00330             {                       
00331                 break;              // if not found, we're done!
00332             }
00333             fclose(fp);             // close the file
00334             n++;                    // and try the next one
00335         }
00336         pc.printf("Data are logged to file: %s...\n\r", filename);
00337         newFile = 0;
00338     }
00339     FILE *fp = fopen(filename, "a");
00340     if(fp == NULL) 
00341     {
00342         pc.printf("Could not open File for write. SD Card present?\n\r");
00343         return 0;
00344     }
00345     fprintf(fp,"%5d,%6.4f,%3d\n\r", plant, Volt, plantRGB);
00346     fclose(fp);
00347     return 1;
00348 }
00349 
00350 /************************************ Main Program **********************************/
00351 int main()
00352 {
00353     bool SDmounted;
00354  
00355     pc.baud(baudrate);
00356     initPWMs();
00357     pc.printf("Welcome to \033[32mFLORANIUM \033[0m Firmware Vers. %3.2f (c)Light Art Vision 2018\n\n\r", firmware);
00358     if (QVGA) TFTinit();
00359     if (QVGA) TFTwelcome();
00360 
00361     thread.start(adc2rgb_thread);
00362     while(1)
00363     {
00364         data2serial();
00365         if (QVGA) data2TFT();
00366         if ((!Record) && (datalogger))
00367         {
00368             if (!SDmounted) // Mount SD-Card if not already mounted  
00369             {
00370                 sd.init();
00371                 fs.mount(&sd);
00372                 SDmounted = true;
00373                 pc.printf("SD Card mounted\n\r");
00374                 
00375             }
00376             SDOK = data2SDCard();
00377         }
00378         else        
00379         {
00380             if (SDmounted)  // Unmount SD-Card if not already unmounted
00381             {
00382                 fs.unmount();
00383                 sd.deinit();
00384                 SDmounted = false;
00385                 pc.printf("SD Card unmounted. You can remove it safely!\n\r");
00386                 newFile = 1;
00387             }
00388         }
00389         if (!QVGA) wait(0.5);
00390     }
00391 }