2036 student lab assignment - students must add code where shown
Dependencies: FFT Terminal_VT100 mbed
Diff: main.cpp
- Revision:
- 0:257c8b623a6f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu Nov 01 19:10:56 2012 +0000 @@ -0,0 +1,474 @@ +// 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 +} +