Components and supplies
Arduino UNO
Resistor 10k ohm
Apps and platforms
Arduino IDE
Processing
Project description
Code
code
csharp
1#define bytesPerPackage 32 2#define switch1 4 //sw1 pin 3#define switch2 3 //sw2 pin 4 5uint8_t bytesRead; 6byte inputBuffer[bytesPerPackage]; 7byte outputBuffer[bytesPerPackage]; 8boolean sw1, sw2; 9 10void setup() { 11 pinMode(switch1, INPUT); 12 digitalWrite(switch1, HIGH); // enable internal pullup 13 pinMode(switch2, INPUT); 14 digitalWrite(switch2, HIGH); 15 ADMUX = B00000000; // set external aref and port 16 ADCSRA = B10101101; // ADC enable, interrupt enable, set default prescaler 17 ADCSRB = B00000000; // free running mode 18 sei(); // enable interrupts 19 ADCSRA |=B01000000; // start first conversion 20 Serial.begin(115200); 21} 22 23void loop() { 24 sw1 = digitalRead(switch1); 25 sw2 = digitalRead(switch2); 26 if (bytesRead >= bytesPerPackage) { // Buffer full. Send the package. 27 cli(); 28 bytesRead = 0; 29 for (uint8_t i = 0; i < bytesPerPackage; i += 2) { 30 byte adch = inputBuffer[i]; 31 if (!sw1) adch |= B00001000; // switch position in bits 10 & 11 of each byte pair 32 if (!sw2) adch |= B00000100; 33 outputBuffer[i] = adch; 34 outputBuffer[i+1] = inputBuffer[i+1]; 35 } 36 sei(); 37 Serial.write(outputBuffer, bytesPerPackage); 38 } 39 40 if (Serial.available()) { // incoming byte -> set prescaler 41 byte inByte = (byte)Serial.read(); 42 cli(); 43 ADCSRA= B10101000|(inByte&B00000111); // last 3 bytes of ADCSRA set the prescaler 44 sei(); 45 ADCSRA |=B01000000; // start first conversion 46 } 47} 48 49ISR(ADC_vect) { 50 if(bytesRead<bytesPerPackage-1){ 51 inputBuffer[bytesRead+1] = ADCL; 52 inputBuffer[bytesRead] = ADCH; 53 bytesRead+=2; 54 } 55} 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
processing code
csharp
1import processing.serial.*; 2import java.awt.event.KeyEvent; 3 4// Settings -------------------------------------------------------------------------- 5int serialBaudRate=115200; 6int bufferSize=10000000; // number of samples (memory use: 2 bytes per sample) 7float samplesPerLine=1; // increment 1 screen line for each [n] samples 8boolean sync=true; // sync to trig 9float trigLevelLPF=.0001; // trigLevel lowpass filter (exponential moving average) 10boolean hold=false; // pause 11int prescaler=5; // ADC prescaler: 3:8 | 4:16 | 5:32 | 6:64 | 7:128 12// ----------------------------------------------------------------------------------- 13 14Serial serial; 15byte[] buffer= new byte[bufferSize*2]; 16int writeIndex, prevWriteIndex, readIndex, trigIndex, trigCounter, loopCounter, windowWidth, windowHeight, offset; 17float voltageRange, sps, frequency, trigLevel, timer; 18int windowX=30; 19int windowY=50; 20boolean connected=false; 21String serialPort; 22 23void settings() { 24 size(1000, 600); 25} 26 27void setup() { 28 background(0); 29 surface.setResizable(true); 30 frameRate(50); 31} 32 33void draw() { 34 windowWidth=width-100; 35 windowHeight=height-100; 36 if (!connected) { 37 background(0, 0, 0); 38 text("ARDUINO OSCILLOSCOPE\ 39\ 40Select serial port:", 25, 25); 41 for (int i=0; i<Serial.list().length; i++) 42 text("F"+(i+1)+" - "+Serial.list()[i], 25, 80+i*20); 43 } else { 44 background(0, 0, 0); 45 46 // update frequency counters every second 47 loopCounter++; 48 if (loopCounter>frameRate) { 49 loopCounter=0; 50 float elapsedSeconds=(millis()-timer)/1000; 51 timer=millis(); 52 sps=(writeIndex-prevWriteIndex)/elapsedSeconds; // sample rate 53 if (sps<0)sps+=bufferSize; 54 prevWriteIndex=writeIndex; 55 frequency=trigCounter/elapsedSeconds; // signal frequency 56 trigCounter=0; 57 } 58 59 // read switch position & set voltage range 60 boolean switch1=((buffer[writeIndex*2]&(byte)8)==8); 61 boolean switch2=((buffer[writeIndex*2]&(byte)4)==4); 62 if (!switch1&&!switch2) voltageRange=20; 63 if (!switch1&&switch2) voltageRange=10; 64 if (switch1&&!switch2) voltageRange=6.64; 65 if (switch1&&switch2) voltageRange=5; 66 67 // print voltage scale 68 for (int n=0; n<=10; n++) 69 text(nf(voltageRange/10*n, 2, 2)+"V", windowX+windowWidth+5, windowY+windowHeight-(n*windowHeight/10)); 70 71 // print interface and statistics 72 text("[F1-F2] ZOOM | [F3] SYNC: "+sync+" | [F4] HOLD: "+hold+" | [F5-F6] TRIG LPF | [F7-F8] PRESCALER: "+nf((pow(2, prescaler)), 1, 0)+" | [<--->] OFFSET", 25, 25); 73 text("frequency: "+nf(frequency, 5, 2)+"Hz" 74 +" | average DCV: "+nf(trigLevel/1024*voltageRange, 2, 2)+"V" 75 +" | samplerate: "+nf(sps, 5, 2)+"Hz" 76 +" | samples per line: "+samplesPerLine 77 +" | division: "+samplesPerLine/sps*(float)width*100+"ms", 25, height-20); 78 79 // draw trigLevel (= average voltage) line 80 stroke(0, 0, 100); 81 int trigLevelHeight=(int)(trigLevel*(float)windowHeight/1024); 82 line(windowX, windowY+windowHeight-trigLevelHeight, windowX+windowWidth, windowY+windowHeight-trigLevelHeight); 83 84 // draw grid 85 stroke(50); 86 for (float n=0; n<=windowWidth; n+=(float)windowWidth/10) 87 line(n+windowX, windowY, n+windowX, windowHeight+windowY); 88 for (float n=0; n<=windowHeight; n+=(float)windowHeight/10) 89 line(windowX, n+windowY, windowX+windowWidth, n+windowY); 90 91 // ------------------------------ 92 // DRAW WAVEFORM 93 // ------------------------------ 94 stroke(255); 95 float prevSampleValue=0; 96 if (sync) readIndex=trigIndex; // sync: start reading from last trig position 97 if (!sync) readIndex=writeIndex; // no sync: start reading from last sample we received 98 readIndex+=offset; 99 float lineIncr=(float)1/samplesPerLine; 100 if (lineIncr<1) lineIncr=1; 101 for (float line=0; line<windowWidth; line+=lineIncr) { // cycle screen lines (from right to left) 102 float sampleValue=(float)getValueFromBuffer((int)((float)readIndex-line*samplesPerLine)); // get the value for the screen line 103 sampleValue*=(float)windowHeight/1024; // scale to windowHeight 104 if (line>0) 105 line(windowX+windowWidth-line, 106 windowY+windowHeight-prevSampleValue, 107 windowX+windowWidth-line-lineIncr, 108 windowY+windowHeight-sampleValue); 109 prevSampleValue=sampleValue; 110 } 111 112 // ------------------------------ 113 // BUFFER INCOMING BYTES & TRIG 114 // ------------------------------ 115 if (hold) { 116 serial.clear(); // HOLD: don't receive samples; clear serial buffer 117 } else { 118 while (serial.available ()>0) { // RUN: receive samples 119 writeIndex++; 120 if (writeIndex>=bufferSize) writeIndex=0; // handle overflow 121 buffer[writeIndex+writeIndex]=(byte)serial.read(); // add 1 sample (2 bytes) to buffer 122 buffer[writeIndex+writeIndex+1]=(byte)serial.read(); 123 trigLevel=trigLevel*(1-trigLevelLPF)+(float)getValueFromBuffer(writeIndex)*trigLevelLPF; // level for trigger intersection = exponential moving average of voltage 124 if (getValueFromBuffer(writeIndex)>=trigLevel&& getValueFromBuffer(writeIndex-1)<trigLevel) { // rising intersect detected 125 trigIndex=writeIndex; // set trigIndex (index of buffer that corresponds to last trig) 126 trigCounter++; // count trigs (to calculate the frequency) 127 } 128 } 129 } 130 } 131} 132 133 134// Read value from buffer 135int getValueFromBuffer(int index) { 136 while (index<0) index+=bufferSize; // handle overflow of circular buffer 137 return((buffer[index*2]&3)<<8 | buffer[index*2+1]&0xff); // convert bytes to int 138} 139 140// Handle keys 141void keyPressed() { 142 if (key == CODED) { 143 if (connected) { 144 if (keyCode == KeyEvent.VK_F1) { 145 samplesPerLine*=1.1; 146 if (samplesPerLine*windowWidth>bufferSize) samplesPerLine=bufferSize/windowWidth; 147 } 148 if (keyCode == KeyEvent.VK_F2) { 149 samplesPerLine/=1.1; 150 if (samplesPerLine<1/(float)windowWidth) samplesPerLine=1/(float)windowWidth; 151 } 152 if (keyCode == KeyEvent.VK_F3) { 153 sync=!sync; 154 } 155 if (keyCode == KeyEvent.VK_F4) { 156 hold=!hold; 157 } 158 if (keyCode == KeyEvent.VK_F5) { 159 if (trigLevelLPF<.01) trigLevelLPF*=10; 160 } 161 if (keyCode == KeyEvent.VK_F6) { 162 if (trigLevelLPF>.000001) trigLevelLPF/=10; 163 } 164 if (keyCode == KeyEvent.VK_F7) { 165 if (prescaler>3) prescaler--; 166 serial.write((byte)prescaler); 167 } 168 if (keyCode == KeyEvent.VK_F8) { 169 if (prescaler<7) prescaler++; 170 serial.write((byte)prescaler); 171 } 172 if (keyCode == LEFT) { 173 offset-=samplesPerLine*20; 174 if (offset<-bufferSize) offset=-bufferSize; 175 } 176 if (keyCode == RIGHT) { 177 offset+=samplesPerLine*20; 178 if (offset>0) offset=0; 179 } 180 } else { 181 serial = new Serial(this, Serial.list()[keyCode-112], serialBaudRate); 182 serial.write((byte)prescaler); 183 connected=true; 184 } 185 } 186}
code
csharp
1#define bytesPerPackage 32 2#define switch1 4 //sw1 pin 3#define switch2 3 //sw2 pin 4 5uint8_t bytesRead; 6byte inputBuffer[bytesPerPackage]; 7byte outputBuffer[bytesPerPackage]; 8boolean sw1, sw2; 9 10void setup() { 11 pinMode(switch1, INPUT); 12 digitalWrite(switch1, HIGH); // enable internal pullup 13 pinMode(switch2, INPUT); 14 digitalWrite(switch2, HIGH); 15 ADMUX = B00000000; // set external aref and port 16 ADCSRA = B10101101; // ADC enable, interrupt enable, set default prescaler 17 ADCSRB = B00000000; // free running mode 18 sei(); // enable interrupts 19 ADCSRA |=B01000000; // start first conversion 20 Serial.begin(115200); 21} 22 23void loop() { 24 sw1 = digitalRead(switch1); 25 sw2 = digitalRead(switch2); 26 if (bytesRead >= bytesPerPackage) { // Buffer full. Send the package. 27 cli(); 28 bytesRead = 0; 29 for (uint8_t i = 0; i < bytesPerPackage; i += 2) { 30 byte adch = inputBuffer[i]; 31 if (!sw1) adch |= B00001000; // switch position in bits 10 & 11 of each byte pair 32 if (!sw2) adch |= B00000100; 33 outputBuffer[i] = adch; 34 outputBuffer[i+1] = inputBuffer[i+1]; 35 } 36 sei(); 37 Serial.write(outputBuffer, bytesPerPackage); 38 } 39 40 if (Serial.available()) { // incoming byte -> set prescaler 41 byte inByte = (byte)Serial.read(); 42 cli(); 43 ADCSRA= B10101000|(inByte&B00000111); // last 3 bytes of ADCSRA set the prescaler 44 sei(); 45 ADCSRA |=B01000000; // start first conversion 46 } 47} 48 49ISR(ADC_vect) { 50 if(bytesRead<bytesPerPackage-1){ 51 inputBuffer[bytesRead+1] = ADCL; 52 inputBuffer[bytesRead] = ADCH; 53 bytesRead+=2; 54 } 55} 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
processing code
csharp
1import processing.serial.*; 2import java.awt.event.KeyEvent; 3 4// Settings -------------------------------------------------------------------------- 5int serialBaudRate=115200; 6int bufferSize=10000000; // number of samples (memory use: 2 bytes per sample) 7float samplesPerLine=1; // increment 1 screen line for each [n] samples 8boolean sync=true; // sync to trig 9float trigLevelLPF=.0001; // trigLevel lowpass filter (exponential moving average) 10boolean hold=false; // pause 11int prescaler=5; // ADC prescaler: 3:8 | 4:16 | 5:32 | 6:64 | 7:128 12// ----------------------------------------------------------------------------------- 13 14Serial serial; 15byte[] buffer= new byte[bufferSize*2]; 16int writeIndex, prevWriteIndex, readIndex, trigIndex, trigCounter, loopCounter, windowWidth, windowHeight, offset; 17float voltageRange, sps, frequency, trigLevel, timer; 18int windowX=30; 19int windowY=50; 20boolean connected=false; 21String serialPort; 22 23void settings() { 24 size(1000, 600); 25} 26 27void setup() { 28 background(0); 29 surface.setResizable(true); 30 frameRate(50); 31} 32 33void draw() { 34 windowWidth=width-100; 35 windowHeight=height-100; 36 if (!connected) { 37 background(0, 0, 0); 38 text("ARDUINO OSCILLOSCOPE\ 39\ 40Select serial port:", 25, 25); 41 for (int i=0; i<Serial.list().length; i++) 42 text("F"+(i+1)+" - "+Serial.list()[i], 25, 80+i*20); 43 } else { 44 background(0, 0, 0); 45 46 // update frequency counters every second 47 loopCounter++; 48 if (loopCounter>frameRate) { 49 loopCounter=0; 50 float elapsedSeconds=(millis()-timer)/1000; 51 timer=millis(); 52 sps=(writeIndex-prevWriteIndex)/elapsedSeconds; // sample rate 53 if (sps<0)sps+=bufferSize; 54 prevWriteIndex=writeIndex; 55 frequency=trigCounter/elapsedSeconds; // signal frequency 56 trigCounter=0; 57 } 58 59 // read switch position & set voltage range 60 boolean switch1=((buffer[writeIndex*2]&(byte)8)==8); 61 boolean switch2=((buffer[writeIndex*2]&(byte)4)==4); 62 if (!switch1&&!switch2) voltageRange=20; 63 if (!switch1&&switch2) voltageRange=10; 64 if (switch1&&!switch2) voltageRange=6.64; 65 if (switch1&&switch2) voltageRange=5; 66 67 // print voltage scale 68 for (int n=0; n<=10; n++) 69 text(nf(voltageRange/10*n, 2, 2)+"V", windowX+windowWidth+5, windowY+windowHeight-(n*windowHeight/10)); 70 71 // print interface and statistics 72 text("[F1-F2] ZOOM | [F3] SYNC: "+sync+" | [F4] HOLD: "+hold+" | [F5-F6] TRIG LPF | [F7-F8] PRESCALER: "+nf((pow(2, prescaler)), 1, 0)+" | [<--->] OFFSET", 25, 25); 73 text("frequency: "+nf(frequency, 5, 2)+"Hz" 74 +" | average DCV: "+nf(trigLevel/1024*voltageRange, 2, 2)+"V" 75 +" | samplerate: "+nf(sps, 5, 2)+"Hz" 76 +" | samples per line: "+samplesPerLine 77 +" | division: "+samplesPerLine/sps*(float)width*100+"ms", 25, height-20); 78 79 // draw trigLevel (= average voltage) line 80 stroke(0, 0, 100); 81 int trigLevelHeight=(int)(trigLevel*(float)windowHeight/1024); 82 line(windowX, windowY+windowHeight-trigLevelHeight, windowX+windowWidth, windowY+windowHeight-trigLevelHeight); 83 84 // draw grid 85 stroke(50); 86 for (float n=0; n<=windowWidth; n+=(float)windowWidth/10) 87 line(n+windowX, windowY, n+windowX, windowHeight+windowY); 88 for (float n=0; n<=windowHeight; n+=(float)windowHeight/10) 89 line(windowX, n+windowY, windowX+windowWidth, n+windowY); 90 91 // ------------------------------ 92 // DRAW WAVEFORM 93 // ------------------------------ 94 stroke(255); 95 float prevSampleValue=0; 96 if (sync) readIndex=trigIndex; // sync: start reading from last trig position 97 if (!sync) readIndex=writeIndex; // no sync: start reading from last sample we received 98 readIndex+=offset; 99 float lineIncr=(float)1/samplesPerLine; 100 if (lineIncr<1) lineIncr=1; 101 for (float line=0; line<windowWidth; line+=lineIncr) { // cycle screen lines (from right to left) 102 float sampleValue=(float)getValueFromBuffer((int)((float)readIndex-line*samplesPerLine)); // get the value for the screen line 103 sampleValue*=(float)windowHeight/1024; // scale to windowHeight 104 if (line>0) 105 line(windowX+windowWidth-line, 106 windowY+windowHeight-prevSampleValue, 107 windowX+windowWidth-line-lineIncr, 108 windowY+windowHeight-sampleValue); 109 prevSampleValue=sampleValue; 110 } 111 112 // ------------------------------ 113 // BUFFER INCOMING BYTES & TRIG 114 // ------------------------------ 115 if (hold) { 116 serial.clear(); // HOLD: don't receive samples; clear serial buffer 117 } else { 118 while (serial.available ()>0) { // RUN: receive samples 119 writeIndex++; 120 if (writeIndex>=bufferSize) writeIndex=0; // handle overflow 121 buffer[writeIndex+writeIndex]=(byte)serial.read(); // add 1 sample (2 bytes) to buffer 122 buffer[writeIndex+writeIndex+1]=(byte)serial.read(); 123 trigLevel=trigLevel*(1-trigLevelLPF)+(float)getValueFromBuffer(writeIndex)*trigLevelLPF; // level for trigger intersection = exponential moving average of voltage 124 if (getValueFromBuffer(writeIndex)>=trigLevel&& getValueFromBuffer(writeIndex-1)<trigLevel) { // rising intersect detected 125 trigIndex=writeIndex; // set trigIndex (index of buffer that corresponds to last trig) 126 trigCounter++; // count trigs (to calculate the frequency) 127 } 128 } 129 } 130 } 131} 132 133 134// Read value from buffer 135int getValueFromBuffer(int index) { 136 while (index<0) index+=bufferSize; // handle overflow of circular buffer 137 return((buffer[index*2]&3)<<8 | buffer[index*2+1]&0xff); // convert bytes to int 138} 139 140// Handle keys 141void keyPressed() { 142 if (key == CODED) { 143 if (connected) { 144 if (keyCode == KeyEvent.VK_F1) { 145 samplesPerLine*=1.1; 146 if (samplesPerLine*windowWidth>bufferSize) samplesPerLine=bufferSize/windowWidth; 147 } 148 if (keyCode == KeyEvent.VK_F2) { 149 samplesPerLine/=1.1; 150 if (samplesPerLine<1/(float)windowWidth) samplesPerLine=1/(float)windowWidth; 151 } 152 if (keyCode == KeyEvent.VK_F3) { 153 sync=!sync; 154 } 155 if (keyCode == KeyEvent.VK_F4) { 156 hold=!hold; 157 } 158 if (keyCode == KeyEvent.VK_F5) { 159 if (trigLevelLPF<.01) trigLevelLPF*=10; 160 } 161 if (keyCode == KeyEvent.VK_F6) { 162 if (trigLevelLPF>.000001) trigLevelLPF/=10; 163 } 164 if (keyCode == KeyEvent.VK_F7) { 165 if (prescaler>3) prescaler--; 166 serial.write((byte)prescaler); 167 } 168 if (keyCode == KeyEvent.VK_F8) { 169 if (prescaler<7) prescaler++; 170 serial.write((byte)prescaler); 171 } 172 if (keyCode == LEFT) { 173 offset-=samplesPerLine*20; 174 if (offset<-bufferSize) offset=-bufferSize; 175 } 176 if (keyCode == RIGHT) { 177 offset+=samplesPerLine*20; 178 if (offset>0) offset=0; 179 } 180 } else { 181 serial = new Serial(this, Serial.list()[keyCode-112], serialBaudRate); 182 serial.write((byte)prescaler); 183 connected=true; 184 } 185 } 186}
processing code 2
csharp
1import processing.serial.*; 2import java.awt.event.KeyEvent; 3 4// Settings -------------------------------------------------------------------------- 5int serialBaudRate=115200; 6int bufferSize=10000000; // number of samples (memory use: 2 bytes per sample) 7float samplesPerLine=1; // increment 1 screen line for each [n] samples 8boolean sync=true; // sync to trig 9float trigLevelLPF=.0001; // trigLevel lowpass filter (exponential moving average) 10boolean hold=false; // pause 11int prescaler=5; // ADC prescaler: 3:8 | 4:16 | 5:32 | 6:64 | 7:128 12// ----------------------------------------------------------------------------------- 13 14Serial serial; 15PFont font= createFont("Lucida Console", 12, false); 16byte[] buffer= new byte[bufferSize*2]; 17int writeIndex, prevWriteIndex, readIndex, trigIndex, trigCounter, loopCounter, windowWidth, windowHeight, offset; 18float voltageRange, sps, frequency, trigLevel, timer; 19int windowX=30; 20int windowY=50; 21boolean connected=false; 22String serialPort; 23 24void setup() { 25 size(1000, 600); 26 background(0, 0, 0); 27 frame.setResizable(true); 28 frameRate(50); 29 textFont(font); 30 text("ARDUINO OSCILLOSCOPE\ 31\ 32Select serial port:", 25, 25); 33 for (int i=0;i<Serial.list().length;i++) 34 text("F"+(i+1)+" - "+Serial.list()[i], 25, 80+i*20); 35} 36 37void draw() { 38 windowWidth=width-100; 39 windowHeight=height-100; 40 41 if (connected) { 42 background(0, 0, 0); 43 44 // update frequency counters every second 45 loopCounter++; 46 if (loopCounter>frameRate) { 47 loopCounter=0; 48 float elapsedSeconds=(millis()-timer)/1000; 49 timer=millis(); 50 sps=(writeIndex-prevWriteIndex)/elapsedSeconds; // sample rate 51 if (sps<0)sps+=bufferSize; 52 prevWriteIndex=writeIndex; 53 frequency=trigCounter/elapsedSeconds; // signal frequency 54 trigCounter=0; 55 } 56 57 // read switch position & set voltage range 58 boolean switch1=((buffer[writeIndex*2]&(byte)8)==8); 59 boolean switch2=((buffer[writeIndex*2]&(byte)4)==4); 60 if (!switch1&&!switch2) voltageRange=20; 61 if (!switch1&&switch2) voltageRange=10; 62 if (switch1&&!switch2) voltageRange=6.64; 63 if (switch1&&switch2) voltageRange=5; 64 65 // print voltage scale 66 for (int n=0; n<=10; n++) 67 text(nf(voltageRange/10*n, 2, 2)+"V", windowX+windowWidth+5, windowY+windowHeight-(n*windowHeight/10)); 68 69 // print interface and statistics 70 text("[F1-F2] ZOOM | [F3] SYNC: "+sync+" | [F4] HOLD: "+hold+" | [F5-F6] TRIG LPF | [F7-F8] PRESCALER: "+nf((pow(2, prescaler)), 1, 0)+" | [<--->] OFFSET", 25, 25); 71 text("frequency: "+nf(frequency, 5, 2)+"Hz" 72 +" | average DCV: "+nf(trigLevel/1024*voltageRange, 2, 2)+"V" 73 +" | samplerate: "+nf(sps, 5, 2)+"Hz" 74 +" | samples per line: "+samplesPerLine 75 +" | division: "+samplesPerLine/sps*(float)width*100+"ms", 25, height-20); 76 77 // draw trigLevel (= average voltage) line 78 stroke(0, 0, 100); 79 int trigLevelHeight=(int)(trigLevel*(float)windowHeight/1024); 80 line(windowX, windowY+windowHeight-trigLevelHeight, windowX+windowWidth, windowY+windowHeight-trigLevelHeight); 81 82 // draw grid 83 stroke(50); 84 for (float n=0; n<=windowWidth; n+=(float)windowWidth/10) 85 line(n+windowX, windowY, n+windowX, windowHeight+windowY); 86 for (float n=0; n<=windowHeight; n+=(float)windowHeight/10) 87 line(windowX, n+windowY, windowX+windowWidth, n+windowY); 88 89 // ------------------------------ 90 // DRAW WAVEFORM 91 // ------------------------------ 92 stroke(255); 93 float prevSampleValue=0; 94 if (sync) readIndex=trigIndex; // sync: start reading from last trig position 95 if (!sync) readIndex=writeIndex; // no sync: start reading from last sample we received 96 readIndex+=offset; 97 float lineIncr=(float)1/samplesPerLine; 98 if (lineIncr<1) lineIncr=1; 99 for (float line=0; line<windowWidth; line+=lineIncr) { // cycle screen lines (from right to left) 100 float sampleValue=(float)getValueFromBuffer((int)((float)readIndex-line*samplesPerLine)); // get the value for the screen line 101 sampleValue*=(float)windowHeight/1024; // scale to windowHeight 102 if (line>0) 103 line(windowX+windowWidth-line, 104 windowY+windowHeight-prevSampleValue, 105 windowX+windowWidth-line-lineIncr, 106 windowY+windowHeight-sampleValue); 107 prevSampleValue=sampleValue; 108 } 109 110 // ------------------------------ 111 // BUFFER INCOMING BYTES & TRIG 112 // ------------------------------ 113 if (hold) { 114 serial.clear(); // HOLD: don't receive samples; clear serial buffer 115 } 116 else { 117 while (serial.available ()>0) { // RUN: receive samples 118 writeIndex++; 119 if (writeIndex>=bufferSize) writeIndex=0; // handle overflow 120 buffer[writeIndex+writeIndex]=(byte)serial.read(); // add 1 sample (2 bytes) to buffer 121 buffer[writeIndex+writeIndex+1]=(byte)serial.read(); 122 trigLevel=trigLevel*(1-trigLevelLPF)+(float)getValueFromBuffer(writeIndex)*trigLevelLPF; // level for trigger intersection = exponential moving average of voltage 123 if (getValueFromBuffer(writeIndex)>=trigLevel&& getValueFromBuffer(writeIndex-1)<trigLevel) { // rising intersect detected 124 trigIndex=writeIndex; // set trigIndex (index of buffer that corresponds to last trig) 125 trigCounter++; // count trigs (to calculate the frequency) 126 } 127 } 128 } 129 } 130} 131 132// Read value from buffer 133int getValueFromBuffer(int index) { 134 while (index<0) index+=bufferSize; // handle overflow of circular buffer 135 return((buffer[index*2]&3)<<8 | buffer[index*2+1]&0xff); // convert bytes to int 136} 137 138// Handle keys 139void keyPressed() { 140 if (key == CODED) { 141 if (connected) { 142 if (keyCode == KeyEvent.VK_F1) { 143 samplesPerLine*=1.1; 144 if (samplesPerLine*windowWidth>bufferSize) samplesPerLine=bufferSize/windowWidth; 145 } 146 if (keyCode == KeyEvent.VK_F2) { 147 samplesPerLine/=1.1; 148 if (samplesPerLine<1/(float)windowWidth) samplesPerLine=1/(float)windowWidth; 149 } 150 if (keyCode == KeyEvent.VK_F3) { 151 sync=!sync; 152 } 153 if (keyCode == KeyEvent.VK_F4) { 154 hold=!hold; 155 } 156 if (keyCode == KeyEvent.VK_F5) { 157 if (trigLevelLPF<.01) trigLevelLPF*=10; 158 } 159 if (keyCode == KeyEvent.VK_F6) { 160 if (trigLevelLPF>.000001) trigLevelLPF/=10; 161 } 162 if (keyCode == KeyEvent.VK_F7) { 163 if (prescaler>3) prescaler--; 164 serial.write((byte)prescaler); 165 } 166 if (keyCode == KeyEvent.VK_F8) { 167 if (prescaler<7) prescaler++; 168 serial.write((byte)prescaler); 169 } 170 if (keyCode == LEFT) { 171 offset-=samplesPerLine*20; 172 if (offset<-bufferSize) offset=-bufferSize; 173 } 174 if (keyCode == RIGHT) { 175 offset+=samplesPerLine*20; 176 if (offset>0) offset=0; 177 } 178 } 179 else { 180 serial = new Serial(this, Serial.list()[keyCode-112], serialBaudRate); 181 serial.write((byte)prescaler); 182 connected=true; 183 } 184 } 185} 186 187
Downloadable files
Circiot
Circiot
Circiot
Circiot
Comments
Only logged in users can leave comments