Advertisement
Guest User

ADC

a guest
Jun 9th, 2015
480
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.69 KB | None | 0 0
  1. /**
  2.  * \brief       ADC 8-bit fast reading of multiple channels for Arduino/ATMega328P
  3.  * \file        adc_speedtest.c
  4.  * \author      Cristian Dobre
  5.  * \version         1.0.1
  6.  * \date        April 2015
  7.  * \copyright       Revised BSD License.
  8.  */
  9.  
  10.  
  11. /**
  12.  * ADC VARIABLES
  13.  * Modify to change analog-to-digital conversion
  14.  */
  15. #define ADC_SENSOR_CHANNELS 8
  16. #define ADC_SENSOR_SAMPLES 6
  17.  
  18. /**  ADC MULTIPLEXER BITS  **/
  19. #define CHN_ADC0 0000
  20. #define CHN_ADC1 0001
  21. #define CHN_ADC2 0010
  22. #define CHN_ADC3 0011
  23. #define CHN_ADC4 0100
  24. #define CHN_ADC5 0101
  25. #define CHN_ADC6 0110
  26. #define CHN_ADC7 0111
  27.  
  28. /**  BIT JOIN TO UINT32  **/
  29. #define ADC_CHN_BIT_CONST( Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7 ) ( 0b ## Q0 ## Q1 ## Q2 ## Q3 ## Q4 ## Q5 ## Q6 ## Q7 )
  30. #define ADC_CHN_BIT_EVAL( Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7 ) ADC_CHN_BIT_CONST( Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7 )
  31. #define ADC_CHN_BIT_COMBINE( Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7 ) ADC_CHN_BIT_EVAL( Q7, Q6, Q5, Q4, Q3, Q2, Q1, Q0 )
  32.  
  33.  
  34. /**
  35.  * ADC SENSOR CHANNELS
  36.  * Analog sensor channels, in order of reading
  37.  */
  38. static const uint32_t adc_channel_mux_bits = ADC_CHN_BIT_COMBINE( CHN_ADC0, CHN_ADC1, CHN_ADC2, CHN_ADC3, CHN_ADC4, CHN_ADC5, CHN_ADC6, CHN_ADC7 );
  39.  
  40.  
  41. /**  ADC CONVERSION VARIABLES  **/
  42. volatile uint8_t adc_channel_samples = ADC_SENSOR_SAMPLES, adc_channel_index, adc_read_value, adc_reading_samples = 0;
  43. volatile uint8_t adc_channel_value[ ADC_SENSOR_CHANNELS ], *adc_channel_readings;
  44. volatile uint16_t adc_current_sensor_sum;
  45. volatile uint32_t adc_current_channel = adc_channel_mux_bits;
  46.  
  47. /**
  48.  * SETUP ADC READING
  49.  */
  50. volatile uint8_t* setup_adc_sweep( void ){
  51.    
  52.     // set reference to vcc
  53.     ADMUX |= _BV(REFS0);
  54.     ADMUX &= ~(_BV(REFS1));
  55.     // align result to the left, we will only use 8 bits of resolution
  56.     ADMUX |= ( _BV(ADLAR) );
  57.     // enable auto triggering and interrupt on conversion complete
  58.     ADCSRA |= ( _BV(ADIE) );
  59.     // set divider to 8, for fast ADC clock rate
  60.     ADCSRA &= ~( _BV(ADPS2) );
  61.     ADCSRA |= ( _BV(ADPS1) | _BV(ADPS0) );
  62.     // disable digital input buffers
  63.     DIDR0 |= ( _BV(ADC5D) | _BV(ADC4D) | _BV(ADC3D) | _BV(ADC2D) | _BV(ADC1D) | _BV(ADC0D) );
  64.     // enable ADC peripheral
  65.     ADCSRA |= _BV(ADEN);
  66.     // allocate memory for ADC readings
  67.     adc_channel_readings = (uint8_t*) malloc( sizeof(uint8_t) * ADC_SENSOR_CHANNELS );
  68.     return adc_channel_readings;
  69. }
  70.  
  71. /**
  72.  * START ADC SWEEP
  73.  */
  74. void start_adc_sweep( void ){
  75.    
  76.     // reset variables
  77.     adc_channel_samples = ADC_SENSOR_SAMPLES;
  78.     adc_current_channel = adc_channel_mux_bits;
  79.     adc_channel_index = adc_current_sensor_sum = 0;
  80.     // set starting channel
  81.     ADMUX = ((uint8_t)( ADMUX & 0xF0 ) + (uint8_t)( adc_current_channel & 0x0F ));
  82.     // start conversion
  83.     ADCSRA |= _BV(ADSC);   
  84.     // set a fixed number of samples
  85.     adc_reading_samples = ADC_SENSOR_CHANNELS * ( ADC_SENSOR_SAMPLES + 1 );
  86.     // copy the new readings into a stable array
  87.     for( uint8_t i = 0; i < ADC_SENSOR_CHANNELS ; i++ )
  88.         *( adc_channel_readings + i ) = adc_channel_value[ i ];
  89. }
  90.  
  91.  
  92. /**
  93.  * ADC INTERRRUPT
  94.  * Triggered when ADC conversion is complete
  95.  */
  96. ISR( ADC_vect ){
  97.    
  98.     // store the current conversion
  99.     adc_read_value = ADCH;
  100.    
  101.     // check for a channel change
  102.     if( adc_channel_samples != 0 ){
  103.         // start the next conversion
  104.         if( adc_reading_samples != 1 ) ADCSRA |= _BV(ADSC);
  105.         // add up the result
  106.         if( adc_channel_samples != ADC_SENSOR_SAMPLES ) adc_current_sensor_sum += adc_read_value;
  107.         adc_channel_samples--;
  108.     } else {
  109.         // switch to the next channel
  110.         if( adc_current_channel == 0UL ) adc_current_channel = adc_channel_mux_bits;
  111.         else adc_current_channel >>= 4;
  112.         // change ADC channel
  113.         ADMUX = ((uint8_t)( ADMUX & 0xF0 ) + (uint8_t)( adc_current_channel & 0x0F ));
  114.         // start the next conversion
  115.         if( adc_reading_samples != 1 ) ADCSRA |= _BV(ADSC);
  116.         // reset channel samples
  117.         adc_channel_samples = ADC_SENSOR_SAMPLES;
  118.         // calculate and save the mean value
  119.         adc_channel_value[ adc_channel_index ] = (uint8_t)((uint16_t)(( adc_current_sensor_sum + adc_read_value ) / ADC_SENSOR_SAMPLES ));
  120.         // reset the sensor sum
  121.         adc_current_sensor_sum = 0;
  122.         // increase sensor index
  123.         if( ++adc_channel_index == ADC_SENSOR_CHANNELS ) adc_channel_index = 0;
  124.     }
  125.     // decrease total samples counter
  126.     adc_reading_samples--; 
  127. }
  128.  
  129.  
  130. volatile uint8_t *sensors;
  131.  
  132. void setup(){
  133.  
  134.   Serial.begin( 115200 );  
  135.   sensors = setup_adc_sweep();
  136.  
  137. }
  138.  
  139.  
  140. void loop(){
  141.  
  142.   uint32_t _start = micros(), _end;
  143.   start_adc_sweep();
  144.   while( adc_reading_samples != 0 );
  145.   _end = micros();
  146.   Serial.print( "Read in " ); Serial.print( _end - _start ); Serial.print( "us \t" );
  147.   for( uint8_t i = 0; i < ADC_SENSOR_CHANNELS ; i++ ){
  148.     Serial.print( *(sensors+i) ); Serial.print( "\t" );
  149.   }
  150.   Serial.println( "" );
  151.   delay(50);  
  152.    
  153. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement