Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

10/07/2016 #61
Moderador

Avatar de D@rkbytes

Realizar 500 veces la lectura del conversor ADC, no se me hace buena idea, aparte de que se puede producir el desborde de la variable contenedora.

Si quieres que la lectura se muestre más estable, usa el Timer 0 porque ya se está usando el Timer1.
Usa el desborde del Timer para incrementar una variable, y cuando llegue a x número, realizas la lectura del ADC.
11/07/2016 #62

Avatar de callecuatro1976

Código:
#include <16f883.h>
#device ADC=10
#use     delay(internal = 8MHz)
#define  LCD_DATA_PORT getenv("SFR:PORTC")
#include <lcd.c>
#define led PIN_B5
int1 flagHayDatos=0; 
float const ticks_us = 4.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Interno)
//float const ticks_us = 8.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Cristal)
 int8 flancos;
int8 flag_flanco;
int16 periodo1,periodo2,periodo3;
int16 tiempo_alto,tiempo_bajo,tiempo_total;
float us_alto,us_bajo,us_total;
float frecuencia;
#INT_EXT
void sdi_externa_RB0 (void)
{
   flancos++;                          // Incrementar la variable "flancos"
   
   if(!flag_flanco)                    // Si el flanco del pulso es bajo...
   {
      if(flancos == 1)                 // Si el conteo de flancos es 1...
      {
         set_timer1(0);                // Limpiar el Timer 1
         periodo1 = get_timer1();      // "periodo1" tendrá el tiempo del pulso en alto.
      }
      if(flancos == 3)                 // Si el conteo de flancos es 3...
         periodo3 = get_timer1();      // "periodo3" tendrá el tiempo del pulso en alto.
         
         EXT_INT_EDGE(H_TO_L);         // Establecer la interrupción por flanco de bajada.
         flag_flanco = 1;              // Indicar que el próximo flanco será de bajada.
   }
   else                                // Caso contrario. (Pulso en estado alto)...
   {
      periodo2 = get_timer1();         // "periodo2" tendrá el valor del pulso en bajo.
      EXT_INT_EDGE(L_TO_H);            // Establecer la interrupción por flanco de subida.
      flag_flanco = 0;                 // Indicar que el próximo flanco será de subida.
       if(flagHayDatos==0){       // Si los datos anteriores han sido procesados ...
      flagHayDatos=1;          // Indico que ya hay nuevos datos de flancos para calcular
    }
   }
    if(flancos > 2)flancos = 0;         // Si la variable "flancos" llega a 3, ponerla a 0.
}
 void main()
{
long int var1=0, var2=0, var3=0;
 float valor, valor1,valor2;
   float duty;
   int8 porcentaje;
   
 setup_adc_ports(sAN1|sAN3);
 setup_adc(ADC_CLOCK_INTERNAL );
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   enable_interrupts(int_ext);
   ext_int_edge(0,L_TO_H);
   enable_interrupts(global);
   
   lcd_init();
   
   #ZERO_RAM   // Limpiar RAM. (Variables en 0)
   
   while (true)
   {
   
 
  for(var1=0;var1<50;var1++)
  {
    valor=valor+ get_timer1();
    delay_us(62);  
  }
   periodo1=valor/50;
   
    for(var2=0;var2<50;var2++)
  {
    valor1=valor1+ get_timer1();
    delay_us(62);  
  }
   periodo2=valor/50;
    for(var3=0;var3<50;var3++)
  {
    valor2=valor2+ get_timer1();
    delay_us(62);  
  }
   periodo3=valor/50;
   
    if(flagHayDatos==1){
    output_HIGH(led);
      if((periodo3 > periodo2) && (periodo2 > periodo1))
      {
         tiempo_alto = periodo2 - periodo1;                 // Obtener el periodo del pulso en estado alto.
         tiempo_bajo = periodo3 - periodo2;                 // Obtener el periodo del pulso en estado bajo.
         tiempo_total = tiempo_alto + tiempo_bajo;          // Obtener el periodo de la frecuencia.
         us_alto = ticks_us * tiempo_alto;                  // Obtener el periodo en microsegundos del pulso en alto.
         us_bajo = ticks_us * tiempo_bajo;                  // Obtener el periodo en microsegundos del pulso en bajo.
         us_total = ticks_us * tiempo_total;                // Obtener los microsegundos en total de la frecuencia.
         frecuencia = 1 / (us_total / 1000000);             // Obtener la frecuencia.
         duty = ((float) tiempo_bajo / (float)(tiempo_bajo + tiempo_alto));
         porcentaje = (duty * 100) + 0.5; // Físicamente el + 0.5 puede no ser necesario. (Ajusta desviación pero consume ROM)
      } 
       flagHayDatos=0; 
    }
      lcd_gotoxy(1,1);
      printf(lcd_putc,"CPS:%03.0fHz",frecuencia);
      lcd_gotoxy(1,2);
      printf(lcd_putc,"DUTY:%02u%c",porcentaje,0x25);
       flagHayDatos=0; 
       
      delay_ms(100); // Retardo para disminuir parpadeos en la pantalla. (No afecta interrupción externa.)
      if(flagHayDatos==0){
      frecuencia = 0;
      porcentaje=0;
      output_low(led);
      }
      
    }
}
El adc me funciona bien, las variaciones las tengo en las muestras de frecuencia y duty es aquí que estoy haciendo un lio bárbaro con el promedio
11/07/2016 #63
Moderador

Avatar de D@rkbytes

Sinceramente no encuentro la complicación a algo tan sencillo como obtener un promedio.
Ya te mencioné sobre otra forma de obtener lecturas más estables.


Enviado desde mi GT-P3110 mediante Tapatalk
11/07/2016 #64

Avatar de callecuatro1976

No me doy idea de como aplicarlo para la frecuencia y el duty te agradecería una mano con un ejemplo.
12/07/2016 #65
Moderador

Avatar de D@rkbytes

Adjunto el código con lo expuesto, usando el Timer 0.
No sé si se consiga buena estabilidad físicamente de ésta forma, pero te puede dar ideas.
Archivos Adjuntos
Tipo de Archivo: rar Main.rar (1,4 KB (Kilobytes), 8 visitas)
12/07/2016 #66

Avatar de callecuatro1976

No me funciono las mediciones no son estables, seguiré intentando la forma de promediar.
13/07/2016 #67
Moderador

Avatar de D@rkbytes

Estuve haciendo pruebas físicamente con el programa que adjunto, y fueron satisfactorias.
La frecuencia se mantiene estable y el ciclo activo cambia conforme éste varíe.

Te vuelvo a recomendar que uses un osciloscopio y un frecuencímetro, porque tal vez las señales que estás tratando de leer, no son estables.
Así, por más que quieras estabilizar eso por software, no lo vas a conseguir.
Archivos Adjuntos
Tipo de Archivo: rar 16F887 Obtener porcentaje del ciclo activo II.rar (47,8 KB (Kilobytes), 6 visitas)
13/07/2016 #68

Avatar de callecuatro1976

Si estuve trabajando bastante con esto y funciona muy bien, la señal entrante es muy baja y ruidosa! se mantiene estable y funciona, hay un solo problema que no se porque lo hace, estas midiendo ejemplo 146hz 58% duty y de golpe te tira 3457hz y queda colgado ahí puse capacitores por todos lados y lo hace pocas veces pero lo hace es ruido tendría que ver la placa de hacerla con mas masa, saludos
14/07/2016 #69
Moderador

Avatar de D@rkbytes

callecuatro1976 dijo: Ver Mensaje
Hay un solo problema que no sé por qué lo hace.
Estás midiendo, ejemplo; 146 Hz. 58% duty y de golpe te tira 3457 Hz y queda colgado ahí.
Posiblemente tengas que cambiar los parámetros del Timer 1 para centrar el conteo alrededor de esa frecuencia.
14/07/2016 #70

Avatar de callecuatro1976

Lo que hice fue cambiar las variables para que cuando hay algún pico así no se pase, con la variable int no se pasa de 225, los parámetros no se como hacerlo, funciona muy bien lo único son esos picos que mete la bobina.

Y estoy tratando de colocar un mensaje de alerta cuando los amper llegan a 2,5 tendría que borrar la pantalla y mostrar "alerta" y cuando baje volver como estaba
If(adc > 200) {
Printf (lcd_putc"alerta" ;
}
Else if (Adc>=200)
14/07/2016 #71
Moderador

Avatar de D@rkbytes

Usa un bucle de retención hasta que el valor de los amperes se estabilice.
Por ejemplo:
while (amps > x)
{
lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"%f Amps.",amps);
delay_ms(x);
}
15/07/2016 #72

Avatar de callecuatro1976

Si lo arme asi, cuando supera los 2,5 amper da la alerta, ahora cuando bajan los amper no vuelve a su posición original porque?

set_adc_channel(3);
delay_us(20);
amper=0;
for(var2=0;var2<300;var2++)
{
amper=amper+ read_adc();
delay_us(62);
}
valor2 = amper / 300;
valor2 = valor2 * 19 / 1023;


lcd_gotoxy(11,2);
printf(lcd_putc,"%4.1f",valor2);

while (valor2 > 2.5)
{
lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"%f amper."valor2);
delay_ms(100);
15/07/2016 #73

Avatar de papirrin

porque el valor de la variable "valor2", no se actualiza dentro del bucle. entra y nunca sale...

falta algo como esto dentro del bucle:

amper=amper+ read_adc();
delay_us(62);
}
valor2 = amper / 300;
valor2 = valor2 * 19 / 1023;
o cambiar el algoritmo.
15/07/2016 #74
Moderador

Avatar de D@rkbytes

Para hacerlo más sencillo, se puede crear la rutina de lectura del conversor y llamarla dentro del bucle.
15/07/2016 #75

Avatar de callecuatro1976

Puedo poner while (read_adc ()>2.5)???
15/07/2016 #76

Avatar de papirrin

callecuatro1976 dijo: Ver Mensaje
Puedo poner while (read_adc ()>2.5)???
no lo creo, porque estas haciendo operaciones para sacar el amperaje, podrias hacer

read_adc ()> a la equivancia en bits de 2.5A

o

while (read_adc ()>100) donde 100 corresponde a 2.5 amperios por ejemplo, no tengo idea de a cuanto equivale.

otra seria hacer una rutina de funcion....
16/07/2016 #77

Avatar de callecuatro1976

while (valor2 >= 2.5){if (valor2 <2.4){break;}

lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"valor superado!");
delay_ms(100);
valor2=0;


ahí casi estoy me falta limpiar bien la pantalla
16/07/2016 #78

Avatar de papirrin

en ese algoritmo no tiene mucho sentido el while, si utilizas solo la condicional es suficiente o sea
if(valor2 >=2.5){
lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"valor superado!");
delay_ms(100);}

Enviado desde mi ZTE Blade L2 mediante Tapatalk
16/07/2016 #79

Avatar de roberttorres

callecuatro1976 dijo: Ver Mensaje
while (valor2 >= 2.5){if (valor2 <2.4){break;}

lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"valor superado!");
delay_ms(100);
valor2=0;


ahí casi estoy me falta limpiar bien la pantalla
Creo, que como dijo el compañero D@rkbytes seria mas sencillo que crearas la rutina de lectura y conversión y lo llamaras desde tu bucle de alerta.
Te paso un ejemplo de voltimetro con alerta cuando llega a los 1 Ampers.:
Archivos Adjuntos
Tipo de Archivo: rar Voltimetro.rar (108,3 KB (Kilobytes), 9 visitas)
17/07/2016 #80

Avatar de callecuatro1976

Me sirvió muchas gracias!

Ahora este ejemplo de voltimetro la medición de los amper la toma en proporción de la tension o es conveniente poner una resistencia shunt?
Y por otro lado se ejecuta más rápido los programas usando funciones, que escribiendo el código a lo largo como lo hacía yo.
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.