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 }