Embedded Software Assignment 2
Dependencies: MCP23017 WattBob_TextLCD mbed
Diff: main.cpp
- Revision:
- 0:0131c822a391
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri May 27 15:33:42 2016 +0000 @@ -0,0 +1,260 @@ +/******************************************************************************************* +* +* 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 +}