3
« Last post by Picuino on Today at 08:53:30 pm »
I have corrected a software problem that caused some ADC conversions to be lost. The ADC conversion now starts at the beginning of the interrupt routine so that there are no delays with overlapping ADC conversions.
It is tested and works better than before.
Arduino program Version 1.0:
/*
Version 1.0 (04/05/2024)
Copyright 2024 Picuino
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
const int PIN_PWM_OUT = 3;
const int PIN_ANALOG = A0;
#define CLK_BOARD 16000000
#define UART_BAUDS 9600
#define TIMER0_PRESET 26 // Must be >= 26
#define TIMER0_FREQ (CLK_BOARD / (((TIMER0_PRESET) + 1) * 64))
const int SAMPLES_PER_LEVEL = 20;
const int LEVELS_PER_MEASURE = TIMER0_FREQ / (SAMPLES_PER_LEVEL * 2);
const float BOARD_CALIBRATION = 4.0;
volatile long adc_sum;
volatile unsigned int adc_enable;
volatile unsigned int adc_value;
volatile unsigned int adc_samples;
volatile unsigned int timer0_state;
volatile unsigned char output_level;
volatile unsigned char output_level_old;
volatile unsigned char adc_measure_end;
void setup() {
Serial.begin(UART_BAUDS);
// Set up output reference signal pin
pinMode(PIN_PWM_OUT, OUTPUT);
// Set up peripherals
timer0_setup();
adc_setup();
// Main Loop
float resistance;
adc_init();
for (;;) {
if (adc_measure_end == 1) {
resistance = adc_sum;
resistance = resistance * (BOARD_CALIBRATION / (1.0 * SAMPLES_PER_LEVEL * LEVELS_PER_MEASURE));
Serial.println(resistance);
adc_init();
}
}
}
void loop() {}
void adc_init(void) {
adc_measure_end = 0;
adc_sum = 0;
timer0_state = 0;
adc_samples = 0;
PORTD |= (1 << PIN_PWM_OUT);
output_level = 1;
output_level_old = 1;
delayMicroseconds(200);
adc_enable = 1;
}
void adc_setup(void) {
analogRead(PIN_ANALOG);
cli(); //stop interrupts
ADMUX = (1 << 6) | (0 << ADLAR);
ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIE) | (0b111);
ADCSRB = 0x00;
sei(); //allow interrupts
}
void timer0_setup(void) {
cli(); //stop interrupts
//set timer0 interrupt at 2kHz
TCCR0A = 0; // set entire TCCR2A register to 0
TCCR0B = 0; // same for TCCR2B
TCNT0 = 0; //initialize counter value to 0
// set compare match register
OCR0A = TIMER0_PRESET;
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS01 and CS00 bits for 64 prescaler
TCCR0B |= (1 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei(); //allow interrupts
}
ISR(TIMER0_COMPA_vect) {
if (adc_enable) {
// ADC Start Conversion
ADCSRA |= (1 << ADSC);
adc_samples++;
delayMicroseconds(15); // Wait for Sample and Hold
// Read and accumulate old ADC value
if (adc_samples) {
// Read ADC old measure
adc_value = ADCW;
// Add measure to accumulator
if (output_level_old == 1) {
adc_sum -= adc_value;
}
if (output_level_old == 0) {
adc_sum += adc_value;
}
}
// Update next state
if (++timer0_state >= (SAMPLES_PER_LEVEL * 2)) {
timer0_state = 0;
}
// Update output reference signal
output_level_old = output_level;
if (timer0_state < SAMPLES_PER_LEVEL) {
PORTD |= (1 << PIN_PWM_OUT);
output_level = 1;
}
else {
PORTD &= ~(1 << PIN_PWM_OUT);
output_level = 0;
}
// Take one measure after several samples
if (adc_samples > SAMPLES_PER_LEVEL * LEVELS_PER_MEASURE * 2) {
adc_measure_end = 1;
adc_enable = 0;
}
}
}
Output measures:
22.57
22.48
22.52
22.50
22.43
22.49
22.40
22.41
22.54
22.35
22.38
22.54
22.53
22.51
22.40
22.35
22.40
22.45
22.48
22.52
22.53
22.44
22.51
22.40
22.41
22.47
22.42
22.53
22.48
22.30
22.35
22.49
22.42
22.41
22.52
22.41
22.35
22.33
22.36
22.38
22.37
22.46
22.49
22.47
22.41
22.38
22.41
22.43
22.55
22.32
22.39
22.46
22.19
22.48
22.34
22.36
22.40
22.37
22.40
22.45
I think that this time I have managed to recover part of the signal “buried” in the noise.
Attached: Vout