Components and supplies
Arduino UNO
Project description
Code
Oscilloscope.ino
c_cpp
1/* 2 File: Oscilloscope.ino 3 Title: Standalone Arduino 6 channel Triggered Oscilloscope 4 Author: Meeker6751 5 Verson: 2018.4.23 6 7 Method: (0) Set the adjustable variables, (1) run the sketch (2) activate the serial plotter. 8 9 Description: This sketch simulates a 6 beam oscilloscope. It is expected that the input(s) presented at the analog pins will be between 10 0 and 5 volts with a maximum frequency of 1 KHz. The adjustable variables are declared in a separate section. These variables can be 11 found after the define statements. 1-6 beams may be selected which display voltages at A0-A5, respectively. Open analog pins produce 12 spurious voltages. 13 14 The oscilloscope runs in 2 modes: 'continuous' (free running) and 'triggered' (start sweep when a criterion is met. The triggering 15 criterion is met when the input signal read off od A0 crosses over a predefined triggering voltage. The criterion is further 16 conditioned by whether it is 'rising' or 'falling' when it crosses the predefined voltage. In triggered mode the total sweep time 17 may be set in milliseconds. The beginning of a triggered sweep is indicated when the timing mark spikes to 5 vdc. 18 19 When sweeping, the analog pin(s) will be sampled every 'SampleInterval' milliseconds. At the bottom of the plot, timing marks 20 (a square wave) will be toggled every 10th 'SampleInterval' milliseconds. 21 22 When more than 1 signal is being sampled, the signal displays may be 'superimposed' or 'channeled'. When channels are used, the 23 voltages on the vertical axis are not calibrated. 24 25 The builtin LED (pin 13) is an indicator of the oscilloscope state: (1) On, continuous mode or sweeping in triggered mode; 26 (2) blinking, Armed in triggered mode, (3) Off, all operations paused (by push button). 27 28 Optionally a push button, can be connected to ground and digital pin 12. When pressed, signal sampling and sweep are stopped. 29 Pressing the push button again resumes the sweep (but with a gap in the signal trace(s)). 30 31 The order of the plotted line legend is: timing marks (blue), trigger level (red, if in triggered mode), analog signals A0-A6, 32 respectively (multi colored). 33*/ 34 35#define ul unsigned long 36#define armed true // trigger and pushbutton state 37#define continuous true // sweep mode (free running) 38#define falling false // trigger slope positive 39#define rising true // trigger slope negative 40#define triggered false // sweep mode (sweep starts when triggered) 41#define sweeping false // sweeping for TriggeredSweepInterval msecs 42#define superimposed true // signals superimposed on display 43#define channeled false // signals channeled on display 44 45// adjustable variables 46int Beams = 6; // number of beams read 47bool DisplayMode = channeled; // 'superimposed' or 'channeled' 48ul SampleInterval = 200; // units: msecs * 10; 0.1 <= SampleInterval 49bool SweepMode = triggered; // 'continuous' or 'triggered' 50ul TriggeredSweepInterval = 40000; // total sweep time, units: seconds * 10,000 51float TriggerDirection = rising; // 'rising' or 'falling' 52float TriggerVolts = 3.5; // trigger vdc; 0 <= TriggerVolts <= 5 53 54// interrupt controlled variables 55ul LastSample = -1; // initially, no last sample 56bool LED = HIGH; 57int BlinkCount = 0; 58ul SweepCount = 0; // counts up to Sweep Interval 59bool Tick = false; // set to true when TickCount = SampleRate 60ul TickCount = 0; // counts up to SampleRate 61bool TimingMark; // toggles every 10th 'Sample Intewrval' 62ul TimingMarkCount = 0; // counts up to SampleInterval * 10 63bool TriggerState; // 'armed' or 'sweeping' 64bool TriggerOnset = false; // marks first tick after trigger occurs 65 66// loop procedure variables 67float ChannelFloor; 68float ChannelHeight; 69bool freeze = false; // true: stop; false: run 70int PBPin = 12; // grounded push button on pin 12 (optional) 71int PBLastState = HIGH; // LOW (pressed) or HIGH (released) 72int PBVal; // inverse logic, push button tied to ground 73float ChannelScale; // proportion og signal to display 74float TriggerDisplay; // vertical position of trigger 75int TriggerLevel; // calculated from 'TriggerVolts' 76float Value; 77 78void interruptSetup() { 79 noInterrupts(); // generate an interrupt every 0.1 msec 80 TCCR2A = 2; // clear timer on compare, OCR2 81 TCCR2B = 2; // 16,000,000Hz/8=2,000,000 Hz; T2 clock ticks every 0.0005 msecs 82 OCR2A = 199; // interrupt = 0.0005*200 = 0.1 msec 83 TIMSK2 = 2; // set the ISR COMPA vect 84 interrupts(); 85} 86 87ISR(TIMER2_COMPA_vect) { // interrupt every 0.1 msecs 88 if (TickCount < SampleInterval) { 89 TickCount++; 90 BlinkCount++; 91 if (BlinkCount >= 500) { 92 BlinkCount = 0.0; 93 LED = !LED; // toggle LED every 50 msecs 94 } 95 } 96 else { // 'SampleInterval' has elapsed 97 Tick = true; 98 TickCount = 0; 99 TimingMarkCount++; // update Timing mark 100 if (TimingMarkCount >= 10) { // 10th 'SDampleInterval' has occurred 101 TimingMark = !TimingMark; 102 TimingMarkCount = 0; 103 } 104 if (SweepMode == triggered) { 105 if (TriggerState == sweeping) { // sweeping, update sweep time 106 SweepCount += SampleInterval; 107 if (SweepCount >= TriggeredSweepInterval) { // sweep complete 108 TriggerState = armed; 109 LastSample = -1; 110 } 111 } 112 else { // armed, look for trigger 113 Value = analogRead(A0); 114 if (LastSample > 0 and 115 ((TriggerDirection == rising and Value >= TriggerLevel and LastSample < TriggerLevel) or 116 (TriggerDirection == falling and Value <= TriggerLevel and LastSample > TriggerLevel))) { 117 TriggerState = sweeping; // triggered 118 SweepCount = 0; 119 TriggerOnset = true; 120 TimingMarkCount = 0; 121 TimingMark = true; 122 } 123 LastSample = Value; 124 } 125 } 126 } 127} 128 129void setup() { 130 pinMode (LED_BUILTIN, OUTPUT); 131 pinMode(PBPin, INPUT); // connected to a grounded push button 132 digitalWrite(PBPin, HIGH); // pullup push button pin 133 Serial.begin(115200); 134 if (SweepMode == continuous) { 135 TriggerState = sweeping; 136 } 137 else { 138 TriggerState = armed; 139 } 140 TriggerLevel = (TriggerVolts / 5.0 ) * 1023; 141 ChannelHeight = 5.0 / Beams; 142 ChannelScale = 5.0 / 1024.0 / Beams; 143 TriggerDisplay = TriggerVolts * ChannelScale + 5.0 - ChannelHeight; 144 interruptSetup(); 145} 146 147void loop() { 148 if (freeze) { 149 digitalWrite(LED_BUILTIN, LOW); 150 } 151 else if (TriggerState == armed) { 152 digitalWrite(LED_BUILTIN, LED); 153 } 154 else { 155 digitalWrite(LED_BUILTIN, HIGH); 156 } 157 PBVal = digitalRead(PBPin); 158 if (PBVal == LOW and PBLastState == HIGH) { // falling edge 159 freeze = !freeze; 160 delay (2); // ignore contact bounce 161 } 162 PBLastState = PBVal; 163 if (!freeze and TriggerState == sweeping) { 164 if (Tick) { // sample if Sample Interval msecs have elapsed 165 if (TimingMark) { // display timing marks and trigger, if present 166 if (TriggerOnset) { 167 Serial.print(5.0); 168 TriggerOnset = false; 169 } 170 else { 171 Serial.print(0.1); 172 } 173 } 174 else { 175 Serial.print(0.0); 176 } 177 Serial.print(" "); 178 ChannelFloor = 5.0 - ChannelHeight; // display trigger level, if applicable 179 if (SweepMode == triggered) { 180 Serial.print(TriggerLevel * ChannelScale + ChannelFloor); 181 Serial.print (" "); 182 } 183 for (int AnalogPin = 0; AnalogPin <= Beams - 1; AnalogPin++) { // sample 1-6 analog signals and display them 184 Value = analogRead(AnalogPin); 185 Value = Value * ChannelScale + ChannelFloor; 186 Serial.print(Value); 187 Serial.print(" "); 188 ChannelFloor -= ChannelHeight; 189 } 190 Tick = false; 191 Serial.println(""); 192 } 193 } 194} 195
Oscilloscope.ino
c_cpp
1/* 2 File: Oscilloscope.ino 3 Title: Standalone Arduino 6 channel 4 Triggered Oscilloscope 5 Author: Meeker6751 6 Verson: 2018.4.23 7 8 Method: 9 (0) Set the adjustable variables, (1) run the sketch (2) activate the serial plotter. 10 11 12 Description: This sketch simulates a 6 beam oscilloscope. It is expected that 13 the input(s) presented at the analog pins will be between 14 0 and 5 volts with 15 a maximum frequency of 1 KHz. The adjustable variables are declared in a separate 16 section. These variables can be 17 found after the define statements. 1-6 beams 18 may be selected which display voltages at A0-A5, respectively. Open analog pins 19 produce 20 spurious voltages. 21 22 The oscilloscope runs in 2 modes: 'continuous' 23 (free running) and 'triggered' (start sweep when a criterion is met. The triggering 24 25 criterion is met when the input signal read off od A0 crosses over a predefined 26 triggering voltage. The criterion is further 27 conditioned by whether it is 28 'rising' or 'falling' when it crosses the predefined voltage. In triggered mode 29 the total sweep time 30 may be set in milliseconds. The beginning of a triggered 31 sweep is indicated when the timing mark spikes to 5 vdc. 32 33 When sweeping, 34 the analog pin(s) will be sampled every 'SampleInterval' milliseconds. At the bottom 35 of the plot, timing marks 36 (a square wave) will be toggled every 10th 'SampleInterval' 37 milliseconds. 38 39 When more than 1 signal is being sampled, the signal displays 40 may be 'superimposed' or 'channeled'. When channels are used, the 41 voltages 42 on the vertical axis are not calibrated. 43 44 The builtin LED (pin 13) is an 45 indicator of the oscilloscope state: (1) On, continuous mode or sweeping in triggered 46 mode; 47 (2) blinking, Armed in triggered mode, (3) Off, all operations paused 48 (by push button). 49 50 Optionally a push button, can be connected to ground 51 and digital pin 12. When pressed, signal sampling and sweep are stopped. 52 Pressing 53 the push button again resumes the sweep (but with a gap in the signal trace(s)). 54 55 56 The order of the plotted line legend is: timing marks (blue), trigger level (red, 57 if in triggered mode), analog signals A0-A6, 58 respectively (multi colored). 59*/ 60 61#define 62 ul unsigned long 63#define armed true // 64 trigger and pushbutton state 65#define continuous true // 66 sweep mode (free running) 67#define falling false // 68 trigger slope positive 69#define rising true // 70 trigger slope negative 71#define triggered false // 72 sweep mode (sweep starts when triggered) 73#define sweeping false // 74 sweeping for TriggeredSweepInterval msecs 75#define superimposed true // 76 signals superimposed on display 77#define channeled false // 78 signals channeled on display 79 80// adjustable variables 81int Beams = 6; 82 // number of beams read 83bool 84 DisplayMode = channeled; // 'superimposed' 85 or 'channeled' 86ul SampleInterval = 200; // 87 units: msecs * 10; 0.1 <= SampleInterval 88bool SweepMode = triggered; // 89 'continuous' or 'triggered' 90ul TriggeredSweepInterval = 40000; // 91 total sweep time, units: seconds * 10,000 92float TriggerDirection = rising; // 93 'rising' or 'falling' 94float TriggerVolts = 3.5; // 95 trigger vdc; 0 <= TriggerVolts <= 5 96 97// interrupt controlled variables 98ul 99 LastSample = -1; // initially, 100 no last sample 101bool LED = HIGH; 102int BlinkCount = 0; 103ul SweepCount 104 = 0; // counts up to Sweep Interval 105bool 106 Tick = false; // set to true 107 when TickCount = SampleRate 108ul TickCount = 0; // 109 counts up to SampleRate 110bool TimingMark; // 111 toggles every 10th 'Sample Intewrval' 112ul TimingMarkCount = 0; // 113 counts up to SampleInterval * 10 114bool TriggerState; // 115 'armed' or 'sweeping' 116bool TriggerOnset = false; // 117 marks first tick after trigger occurs 118 119// loop procedure variables 120float 121 ChannelFloor; 122float ChannelHeight; 123bool freeze = false; // 124 true: stop; false: run 125int PBPin = 12; // 126 grounded push button on pin 12 (optional) 127int PBLastState = HIGH; // 128 LOW (pressed) or HIGH (released) 129int PBVal; // 130 inverse logic, push button tied to ground 131float ChannelScale; // 132 proportion og signal to display 133float TriggerDisplay; // 134 vertical position of trigger 135int TriggerLevel; // 136 calculated from 'TriggerVolts' 137float Value; 138 139void interruptSetup() { 140 141 noInterrupts(); // generate 142 an interrupt every 0.1 msec 143 TCCR2A = 2; // 144 clear timer on compare, OCR2 145 TCCR2B = 2; // 146 16,000,000Hz/8=2,000,000 Hz; T2 clock ticks every 0.0005 msecs 147 OCR2A = 199; 148 // interrupt = 0.0005*200 149 = 0.1 msec 150 TIMSK2 = 2; // 151 set the ISR COMPA vect 152 interrupts(); 153} 154 155ISR(TIMER2_COMPA_vect) { // 156 interrupt every 0.1 msecs 157 if (TickCount < SampleInterval) { 158 TickCount++; 159 160 BlinkCount++; 161 if (BlinkCount >= 500) { 162 BlinkCount = 0.0; 163 164 LED = !LED; // toggle 165 LED every 50 msecs 166 } 167 } 168 else { // 169 'SampleInterval' has elapsed 170 Tick = true; 171 TickCount = 0; 172 TimingMarkCount++; 173 // update Timing mark 174 if 175 (TimingMarkCount >= 10) { // 10th 'SDampleInterval' 176 has occurred 177 TimingMark = !TimingMark; 178 TimingMarkCount = 0; 179 180 } 181 if (SweepMode == triggered) { 182 if (TriggerState == sweeping) 183 { // sweeping, update sweep time 184 SweepCount 185 += SampleInterval; 186 if (SweepCount >= TriggeredSweepInterval) { // 187 sweep complete 188 TriggerState = armed; 189 LastSample = -1; 190 191 } 192 } 193 else { // 194 armed, look for trigger 195 Value = analogRead(A0); 196 if (LastSample 197 > 0 and 198 ((TriggerDirection == rising and Value >= TriggerLevel and 199 LastSample < TriggerLevel) or 200 (TriggerDirection == falling and Value 201 <= TriggerLevel and LastSample > TriggerLevel))) { 202 TriggerState = sweeping; 203 // triggered 204 SweepCount = 0; 205 206 TriggerOnset = true; 207 TimingMarkCount = 0; 208 TimingMark 209 = true; 210 } 211 LastSample = Value; 212 } 213 } 214 } 215} 216 217void 218 setup() { 219 pinMode (LED_BUILTIN, OUTPUT); 220 pinMode(PBPin, INPUT); // 221 connected to a grounded push button 222 digitalWrite(PBPin, HIGH); // 223 pullup push button pin 224 Serial.begin(115200); 225 if (SweepMode == continuous) 226 { 227 TriggerState = sweeping; 228 } 229 else { 230 TriggerState = armed; 231 232 } 233 TriggerLevel = (TriggerVolts / 5.0 ) * 1023; 234 ChannelHeight = 5.0 / 235 Beams; 236 ChannelScale = 5.0 / 1024.0 / Beams; 237 TriggerDisplay = TriggerVolts 238 * ChannelScale + 5.0 - ChannelHeight; 239 interruptSetup(); 240} 241 242void loop() 243 { 244 if (freeze) { 245 digitalWrite(LED_BUILTIN, LOW); 246 } 247 else if 248 (TriggerState == armed) { 249 digitalWrite(LED_BUILTIN, LED); 250 } 251 else 252 { 253 digitalWrite(LED_BUILTIN, HIGH); 254 } 255 PBVal = digitalRead(PBPin); 256 257 if (PBVal == LOW and PBLastState == HIGH) { // falling 258 edge 259 freeze = !freeze; 260 delay (2); // 261 ignore contact bounce 262 } 263 PBLastState = PBVal; 264 if (!freeze and TriggerState 265 == sweeping) { 266 if (Tick) { // 267 sample if Sample Interval msecs have elapsed 268 if (TimingMark) { // 269 display timing marks and trigger, if present 270 if (TriggerOnset) { 271 272 Serial.print(5.0); 273 TriggerOnset = false; 274 } 275 276 else { 277 Serial.print(0.1); 278 } 279 } 280 else 281 { 282 Serial.print(0.0); 283 } 284 Serial.print(" "); 285 ChannelFloor 286 = 5.0 - ChannelHeight; // display trigger level, 287 if applicable 288 if (SweepMode == triggered) { 289 Serial.print(TriggerLevel 290 * ChannelScale + ChannelFloor); 291 Serial.print (" "); 292 } 293 294 for (int AnalogPin = 0; AnalogPin <= Beams - 1; AnalogPin++) { // sample 295 1-6 analog signals and display them 296 Value = analogRead(AnalogPin); 297 298 Value = Value * ChannelScale + ChannelFloor; 299 Serial.print(Value); 300 301 Serial.print(" "); 302 ChannelFloor -= ChannelHeight; 303 } 304 305 Tick = false; 306 Serial.println(""); 307 } 308 } 309} 310
Downloadable files
6 Channel Oscilloscope
6 Channel Oscilloscope
Comments
Only logged in users can leave comments
Meeker6751
0 Followers
•0 Projects
0