Components and supplies
Capacitor 100 nF
Resistor 220 ohm
Arduino UNO
Project description
Code
very_fast_analog_read
c_cpp
reads analog data at 77 kHz or faster
1/* This small program shows that Arduino UNO is capable of recording analog readings at a rate of at least 77 kHz (maybe even 154 kHz). 2 * First, the analog digital converter setup registers (ADSCRA and ADSCRB) are set in such a way that analog values will be read and put in the ADCH register continuously at a rate of 77 kHz. 3 * This ADCH register may then be read at any desired frequency. If the reading frequency is faster than 77kHz, the same value will be reported multiple times. 4 * Advantage of this approach is that no interrupt is needed (most sketches that I found so far wait for the analog read to get a new fresh result and will then read that value). 5 * 6 * Instead of 10-bit, only the 8 most significant bits are read. This reduces noise and allows for much more compact storage. An 8 bit number can be stored in a byte, a 10 bit number 7 * will take an integer (2 bytes). At a sampling rate of 77 kHz, the memory of arduino will be full very rapidly.... 8 * 9 * Timer2 is used to read the values at regular intervals. First the timer overflow flag is set to zero. Then actions are performed. 10 * Then the controller waits for the overflow flag to be set. As long as the execution time of all actions fits in the period for the flag to be set, this will yield a very regular sampling. 11 * 12 * The result is shown as a graph in the Serial Monitor. I guess a graphical display will allow for a much better view of the data (work to be done). 13 * 14 * Author: Koen Meesters 15 * Date: 16/09/2020 16 * 17 * Electrical scheme used for testing: 18 * 19 * 20 * Pin 8----[ 220 OHM ]----+----[ 220 OHM ]----+-----[ 220 OHM ]----+-------- Pin A0 21 * | | | 22 * | | | 23 * === 100 nF === 100 nF === 100 nF 24 * | | | 25 * | | | 26 * GND --------------------+-------------------+--------------------+ 27 * 28 * 29 */ 30 31void setup() { 32 Serial.begin(9600); 33 delay(1000); 34 Serial.println("start setup"); 35 delay(1000); 36 37 /* The bit of code below was taken from: 38 * http://yaab-arduino.blogspot.it/p/oscope.html 39 */ 40 ADCSRA = 0; // clear ADCSRA register 41 ADCSRB = 0; // clear ADCSRB register 42 ADMUX |= (0 & 0x07); // set A0 analog input pin 43 ADMUX |= (1 << REFS0); // set reference voltage 44 ADMUX |= (1 << ADLAR); // left align ADC value to 8 bits from ADCH register 45 46 // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles] 47 // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles 48 //ADCSRA |= (1 << ADPS2) | (1 << ADPS0); // 32 prescaler for 38.5 KHz 49 ADCSRA |= (1 << ADPS2); // 16 prescaler for 76.9 KHz 50 //ADCSRA |= (1 << ADPS1) | (1 << ADPS0); // 8 prescaler for 153.8 KHz 51 52 ADCSRA |= (1 << ADATE); // enable auto trigger 53// ADCSRA |= (1 << ADIE); // enable interrupts when measurement complete --> KM: disabled here, because no interrupts will be used 54 ADCSRA |= (1 << ADEN); // enable ADC 55 ADCSRA |= (1 << ADSC); // start ADC measurements 56 57// set Timer2 to fast PWM, no prescaling, inverted pin 3 58// in this sketch only the overflow flag of Timer2 will be used to trigger the reading frequency. 59 TCCR2A = 0; 60 TCCR2B = 0; 61 TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(COM2B0) | _BV(WGM21) | _BV(WGM20); 62 TCCR2B = _BV(CS20); 63 64 delay(1000); 65 pinMode(8, OUTPUT); //for testing a square wave signal will be produced on pin 8 66 Serial.println("end setup"); 67 delay(1000); 68} 69 70const byte maxData = 255; //this value could be chosen larger if desired 71byte data[maxData]; //here the data will be stored 72unsigned long int t0 = 0; //(t1-t0)/255 should be equal to 1/77000*1000000 (otherwise the execution time of the actions is to large). 73unsigned long int t1 = 0; 74 75bool state = 0; //state of output at pin 8 76 77void loop() { 78 t0 = micros(); 79 80 TIFR2 = TIFR2 | _BV(TOV2); //reset overflow flag 81 82 for (int i=0; i<maxData; i++) { 83 data[i] = ADCH; //read the analog value and store in memory 84 PORTB = byte(state); //this statement puts the square wave at pin 8 (pin 8 is the least significant bit of PORTB) 85 if((i&B00000111) == 0) {state = !state;} /* prescaler to set frequency of square wave at pin 8: 86 * B00111111 = 64 B00011111=32 B00001111=16 B00000111=8, frequency will be: Timer2Freq/(prescaler*2) 87 */ 88 89 /* More statements could be put here. Perhaps data could be written to SD card, but I did not test if writing of one character to SD card 90 * can be performed in the little time available here 91 */ 92 93 while((TIFR2 & _BV(TOV2)) == 0) { 94 ; //wait for timer overflow flag 95 } 96 TIFR2 = TIFR2 | _BV(TOV2); //reset overflow flag 97 } 98 99 t1 = micros(); 100 101 Serial.println(t0); 102 Serial.println(t1); 103 Serial.println(t1-t0); 104 105 for (int i=0; i<maxData; i++) { 106 Serial.println(data[i]); 107 } 108 109 makeGraph(maxData); 110 delay(2000); 111} 112 113//make a Graph on the Serial monitor 114void makeGraph(byte numData) { 115 116 const byte horLineInt = 8; 117 const byte verLineInt = 16; 118 const byte y_offset = 32; 119 120 const byte screenHeight = 64; 121 const byte screenWidth = 128; 122 if(numData<screenWidth) {numData = screenWidth;} //only data that fit on the screen will be shown 123 124 125 for (byte y=0; y<=screenHeight; y++) { //each line, starting at bottom of the graph 126 for (byte t=0; t<numData; t++) { //each character, starting from left to right 127 char character = ' '; //put a space 128 if (t%verLineInt == 0) { 129 character = '|'; //put a vertical line for the grid on regular intervals 130 } 131 if ((screenHeight-y-y_offset)%horLineInt == 0) { 132 character = '-'; //put a horizontal line for the grid on regular intervals 133 if (y == y_offset) { 134 character = 'o'; //put a horizontal line with zeros in the grid 135 } 136 if (t%verLineInt == 0) { 137 character = '+'; //put a '+' where horizontal and vertical grid lines meet 138 } 139 } 140 if (round(data[t]/4.0) == screenHeight-y) { 141 character = 'x'; //if data point supposed to be here, then put an 'x' 142 } 143 Serial.print(character); //put the character on the Serial Monitor 144 } 145 Serial.println(); //next line 146 } 147 Serial.println("+---------------+ = 128 micro sec"); //add horizontal scale dimenstion 148 // 01234567890123456 149 Serial.println("Full scale on vertical axis is -5V to 0V to +5V"); //add vertical scale data 150} 151 152 153
very_fast_analog_read
c_cpp
reads analog data at 77 kHz or faster
1/* This small program shows that Arduino UNO is capable of recording analog readings at a rate of at least 77 kHz (maybe even 154 kHz). 2 * First, the analog digital converter setup registers (ADSCRA and ADSCRB) are set in such a way that analog values will be read and put in the ADCH register continuously at a rate of 77 kHz. 3 * This ADCH register may then be read at any desired frequency. If the reading frequency is faster than 77kHz, the same value will be reported multiple times. 4 * Advantage of this approach is that no interrupt is needed (most sketches that I found so far wait for the analog read to get a new fresh result and will then read that value). 5 * 6 * Instead of 10-bit, only the 8 most significant bits are read. This reduces noise and allows for much more compact storage. An 8 bit number can be stored in a byte, a 10 bit number 7 * will take an integer (2 bytes). At a sampling rate of 77 kHz, the memory of arduino will be full very rapidly.... 8 * 9 * Timer2 is used to read the values at regular intervals. First the timer overflow flag is set to zero. Then actions are performed. 10 * Then the controller waits for the overflow flag to be set. As long as the execution time of all actions fits in the period for the flag to be set, this will yield a very regular sampling. 11 * 12 * The result is shown as a graph in the Serial Monitor. I guess a graphical display will allow for a much better view of the data (work to be done). 13 * 14 * Author: Koen Meesters 15 * Date: 16/09/2020 16 * 17 * Electrical scheme used for testing: 18 * 19 * 20 * Pin 8----[ 220 OHM ]----+----[ 220 OHM ]----+-----[ 220 OHM ]----+-------- Pin A0 21 * | | | 22 * | | | 23 * === 100 nF === 100 nF === 100 nF 24 * | | | 25 * | | | 26 * GND --------------------+-------------------+--------------------+ 27 * 28 * 29 */ 30 31void setup() { 32 Serial.begin(9600); 33 delay(1000); 34 Serial.println("start setup"); 35 delay(1000); 36 37 /* The bit of code below was taken from: 38 * http://yaab-arduino.blogspot.it/p/oscope.html 39 */ 40 ADCSRA = 0; // clear ADCSRA register 41 ADCSRB = 0; // clear ADCSRB register 42 ADMUX |= (0 & 0x07); // set A0 analog input pin 43 ADMUX |= (1 << REFS0); // set reference voltage 44 ADMUX |= (1 << ADLAR); // left align ADC value to 8 bits from ADCH register 45 46 // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles] 47 // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles 48 //ADCSRA |= (1 << ADPS2) | (1 << ADPS0); // 32 prescaler for 38.5 KHz 49 ADCSRA |= (1 << ADPS2); // 16 prescaler for 76.9 KHz 50 //ADCSRA |= (1 << ADPS1) | (1 << ADPS0); // 8 prescaler for 153.8 KHz 51 52 ADCSRA |= (1 << ADATE); // enable auto trigger 53// ADCSRA |= (1 << ADIE); // enable interrupts when measurement complete --> KM: disabled here, because no interrupts will be used 54 ADCSRA |= (1 << ADEN); // enable ADC 55 ADCSRA |= (1 << ADSC); // start ADC measurements 56 57// set Timer2 to fast PWM, no prescaling, inverted pin 3 58// in this sketch only the overflow flag of Timer2 will be used to trigger the reading frequency. 59 TCCR2A = 0; 60 TCCR2B = 0; 61 TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(COM2B0) | _BV(WGM21) | _BV(WGM20); 62 TCCR2B = _BV(CS20); 63 64 delay(1000); 65 pinMode(8, OUTPUT); //for testing a square wave signal will be produced on pin 8 66 Serial.println("end setup"); 67 delay(1000); 68} 69 70const byte maxData = 255; //this value could be chosen larger if desired 71byte data[maxData]; //here the data will be stored 72unsigned long int t0 = 0; //(t1-t0)/255 should be equal to 1/77000*1000000 (otherwise the execution time of the actions is to large). 73unsigned long int t1 = 0; 74 75bool state = 0; //state of output at pin 8 76 77void loop() { 78 t0 = micros(); 79 80 TIFR2 = TIFR2 | _BV(TOV2); //reset overflow flag 81 82 for (int i=0; i<maxData; i++) { 83 data[i] = ADCH; //read the analog value and store in memory 84 PORTB = byte(state); //this statement puts the square wave at pin 8 (pin 8 is the least significant bit of PORTB) 85 if((i&B00000111) == 0) {state = !state;} /* prescaler to set frequency of square wave at pin 8: 86 * B00111111 = 64 B00011111=32 B00001111=16 B00000111=8, frequency will be: Timer2Freq/(prescaler*2) 87 */ 88 89 /* More statements could be put here. Perhaps data could be written to SD card, but I did not test if writing of one character to SD card 90 * can be performed in the little time available here 91 */ 92 93 while((TIFR2 & _BV(TOV2)) == 0) { 94 ; //wait for timer overflow flag 95 } 96 TIFR2 = TIFR2 | _BV(TOV2); //reset overflow flag 97 } 98 99 t1 = micros(); 100 101 Serial.println(t0); 102 Serial.println(t1); 103 Serial.println(t1-t0); 104 105 for (int i=0; i<maxData; i++) { 106 Serial.println(data[i]); 107 } 108 109 makeGraph(maxData); 110 delay(2000); 111} 112 113//make a Graph on the Serial monitor 114void makeGraph(byte numData) { 115 116 const byte horLineInt = 8; 117 const byte verLineInt = 16; 118 const byte y_offset = 32; 119 120 const byte screenHeight = 64; 121 const byte screenWidth = 128; 122 if(numData<screenWidth) {numData = screenWidth;} //only data that fit on the screen will be shown 123 124 125 for (byte y=0; y<=screenHeight; y++) { //each line, starting at bottom of the graph 126 for (byte t=0; t<numData; t++) { //each character, starting from left to right 127 char character = ' '; //put a space 128 if (t%verLineInt == 0) { 129 character = '|'; //put a vertical line for the grid on regular intervals 130 } 131 if ((screenHeight-y-y_offset)%horLineInt == 0) { 132 character = '-'; //put a horizontal line for the grid on regular intervals 133 if (y == y_offset) { 134 character = 'o'; //put a horizontal line with zeros in the grid 135 } 136 if (t%verLineInt == 0) { 137 character = '+'; //put a '+' where horizontal and vertical grid lines meet 138 } 139 } 140 if (round(data[t]/4.0) == screenHeight-y) { 141 character = 'x'; //if data point supposed to be here, then put an 'x' 142 } 143 Serial.print(character); //put the character on the Serial Monitor 144 } 145 Serial.println(); //next line 146 } 147 Serial.println("+---------------+ = 128 micro sec"); //add horizontal scale dimenstion 148 // 01234567890123456 149 Serial.println("Full scale on vertical axis is -5V to 0V to +5V"); //add vertical scale data 150} 151 152 153
Downloadable files
RC filter used for demo.
Shapes square wave of pin 8. Resulting signal is fed into pin A0.
RC filter used for demo.
Comments
Only logged in users can leave comments
ArduinoKoen
0 Followers
•0 Projects
Table of contents
Intro
2
0