Saludos a todos!
Recurro a ustedes para que puedan ayudarme un poco con un programa que necesito para la uni. Mi proyecto requiere de la medición de un voltaje AC en una resistencia, para ésto estoy usando el pic16f88 programando con CCS.
Para sincronizar el medidor con el voltaje AC de 60 Hz, utilizo la interrupción externa por el pin RB0 que da una interrupción cuando hay un flanco de subida en la onda senoidal (cambio del semiciclo negativo al semiciclo positivo), de esta manera se activa el timer0 que esperará a que la onda llegue al valor pico (Tosc/4) para activar el conversor analógico digital y realizar la medición.
Mi problema es que tras hacer el programa no logro que me realice el trabajo bien
... No sé si el problema es con la interrupción externa o con el timer, pero el ADC está realizando mediciones aleatorias en vez de mostrarme siempre un mismo valor (el valor pico de la onda).
La señal va introducida al pic directamente de la red, mediante un juego de resistencia que adapta el voltaje a valores en un rango de 0-5V
Les anexo aquí el cuerpo del programa para que me digan si ven que es lo que falla
#include <16F88.h>
#device adc=10
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8)
#use fast_io(b)
#use fast_io(a)
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOCPD //No EE protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOMCLR //Master Clear pin disabled
#FUSES NOPUT //Power Up Timer
#FUSES NOBROWNOUT //no reset when brownout detected
float valor; // valores analogicos
float factor,c_rms,tension,corriente,v_rms; // factor de conversion
/* Interrupcion paso por cero */
#int_RB
void int_RB_isr(void){
// se desactiva la interrupcion de paso por cero
disable_interrupts(INT_RB);
set_timer0(126);
enable_interrupts(INT_TIMER0);
}
/* Interrupcion por tiempo la lanza la interrupcion paso por cero */
#INT_TIMER0
void TIMER_isr(void){
// desactivamos la interrupcion, este periodo de tiempo se desprecia
disable_interrupts(INT_TIMER0);
// leemos el valor
valor=read_adc();
// calculamos la constante de conversion que es el valor leido/valor maximo
factor=(valor/1024);
// damos forma al valor leido, siendo el rango de 169.7v de pico a pico
tension=(factor*169.705627);
tension=169.705627-tension;
// calculamos el valor eficaz
v_rms=(factor*120);
corriente=tension/(0.1);
c_rms=(v_rms/(0.1));
// se activa la interrupcion de paso por cero
enable_interrupts(INT_RB);
}
void main(){
// define velocidad del reloj
setup_oscillator(OSC_4MHZ);
// inicializa variables
SET_TRIS_A(0x01);
set_tris_b(0x25);
// GP0 como entrada analogica con refencia Vdd-Vss
setup_adc_ports(sAN0|VSS_VDD);
// Muestreo del ADC
setup_adc(ADC_CLOCK_INTERNAL);
// seleccionamos el canal 0 del adc
set_adc_channel(0);
disable_interrupts(INT_EXT);
disable_interrupts(INT_TIMER0);
// activamos la global
enable_interrupts(GLOBAL);
// configuramos el timer 0 para tener un overflow cada 60Hz/4 a 4Mhz, es decir conteo cada 4.166us = Fosc/4
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
//Define flanco de subida (Para la activacion de la interrupcion)
ext_int_edge(INT_EXT,L_TO_H);
// activa la interrupcion de paso por cero
enable_interrupts(INT_RB);
// bucle principal
while (true)
{printf("%f \r",valor);}
}