New test.
I have found that if I increase the ADC frequency a little above what is recommended, the outputs are even more stable.
I have increased the samples per cycle to 32. I had to modify the program a bit. It is now more flexible. I have also added a name for one “magic number”. The program works well measuring inductances, capacitors and resistors. Although it still has more error than I would like.
/*
Version 4.3 (11/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.
*/
#include <stdint.h>
#define CLK_BOARD 16000000
#define UART_BAUDS 115200
#define MEASURE_TIME 1
#define SAMPLES_PER_WAVE 32
#define PIN_SIGNAL_OUT 3
#define PIN_DEBUG_OUT 5
#define PIN_ANALOG A6
#define PIN_ANALOG_MUX 6
#define PIN_SCK 13
#define PIN_SDI 12
#define PIN_CNV 10
#define TIMER2_PERIOD 220
#define TIMER2_FREQ (CLK_BOARD / ((TIMER2_PERIOD + 1) * 64 * 2))
#define TIMER0_PERIOD (110 - 1)
#define TIMER0_PHASE_ADJUST (-20)
#define TIMER0_FREQ (CLK_BOARD / ((TIMER0_PERIOD + 1) * 8))
#define SAMPLES_PER_MEASURE (SAMPLES_PER_WAVE * (long) ((MEASURE_TIME) * (TIMER0_FREQ) / SAMPLES_PER_WAVE))
const int16_t SIN_INTEGER[SAMPLES_PER_WAVE + SAMPLES_PER_WAVE / 4] = {
5,14,23,31,38,43,47,49,
49,47,43,38,31,23,14,5,
-5,-14,-23,-31,-38,-43,-47,-49,
-49,-47,-43,-38,-31,-23,-14,-5,
5,14,23,31,38,43,47,49,
};
const float BOARD_CALIBRATION = 0.5040 / (SAMPLES_PER_MEASURE); // Converts measure to milliohms
volatile int32_t adc_acc_inphase;
volatile int32_t adc_acc_quadrature;
volatile int16_t adc_samples;
volatile uint8_t adc_measuring;
volatile uint8_t level_state;
volatile uint8_t level_state_old;
float resistance_inphase;
float resistance_quadrature;
void setup() {
Serial.begin(UART_BAUDS);
// Set up output reference signal pin
pinMode(PIN_SIGNAL_OUT, OUTPUT);
pinMode(PIN_DEBUG_OUT, OUTPUT);
// Print initial info
print_info();
// Set up peripherals
timer0_setup();
timer2_setup();
timer_synchronize();
adc_setup();
// Inits measure
measure_init();
while (adc_measuring == 1);
measure_init();
}
void loop() {
// Main Loop
while (1) {
if (adc_measuring == 0) {
resistance_inphase = -adc_acc_inphase;
resistance_quadrature = -adc_acc_quadrature;
resistance_inphase *= BOARD_CALIBRATION;
resistance_quadrature *= BOARD_CALIBRATION;
print_values(resistance_inphase, resistance_quadrature);
measure_init();
}
}
}
void print_info(void) {
Serial.println();
Serial.print("SAMPLE_FREQUENCY = ");
Serial.print(1.0 * TIMER0_FREQ);
Serial.println(" Hz");
Serial.print("MEASURE_SIGNAL_FREQUENCY = ");
Serial.print(1.0 * TIMER2_FREQ);
Serial.println(" Hz");
Serial.print("SAMPLE_TIME = ");
Serial.print(1.0 * SAMPLES_PER_MEASURE / TIMER0_FREQ);
Serial.println(" s");
}
void print_values(float resistance_inphase, float resistance_quadrature) {
Serial.print(resistance_inphase, 2);
Serial.print("\tmOhm R \t");
if (resistance_quadrature > 0) {
Serial.print(resistance_quadrature, 2);
Serial.print("\tmOhm Z_L \t");
if (resistance_quadrature > 5.0) {
Serial.print(resistance_quadrature * 1000.0 / (TIMER2_FREQ * 2.0 * 3.1415927));
Serial.println("\tuHenrys");
}
else {
Serial.println();
}
}
else {
Serial.print(-resistance_quadrature, 2);
Serial.print("\tmOhm Z_C \t");
if (resistance_quadrature < -5.0) {
Serial.print(1000000000.0 / (-resistance_quadrature * TIMER2_FREQ * 2.0 * 3.1415927));
Serial.println("\tuFarads");
}
else {
Serial.println();
}
}
}
void adc_setup(void) {
analogRead(PIN_ANALOG);
cli(); // Stop interrupts
ADMUX = (1 << 6) |
(0 << ADLAR) |
(PIN_ANALOG_MUX << 0);
ADCSRA = (1 << ADEN) |
(0 << ADSC) |
(0 << ADATE) |
(0 << ADIE) |
(0b110); // Division factor
ADCSRB = 0x00;
sei(); // Allow interrupts
}
void measure_init(void) {
delayMicroseconds(1000);
cli();
adc_acc_inphase = 0;
adc_acc_quadrature = 0;
level_state = SAMPLES_PER_WAVE * 0.25;
level_state_old = 0;
adc_samples = 0;
ADCW = 0;
sei();
while ((PIND & (1 << PIN_SIGNAL_OUT)) != 0);
while ((PIND & (1 << PIN_SIGNAL_OUT)) == 0);
adc_measuring = 1;
}
void timer0_setup(void) {
cli(); // Stop interrupts
// set compare match register
TCCR0A = (0 << 6) | // OOM0A. 0=OC0A disconnected. 1=Toggle OC0A on compare match (p.84)
(0 << 4) | // COM0B. 0=OC0B disconnected. 1=Toggle OC0B on compare match (p.85)
(2 << 0); // WGM0. PWM mode. 1=phase correct 2=CTC (p.86)
TCCR0B = (0 << 7) | // FOC0A.
(0 << 6) | // FOC0B.
(0 << 3) | // WGM02.
(2 << 0); // CLOCK source.
OCR0A = TIMER0_PERIOD;
OCR0B = TIMER0_PERIOD / 2;
TIMSK0 = (0 << 2) | // OCIE0B. Match B Interrupt Enable
(1 << 1) | // OCIE0A. Match A Interrupt Enable
(0 << 0); // TOIE0. Overflow Interrupt Enable
TIFR0 = 0;
TCNT0 = 0; // Initialize Timer0 counter
sei(); // Allow interrupts
}
void timer2_setup(void) {
cli(); // Stop interrupts
TCCR2A = (1 << 6) | // OOM2A. 0=OC2A disconnected. 1=Toggle OC2A on compare match (p.128)
(2 << 4) | // COM2B. 2=Clear OC2B on compare match (p.129)
(1 << 0); // WGM2. PWM mode. 1=phase correct (p.130)
TCCR2B = (0 << 7) | // FOC2A.
(0 << 6) | // FOC2B.
(1 << 3) | // WGM22.
(4 << 0); // CLOCK source.
OCR2A = TIMER2_PERIOD;
OCR2B = TIMER2_PERIOD / 2;
TIMSK2 = (0 << 2) | // OCIE2B. Match B Interrupt Enable
(0 << 1) | // OCIE2A. Match A Interrupt Enable
(0 << 0); // TOIE2. Overflow Interrupt Enable
TIFR2 = 0;
TCNT2 = 0; // Initialize Timer2 counter
sei(); // Allow interrupts
}
void timer_synchronize(void) {
cli(); // Stop interrupts
while ((PIND & (1 << PIN_SIGNAL_OUT)) != 0);
while ((PIND & (1 << PIN_SIGNAL_OUT)) == 0);
GTCCR = (1 << TSM) | (1 << PSRASY) | (1 << PSRSYNC); // halt all timers
TCNT0 = TIMER0_PERIOD / 2 + TIMER0_PHASE_ADJUST; // Initialize Timer0 counter
GTCCR = 0; // release all timers
sei(); // Allow interrupts
}
// Timer0 interrupt handler
ISR(TIMER0_COMPA_vect) {
int16_t adc_value;
if (adc_measuring == 1) {
// ADC Start Conversion
ADCSRA |= (1 << ADSC);
// Read last conversion
adc_value = ADCW;
// Accumulate values (10us)
adc_acc_inphase += (int32_t) adc_value * SIN_INTEGER[level_state_old];
adc_acc_quadrature += (int32_t) adc_value * SIN_INTEGER[level_state_old + SAMPLES_PER_WAVE / 4];
// Update next state
level_state_old = level_state;
level_state++;
if (level_state >= SAMPLES_PER_WAVE)
level_state = 0;
adc_samples++;
if (adc_samples > SAMPLES_PER_MEASURE) {
adc_measuring = 0;
}
}
}
// Timer2 interrupt handler
ISR(TIMER2_COMPA_vect) {
}
void debug_pin_pulse(void) {
PORTD |= (1 << PIN_DEBUG_OUT);
delayMicroseconds(4);
PORTD &= ~(1 << PIN_DEBUG_OUT);
}
Measuring a cable:
SAMPLE_FREQUENCY = 18181.00 Hz
MEASURE_SIGNAL_FREQUENCY = 565.00 Hz
SAMPLE_TIME = 1.00 s
71.26 mOhm R 1.62 mOhm Z_C
71.19 mOhm R 1.77 mOhm Z_C
71.28 mOhm R 1.70 mOhm Z_C
71.39 mOhm R 1.63 mOhm Z_C
71.27 mOhm R 1.68 mOhm Z_C
71.21 mOhm R 1.49 mOhm Z_C
71.31 mOhm R 1.62 mOhm Z_C
71.18 mOhm R 1.51 mOhm Z_C
71.39 mOhm R 1.58 mOhm Z_C
71.10 mOhm R 1.66 mOhm Z_C
71.15 mOhm R 1.53 mOhm Z_C
71.17 mOhm R 1.50 mOhm Z_C
71.26 mOhm R 1.47 mOhm Z_C
71.15 mOhm R 1.52 mOhm Z_C
71.35 mOhm R 1.73 mOhm Z_C
71.22 mOhm R 1.67 mOhm Z_C
71.14 mOhm R 1.55 mOhm Z_C
71.07 mOhm R 1.41 mOhm Z_C
71.24 mOhm R 1.71 mOhm Z_C
71.31 mOhm R 1.45 mOhm Z_C
71.07 mOhm R 1.44 mOhm Z_C
71.19 mOhm R 1.59 mOhm Z_C
71.16 mOhm R 1.69 mOhm Z_C
71.16 mOhm R 1.51 mOhm Z_C
71.15 mOhm R 1.73 mOhm Z_C
71.25 mOhm R 1.66 mOhm Z_C
71.04 mOhm R 1.71 mOhm Z_C
71.07 mOhm R 1.77 mOhm Z_C
Measuring an inductance:
SAMPLE_FREQUENCY = 18181.00 Hz
MEASURE_SIGNAL_FREQUENCY = 565.00 Hz
SAMPLE_TIME = 1.00 s
25.11 mOhm R 198.29 mOhm Z_L 55.86 uHenrys
25.00 mOhm R 198.23 mOhm Z_L 55.84 uHenrys
24.96 mOhm R 198.24 mOhm Z_L 55.84 uHenrys
25.05 mOhm R 198.28 mOhm Z_L 55.85 uHenrys
25.06 mOhm R 198.04 mOhm Z_L 55.79 uHenrys
25.00 mOhm R 198.28 mOhm Z_L 55.85 uHenrys
24.98 mOhm R 198.09 mOhm Z_L 55.80 uHenrys
25.01 mOhm R 198.22 mOhm Z_L 55.84 uHenrys
25.06 mOhm R 198.16 mOhm Z_L 55.82 uHenrys
25.08 mOhm R 198.15 mOhm Z_L 55.82 uHenrys
24.97 mOhm R 198.34 mOhm Z_L 55.87 uHenrys
24.96 mOhm R 198.33 mOhm Z_L 55.87 uHenrys
24.86 mOhm R 198.09 mOhm Z_L 55.80 uHenrys
25.03 mOhm R 198.13 mOhm Z_L 55.81 uHenrys
25.00 mOhm R 198.29 mOhm Z_L 55.86 uHenrys
25.10 mOhm R 198.17 mOhm Z_L 55.82 uHenrys
25.02 mOhm R 198.02 mOhm Z_L 55.78 uHenrys
25.10 mOhm R 198.40 mOhm Z_L 55.89 uHenrys
25.08 mOhm R 198.21 mOhm Z_L 55.83 uHenrys
25.02 mOhm R 198.21 mOhm Z_L 55.83 uHenrys
25.07 mOhm R 198.04 mOhm Z_L 55.79 uHenrys
25.01 mOhm R 198.15 mOhm Z_L 55.82 uHenrys
24.99 mOhm R 198.16 mOhm Z_L 55.82 uHenrys
24.97 mOhm R 198.28 mOhm Z_L 55.85 uHenrys
24.87 mOhm R 198.05 mOhm Z_L 55.79 uHenrys
24.90 mOhm R 198.02 mOhm Z_L 55.78 uHenrys
24.87 mOhm R 198.26 mOhm Z_L 55.85 uHenrys
25.01 mOhm R 198.29 mOhm Z_L 55.86 uHenrys
Measuring a capacitor:
SAMPLE_FREQUENCY = 18181.00 Hz
MEASURE_SIGNAL_FREQUENCY = 565.00 Hz
SAMPLE_TIME = 1.00 s
107.67 mOhm R 322.08 mOhm Z_C 874.60 uFarads
107.67 mOhm R 321.94 mOhm Z_C 874.98 uFarads
107.60 mOhm R 321.87 mOhm Z_C 875.15 uFarads
107.64 mOhm R 322.09 mOhm Z_C 874.57 uFarads
107.53 mOhm R 321.84 mOhm Z_C 875.24 uFarads
107.52 mOhm R 322.13 mOhm Z_C 874.47 uFarads
107.47 mOhm R 321.90 mOhm Z_C 875.10 uFarads
107.62 mOhm R 321.91 mOhm Z_C 875.07 uFarads
107.41 mOhm R 321.94 mOhm Z_C 874.98 uFarads
107.52 mOhm R 322.02 mOhm Z_C 874.75 uFarads
107.48 mOhm R 322.00 mOhm Z_C 874.82 uFarads
107.60 mOhm R 321.84 mOhm Z_C 875.26 uFarads
107.47 mOhm R 321.93 mOhm Z_C 875.00 uFarads
107.48 mOhm R 321.68 mOhm Z_C 875.67 uFarads
107.34 mOhm R 321.85 mOhm Z_C 875.22 uFarads
107.38 mOhm R 321.95 mOhm Z_C 874.94 uFarads
107.45 mOhm R 321.84 mOhm Z_C 875.26 uFarads
107.48 mOhm R 321.93 mOhm Z_C 875.01 uFarads
107.21 mOhm R 321.91 mOhm Z_C 875.06 uFarads
107.28 mOhm R 321.87 mOhm Z_C 875.16 uFarads
107.61 mOhm R 321.83 mOhm Z_C 875.29 uFarads
107.34 mOhm R 321.89 mOhm Z_C 875.11 uFarads
107.44 mOhm R 321.96 mOhm Z_C 874.93 uFarads
107.28 mOhm R 321.81 mOhm Z_C 875.34 uFarads
107.29 mOhm R 321.88 mOhm Z_C 875.14 uFarads
107.38 mOhm R 321.86 mOhm Z_C 875.19 uFarads