Opacity meter

Dependencies:   PinDetect mbed

main.cpp

Committer:
BPPearson
Date:
2016-01-05
Revision:
0:0d9dd22ca491

File content as of revision 0:0d9dd22ca491:

#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);
    }
}