MCU
아트메가 오실로스코프
naudhizb
2014. 10. 24. 01:26
반응형
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | /* AVR oscilloscope with 128x64 graphic LCD. AVR: ATmega32 at 16MHz (external crystal). OpAmp: LM358 is connected on PA0 (ADC0). Created by Serasidis Vassilis Home: http://www.serasidis.gr e-mail: info@serasidis.gr and avrsite@yahoo.gr History: - V2.00 on 14 Mar 2011 by Vassilis Serasidis. * gLCD library was improved and alphanumeric font was included ('font3x6.h' file). * Information about the measured waveform such as Voltage (Vpp) and frequency (kHz) is appeared on LCD. * Sampling rate has been increased because sample accuracy reduced to 8-bit instead of 10-bit and the ADC prescaler reduced from 16 to 4. That gives a much faster sampling rate. * RAM requirement has been reduced from ~1200 bytes to 335 bytes. That gives you the chance to use some other AVR micro controller with lower RAM than 2kB (firmwares 1.00 and 1.01 need AVRs with 2kB of RAM ). * A problem with buttons S3 (PC4 pin) and S7 (PC2 pin) was fixed. - V1.01 on 26 Jun 2008 by Anantha Narayanan. Solved a delay issue. - V1.00 on 03 Aug 2007 by Vassilis Serasidis. Initial version. Only waveform is appeared on LCD. All source code files of "AVR oscilloscope" project are distributed under GPL V3 (General Public License). */ #include <avr/io.h> // include I/O definitions (port names, pin names, etc) #include <avr/interrupt.h> #include "glcd.c" /* define CPU frequency in MHz here if not defined in Makefile */ #ifndef F_CPU #define F_CPU 16000000UL #endif #define msUp 1 #define msDwn 4 #define YposUp 0 #define YposDwn 3 #define freeze 2 #define AC 0 #define DC 1 #define SQUARE 2 #define TRUE 0 #define FALSE 1 unsigned int dataCounter = 0; unsigned int timeDiv = 0; unsigned char trigger = 0; unsigned char findZero = 0; unsigned char upLimit = 0; unsigned char lowLimit = 255; unsigned char prevADCvalue = 0; unsigned char voltageType = AC; unsigned char complete = TRUE; unsigned int voltage; unsigned char frequency; unsigned int ADCvalue; unsigned char hex2asciiBuffer[4]; signed char Ypos = 0; signed char Ypos2 = 0; signed char position = 0; void ADC_init (void); void hex2Ascii(unsigned int data, unsigned char Buffer[4]); int main (void) { unsigned int i,k; unsigned long endOfPeriod=0; unsigned char freqComplete=0; unsigned int maxVoltage=0; DDRC = 0b00000000; PORTC = 0b11111111; DDRA = 0b00000000; glcdInit(); ADC_init(); createWelcomeScreen(); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); _delay_ms(4000); createRaster(); createWave(); for(;;) { if (~PINC & (1<<msUp) && (timeDiv <= 120)) timeDiv += 1; if (~PINC & (1<<msDwn) && (timeDiv >= 1)) timeDiv -= 1; if (~PINC & (1<<YposUp) && (Ypos2 <= 60)) Ypos2++; if (~PINC & (1<<YposDwn) && (Ypos2 >= -60)) Ypos2--; if (~PINC & (1<<freeze)) while (~PINC & (1<<freeze)); // It freezes the display to watch the wave. //--------v // Read 100 samples from analog input. // From these 100 samples we can find the middle of the signal to be used as trigger... // ... the Volts peak-to-peak and the frequency of the measured signal. findZero = 0; upLimit = 0; lowLimit = 255; endOfPeriod = 0; freqComplete = 0; complete = FALSE; for (i=2; i<15000; i++) { ADCSRA |= (1 << ADSC); // Enable ADC loop_until_bit_is_set(ADCSRA, ADIF); // wait until conversion complete. ADCvalue = ADCH; //------------------------------------------------------v // Find the end of the first period that is appeared on LCD. // The beginning of the period is always the first pixel on the left of LCD. //Find the start of the period of the measured waveform. if((ADCvalue > trigger) && (prevADCvalue < ADCvalue) && (freqComplete == 0)) freqComplete = 1; //If you have found the start of the period, find the rise of the waveform. if((ADCvalue < trigger) && (prevADCvalue < ADCvalue) && (freqComplete == 1)) freqComplete = 2; //The next step is to find the start of the next period... if((ADCvalue > trigger) && (prevADCvalue < ADCvalue) && (freqComplete == 2)) { freqComplete = 3; //Wow! we found the end of the first period. endOfPeriod = ((23000)/(i/2)); //Calculate the frequency that will be displayed on LCD. } //------------------------------------------------------^ prevADCvalue = ADCvalue; // Get a backup of the current ADC value. for(k=timeDiv;k>0;k--) // Make a delay to see on LCD low-frequency waveforms. Normally, the minimum waveform that can be entirely displayed on LCD is 310 Hz. { ADCSRA |= (1 << ADSC); // Enable ADC loop_until_bit_is_set(ADCSRA, ADIF); // wait until conversion complete. ADCvalue = ADCH; } if (upLimit < ADCvalue) // Find the higher voltage level of the input waveform. upLimit = ADCvalue; if (lowLimit > ADCvalue) // Find the lower voltage level of the input waveform. lowLimit = ADCvalue; maxVoltage = (upLimit * 2); // Maximum voltage on ADC pin is calculated from upLimit register (255*2=510 = 5.10V). if (ADCvalue > 0) { voltage = ((upLimit-lowLimit)*2); //Get the Vpp and store it to "voltage" (Volts Peak-to-peak of inputed waveform). ADCvalue += 5; ADCvalue /= 5; ADCvalue += 2; }else ADCvalue = 2; position = ADCvalue + Ypos2 +5; if ((position <= 63) && (position >= 0) && (i<100)) // Adjust Up-Down the wave on LCD. fillDataLcdBuffer(i,position); else if(i<100) fillDataLcdBuffer(i,0); if((i>100)&&(freqComplete==3)) //If i>100 and freqComplete=3 that means that our waveform is outside of LCD displaying area. break; //Do not wait until i=15000. Terminate this loop ("for (i=0; i<15000; i++)") } if(upLimit != lowLimit) trigger = (((upLimit - lowLimit)/2)+ lowLimit); // Find the middle of the wave to be used as trigger. else trigger = upLimit; //--------^ //--------- Print Volts peak-to-peak and frequency on display ------------- restoreRaster(); createWave(); line=3; //Show the DC voltage column=109; gLCDgotoXY(line,column); hex2Ascii(maxVoltage,hex2asciiBuffer); GLCD_WriteChar(hex2asciiBuffer[2]); sendDataOnLCD(0b01000000); //Print one dot character on LCD (only 1 column length). sendDataOnLCD(0); GLCD_WriteChar(hex2asciiBuffer[1]); GLCD_WriteChar(hex2asciiBuffer[0]); sendDataOnLCD(0x00); GLCD_WriteChar('V'); line=4; //Show the Vpp (Volts peak-to-peak). column=109; gLCDgotoXY(line,column); hex2Ascii(voltage,hex2asciiBuffer); GLCD_WriteChar(hex2asciiBuffer[2]); sendDataOnLCD(0b01000000); //Print one dot character on LCD (only 1 column length). sendDataOnLCD(0); GLCD_WriteChar(hex2asciiBuffer[1]); GLCD_WriteChar(hex2asciiBuffer[0]); sendDataOnLCD(0x00); GLCD_WriteChar('V'); line=6; // Go to 6th line on LCD. column=122; gLCDgotoXY(line,column); if(timeDiv == 0) // If 'timeDiv' = 0 then the frequency in to the 'endOfPeriod' variable is real. GLCD_WriteChar(0x5c); // So, print on LCD the "Play" character. '0x5c' is the '\' character ("Play" symbol). else GLCD_WriteChar(']'); // If 'timeDiv' is not zero that means we have shrink the waveform. So, print the "Pause" symbol on LCD. if(timeDiv == 0) // If 'timeDiv' = 0 then the frequency in to the 'endOfPeriod' variable is real. { line=7; // Go to 7th line and print on LCD the waveform's frequency column=102; gLCDgotoXY(line,column); if(endOfPeriod <10000) // The maximum frequency that can be displayed on LCD is 9999 Hz. { gLCDgotoXY(line,column); hex2Ascii(endOfPeriod,hex2asciiBuffer); GLCD_WriteChar(hex2asciiBuffer[3]); GLCD_WriteChar(hex2asciiBuffer[2]); GLCD_WriteChar(hex2asciiBuffer[1]); GLCD_WriteChar(hex2asciiBuffer[0]); } } // if 'timeDiv' > 0 do not update the frequency. Keep the previous frequency value instead. //------------------------------------------------------- dataCounter = 0; complete = FALSE; freqComplete = 0; do //Wait in this loop until you find again the start of the measured waveform. { prevADCvalue = ADCvalue; ADCSRA |= (1 << ADSC); // Enable ADC loop_until_bit_is_set(ADCSRA, ADIF); ADCvalue = ADCH; //Find the start of the period of the measured waveform. if((ADCvalue > trigger) && (prevADCvalue < ADCvalue) && (freqComplete == 0)) freqComplete = 1; //If you have found the start of the period, find the rise of the waveform. if((ADCvalue < trigger) && (prevADCvalue < ADCvalue) && (freqComplete == 1)) freqComplete = 2; //The next step is to find the start of the next period... if((ADCvalue > trigger) && (prevADCvalue < ADCvalue) && (freqComplete == 2)) { freqComplete = 3; complete = TRUE; } if(dataCounter > 3000) complete = TRUE; dataCounter++; }while(complete == FALSE); } } //=============================================================================== // Initializing the Analog to Digital Converter (ADC). //=============================================================================== void ADC_init (void) { ADMUX = 0b01100000; // PA0 -> ADC0, ADLAR=1 (8-bit) ADCSRA |= ((1<<ADEN) | (1<<ADSC) | (1<<ADPS1)); // ADC prescaler at 4 } //=============================================================================== // Function that converts an integer into 4 ASCII-character bytes. // For example if 'data' contains the number "6543" then // Buffer[3] = '6' Buffer[2]='5' Buffer[1]='4' Buffer[0]='3'. // I know, I could have used the 'itoa' function to do the conversion from integer into ASCII // but my function is easier and more convenient to be handled. //=============================================================================== void hex2Ascii(unsigned int data, unsigned char Buffer[4]) { Buffer[3] = ((data/1000)+0x30); data %= 1000; Buffer[2] = ((data/100)+0x30); data %= 100; Buffer[1] = ((data/10)+0x30); Buffer[0] = ((data%10)+0x30); } | cs |
반응형