Adjunto programa con el que estoy trabajando.
Con el PIC18F2550 a 48Mhz no he tenido problemas de velocidad.
Se puede multiplicar la lectura del ADC por el valor del seno y por el valor del coseno con 4 instrucciones de multiplicación de tipo byte muy rápidas (4 ciclos de reloj cada una).
/****************************************************************************
LOCK-IN DIGITAL AMPLIFIER
IMPEDANCE METER
License:
========
Creative Commons Reconocimiento-CompartirIgual 3.0 España License.
Work title: Picuino C Library
Attribute work to name: Picuino
Attribute work to URL: https://sites.google.com/site/picuino
THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. NOBODY SHALL,
IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
****************************************************************************/
/****************************************************************************
GLOBAL INCLUDE AND DEFINITIONS
****************************************************************************/
#include <p18cxxx.h>
#include <stdio.h>
#include <math.h>
#include "rs232.h"
#include "configuration.h"
static unsigned char isr_ticks, isr_go, phi;
/*
Seno(x) adaptado a un byte para la multiplicación
sen[n] = int(127.5 + 127*sen(n*2*pi/32))
Promedio = 127
*/
#define DC 127
#define seno_0 0
#define seno_1 25
#define seno_2 49
#define seno_3 71
#define seno_4 90
#define seno_5 106
#define seno_6 117
#define seno_7 125
#define seno_8 127
const unsigned char seno[] = {
DC + seno_0, DC + seno_1, DC + seno_2, DC + seno_3, DC + seno_4, DC + seno_5, DC + seno_6, DC + seno_7,
DC + seno_8, DC + seno_7, DC + seno_6, DC + seno_5, DC + seno_4, DC + seno_3, DC + seno_2, DC + seno_1,
DC - seno_0, DC - seno_1, DC - seno_2, DC - seno_3, DC - seno_4, DC - seno_5, DC - seno_6, DC - seno_7,
DC - seno_8, DC - seno_7, DC - seno_6, DC - seno_5, DC - seno_4, DC - seno_3, DC - seno_2, DC - seno_1,
};
const unsigned char coseno[] = {
DC + seno_8, DC + seno_7, DC + seno_6, DC + seno_5, DC + seno_4, DC + seno_3, DC + seno_2, DC + seno_1,
DC - seno_0, DC - seno_1, DC - seno_2, DC - seno_3, DC - seno_4, DC - seno_5, DC - seno_6, DC - seno_7,
DC - seno_8, DC - seno_7, DC - seno_6, DC - seno_5, DC - seno_4, DC - seno_3, DC - seno_2, DC - seno_1,
DC + seno_0, DC + seno_1, DC + seno_2, DC + seno_3, DC + seno_4, DC + seno_5, DC + seno_6, DC + seno_7,
};
// sen[n] para producir una tensión de salida en el puerto B Conversor R-2R de 6 bits
// 0 - 63
const unsigned char seno_port[] =
/* {
104, 124, 144, 160, 176, 192, 200, 208,
208, 208, 200, 192, 176, 160, 144, 124,
104, 84, 64, 48, 32, 16, 8, 0,
0, 0, 8, 16, 32, 48, 64, 84,
}; */
{
124, 148, 172, 192, 212, 228, 240, 244,
248, 244, 240, 228, 212, 192, 172, 148,
124, 100, 76, 56, 36, 20, 8, 4,
0, 4, 8, 20, 36, 56, 76, 100,
};
/****************************************************************************
INTERRUPT SERVICE ROUTINE
****************************************************************************/
#pragma interrupt isr_low_main
void isr_low_main(void) {
// Timer2 interrupt counter
if (PIR1bits.TMR2IF == 1) {
PIR1bits.TMR2IF = 0;
if (--isr_ticks==0) {
isr_ticks = 3;
isr_go = 1;
// Compute next output signal
phi++;
phi &= 0x1F;
PORTB = seno_port[phi];
// ADC Hold and Start Analog-Digital conversion
ADCON0bits.GO = 1;
}
}
}
#pragma code high_vector=0x08
void isr_high(void) {
_asm GOTO isr_low_main _endasm
}
#pragma code low_vector=0x18
void isr_low(void) {
_asm GOTO isr_low_main _endasm
}
/****************************************************************************
PROGRAM FUNCTIONS
****************************************************************************/
#pragma code
/*
Timer 2 configure and reset
*/
void timer2_init(void) {
TMR2 = 0;
T2CON = (unsigned char)
(0<<3) // postscaler
// 0 = 1:1 postscaler
// 1 = 1:2 postscaler
// 15 = 1:16 postscaler
+(1<<2) // TMR2ON: 1 = Timer2 is on
+(0b00); // T2CKPS: Timer2 Clock Prescale Select bits
// 1x = 1:16 Prescaler value
// 01 = 1:4 Prescaler value
// 00 = 1:1 Prescaler value
PR2 = 124; // PWM Period = [(PR2) + 1] • TCY •(TMR2 Prescale Value)]
PIR1bits.TMR2IF = 0;
PIE1bits.TMR2IE = 1;
IPR1bits.TMR2IP = 0;
}
/*
Init ADC
Select input pin to sample and hold circuit
*/
void adc_init(unsigned char channel) {
// Configure ADC
ADCON0 = 0b00000001 + (channel<<2); // ADC on. Select channel
ADCON1 = 0b00000000; // Analog inputs
ADCON2 = (unsigned char)
(1<<7) // ADFM: 0 = Result Left justified
+(2<<3) // ACQT2: A/D Acquisition Time
// 7 = 20 Tad
// 6 = 16 Tad
// 5 = 12 Tad
// 4 = 8 Tad
// 3 = 6 Tad
// 2 = 4 Tad
// 1 = 2 Tad
// 0 = 0 Tad
+(6); // ADCS2: A/D Conversion Clock
// 7 = Frc
// 6 = Fosc/64
// 5 = Fosc/16
// 4 = Fosc/4
// 3 = Frc
// 2 = Fosc/32
// 1 = Fosc/8
// 0 = Fosc/2
}
/* Print float number with sign */
void print_float(static float num) {
if (num<0)
printf ("-%lu\t", (long)-num);
else
printf ("%lu\t", (long)num);
}
/* Compute modulo of a vector */
float modulo(static float x, static float y) {
return sqrt(x*x + y*y);
}
/* Compute angle of a vector */
float angle(static float x, static float y) {
if (x == 0) {
if (y > 0) return 3.141592654/2.0;
else return -3.141592654/2.0;
}
return atan(y/x);
}
/****************************************************************************
MAIN PROGRAM
****************************************************************************/
void main(void) {
static float Vz_re, Vz_im, Vz_mod, Vz_phi;
static float Vr_re, Vr_im, Vr_mod, Vr_phi;
static float Z_re, Z_im, Z_mod, Z_phi;
static unsigned char sen, cos;
static unsigned int counter, samples;
static long seno_mul_sum, seno_mul_sum2;
static long coseno_mul_sum, coseno_mul_sum2;
static long vin_sum;
static union {
unsigned int word;
struct {
unsigned char lob;
unsigned char hib;
};
} mul, vin;
// Peripheral config
TRISB = 0b00000011; // Digital to Analog output
TRISA = 0b11111111;
rs232_init();
adc_init(ANALOG_RA0_CHANNEL);
timer2_init();
// Interrupt config
RCONbits.IPEN = 0;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
rs232_puts("System OK\n");
samples = 32*1024;
// Main loop
while(1) {
counter = samples;
seno_mul_sum = seno_mul_sum2 = 0;
coseno_mul_sum = coseno_mul_sum2 = 0;
vin_sum = 0;
TRISCbits.TRISC0 = 0;
// wait first step and read ADC
while(phi!=0);
while(ADCON0bits.GO == 1);
vin.lob = ADRESL;
vin.hib = ADRESH;
// Compute 32*1024 samples
do {
// wait next step
isr_go = 0;
while(isr_go==0);
// Compute sen, cos and Increment pointers
sen = seno[phi];
cos = coseno[phi];
// Lock-in detector
vin_sum += vin.word;
// Compute Vin * sen
mul.lob = vin.lob * sen;
mul.hib = PRODH;
seno_mul_sum += (unsigned long)mul.word;
mul.lob = vin.hib * sen;
mul.hib = PRODH;
seno_mul_sum2 += (unsigned long)mul.word;
// Compute Vin * cos
mul.lob = vin.lob * cos;
mul.hib = PRODH;
coseno_mul_sum += (unsigned long)mul.word;
mul.lob = vin.hib * cos;
mul.hib = PRODH;
coseno_mul_sum2 += (unsigned long)mul.word;
// Read Analog-Digital conversion
while(ADCON0bits.GO == 1);
vin.lob = ADRESL;
vin.hib = ADRESH;
} while(--counter);
// Add low mul and high mul
seno_mul_sum += seno_mul_sum2<<8;
coseno_mul_sum += coseno_mul_sum2<<8;
// Compute X,Y components without DC
Vz_re = seno_mul_sum - (vin_sum*127);
Vz_im = coseno_mul_sum - (vin_sum*127);
// print results
printf ("\r\n");
#define VZ_CORRECTION 0.99099*0.9875
Vz_re *= VZ_CORRECTION*2.0*5.0/(1024.0*127.0*32.0*1024.0*1.41421);
Vz_im *= VZ_CORRECTION*2.0*5.0/(1024.0*127.0*32.0*1024.0*1.41421);
Vz_phi = angle(Vz_re, Vz_im)-(16.780*3.1415927/180.0);
Vz_mod = modulo(Vz_re, Vz_im);
Vz_re = Vz_mod * sin(Vz_phi+1.570796327);
Vz_im = Vz_mod * sin(Vz_phi);
//printf ("Vz_re=\t"); print_float(Vz_re*10000.0);
//printf ("Vz_im=\t"); print_float(Vz_im*10000.0);
printf ("Vz_mod=\t"); print_float(Vz_mod*1000.0);
printf ("Vz_phi=\t"); print_float(Vz_phi*(1000.0*180.0/3.1415927));
Vr_re = 0.8002 - Vz_re;
Vr_im = 0.0000 - Vz_im;
Vr_mod = modulo(Vr_re, Vr_im);
Vr_phi = angle(Vr_re, Vr_im);
printf ("Vr_mod=\t"); print_float(Vr_mod*1000.0);
printf ("Vr_phi=\t"); print_float(Vr_phi*(1000.0*180.0/3.1415927));
Z_mod = 990.0 * Vz_mod / Vr_mod;
Z_phi = Vz_phi - Vr_phi;
Z_re = Z_mod * sin(Z_phi+1.570796327);
Z_im = Z_mod * sin(Z_phi);
//printf ("Z_mod=\t"); print_float(Z_mod*10.0);
//printf ("Z_phi=\t"); print_float(Z_phi*(100.0*180.0/3.1415927));
printf ("R=\t"); print_float(Z_re*10.0);
printf ("Zc=\t"); print_float(Z_im*10.0);
Z_im = 1000000000.0/(6283.1853*Z_im);
printf ("C[nF]=\t"); print_float(Z_im);
}
}
Saludos.