Autor Tema: Problema con interrupción externa y Timer0 en pic16f88... Voltímetro AC digital  (Leído 3840 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

Desconectado gustavokun

  • PIC10
  • *
  • Mensajes: 3
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);}
}
« Última modificación: 16 de Marzo de 2009, 17:04:08 por gustavokun »

Desconectado vtasco

  • PIC12
  • **
  • Mensajes: 72
Hola, yo creo que te estás complicando, lo más sencillo sería rectificar esa onda, con un diodo, y un condensador debiera ser suficiente, (puedes escalar antes de rectificar, para no tener un voltaje DC muy alto), y luego simplemente medir su valor DC, y aplicar el valor de escalamiento que corresponda.

suerte!

Desconectado gustavokun

  • PIC10
  • *
  • Mensajes: 3
Bueno en realidad no creo que esté tan complicado... el programa debería funcionar porque me guié de un programa similar pero que trabaja para una red de 220V a 50 Hz, simplemente hice las conversiones necesarias pero por alguna razón no está dando en el clavo... supongo que me falta algún detalle ya que no se mucho de programación en C.

De todas maneras si puedes explicarme mejor tu idea, no entiendo mucho lo que quieres decir... osea, si el valor del voltaje AC cambia (que es lo que quiero detectar), el valor del componente DC no se mantiene igual?

Explicame un poco tu idea por favor... y Gracias!

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Yo creo que la interrupción externa no te detecta justamente es paso por cero y por eso los valores aleatorios. Prueba utilizando los comparadores analógicos para detectar el cruce por cero.
Otra forma de hacerlo seria no usando el temporizador, y cuando detecta el flanco, muestrear la señal senoidal hasta detectar el máximo valor, algo así:
Código: C
  1. TENSION_M=0;
  2.       do{
  3.          VALOR_MAX=TENSION_M;
  4.          TENSION_M=read_adc();
  5.       }while(TENSION_M>VALOR_MAX);

Tomará valores hasta que la medida actual sea menor que la anterior, entonces ya se detecto el máximo y se guarda en VALOR_MAX. Creo es viable ya que la frecuencia de la señal es baja.

Saludos!
« Última modificación: 17 de Marzo de 2009, 00:52:32 por Suky »
No contesto mensajes privados, las consultas en el foro

Desconectado gustavokun

  • PIC10
  • *
  • Mensajes: 3
Gracias Suky por tu idea, es bastante sencilla y creo que debe funcionar...
Voy a probar y te aviso!

Desconectado jo.an.

  • PIC16
  • ***
  • Mensajes: 120
Voltímetro AC digital
« Respuesta #5 en: 25 de Febrero de 2010, 04:49:39 »
Saludos a todos:Creo (no estoy seguro)que se podria utilizar un transformador pequeño con entrada de 220 0 110 y una salida de unos 4 voltios y rectificarla (he quemado varias cosas por andar con la corriente de la red) tal vez lo podamos utilizar con el mismo principio que el sensor de temperatura,que por la variacion de milivoltios nos da la lectura en el display(se me ocurre).Si teneis algo de esto en asembler agradeceria vuestra ayuda.att jose