Embedded Software Assignment 2

Dependencies:   MCP23017 WattBob_TextLCD mbed

main.cpp

Committer:
usmb192
Date:
2016-05-27
Revision:
0:0131c822a391

File content as of revision 0:0131c822a391:

/*******************************************************************************************
*
*    Cyclic Execution based Frequency Measurement ( Embedded Software Assignment 2 )
*
*                   a program that runs a cyclic execution demo
*                       actions are for example
*               frequency measurement and serial logging
*
*
* @author Markus
* @version 1.0
* @lastupdate 02.03.2016 
*                             
*
*******************************************************************************************/

// ########
// INCLUDES
// ########

#include "mbed.h"                                                   // mbed header file
#include "MCP23017.h"                                               // include 16-bit parallel I/O header file
#include "WattBob_TextLCD.h"                                        // include 2*16 character display header file
#include "AnalogIn.h"                                               // include Analog communication
#include <deque>                                                    // used for the avaraging

// #######################
// CONFIGURATION VARIABLES
// #######################

#define SAMPLE_FREQ_US 1
#define TICKRATE_US 12500
#define NYQUIST_CORR 2.002
#define WATCHDOG_PULSE_TIME_MS 5

// ###############################
// ALL PORTS USED ARE DEFINED HERE
// ###############################

#define AnalogPort1 p17                                             // used for Analog Input 1
#define AnalogPort2 p16                                             // used for Analog Input 2
#define FrequencyPort p15                                           // used to measure frequency
#define SwitchPort p5                                               // used for the error code switch
#define WatchPort p6                                                // used for the watchdog pulse
#define OnOffPort p7                                                // used for the on/off switch
#define TaskExecPort p8                                             // used for the task execution pulse


// ####################################
// MISC VARIABLES (shouln't be changed)
// ####################################

MCP23017            *par_port;                                      // pointer to 16-bit parallel I/O object
WattBob_TextLCD     *lcd;                                           // pointer to 2*16 chacater LCD object
Serial              serpc(USBTX, USBRX);                            // serial usb connection tx, rx
Ticker ticker;                                                      // our ticker that runs the main function

DigitalIn dInFreq(FrequencyPort);                                   // Port for the frequency measurement
DigitalIn dInSwitch(SwitchPort);                                    // Port for the switch
DigitalOut dOutWatchd(WatchPort);                                   // Port for WatchDog pulse
DigitalIn dInOnOff(OnOffPort);                                      // Port for the On/Off Switch
DigitalOut dOutTaskExec(TaskExecPort);

std::deque<float> AnalogDB1;                        
std::deque<float> AnalogDB2;

int tick_counter(0);                                                // used for counting the ticks / slots
bool OnOffSwitchStatus(0);                                          // saving the last switch status
int freq(0);                                                        // saving the last frequency status
int error_last(9);                                                  // we init with an impossible error number only 0 and 3 are
                                                                    // possible, using this we force an initialization
                                                                    
float avgAn1(0);                                                    // saving the last avarage of analog 1
float avgAn2(0);                                                    // saving the last avarage of analog 2
bool Switch1(0);                                                    // saving the last switch status

DigitalOut ledd1(LED1);                                             
DigitalOut ledd3(LED3);

// ################################
// FORWARD DECLARATION OF FUNCTIONS
// ################################

void SendPulse(int ms, DigitalOut pn);
void tick();
void printLCD(int& freq,bool& sw, float& avgAn1, float& avgAn2);
void logTime(int TaskNumber);

int MeasureFrequency(DigitalIn& freqIn,int samplingFreqUS);
float ReadAnalogInAVG(std::deque<float>& db,PinName Port);
int CheckError(bool& Switch1,float& avgAn1,float& avgAn2);

/*
========================================================================================
=                                                                                      =
=                       MAIN PROCEDURE - generating the Blocks                         =
=                                                                                      =
========================================================================================
*/
// ############################
// the entrance for the program
// ############################

int main()
{
    serpc.baud(19200);                                              // setup the bautrate
    serpc.printf("Init Software\r\n");
    par_port = new MCP23017(p9, p10, 0x40);                         // initialise 16-bit I/O chip (0x40 = 64)
    lcd = new WattBob_TextLCD(par_port);                            // initialise 2*26 char display
    par_port->write_bit(1,BL_BIT);                                  // turn LCD backlight ON
    lcd->cls();                                                     // clear display
    lcd->locate(0,0);                                               // set cursor to location (0,0) - top left corner
    lcd->printf("f0000 S0");                                        // print labels on the lcd
    lcd->locate(1,0);                                               
    lcd->printf("a1 0.00  a2 0.00");
    ticker.attach_us(&tick, TICKRATE_US);                           // attach the ticker to a procedure
}

// #########################
// the main loop (as ticker)
// #########################
void tick()
{
    // use a timing pulse -> extra digi port -> everytime something happens -> sent pulse
    
    // tickcounter%interval==offset
    if((tick_counter%80)==1) {
        //every 1000 mS
        freq = MeasureFrequency(dInFreq,SAMPLE_FREQ_US);            // measure the frequency

    } else if((tick_counter%24)==2) {
        //every 300 mS, check Switch1 (for error)
        if (dInSwitch)                                              // check the switch status for later use
            Switch1 = true;
        else Switch1 = false;

    } else if((tick_counter%24)==3) {
        // (460 mS) now 300 mS, send watchdog pulse
        SendPulse(WATCHDOG_PULSE_TIME_MS,dOutWatchd);               // send the watchdog pulse

    } else if((tick_counter%32)==4) {
        // every 400 mS
        // EXECUTION SIGNAL!
        SendPulse(10,dOutTaskExec);                                 // sending the execution signal
        avgAn1 = ReadAnalogInAVG(AnalogDB1,AnalogPort1);            // reaning analog values
        avgAn2 = ReadAnalogInAVG(AnalogDB2,AnalogPort2);            // ^^

    } else if((tick_counter%160)==5) {
        // every 2000 Ms
        printLCD(freq,Switch1,avgAn1,avgAn2);                       // print to the lcd screen

    } else if((tick_counter%64)==8) {
        // every 800 mS
        int error_current = CheckError(Switch1,avgAn1,avgAn2);
        if (error_last!=error_current) {                            // we check if the error changed (safe to time )
            if(!error_current) {                                    // we check if its zero
                ledd1=1;
                ledd3=0;
            } else {                                                // else it must be 3
                ledd1=0;
                ledd3=1;
            }
            error_last=error_current;
        }
        
    } else if((tick_counter%400)==9) {
        // every 5000 mS - print to serial
           serpc.printf("%i,%i%,%i,%i\r\n",freq,Switch1,(int)avgAn1,(int)avgAn2);

    } else {
        // in every other slot, check the on off switch
        if(OnOffSwitchStatus!=dInOnOff) {                           // checking the on off switch
            OnOffSwitchStatus = dInOnOff;                           // safe the last switch status
            par_port->write_bit(OnOffSwitchStatus,BL_BIT);          // turn LCD backlight ON/OFF
        }
    }

    tick_counter++;
}

/*
========================================================================================
=                                                                                      =
=                                  FUNCTIONS BLOCK                                     =
=                                                                                      =
========================================================================================
*/

// #########################################################################################
// prints to the lcd, only overwrites values that are necesarry to overwrite (safes some mS)
// #########################################################################################
void printLCD(int& freq,bool& sw, float& avgAn1, float& avgAn2)
{
    lcd->locate(0,1);
    lcd->printf("%04i",freq);                                       // write the frequency to the lcd board
    lcd->locate(0,7);
    lcd->printf("%i",sw);                                           // write the switch value
    lcd->locate(1,3);
    lcd->printf("%.2f",avgAn1);                                     // write avarage analog value 1
    lcd->locate(1,12);
    lcd->printf("%.2f",avgAn2);                                     // write avarage analog value 2
}

// #################################################
// checks the error status and returns it as integer
// #################################################
int CheckError(bool& Switch1,float& avgAn1,float& avgAn2)
{
    if(Switch1 && (avgAn1 > avgAn2))                                // if swicht1 AND averageAnalogValue1 > averageAnalogValue2
        return 3;
    return 0;
}

// ####################################################################
// reads analog values and returns the average over the last 4 readings
// ####################################################################
float ReadAnalogInAVG(std::deque<float>& db,PinName Port)           // (we are using deque because you cant iterate over a queue)
{
    AnalogIn Ain(Port);
    float sum(0);
    if(db.size()>=4)                                                // if we already got 4 values, we have to
        db.pop_front();                                             // make space by deleting the oldest value
    db.push_back(Ain.read());                                       // safe a new reading
    for(deque<float>::const_iterator i = db.begin(); i != db.end(); ++i)
        sum+= *i;                                                   // calculate the average by iterating over the queue
    return sum/db.size();
}

// ##################################################
// used for sending a short pulse for ms Milliseconds
// ##################################################
void SendPulse(int ms, DigitalOut pn)
{
    pn = 1;                                                         // set the analog port high
    wait_ms(ms);                                                    // wait for ms Milliseconds
    pn = 0;                                                         // set the analog port low
}

// ###################################################
// measures the frequency and returns an integer in Hz
// ###################################################
int MeasureFrequency(DigitalIn& freqIn,int samplingFreqUS)
{
    Timer timer;                                                    // timer used to time
    if(!freqIn) {                                                   // if the edge is low
        while(!freqIn)                                              // wait for the edge
            wait_us(samplingFreqUS);                                // let the cpu do nothing meanwhile
        timer.start();                                              // now we can start counting
        while(freqIn)                                               // as long as the freq is high
            wait_us(samplingFreqUS);
    } else {                                                        // else.. it has to be 1
        while(freqIn)                                               // wait for the edge
            wait_us(samplingFreqUS);                                // let the cpu do nothing meanwhile
        timer.start();                                              // now we can start counting
        while(!freqIn)                                              // as long as the frequency is slow
            wait_us(samplingFreqUS);                                // let the cpu do nothing
    }
    timer.stop();                                                   // stop the timer - measuring finished
    return 1000000.0/(timer.read_us()*NYQUIST_CORR);                // Convert to period multiply by 1mil to get freq and correct by Nequ
}