2036 student lab assignment - students must add code where shown

Dependencies:   FFT Terminal_VT100 mbed

main.cpp

Committer:
4180_1
Date:
2012-11-01
Revision:
0:257c8b623a6f

File content as of revision 0:257c8b623a6f:

// mymbedDAQ - Electronic Test Instrument Concept Demo & Lab assignment
// CODE MUST BE ADDED BY STUDENTS WHERE INDICATED!!!!!!!!!!!!!!!
// Uses VT100 terminal application on PC
// Needs terminal and FFT libs
//
// NOTE: for test signals must connect
// P18 to P16 (sine wave from D/A to A/D)
// P13 to P12 (digital test signal from serial port to LA digital input)
// P21 to P15 (PWM for square wave to A/D)
//
#include "mbed.h"
#include "FFT.h"
#include "Terminal.h"
#include <vector>
using namespace std;

// **********************************************************************************************
#define N 128 //number of analog samples to take - need power of two for FFT
float FFT_Data[N*2]; //complex data space for analog signal's FFT-1D array with real & imag pairs
float Data[N]; //data space for (real) analog signal samples
float Analog_Voltage; //used for DMM voltage reading
float Analog_out_value[N]; // Analog values of precomputed sine wave for D/A (function generator)
unsigned char PowerInt[N/2]; //used to store scaled magnitude of FFT bars (positive only)

// note use of volatile for an interrupt set global variable!
volatile int take_sample; //sample period timer flag - set by interrupt

vector <int> Digital_Signal (100); // use a vector for sample data for Logic Analyzer

char input_char; //character read from PC terminal application window
bool sine=true; //sine or square wave flag for test signal input
bool square=true; //50% or 25% duty cycle on square wave test signal


//Digital Signals for Logic Analyzer

// Used to read in digital signals
DigitalIn   LogicAnalyzer_test_signal_in(p12);
// Used for digital test signal output
Serial      LogicAnalyzer_test_signal_out(p13,p14);

//Analog I/O Signals for DMM, Oscilloscope, and Spectrum Analyzer

// Analog A/D Input
AnalogIn    Analog_test_signal_in(p16);
// Analog D/A output test signal (for sine wave function generation)
AnalogOut   Analog_test_signal_out(p18);


// PWM is used for alternate analog square wave signal source

// Analog A/D Input used for square wave
AnalogIn    PWM_test_signal(p15);
// PWM output pint that generates a square wave
PwmOut PWM_Output(p21);

//unsed Analog input pins set to digital to reduce A/D noise
DigitalOut  d2(p17);
DigitalOut  d3(p19);
DigitalOut  d4(p20);

//VT100 ANSI Terminal connected to PC
Terminal PC(USBTX, USBRX);


// **********************************************************************************************

void Take_Analog_Signal_Samples(float Analogs[]);
void Graphic_Display_Spectrum(unsigned char *Data);
void Graphic_Display_Time(float *Data);
void Digital_Multimeter();
void Logic_Analyzer();
void Oscilloscope();
void Spectrum_Analyzer();
void Function_Select();
void Duty_Cycle();

// **********************************************************************************************

int main()
{
// Start PWM hardware for a continuous square wave signal ouput with a 50% duty cycle
    PWM_Output=0.5;
    PWM_Output.period(0.0128);
    while(1) {
// clear screen and print user menu selections
        PC.cls();
        PC.locate(0,5);
        PC.printf("       1 - Digital Multimeter\n\r");
        PC.printf("       2 - Logic Analyzer\n\r");
        PC.printf("       3 - Oscilloscope\n\r");
        PC.printf("       4 - Spectrum Analyzer \n\r");
        PC.printf("       5 - Function Generation - toggles between sine & square wave signal\n\r");
        PC.printf("       6 - Duty Cycle - toggles between 50%% and 25%% duty cycle on square wave");
        PC.locate(0,0);
        PC.printf("   Select Electronic Test Instrument (type 1...5)");
        // reads a character from the PC terminal appication window
        input_char=PC.getc();
        // echo back selection char for human display on PC
        PC.putc(input_char);
        // delay for slow human to see character
        wait(.5);
//ADD CODE HERE
        // select instrument demo using input_char switch statement
        // case for each function below
        //  1 Digital_Multimeter();
        //  2 Logic_Analyzer();
        //  3 Oscilloscope();
        //  4 Spectrum_Analyzer();
        //  5 Function Select();
        //  6 Duty Cycle();





//END ADD CODE HERE
    }
}

//*********************************************************************************************
// toggles a flag between a sine or square wave test output
// sine flag is used in Take_Analog_Signal_Samples
void Function_Select()
{
    sine=!sine;
}

//**********************************************************************************************
// Toggles the hardware PWM output between a 25% and 50% duty cycle square wave
// square flag stores state
void Duty_Cycle()
{
    if (square)
        PWM_Output=0.25;
    else
        PWM_Output=0.5;
    square=!square;
    //PWM hardware needs a bit of setup time to adjust
    wait(.25);
}

// **********************************************************************************************

void Digital_Multimeter()
{
// PC.readable() indicates another character is available to read
// but it does not read the character or wait for a character
// It is a handy way to break out of a loop if any key is hit
    while(!PC.readable()) {
        // Digital Multimeter - reads an analog voltage on pin 16
        // D/A output is connected to A/D input  (0..3.3V range only!)
        PC.cls(); //clear screen
        PC.locate(9,0); // move cursor to 9,0
        PC.printf("Digital Multimeter"); // print title
        PC.locate(22,12);
        PC.printf("  volts DC"); // label for voltage reading
        // Plot Y Axis tick marks with labels
        for(int i=21; i>3; i--) {
            PC.locate(7,i);
            // put a label every 1 volt on axis
            if((i-1)%5==0) {
                PC.putc('+');
                PC.locate(1,i);
                PC.printf("%d.0V",int((21.0-i)/16.0*3.3));
            } else PC.putc('-');
        }
        for(int i=0; i<=64; i++) {
            // Output the Analog test signal using D/A output 'Analog_test_signal_out
            // makes D/A outputvoltage increase linear from 0 to 3.3
            // (but scaled from 0 to 1.0 in C/C++) using loop value i to change it
//ADD CODE HERE - 1 line

//END ADD CODE HERE
            // Print voltage at 15,12
            PC.locate(15,12);
//ADD CODE HERE
            // read in the analog voltage using A/D input "Analog_test_signal_in"
            // multiply value by 3.3 to convert to actual voltage level
            // save in "Analog_Voltage"

            // Print Analog_Voltage*3.3 in "%7.3F" format

            // Display Analog Level Bar but only every four display updates (i%4) for faster updates
            // on PC use char(219) for a solid bar graphics character or a space ' ' to erase
            // use locate to draw a vertical bar





        }
//END ADD CODE HERE
    }
    // delay to allow time to view each display
    wait(1);
}

// **********************************************************************************************

void Logic_Analyzer()
{
    // Logic Analyzer
    // Reads in a serial digital output pin (0 or 3.3V)
    // pin 13 TX serial output tied to pin12 digital input
    while(!PC.readable()) {
        // Loop through several ASCII characters for display test
        for(int c='A'; c<='z'&&!PC.readable(); c=c+1) {
            PC.cls();
            Digital_Signal.clear();
            PC.locate(15,0);
            PC.printf("Logic Analyzer Display - RS-232 Serial ASCII character %c 0x%X",char(c), int(c));
            // Sample digital data for display - need 80 samples (have 80 display cols)
            for(int i=0; i<80; i++) {
                // Test signal for Logic Analyzer
                // Send out a new character char(c) using the serial port
                // after a small delay so that it will show up in middle of display
                if(i==6) LogicAnalyzer_test_signal_out.putc(char(c));
//ADD CODE HERE
// Use "Digital_Signal" vector to store data from "LogicAnalyzer_test_signal_in" (DigitalIn pin)

                // time delay is used to adjust sample time interval
                // a hardware timer would be more accurate
                // that will be explained later in the oscilloscope example
                // some adjustment to time delay here might be needed for your code
                // scale so that you can see entire ASCII character on display
                wait(.00002);
            }
            //Display data
            //Move cursor to 0,15 or 0,5 based on first digital bit from Digital_Signal[i]
            //Scan through data samples from left to right and draw the high or low line
            //Locate is only needed when changing between high or low value
            //loop through 80 sample values
            PC.locate(0,(15 - int(float(Digital_Signal[0])*10.0)));
            for(int i=0; i<80; i++) {
                // If no change in digital signal, or fist bit just output a horiz bar char(196)?

                // if A 1 to 0 transisition occured
                // draw a vertical line with correct bar and corner characters (191, 179, 192)
                // PC.locate(col,row) is needed for vertical line drawing





                //if A 0 to 1 transisiton occured
                // draw a vertical line with correct bar and corner characters (217, 179, 218)





            }
            //plot X axis tick marks and labels
            //only initial locate needed
            PC.locate(0,20);






//END ADD CODE HERE
            // delay to allow time to view each display
            wait(1);
        }
    }
}
// **********************************************************************************************

void Oscilloscope()
{
    while(!PC.readable()) {
        // Oscilloscope
        // D/A sends out a sine wave and the A/D reads it back in
        // PWM hardware sends out a square wave to another A/D input
        // loop through increasing the frequency of the test signals for each display
        for(int i=1; i<11&&!PC.readable(); i++) {
            //Setup square wave signal source period - increase each loop iteration
            PWM_Output.period(0.0128/i);
            wait(0.25);
            // Precompute sine wave values for faster D/A output to save execution time
            // Need to add DC bias and scale sine wave from 0...1.0 for analog out function
            // (i.e. not just -1..1)
            // need N samples of one sine cycle first time - then make it i times faster each
            // loop iteration - samples go in Analog_out_value[k]
            for(int k=0; k<N; k++) {
//ADD CODE HERE - 1 line to compute sine values

//END ADD CODE HERE
            }
            //Reads analog samples using test signals setup above
            Take_Analog_Signal_Samples(Data);
            //Displays an analog signal in time
            Graphic_Display_Time(Data);
            // delay to allow time to view each display
            wait(2);
        }
    }
}

// **********************************************************************************************
void Spectrum_Analyzer()
{
    while(!PC.readable()) {
        // Spectrum Analyzer
        // Compute FFT of sampled signal
        // D/A sends out a sine wave and the A/D reads it back in
        // loop through increasing the frequency of test signals for each display
        for(int i=1; i<11&&!PC.readable(); i++) {
            //Setup square wave signal source with correct period
            PWM_Output.period(.0128/i);
            wait(0.25);
            //Precompute sine wave values for D/A output to save execution time
            //same as Oscilloscope code earlier
            for(int k=0; k<N; k++) {
//ADD CODE HERE - line

//END ADD CODE HERE
            }
            //Reads analog samples
            Take_Analog_Signal_Samples(Data);
            // put data in complex format for FFT code (real followed by imag=0 in 2*N 1D array)
            // Required by Numerical Recipes in C++ Algorithm for FFT used in in vFFT.cpp
            for(int k=0; k<N; k++) {
                FFT_Data[k*2]=Data[k];
                FFT_Data[k*2+1] = 0.0;
            }
            Graphic_Display_Time(Data);
            // delay to allow time to view each time display
            wait(2);
            // Spectrum Analyzer
            // Compute FFT of sampled signal
            vFFT(FFT_Data-1,N);
            // Compute magnitude for positive frequency display
            // scaled and returned in a char array
            vCalPowerInt(FFT_Data,PowerInt,N/2);
            // Display Frequency content of sampled signal
            Graphic_Display_Spectrum(PowerInt);
            // delay to allow time to view each frequency display
            wait(2);
        }
    }
}


// **********************************************************************************************
// Functions to sample Analog input data at an accurate 10Khz rate (every 100 us)
// used by Oscilloscope and Spectrum Analyzer
void Sample_timer_interrupt(void)
{
    // Sets flag when time to read in another analog sample
    // Timer interrupt comes here when a it hits every sample time interval
    take_sample=1;
}
void Take_Analog_Signal_Samples(float Analogs[])
{
    // setup a timer to determine accurate sample time
    Ticker Sample_Period;
    // reset sample time interval flag
    take_sample=0;
    // output first D/A value for sine wave
    Analog_test_signal_out=Analog_out_value[0];
    // Start periodic timer interrupts to ensure accurate control of sample time interval
    // Sample_timer_interrupt is "called" every 100 us by hardware interrupt signal
    Sample_Period.attach_us(&Sample_timer_interrupt,100); // 100 us, 10.000 KHz
    // Take N analog samples at sample period
    // timing is critical inside loop here - needs to be fast
    for(int k=0; k<N; k++) {
        // wait and spin here until sample timer interrupt routine sets take sample flag
        while(take_sample==0) {};
        // next sample period reached (timer interrupt has set take_sample==1)
        // reset take sample
        take_sample=0;

        // select sine or square input source using "sine" bool flag in if - two A/D input channels
        //read in next sample into Analogs[k]
//ADD CODE HERE





//END ADD CODE HERE
    }
    // got the N analog samples
    // so turn off sample timer interrupts
    Sample_Period.detach();
    return;
}

// **********************************************************************************************
void Graphic_Display_Spectrum(unsigned char *Data)
// plots frequency bars using data array - 64 values
{
    char max_value=0;
// clear screen
    PC.cls();
    PC.locate(15,0);
// print title
    PC.printf("Spectrum Analyzer - Frequency Domain Display");
//ADD CODE HERE
    //plot X axis tick marks with labels





//END ADD CODE HERE
    // Find max Data[i] value for autoscaling feature
    // max value bar should fill the screen display area
    for (int i=0; i<N/2; i++) {
        if (Data[i] > max_value) max_value = Data[i];
    }
//ADD CODE HERE
    // Plot Y Axis tick marks with labels






// use max value for Y axis auto scaling and axis label value calculations
// draw the frequency bars using Data[i] values (0..N/2 i.e., the positive spectrum only)
// loop though 20 lines starting at top left of bar display area (lines 1-20)
    for(int i=2; i<=21; i++) {
        // then loop through each display bar across 64 cols of display area
        // if scaled Data[col] value> current line (height) move cursor and print a bar char(222)
        // values in Data[col] are in range from 0 to max_value
        // scale so that max_value bar height is number of characters in display area
        // loop through 64 columns across display
        for(int k=0; k<(N/2); k++) {
//            if( Data[k]...
        }
//END ADD CODE HERE
    }

}

//************************************************************************************************
void Graphic_Display_Time(float *Data)
// displays Data vs time for Oscilloscope style display
{
// clear screen
    PC.cls();
    PC.locate(20,0);
// print title
    PC.printf("Oscilloscope - Time Domain Display");
//ADD CODE HERE
    // Plot Y Axis tick marks with labels





    // plot X axis tick marks with labels






    // loop through each sampled Data[i] value (0..N)
    // scale to display area, move to proper col,row
    // and plot each point using a '.' (period)
    // 128 points in 64 display columns so two samples per column
    // (but likely value is in a different row)
    // loop through data values
    for(int i=0; i<N; i++ ) {

    }
//END ADD CODE HERE
}