Sorry if this is a bit long, but it is probably better to have all the code rather than just some of it.
This code is meant to output a sine-wave and synchronously measure the induced voltage in a pair of secondary coils.
Because it is AC coupled I need to subtract the zero-volts ADC counts from the measured voltage. To do this I populate an array with the ADC counts of all 6 channels in the setup() function before activating the sine wave
My problem is that the first value in the array (Z[0]) doesn't stay static. In the incuded code it is Serial.print-ed and it changes just like the V[0] does when I twiddle the test-rig potentiometer.
I have checked that the setup() function isn't running continuously. I am probably missing something obvious, but I am truly baffled.
(Incidentally, I know that I am measuring 6 values and using 2, the code isn't finished)
#include "avr/pgmspace.h"
// table of 256 sine values / one sine period / stored in flash memory
PROGMEM prog_uchar sine256[] = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
};
PROGMEM prog_uchar arctan256[] = {
0,0,0,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,8,8,9,9,9,9,10,10,10,10,10,11,11,11,11,11,12,12,12,12,13,13,13,13,13,14,14,14,14,14,15,15,15,15,16,16,16,16,16,17,17,17,17,17,
18,18,18,18,18,19,19,19,19,19,20,20,20,20,20,21,21,21,21,21,22,22,22,22,22,22,23,23,23,23,23,24,24,24,24,24,25,25,25,25,25,25,26,26,26,26,26,27,27,27,27,27,27,28,28,28,28,28,29,29,29,29,29,29,30,30,30,30,30,30,
31,31,31,31,31,31,32,32,32,32,32,32,32,33,33,33,33,33,33,34,34,34,34,34,34,35,35,35,35,35,35,35,36,36,36,36,36,36,36,37,37,37,37,37,37,37,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,
41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45
};
byte EP[] = { B00, B01, B11, B10 }; // Encoder pattern
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int ledPin = 13; // LED pin 7
int testPin = 7;
volatile long V[5]; // Analogue values
int Z[5]; // Zero-offset values for each channel
int Q[2]; // Three Quadrature encoders
int A[2]; // Three Angles
long Cos;
long Sin;
volatile byte index; // index to current mux channel
volatile byte icnt; // var inside interrupt
void setup()
{
pinMode(13, OUTPUT); // sets the digital pin as output
Serial.begin(115200); // connect to the serial port
pinMode(6, OUTPUT); // sets the digital pin as output
pinMode(7, OUTPUT); // sets the digital pin as output
pinMode(11, OUTPUT); // pin11= PWM output / frequency output
pinMode(2, OUTPUT); // Encoder 0 Phase A
pinMode(3, OUTPUT); // Encoder 0 Phase B
pinMode(4, OUTPUT); // Encoder 0 Phase Z
//First populate the zero-volt value for each channel
for (int i = 0 ; i <= 5 ; i++) { // iterate through channels
for (int j = 1 ; j<=1000 ; j++) { // 1000 samples should do
V[i] = V[i] + analogRead(i);
}
Z[i] = V[i] / 1000;
V[i] = 0;
Serial.println(Z[i], DEC);
}
Setup_timer2();
// disable interrupts to avoid timing distortion
cbi (TIMSK0,TOIE0); // disable Timer0 !!! delay() is now not available
sbi (TIMSK2,TOIE2); // enable Timer2 Interrupt
SetupADC();
}
void loop()
{
sbi (TIMSK2,TOIE2); // enable Timer2 Interrupt
while(1) {
Cos = V[0] - Z[0];
Sin = V[1] - Z[1];
A[0] = arctan(Cos, Sin);
Serial.println(Z[0], DEC);
// Count till the Quadrature counter equals the angle
if ((Q[0] - A[0]) > 120 || (Q[0] - A[0]) < 0)
{
Q[0]++ ;
}
else if ((A[0] - Q[0]) > 120 || (A[0] - Q[0]) < 0)
{
Q[0]-- ;
}
Q[0] = Q[0] % 360 ;
// Set the encoder bits accordingly
if (Q[0] == 0) sbi(PORTD, 4);
else cbi(PORTD,4);
if (EP[Q[0] & 3] & 1) sbi(PORTD, 2);
else cbi(PORTD,2);
if (EP[Q[0] & 3] & 2) sbi(PORTD, 3);
else cbi(PORTD,3);
}
}
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/510 = 31372.55 Hz clock
void Setup_timer2() {
// Timer2 Clock Prescaler to : 1
sbi (TCCR2B, CS20);
cbi (TCCR2B, CS21);
cbi (TCCR2B, CS22);
// Timer2 PWM Mode set to Phase Correct PWM
cbi (TCCR2A, COM2A0); // clear Compare Match
sbi (TCCR2A, COM2A1);
sbi (TCCR2A, WGM20); // Mode 1 / Phase Correct PWM
cbi (TCCR2A, WGM21);
cbi (TCCR2B, WGM22);
}
//Setup ADC
void SetupADC() {
cbi(ADMUX, REFS1);
sbi(ADMUX, REFS0); // Internal AREF (5V)
cbi(ADMUX, ADLAR); // Not left-aligned
cbi(ADMUX, MUX3);
cbi(ADMUX, MUX2);
cbi(ADMUX, MUX1);
cbi(ADMUX, MUX0); // Set the Mux to zero to begin
sbi(ADCSRA, ADEN); // Enable the ADC
cbi(ADCSRA, ADSC); // Don't start conversion yet
cbi(ADCSRA, ADATE); // No auto-trigger
cbi(ADCSRA, ADIF); // Not sure if that is possible or wise
sbi(ADCSRA, ADIE); // Conversion-complete Interrupt to process data
cbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0); // Fastest possible ADC clock. Probably not ideal.
}
//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {
sbi(PORTD,7); // Test / set PORTD,7 high to observe timing with a oscope
icnt=icnt+16; // use upper 8 bits for phase accu as frequency information
// read value fron ROM sine table and send to PWM DAC
OCR2A=pgm_read_byte_near(sine256 + icnt);
if (icnt == 96) {
sbi(ADCSRA, ADSC); // Start Conversion
sbi(PORTB,5); // LED on to show start of conversion
}
cbi(PORTD,7); // reset PORTD,7
}
// ADC Conversion Complete Interrupt
ISR(ADC_vect) {
V[index] = ADCL | ADCH<<8; //get the data
if (++index > 5) index = 0; // increment the ADC channel number with wrap
ADMUX = (ADMUX & B11110000) | index; // set the ADC channel
cbi(PORTB,5); // Reset Pin13 to show end of conversion
}
int arctan(long V1, long V2) {
//Handle the quadrants explicitly
if (V1 < 0)
{
if (V2 < 0)
{
if (V1 < V2) // 180-225
{
return 180 + pgm_read_byte_near(arctan256 + 256 * V2 / V1);
}
else // 225-270
{
return 270 - pgm_read_byte_near(arctan256 + 256 * V1 / V2);
}
}
else // V2 => 0
{
if (-V1 < V2) // 90-135
{
return 90 + pgm_read_byte_near(arctan256 - 256 * V2 / V1);
}
else // 135-180
{
return 180 - pgm_read_byte_near(arctan256 - 256 * V2 / V1);
}
}
}
else // V1 => 0
{
if (V2 < 0)
{
if (V1 < -V2) // 270-315
{
return 270 + pgm_read_byte_near(arctan256 - 256 * V1 / V2);
}
else // 315-360
{
return 360 - pgm_read_byte_near(arctan256 - 256 * V2 / V1);
}
}
else // V2 => 0
{
if (V1 < V2) // 45-90
{
return 90 - pgm_read_byte_near(arctan256 + 256 * V1 / V2);
}
else // 0-45
{
return pgm_read_byte_near(arctan256 + 256 * V2 / V1);
}
}
}
}