Components and supplies
Arduino UNO
Apps and platforms
Microsoft Excel
Project description
Code
Source Code
arduino
1/* 2 Name: DigitalAnalyzer.ino 3 Version: 1.1 4 Created: Jan 2019 5 Last Updated: 25. Feb. 2019 6 Author: dr.shihan 7 8 Analyze digital inputs on up to six channels using the Atmega 328 (e.g. Arduino Uno / Nano / Ethernet / Mini). 9 https://create.arduino.cc/projecthub/drshihan/digitalanalyzer-a8754a 10 11 12 Change Log: 13 14 V1.1: 15 - DirectMode could not be exited and calling FastMode after DirectMode didn't work out correctly 16 - corrected the frequency generator for frequencies below 30 Hz 17 18*/ 19 20// written for ATmega 48/88/168/328 (e.g. Arduino Uno / Nano) 21// according to the available SRAM on your controller, you need to adjust the 'maxSamples' (see below) 22 23#define FastMode 0 24#define DirectMode 1 25int Mode = FastMode; 26 27#define maxSamples 300 //set this according to the available SRAM on your Controller (ATmega48: 30; ATmega88 & ATmega168: 130; ATmega328: 300) 28unsigned int Samples; 29 30byte Channels[6] = { 2, 3, 4, 5, 6, 7 }; //Input Pins (2-7) 31byte ChannelCount = sizeof(Channels) / sizeof(Channels[0]); 32volatile unsigned long TimestampBuffer[maxSamples]; 33volatile byte ChannelBuffer[maxSamples]; 34volatile unsigned int WritePosition = 0; 35unsigned int ReadPosition = 0; 36volatile bool BufferOverflow = false; 37 38volatile bool Recording = false; 39volatile bool Sending = false; 40 41volatile unsigned int tmr1ovf = 0; 42 43double f; //output frequency on Pin 11 44int prescaler; // for frequency generator 45int tmr2ovf = 0; 46int tmr2ovf_switch = 0; 47 48String Input; 49int i, j; 50 51 52void setup() { 53 Serial.begin(115200); 54 for (i = 0; i < ChannelCount; i++) { 55 pinMode(Channels[i], INPUT_PULLUP); 56 } 57 Help(); 58 59 //disable timer0 with micros, millis, etc. for not getting distracted 60 TIMSK0 = 0; 61} 62 63 64void loop() { 65 if (Serial.available() > 0) { 66 Input = Serial.readStringUntil('\n'); 67 } 68 else { 69 Input = ""; 70 } 71 72 if (Input != "") { 73 74 // abort current recording 75 if ((Input[0] == 'x') && Recording) { 76 StopRecording(); 77 Help(); 78 return; 79 } 80 81 if (Recording) { 82 Serial.println(F("I'm already recording. Please abort the recording with 'x'.")); 83 return; 84 } 85 86 // channel selection 87 else if (Input[0] == 'c') { 88 ChannelCount = Input.length() - 1; 89 if (ChannelCount > 6) { 90 Serial.println(F("There are at most 6 channels that can be observed (pins 2 - 7).")); 91 return; 92 } 93 for (i = 0; i < ChannelCount; i++) { 94 Channels[i] = Input[i + 1] - 48; //ASCII-conversion from (char) to (int) 95 if ((Channels[i] < 2) || (Channels[i] > 7)) { 96 Serial.println(F("Only pins 2 - 7 can be chosen.")); 97 ChannelCount = 0; 98 return; 99 } 100 pinMode(Channels[i], INPUT_PULLUP); 101 } 102 103 Serial.print(F("Active Channels (")); 104 Serial.print(ChannelCount); 105 Serial.print(F("): ")); 106 if (ChannelCount > 0) { Serial.print(Channels[0]); } 107 for (i = 1; i < ChannelCount; i++) { 108 Serial.print(F(", ")); 109 Serial.print(Channels[i]); 110 } 111 Serial.println(); 112 Help(); 113 } 114 115 116 // frequency generator: 117 else if (Input[0] == 'f') { 118 pinMode(11, OUTPUT); 119 120 //using Timer 2 with CTC-Mode 121 f = Input.substring(1).toDouble(); 122 if (f < 0.007451) { // turn off 123 f = 0; 124 TCCR2A = 0b00000000; 125 TCCR2B = 0b00000000; 126 Serial.println(F("Frequency generator turned off.")); 127 return; 128 } 129 else if (f < 30.517578125) { 130 prescaler = 1024; 131 TCCR2A = 0b00000010; 132 TCCR2B = 0b00000111; 133 TCNT2 = 0; 134 OCR2A = 15; // there is a overflow every 1,024ms 135 TIMSK2 = 0b00000010; 136 137 tmr2ovf_switch = 488.28125 / f; 138 Serial.print(F("Current frequency set to [Hz]: ")); 139 f = 488.28125 / tmr2ovf_switch; 140 Serial.println(f,3); 141 Help(); 142 return; 143 } 144 else if (f < 122.0703125) { 145 prescaler = 1024; 146 TCCR2B = 0b00000111; 147 } 148 else if (f < 244.140625) { 149 prescaler = 256; 150 TCCR2B = 0b00000110; 151 } 152 else if (f < 488.28125) { 153 prescaler = 128; 154 TCCR2B = 0b00000101; 155 } 156 else if (f < 976.5625) { 157 prescaler = 64; 158 TCCR2B = 0b00000100; 159 } 160 else if (f < 3906.25) { 161 prescaler = 32; 162 TCCR2B = 0b00000011; 163 } 164 else if (f < 31250.0) { 165 prescaler = 8; 166 TCCR2B = 0b00000010; 167 } 168 else if (f < 8000000.0) { 169 prescaler = 1; 170 TCCR2B = 0b00000001; 171 } 172 else { 173 f = 8000000.0; 174 prescaler = 1; 175 TCCR2B = 0b00000001; 176 } 177 178 TCCR2A = 0b01000010; 179 OCR2A = (byte)(8000000.0 / prescaler / f) - 1; 180 Serial.print(F("Current frequency set to [Hz]: ")); 181 f = 8000000.0 / prescaler / (1 + OCR2A); 182 Serial.println(f,3); 183 Help(); 184 } 185 186 187 // recording instructions 188 else if (Input.toInt() >= 0L) { 189 Samples = Input.toInt(); 190 if (Samples > maxSamples) { 191 Samples = maxSamples; 192 Serial.print(F("Maximum Samples: ")); 193 Serial.println(maxSamples); 194 Mode = FastMode; 195 } 196 else if (Samples == 0) { 197 Mode = DirectMode; 198 } 199 else 200 { 201 Mode = FastMode; 202 } 203 StartAnalyzing(); 204 } 205 } 206 207 208 // output 209 if (Mode == FastMode) { 210 if (Sending) { 211 Send(); 212 Sending = false; 213 Help(); 214 } 215 delay(500); //only relevant while recording in FastMode 216 } 217 else if (Recording) { // && (Mode == DirectMode) 218 while (ReadPosition != WritePosition) { // if recording is stopped, the remaining data will also be sent 219 if (ReadPosition == 0) { 220 SendLine(TimestampBuffer[ReadPosition], ChannelBuffer[maxSamples - 1], ChannelBuffer[ReadPosition]); 221 } 222 else { 223 SendLine(TimestampBuffer[ReadPosition], ChannelBuffer[ReadPosition - 1], ChannelBuffer[ReadPosition]); 224 } 225 ReadPosition++; 226 if (ReadPosition == maxSamples) { 227 ReadPosition = 0; 228 } 229 if (Serial.available() > 0) { 230 return; 231 } 232 } 233 if (BufferOverflow) { 234 Serial.println("!!! Bufferoverflow !!!"); 235 BufferOverflow = false; 236 Mode = FastMode; 237 Help(); 238 } 239 } 240} 241 242 243// pin change 2 - 7 interrupt 244ISR(PCINT2_vect) { 245 WritePosition += 1; 246 ChannelBuffer[WritePosition] = PIND; 247 TimestampBuffer[WritePosition] = mymicros(); 248 249 if (Mode == FastMode) { 250 if (WritePosition >= Samples) { 251 StopRecording(); 252 } 253 } 254 255 else { // if (Mode == DirectMode) 256 if (WritePosition == ReadPosition - 10) { 257 StopRecording(); 258 BufferOverflow = true; 259 } 260 if (WritePosition == maxSamples - 1) { 261 WritePosition = 65535U; 262 263 } 264 } 265} 266 267// timer1 overflow interrupt (for mymicros()) 268ISR(TIMER1_OVF_vect) { 269 tmr1ovf++; 270} 271 272// timer2 overflow interrupt (for frequency generator with slow frequencies below 30.517578125 Hz) 273ISR(TIMER2_COMPA_vect) { 274 tmr2ovf++; 275 if (tmr2ovf == tmr2ovf_switch) { 276 PORTB ^= 0b00001000; //toggle pin 11 277 tmr2ovf = 0; 278 } 279} 280 281unsigned long mymicros() { 282 return ((unsigned long)tmr1ovf << 16) + TCNT1; 283} 284 285 286void StartAnalyzing() { 287 Serial.print(F("Time[us]")); 288 for (j = 0; j < ChannelCount; j++) { 289 Serial.print(F(" Channel_")); 290 Serial.print(Channels[j]); 291 } 292 Serial.println(); 293 294 WritePosition = 0; 295 ReadPosition = 0; 296 297 cli(); 298 299 PCMSK2 = 0; // Pin Change Mask Register 2: Only set interrupt for selected Channels (Pins) 300 for (i = 0; i < ChannelCount; i++) { 301 PCMSK2 |= 1 << Channels[i]; 302 } 303 TCNT1 = 0; // reset timer1 to 0 304 tmr1ovf = 0; // reset timer1 to 0 305 TimestampBuffer[0] = mymicros(); 306 Recording = true; 307 308 ChannelBuffer[0] = PIND; 309 TCCR1A = 0b00000000; 310 TCCR1B = 0b00000010; // start timer1 with prescaler 8 = 2MHz = 0.5us 311 TCCR1C = 0b00000000; 312 PCICR = 0b00000100; // Pin Change Interrupt Control Register: Set PCI0 for Pins 0 to 7 313 TIMSK1 = 0b00000001; // enable timer1 overflow interrupt 314 315 sei(); 316} 317 318 319void StopRecording() { 320 PCICR = 0; //turn of input interrupts 321 if (Mode == FastMode) { Sending = true; } 322 Recording = false; 323 TCNT1 = 0; // reset timer1 to 0 324 tmr1ovf = 0; // reset timer1 to 0 325} 326 327 328void Send() { 329 for (i = 1; i < WritePosition; i++) { 330 SendLine(TimestampBuffer[i], ChannelBuffer[i - 1], ChannelBuffer[i]); 331 } 332} 333 334void SendLine(unsigned long t, byte chBefore, byte chAfter) { 335 Serial.print(t / 2.0); //for prescaler 8 = 2MHz = 0.5 us 336 for (j = 0; j < ChannelCount; j++) { 337 Serial.print(" "); 338 Serial.print((chBefore >> Channels[j]) & 1); 339 } 340 Serial.println(); 341 342 Serial.print(t / 2.0);//for prescaler 8 = 2MHz = 0.5 us 343 for (j = 0; j < ChannelCount; j++) { 344 Serial.print(" "); 345 Serial.print((chAfter >> Channels[j]) & 1); 346 } 347 Serial.println(); 348} 349 350void Help() { 351 Serial.println(); 352 Serial.println(F("There are two modes: FastMode and DirectMode.")); 353 Serial.print(F("While using FastMode you need to send the number of samples to be recorded via SerialMonitor to the Controller (e.g. '140'). This amount of samples will be recorded and printed afterwards. It is possible to detect about 100,000 samples per second, however (as SRAM as limited) only ")); 354 Serial.print(maxSamples); 355 Serial.println(F(" samples can be recorded.")); 356 Serial.println(F("While using DirectMode, each detected Sample will be printed directly to the SerialMonitor. It is possible to detect about 200 samples per second without running into a buffer overflow. Faster samplerates will lead to a buffer overlow and recording will be stopped automatically.")); 357 Serial.println(F("To call DirectMode, you need to send a '0' via SerialMonitor to the controller.")); 358 Serial.println(F("There are six channels that can be recorded (pins 2 - 7). To set the supervised channels, enter e.g. 'c245' to observe pins 2, 4 and 5. The input pins are internally connected to pull-up resistors. It doesn't matter how many channels are observed, the possible recordable samplerate is not effected.")); 359 Serial.println(F("The current recording can be aborted by sending 'x' to the controller. The recored samples will be printed out.")); 360 Serial.println(F("It is possible to call a frequncy generator on pin 11. To enable it, you need to send e.g. 'f123.456' via SerialMonitor, where the number represents the frequency (in this case 123.456 Hz). A frequency between 0.007451 and 8,000,000 Hz can be chosen, however not infintely variable. The exact output frequency is printed below. The maximum recording speed (samplerate) is not influenced by the frequency generator.")); 361 Serial.println(F("All inputs need to be completed with a 'LineFeed' (see setting in SerialMonitor).")); 362 Serial.print(F("Active Channels (")); 363 Serial.print(ChannelCount); 364 Serial.print(F("): ")); 365 if (ChannelCount > 0) { Serial.print(Channels[0]); } 366 for (i = 1; i < ChannelCount; i++) { 367 Serial.print(F(", ")); 368 Serial.print(Channels[i]); 369 } 370 Serial.println(); 371 Serial.print(F("Current frequency [Hz]: ")); 372 Serial.println(f,3); 373 Serial.println(); 374} 375
Downloadable files
simple setup for self testing
simple setup for self testing
simple setup for self testing
simple setup for self testing
Comments
Only logged in users can leave comments
drshihan
0 Followers
•0 Projects
Table of contents
Intro
3
0