TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: aripod en 13 de Octubre de 2010, 15:24:42

Título: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 13 de Octubre de 2010, 15:24:42
Estoy haciendo un puente H, para lo que voy a usar el ADC(PIN_A0) para ver una tension en un potenciometro linea, que de acuerdo a su posicion sera el sentido y velocidad de giro del motor, en el medio apagado. El tema de esa referencia y a partir de la misma obtener el PWM con el duty necesario esta andando, resta ver si estan bien las constantes en el codigo para ver si se corresponden a los tiempos que quiero.
El problema lo tengo en la interrupcion int_rb, la cual voy a usarla para medir las RPM del motor. En si lo que tengo que hacer es medir la frecuencia del tren de pulsos que obtengo del optoacoplado. Dejo el codigo para ver si me pueden dar una mano, ya que no esta ingresando a la #int_rb (pude comprobarlo con el debugger proteus VSM)-

Código: [Seleccionar]
#include <16F877A.h>
#device adc=10
#use delay (clock=4000000)
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT
#include<lcd_flex.h>


void main(void)
{
float duty=0,dutylcd=0, rpm=1200, vref=5,vref2=0,adc=0;

//set_tris_a(0x00); Ver si hace falta poner todo como salida.
set_tris_b(0xFF);
set_tris_c(0x00);
set_tris_d(0x00);

/*output_a(0);
output_b(0);          Ver si hace falta poner todo en cero.
output_c(0);
output_d(0);*/

lcd_init();
delay_ms(10);
output_b(0);
output_c(0);

//Configuracion del ADC:
setup_adc_ports(NO_ANALOGS);
setup_adc_ports(RA0_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);

enable_interrupts(int_rb);
enable_interrupts(global);

vref=(float) read_adc()*0.0048828125; // (5v/1024)=0,0048828125=4,88mV
vref2=vref;
lcd_gotoxy(1,1);
printf(lcd_putc,"V:+%.2fv",vref);

//Configuracion del PWM:
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,65.66667,1);  
dutylcd=20*vref; //(100%/5V)*vref = 20*vref
duty=vref*204.6; //(1023/100%)*dutylcd = 10.23*dutylcd = 10.23*20*vref=204.6*vref
set_pwm1_duty(duty);

lcd_gotoxy(10,1);
printf(lcd_putc,"D:%.1f",dutylcd);
lcd_putc('%');

lcd_gotoxy(3,2);
printf(lcd_putc, "RPM: %.1f",rpm);
while(1)
{
if(vref2!=vref)
{
vref2=vref;
lcd_gotoxy(1,1);
printf(lcd_putc,"V:+%.2fv",vref);

duty=20*vref; //(100%/5V)*vref
lcd_gotoxy(10,1);
dutylcd=20*vref; //(100%/5V)*vref = 20*vref
duty=vref*204.6; //(1023/100%)*dutylcd = 10.23*dutylcd = 10.23*20*vref=204.6*vref
set_pwm1_duty(duty);
printf(lcd_putc,"D:%.1f",dutylcd);
lcd_putc('%');

lcd_gotoxy(3,2);
printf(lcd_putc, "RPM: %.1f",rpm);
}

vref=(float) read_adc()*0.0048828125; // (5v/1024)=0,0048828125=4,88mV
delay_ms(1);
}
}

#int_rb
void frec(void)
{
if(input(pin_B4)==1)
output_high(pin_C0);
if(input(pin_B5)==1)
output_low(pin_C0);
}

Actualizacion 1: Recien llego del lab, en PWM esta a la frecuencia que quiero (15kHz), pero no el ciclo de trabajo. Lo que yo quiero es sea lineal la variacion con una tension de referencia (para la que uso el ADC), pero me parece que estoy asignando mal la funcion set_pwm1_duty(duty); El valor de la variable duty tiene que ser el valor del duty propiamente? es decir, de 0 a 100 o tengo que hacer una regla de 3 simples, con 100% de duty son 1023 por los 10 bits que utiliza el pwm?? Gracias!!
Título: Re: No entra en #int_rb
Publicado por: KALLITOS en 13 de Octubre de 2010, 19:07:37
Hola aripod, recuerdo haber leído aqui en el foro sobre este problema, creo que se soluciona leyendo el portb dentro de la interrupcion.

Usa el buscador, este problema ya ha sido tratado.

Saludos
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 14 de Octubre de 2010, 03:53:49
Actualizacion 1: Recien llego del lab, en PWM esta a la frecuencia que quiero (15kHz), pero no el ciclo de trabajo. Lo que yo quiero es sea lineal la variacion con una tension de referencia (para la que uso el ADC), pero me parece que estoy asignando mal la funcion set_pwm1_duty(duty); El valor de la variable duty tiene que ser el valor del duty propiamente? es decir, de 0 a 100 o tengo que hacer una regla de 3 simples, con 100% de duty son 1023 por los 10 bits que utiliza el pwm?? Gracias!!

Hola amigo, el valor de la variable duty, tiene que ser un valor entre 0 y 1023 si configuras el ADC = 10 bits, si lo configuras a 8 bits será entre 0 y 255, tienes que hacer una simple regla de 3.

Te subo un archivo totalmente comentado que espero que te sirva de ayuda.

Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 09:25:00
El archivo adjunto esta solo la simulacion...
Entonces esta bien si quiero que el duty sea proporcional a la vref segunn la tension del potencionmetro (de 0 a 5v), con hacer duty=read_adc() tendria una linealidad entre el potenciometro y el duty, verdad? Si esto llega a estar bien, estoy haciendo otra cosa mal porque varia el duty pero en muy poca variacion de vref digamos.
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 14 de Octubre de 2010, 10:51:52
Lo siento antes me he equivocado al subir el archivo, aqui lo tienes, si en teoria seria eso, si lees el valor y lo pones directamente en duty te iria bien, aqui te lo vuelvo a subir...

Lo siento  :oops::?
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 12:13:24
Estoy entonces convirtiendo y el valor ese directamente lo envio al duty:

Código: [Seleccionar]
vref=(float) read_adc()*0.0048828125; // (5v/1024)=0,0048828125=4,88mV
vref2=vref;
lcd_gotoxy(1,1);
printf(lcd_putc,"V:+%.2fv",vref);

//Configuracion del PWM:
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,66,1);  
dutylcd=20*vref; //(100%/5V)*vref = 20*vref
//duty=vref*204.6; //(1023/100%)*dutylcd = 10.23*dutylcd = 10.23*20*vref=204.6*vref
delay_ms(10);
set_pwm1_duty(511); //Para que arranque en 50%.

lcd_gotoxy(10,1);
printf(lcd_putc,"D:%.1f",dutylcd);
lcd_putc('%');

lcd_gotoxy(3,2);
printf(lcd_putc, "RPM: %.1f",rpm);
while(1)
{
if(vref2!=vref)
{
vref2=vref;
lcd_gotoxy(1,1);
printf(lcd_putc,"V:+%.2fv",vref);

duty=20*vref; //(100%/5V)*vref
lcd_gotoxy(10,1);
dutylcd=20*vref; //(100%/5V)*vref = 20*vref
//duty=(int) vref*204.6; //(1023/100%)*dutylcd = 10.23*dutylcd = 10.23*20*vref=204.6*vref
duty=read_adc();
delay_ms(10);
set_pwm1_duty(duty);
printf(lcd_putc,"D:%.1f",dutylcd);
lcd_putc('%');

lcd_gotoxy(3,2);
printf(lcd_putc, "RPM: %.1f",rpm);
}

vref=(float) read_adc()*0.0048828125; // (5v/1024)=0,0048828125=4,88mV
delay_ms(1);
}
}

Tendra algo que ver que se esta modificando todo el tiempo el duty y no le da tiempo suficiente?

Ahora que estoy probando es ese el funcionamiento, pero una vez que maneje bien el duty digamos, tengo que poner el duty que muestro en el lcd (dutylcd) debe ser el de la señal, entonces tendria que hacer (1024/100)*dutylcd, verdad? Eso tiene que ser int o puede ser float o no importa el tipo?
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 12:31:43
Estas trabajando a 4MHz, Frecuencia del PWM 14925.37Hz con PR2=66, resolución 8.066, entonces 0% ->0, 100% -> 268.



Saludos!
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 12:34:19
Estas trabajando a 4MHz, Frecuencia del PWM 14925.37Hz con PR2=66, resolución 8.066, entonces 0% ->0, 100% -> 268.



Saludos!

Me podrias explicar como hiciste ese calculo??
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 12:50:45
En el datasheet están la formulas para el cálculo de la frecuencia y de la resolución. Solo hay que reemplazar valores


Saludos!
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 13:00:53
Calculo bien la resolucion, pero como lo relacionas con los bits?
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 13:14:12
Calculo bien la resolucion, pero como lo relacionas con los bits?

2^(Resolución)   :mrgreen:
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 13:17:00
Hagamos de cuenta ke no pregunte eso y ke kede entre nosotros!!jaja
gracias!!

Otra duda....no quiero estar haciendo output_high(PIN_C1) por ejemplo, sino en vez hacer q=1 y que q sea el pin C1, me explico? Igual para output_low(PIN_C1)
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 13:20:03
Puedes hacer:

#bit q=0x07.1  // Creo que el 0x07 es el puerto C  :mrgreen:

El tris debe estar configurado correctamente  ;-)


saludos!
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 14:21:41
Declare globalmente para poder usarlo en el main y en las distintas funciones y me da un error cuando compilo: A numeric expression must appear here. Aclaro, estoy haciendo q=1 o q=0
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 15:06:40
Declare globalmente para poder usarlo en el main y en las distintas funciones y me da un error cuando compilo: A numeric expression must appear here. Aclaro, estoy haciendo q=1 o q=0

Lo hiciste correctamente? En la ayuda de CCS hay más ejemplos.

Saludos!
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 15:08:00
Código: [Seleccionar]
#include <16F877A.h>
#device adc=10
#use delay (clock=4000000)
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT
#include<lcd_flex.h>

void control(float dutylcd);

#define q1=PIN_C4
#define q2=PIN_C5
#define q3=PIN_C6
#define q4=PIN_C7

void main(void)
{
int duty=0; //VER SI duty SE LO DECLARA COMO FLOAT!
float dutylcd=0, rpm=1200, vref=5,vref2=0,adc=0;

//set_tris_a(0x00); Ver si hace falta poner todo como salida.
set_tris_b(0xFF);
set_tris_c(0x00);
set_tris_d(0x00);

/*output_a(0);
output_b(0);          Ver si hace falta poner todo en cero.
output_c(0);
output_d(0);*/

lcd_init();
delay_ms(10);
output_b(0);
output_c(0);

//Configuracion del ADC:
setup_adc_ports(NO_ANALOGS);
setup_adc_ports(RA0_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);

enable_interrupts(int_rb);
enable_interrupts(global);

vref=(float) read_adc()*0.0048828125; // (5v/1024)=0,0048828125=4,88mV
vref2=vref;
lcd_gotoxy(1,1);
printf(lcd_putc,"V:+%.2fv",vref);

//Configuracion del PWM:
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,66,1);
//Resolucion = log(Fosc/Fpwm)/log(2)=8,066 --> 2^(Resolución)=268
//DUTY: 0% ->0, 100% -> 268
dutylcd=20*vref; //(100%/5V)*vref = 20*vref
duty=2.68*dutylcd; //(268/100%)*dutylcd%=2.68*dutylcd
set_pwm1_duty(duty);
delay_ms(1);

lcd_gotoxy(10,1);
printf(lcd_putc,"D:%.1f",dutylcd);
lcd_putc('%');

lcd_gotoxy(3,2);
printf(lcd_putc, "RPM: %.1f",rpm);
while(1)
{
if(vref2!=vref)
{
vref2=vref;
lcd_gotoxy(1,1);
printf(lcd_putc,"V:+%.2fv",vref);

duty=20*vref; //(100%/5V)*vref
lcd_gotoxy(10,1);
dutylcd=20*vref; //(100%/5V)*vref = 20*vref
duty=2.68*dutylcd; //(268/100%)*dutylcd%=2.68*dutylcd
set_pwm1_duty(duty);
delay_ms(1);
printf(lcd_putc,"D:%.1f",dutylcd);
lcd_putc('%');

lcd_gotoxy(3,2);
printf(lcd_putc, "RPM: %.1f",rpm);

control(dutylcd);
}

vref=(float) read_adc()*0.0048828125; // (5v/1024)=0,0048828125=4,88mV
delay_ms(1);

/*setup_adc_ports(RA1_ANALOG);
adc=read_adc();*/
}
}

#int_rb
void frec(void)
{
if(input(pin_B4)==1)
output_high(pin_C0);
if(input(pin_B5)==1)
output_low(pin_C0);
}


void control(float dutylcd)
{
if(dutylcd<48)
{
q1=1;
q2=0;
q3=1;
q4=0;
}

if(dutylcd>=48 && dutylcd<=52)
{
q1=0;
q2=0;
q3=1;
q4=1;
}

if(dutylcd>52)
{
q1=0;
q2=1;
q3=0;
q4=1;
}
}
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 15:20:25
 :shock:

#bit q=0x07.1  // Creo que el 0x07 es el puerto C  :mrgreen:


Sino, no funciona  :mrgreen:
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 15:27:40
Ahi funciono, pero si en el 16f877.h tiene #define PIN_C0  56 no deberia andar??
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: Suky en 14 de Octubre de 2010, 15:33:05
Ahi funciono, pero si en el 16f877.h tiene #define PIN_C0  56 no deberia andar??

No. Esa es una definición propia del compilador. "Él entiende como aplicarlo"  :mrgreen:
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 14 de Octubre de 2010, 22:23:44
Vuelvo del lab. El 100% del duty o 99% mejor dicho es con el valor de duty=63 no 268 como da el calculo...

Otra duda,,,,,necesito estar sensando constantemente otra tension, para lo ke pensaba usar el ADC del pin A2, tengo ke ir "apagando" el ADC del pin A1 y "prender" el del A2 y luego al reves??
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: jhozate en 14 de Octubre de 2010, 23:28:53
Otra duda,,,,,necesito estar sensando constantemente otra tension, para lo ke pensaba usar el ADC del pin A2, tengo ke ir "apagando" el ADC del pin A1 y "prender" el del A2 y luego al reves??
el ADC es uno solo, lo que multiplexas es el canal.
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 15 de Octubre de 2010, 00:20:03
Clarisimo, cambie al canal 0 y 1 segun necesitaba y anda a la prefeccion. Gracias!

Alguna idea por el tema del duty? Estoy haciendo la regla de tres simples pero tomando el 63 como duty al 100%, pero es un "parche" descubierto con el osciloscopio....no es la idea,,,me gustaria que "quede bien" :)
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 15 de Octubre de 2010, 03:34:20
buenas, intenta no hacer operaciones en el momento que cojes el readADC.
Y despues de leer el ADC siempre es mejor esperarse un poco.

Código: C
  1. vref=(float) read_adc()*0.0048828125 begin_of_the_skype_highlighting              0048828125      end_of_the_skype_highlighting;        // (5v/1024)=0,0048828125 begin_of_the_skype_highlighting              0048828125      end_of_the_skype_highlighting=4,88mV
  2. vref2=vref;
  3. lcd_gotoxy(1,1);
  4. printf(lcd_putc,"V:+%.2fv",vref);
Yo esto no lo haria, primero lees el ADC y luego haces lo que quieras, yo lo hago de la siguiente forma y me funciona perfectamente tomando el máximo valor como 1023 y el minimo como 0.

Aqui te dejo el trozo de codigo que yo utilizo, si quieres pruebalo en la protoboard porque funciona perfectamente.

Código: C
  1. medicio=read_adc();   //guardo el valor de adc en medicio
  2.    delay_us(20);
  3.    proporcio=((medicio+29)*0.80986);  //hago las peraciones que quiera y mas...
  4.    Vprop=(proporcio*0.01953);
  5.    lcd_gotoxy(1,1);
  6.    printf(lcd_putc,"A=%0Lu",medicio);   //muestro por el lcd todos los valores empezando por lo que me lee por adc
  7.    lcd_gotoxy(9,1);
  8.    printf(lcd_putc,"P = %u",proporcio);  //resultado de la primera operacion
  9.    lcd_gotoxy(1,2);
  10.    printf(lcd_putc,"V = %f",Vprop);       //resultado de la segunda operacion
  11.    set_pwm1_duty(proporcio);             //hago el duty

espero que te sirva de ayuda  ;-)
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 15 de Octubre de 2010, 09:10:33
Voy a seguir tu consejo. Alguna idea del tema del duty??
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 16 de Octubre de 2010, 08:21:58
que quieres decir con lo de alguna idea con lo del duty? no entiendo que quieres decir con lo de 268 como da el calculo, lo máximo a lo que te puede llegar el duty o el ADC es 256 porque lo defines como ADC = 8 bits
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 16 de Octubre de 2010, 11:41:51
El adc esta en 10 bits, el 268 es por la resolucion del PWM (8.066), lo que da los 268, pero en el osciloscopio comprobe que el duty al 100% se da con 63 no con 268. Sera porque uso la variable para modificar el duty como int???
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 16 de Octubre de 2010, 18:07:00
Si tienes que definir esa variable como int16, en eso no me habia fijado ;-)
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 17 de Octubre de 2010, 19:49:58
Cambie a int16, mañana voy a probar en el osciloscopio, seguro ahi anda ;).

Pase a la parte de la interrupcion....quiero que detecto flancos de subida, lei que es por RB0. Declare en el main:

Código: [Seleccionar]
ext_int_edge(L_TO_H);
enable_interrupts(int_ext);
enable_interrupts(global);

y la funcion de interrupcion es:

Código: [Seleccionar]
#int_ext
void ext_isr(void)
{
output_high(PIN_C0);
delay_ms(200);
output_low(PIN_C0);
}

Obviamente, RB0 esta declarado como entrada y C0 como salida....pero no esta entrando en la interrucpio y no logro darme cuenta que es lo que esta faltando en el codigo....segun los ejemplos que vi no hay que poner nada mas que la declaracion de la interrupcion, que flanco quiero y nada mas...
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 18 de Octubre de 2010, 05:55:41
En teoria es asi como dices tu... digo en teoria porque yo tambien lo necesitava hacer para contar un tren de pulsos pero no me funcionaba ni a la de 3... por esa razon y como el programa no tenia que hacer nada mas que esperar los pulsos lo decidi hacer de forma "bruta" que seria esperando el flanco de subida y contando el tiempo hasta que bajara otra vez, si te sirve te puedo enviar el trozo de codigo que hace esa función.
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 18 de Octubre de 2010, 10:37:26
Será problema del CCS que no configura bien los registros? Gracias por ofrecerme tu prog, pero desafortunadamente si tengo que ir haciendo otras cosas no solo esperar el tren de pulsos....espero que alguien haya tenido suerte con la int_ext y se de una vuelta por el thread :)
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: aripod en 19 de Octubre de 2010, 22:17:56
El PWM con int16 anda perfecto. Me olvide de ver si entra a la interrupcion! Mañana traigo novedades.
Título: Re: Dudas Varias (PWM, Int_RB)
Publicado por: f-traxx en 20 de Octubre de 2010, 04:25:01
Perfecto aripod, ya solucionaste el problema!! :-/ a mi alguna vez estas tonterias de declarar la variable mas pequeña de lo que toca también me ha traido problemas.

Mira lo de la interrupción, y si te funciona... me copiare ese trozo de codigo... Con tu consentimiento claro esta... ;-) jeje


Saludos

F-traxx