Opacity meter

Dependencies:   PinDetect mbed

Revision:
0:0d9dd22ca491
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jan 05 16:44:13 2016 +0000
@@ -0,0 +1,407 @@
+#include "mbed.h"
+#include "PinDetect.h"
+
+#define COMMAND 0
+#define DATA 1
+
+#define AVERAGE       0
+#define MEDIAN        1
+#define RATEOFCHANGE  2
+#define BINAVERAGE    3
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+AnalogIn opacity(p15);
+AnalogOut fOpacity(p18);
+BusInOut databus(p21, p22, p23, p24, p25, p26, p27, p28);
+DigitalOut registerSelect(p5);
+DigitalOut readWriteClock(p6);
+DigitalOut readWrite(p7);
+DigitalIn unlocked(p8);
+PinDetect calibUp(p10);
+PinDetect calibDown(p9);
+Ticker updateLCD;
+LocalFileSystem local("local");
+
+float instantOpacity;
+float filteredOpacity = 0.0;
+char *helloStr = "Hello";
+int filterAlgorithm = AVERAGE;
+float anIn1Sum;
+float anIn1SumSqr;
+float stdDevCount;
+float standardDeviation;
+float calibFactor = 1.0;
+int showCalibFactor = 0;
+float anInVals[100];
+int anInIdx = 0;
+
+
+void readConfigFile()
+{
+    
+    FILE *fp = fopen("/local/config.dat", "r");
+
+    if (fp != NULL)
+    {
+        fscanf(fp, "%f", &calibFactor); 
+        fclose(fp);
+    }
+}
+
+
+
+void writeConfigFile()
+{
+    FILE *fp = fopen("/local/config.dat", "w");
+
+    if (fp != NULL)
+    {
+        fprintf(fp, "%5.3f\n", calibFactor);
+        fclose(fp);
+    }
+}
+
+
+
+
+void incCalibFactor(){
+    
+    //pc.printf("%d\n", unlocked.read());
+    if (unlocked == false){
+        calibFactor += 0.01;
+        //pc.printf("Inc\n");
+        showCalibFactor = 5;
+        
+        writeConfigFile();
+    }
+}
+
+
+void decCalibFactor(){
+    
+    if (unlocked == false){
+        calibFactor -= 0.01;
+        //pc.printf("Dec\n");
+        showCalibFactor = 5;
+
+        writeConfigFile();
+    }
+}
+
+
+void writeToLCD(bool rs, char data){
+
+    // set register select pin 
+    registerSelect = rs;
+    
+    // set read/write pin to write
+    readWrite = 0;
+    
+    // set bus as output
+    databus.output();
+    
+    // put data onto bus
+    databus = data;
+    
+    // pulse read/write clock
+    readWriteClock = 1;
+    
+    wait_us(1);
+    
+    readWriteClock = 0;
+
+    wait_us(1);
+    
+    // clear data bus
+    databus = 0;
+    
+    //pc.printf("%02x\n", data);
+    
+}
+
+
+char readFromLCD(bool rs){
+
+    char data;
+    
+    // set register select pin 
+    registerSelect = rs;
+    
+    // set read/write pin to read
+    readWrite = 1;
+    
+    // set bus as output
+    databus.input();
+    
+    // put data onto bus
+    data = databus;
+    
+    // pulse read/write clock
+    readWriteClock = 1;
+    
+    wait_us(10);
+    
+    readWriteClock = 0;
+    
+    return data;
+}
+
+
+void resetLCD(){
+}
+
+
+void initLCD(){
+    
+    // wait 15 ms to allow LCD to initialise
+    wait_ms(15);
+    
+    // set interface for 8 bit mode
+    writeToLCD(COMMAND, 0x30);
+
+    // give it time    
+    wait_ms(5);
+
+    // set interface for 8 bit mode again
+    writeToLCD(COMMAND, 0x30);
+
+    // give it time    
+    wait_us(100);
+
+    // set interface for 8 bit mode again, last one before we can configure the display
+    writeToLCD(COMMAND, 0x30);
+
+    // give it time    
+    wait_us(500);
+    
+    // set interface for 8 bit mode, 2 display lines and 5 x 8 character font
+    writeToLCD(COMMAND, 0x38);
+
+    // give it time    
+    wait_us(100);
+    
+    // display off
+    writeToLCD(COMMAND, 0x08);
+
+    // give it time    
+    wait_us(100);
+    
+    // clear the screen
+    writeToLCD(COMMAND, 0x01);
+
+    // give it time to finish    
+    wait_ms(2);
+
+    // set entry mode to increment cursor position cursor on write
+    writeToLCD(COMMAND, 0x03);
+    
+    // give it time to finish    
+    wait_us(100);
+
+    // position cursor at home
+    writeToLCD(COMMAND, 0x02);
+    
+    // give it time to finish    
+    wait_ms(2);
+
+    // display on
+    writeToLCD(COMMAND, 0x0F);
+}
+
+
+
+
+void positionCursor(uint8_t x, uint8_t y){
+
+    if (x > 7) x = 0;
+    
+    if (y == 1)
+        writeToLCD(COMMAND, 0x80 + 0x40 + x);
+    else
+        writeToLCD(COMMAND, 0x80 + 0x00 + x);
+        
+    wait_us(50);
+}
+
+
+void displayString(int x, int y, char *str){
+    
+    // position cursor
+    positionCursor(x, y);    
+    
+    // write string to screen
+    for (int i=0; i<strlen(str); i++){
+        writeToLCD(DATA, str[i]);
+        
+        wait_us(50);
+    }
+}
+
+
+void standardDeviationCalc(float opacity)
+{
+    // add to standard deviation accumulators
+    anIn1Sum += opacity;
+    anIn1SumSqr += (opacity * opacity);
+    
+    // increment standard deviation counter
+    stdDevCount++;
+    
+    // if enough readings for the standard deviation calculation
+    if (stdDevCount >= 100)
+    {
+        // calculate the standard deviation
+        // std dev = sqrt( (n * sum(x2) - sum(x)2)) / (n * (n - 1)))
+        standardDeviation = ((stdDevCount * anIn1SumSqr) - (anIn1Sum * anIn1Sum)) / (stdDevCount * (stdDevCount - 1));
+        if (standardDeviation > 0.0)
+            standardDeviation = sqrt(standardDeviation);
+        else
+            standardDeviation = sqrt(-standardDeviation);
+        
+        // clear standard deviation accumulators for next set of readings
+        anIn1Sum = 0.0;
+        anIn1SumSqr = 0.0;
+        stdDevCount = 0;
+    }
+ }
+ 
+ 
+ void updateDisplay(){
+    char str[20];
+    
+    sprintf( str, "o %5.1f", filteredOpacity * 104.0 * calibFactor);
+
+    displayString(0, 0, str);
+    
+    if (showCalibFactor == 0){
+        sprintf( str, "s %5.2f", standardDeviation);
+
+        displayString(0, 1, str);
+    }
+    else{
+        sprintf( str, "m %5.2f", calibFactor);
+
+        displayString(0, 1, str);
+
+        showCalibFactor--;
+    }
+}
+ 
+ 
+ 
+int main() {
+    float binVal[10];
+    int binCnt[10];
+    int maxCnt = 0;
+    int maxIdx = 0;
+    
+    initLCD();
+    
+    filterAlgorithm = BINAVERAGE;
+    
+    calibUp.mode(PullUp);
+    calibDown.mode(PullUp);
+    unlocked.mode(PullUp);
+    calibUp.attach_deasserted(&incCalibFactor);
+    //calibUp.attach_deasserted_held(&incCalibFactor);
+    calibDown.attach_deasserted(&decCalibFactor);
+    //calibDown.attach_deasserted_held(&decCalibFactor);
+    
+    calibUp.setSampleFrequency();
+    calibDown.setSampleFrequency();
+
+    updateLCD.attach(&updateDisplay, 0.5);
+
+    readConfigFile();
+
+    // initialise analog input values
+    for (int i=0; i<100; i++)
+        anInVals[i] = opacity.read();
+        
+    while(1) {
+        // read next analog input value into circular buffer
+        anInVals[anInIdx] = opacity.read();
+        
+        // increment anInIdx and check for wrap 
+        anInIdx++;
+        if (anInIdx >= 100)
+            anInIdx = 0;
+        
+        // filter analog inputs with required algorithm
+        switch (filterAlgorithm)
+        {
+            case AVERAGE:
+                float accumulator = 0.0;
+                for (int i=0; i<100; i++)
+                {
+                    accumulator += anInVals[i];
+                }
+                instantOpacity = accumulator / 100;
+                break;
+            case MEDIAN:
+                float tempF;
+                for (int j=1; j<100; j++)
+                {
+                    for (int i=1; i<100; i++)
+                    {
+                        if (anInVals[i] < anInVals[i-1])
+                        {
+                            // swap places
+                            tempF = anInVals[i-1] ;
+                            anInVals[i-1] = anInVals[i];
+                            anInVals[i] = tempF;
+                        }
+                    }
+                }
+                instantOpacity = anInVals[49];
+                break;
+            case RATEOFCHANGE:
+                break;
+            case BINAVERAGE:
+                // initialise bins to zero
+                for (int i=0; i<10; i++)
+                {
+                    binVal[i] = 0.0;
+                    binCnt[i] = 0;
+                }
+                
+                // sort analog input values into one of ten bins
+                for (int i=0; i<100; i++)
+                {
+                    int binIdx = anInVals[i] * 10.0;
+                    if (binIdx > 9) 
+                        binIdx = 9;
+                    binVal[binIdx] += anInVals[i];
+                    binCnt[binIdx]++;
+                }
+
+                maxCnt = 0;
+                maxIdx = 0;
+                // find the bin with most values added
+                for (int i=0; i<10; i++)
+                {
+                    if (binCnt[i] > maxCnt)
+                    {
+                        maxCnt = binCnt[i];
+                        maxIdx = i;
+                    }
+                }
+                
+                instantOpacity = binVal[maxIdx] / binCnt[maxIdx];
+                break;
+        }
+
+        standardDeviationCalc(instantOpacity);
+    
+        // apply a filter to the instant reading to get the filtered reading
+        filteredOpacity = (instantOpacity * 0.05) + (filteredOpacity * 0.95);
+    
+        fOpacity.write(filteredOpacity  * calibFactor);
+
+        wait(0.1);
+    }
+}