Autor Tema: Timer0_PIC18F4550_No_se_que_pasa  (Leído 20265 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #30 en: 17 de Diciembre de 2013, 18:38:42 »
Hola,

mis sugerencias son: si pensás interrumpir en intervalos muy pequeños de tiempo, configurar el Timer0 en modo 8 bits. De esa manera te ahorras tener que escribir un registro. El código que hiciste es bastante impreciso, especialmente cuando le agregues otras fases. No me parece la mejor forma de acercarse a lo que estás intentando hacer.

Entonces, y esto es sólo mi opinión y consideración:
1) utilizar la interrupción de alta prioridad para la generación de PWM por soft. Esto siempre es importante si a futuro se llega a agregar alguna otra. Necesita ser de alta prioridad en ese caso.

2) Si es la única interr. dentro del vector elegido, NO verificar el flag TMR0IF. Es evidente que el motivo de la interr. fue ese y no otro.

3) Lo primero que haces dentro del vector de interr. es precargar el valor del Timer0. De esta manera todo el codigo que agregues debajo no afectará la frecuencia del PWM. Todo el código que se ejecute antes de la precarga, afecta a la frecuencia del PWM. Incluso la cosa empeora cuando ponés IF, WHILE, FOR, etc antes de la precarga porque puede que no siempre se ejecute la mísma cantidad de instrucciones, lo que empeora la cosa porque puede hacer variar la frecuencia incluso entre interrupciones.

4) Hay veces, como en este caso, en que la generación del PWM es mejor que ocurra DENTRO de la interrupción. Eso garantiza sincronización e incluso, para este caso particular de PWM por software, optimización de las instrucciones necesarias para lograrlo. Hay que lograr que el PWM se genere con la menor cantidad de uso del CPU posible.

5) La mejor aproximación, a mi parecer (y llevo años haciendo PWM's por software de todo tipo en desarrollos comerciales) es esta:

Suponiendo que necesitás 3 fases de PWM @ 25Khz c/u y con posibilidad de phase-shifting, con una resolución de duty y phase-shift del 10%:

Con un micro como el 18F4550 corriendo a 48Mhz (frecuencia máxima del uC ese), necesitás interrumpir cada 1000000 / 25000 / 10 = 4 uS lo que en instrucciones son 48. Está muy jugada la cosa. No sé si va a funcionar, pero podemos intentarlo. El código debajo es usando C, si usás ASM seguro te ganás unas cuántas instrucciones.

Código: C#
  1. //..
  2. #include <stdint.h>
  3. //..
  4.  
  5. //Definir los pines a usar como PWM
  6. #define PWM1    LATBbits.LATB1
  7. #define PWM2    LATBbits.LATB2
  8. #define PWM3    LATBbits.LATB3
  9.  
  10. //..
  11.  
  12. //Declarar 3 contadores, uno por PWM. No sólo decidirán el duty de cada fase sino que además, la distancia entre ellos decidirá el phase-shifting:
  13. uint8_t counter1, counter2, counter3;
  14.  
  15. //declaramos otras 3 variables, estas llevan el valor actual del PWM (en pasos de 10%, es decir, desde 0% al 100%. Son 11 valores pero el PWM se come un paso (si necesitás más explicación del por qué del paso que se come, la puedo exponer después. Por eso la división es por 10 y no por 11 en los cálculos del tiempo).
  16. uint8_t PWM1value,PWM2value,PWM3value;
  17.  
  18. //en el código de la interr:
  19.  
  20. pragma interrupt Interrupt_ISR_TMR0
  21. void  Interrupt_ISR_TMR0 (void)
  22. {
  23.         TMR0=230;         //Hay que ajustarlo. Lo elegí para que quede un poco por debajo de 25Khz. Cuando menos interrumpa el timer, más tiempo de procesador para hacer otras cosas.
  24.         INTCONbits.TMR0IF=0;   //Borramos bandera. Puede que el compilador lo haga automáticamente. Hay que verificarlo. Te podés ahorrar la instrucción en ese caso
  25.  
  26.        if(++counter1 > 10) counter1 = 1;   //nunca los hago valer 0, ese es el paso que me "como" del PWM para generar el duty del PWM fiel a lo que debe ser
  27.        if(++counter2 > 10) counter2 = 1;
  28.        if(++counter3 > 10) counter3 = 1;
  29.  
  30.        if(PWM1value >= counter1) PWM1 = 1; else PWM1 = 0;    
  31.        if(PWM2value >= counter2) PWM2 = 1; else PWM2 = 0;
  32.        if(PWM3value >= counter3) PWM3 = 1; else PWM3 = 0;  
  33.  }
  34.  
  35.  
  36. void main()
  37. {
  38.     //falta código de inicialización, etc...
  39.  
  40.      //inicializo contadores de PWM
  41.      counter1 = 1;
  42.      counter2 = 1;
  43.      counter3 = 1;
  44.      set_pwm_duty(1,4,9);    //seteo los dutys de 3 fases: 10% para la fase 1, 40% para la fase 2 y 90% para la fase 3.
  45.      set_pwm_shift(0,0);        //seteo phase-shift de 0% para la fase 2 y para la fase 3, ambas siempre con respecto a la fase 1. La fase  1 no se toca, ya que es la referencia
  46.  
  47.    //falta config interr. Tmr0, etc. similar a lo que tenías en tu código, sólo que configurando el Tmr0 a 8 bits y el prescaler a 1:2
  48.  
  49.   while(1)
  50.   {
  51.       delay_ms(2000);           //demora de 2 segundos (mucho más en realidad por todo el % de tiempo de procesador que consume la interr del Timer)
  52.       set_pwm_duty(5,5,5);    //seteo los dutys de las 3 fases al 50% para que se vea bien el phase-shift que quiero establecer justo debajo de esto
  53.       set_pwm_shift(3,7);        //seteo phase-shift de 30% para la fase 2, y 70% para la fase 3, ambas siempre con respecto a la fase 1. La fase  1 no se toca, ya que es la referencia
  54.  
  55.       delay_ms(2000);           //demora de 2 segundos (mucho más en realidad por todo el % de tiempo de procesador que consume la interr del Timer)
  56.       set_pwm_duty(1,4,9);    //seteo los dutys de 3 fases: 10% para la fase 1, 40% para la fase 2 y 90% para la fase 3.
  57.       set_pwm_shift(0,0);        //seteo phase-shift de 0% para la fase 2 y para la fase 3, ambas siempre con respecto a la fase 1. La fase  1 no se toca, ya que es la referencia
  58.   }
  59.  
  60. }
  61.  
  62. inline void set_pwm_duty(uint8_t phase1Value, uint8_t phase2Value, uint8_t phase3Value)
  63. {
  64.     PWM1value = phase1Value;
  65.     PWM2value = phase2Value;
  66.     PWM3value = phase3Value;
  67. }
  68.  
  69. void set_pwm_shift(uint8_t phase2Shift, uint8_t phase3Shift)
  70. {
  71.     uint8_t tmp;
  72.  
  73.     tmp = (counter1+ phase2Shift) % 11;
  74.     if(!tmp) tmp++;              //no dejar que valga nunca 0
  75.     counter2 = tmp;
  76.  
  77.     tmp = (counter1+ phase3Shift) % 11;
  78.     if(!tmp) tmp++;              //no dejar que valga nunca 0
  79.     counter3 = tmp;
  80. }



Entonces, lo que deberías ver es durante varios segundos las 3 fases con phase shift 0 y con un duty del 10% la 1era, 40% la segunda y 90% la tercera.
Luego, cambia durante otros cuantos segundos y debería mostrar las 3 fases con un duty del 50% pero la fase 2 despazada un 30% con respecto a la fase 1 y la fase 3 despalzada un 70% con respecto a la fase 1.

Por supuesto que podés cambiar los valores de duty y shift a gusto en cualquier momento. No he testeado el código. Sólo lo estoy escribiendo mientras respondo, por ende puede tener errores. Probalo y nos contás si funciona.

Saludos.
 


« Última modificación: 17 de Diciembre de 2013, 19:47:46 por BrunoF, Razón: Agrego [code] »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #31 en: 17 de Diciembre de 2013, 19:48:15 »
BrunoF muchas gracias por esa explicación la verdad el ponerme a leer y mirar el código que escribiste he llegado a una conclusión que me  falta muchoooo camino por recorrer  :shock: :shock: para llegar al nivel que uds tiene. Me siento muy contento de que existan personas como uds que estan para ayudar. Me voy a poner a entender el codigo y a probarlo.

Tengo una preguntica cuando hablas de Necesitas interrumpir cada 1000000/25000/ 10. No entiendo de donde salen esos valores, el 10 como tu dices mas abajo es para hacer los salto de 0% a 100% con una resolución del 10% pero "1000000 y 25000" esos valores de donde salen?

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #32 en: 17 de Diciembre de 2013, 19:56:20 »
Hola Alvaro,

lo que pasa es que tal vez hace más tiempo que estamos dando vuelta con los uC y ya nos hemos armado de mañas y truquitos que uno recuerda y reutiliza seguido. Además, conocer cómo funciona un uC a fondo lleva años. Fuera de eso, no somos más capaces ni inteligentes que el resto, al menos así me considero yo. Sólo estamos un poco más viejos en esto. :D

1 segundo = 1000000uS

Como tu frecuencia deseada es de 25Khz, necesitaríamos interrumpir 25000 veces por segundo: 1000000 / 25000 = 40uS.

Ahora, como supuse un delta duty y shift-phase del 10%, eso nos da que por cada período, podemos establecer 11 valores posibles. Como la generación de PWM se come uno, nos quedan 10. Entonces  tenemos que poder generar el ancho de duty correcto. Para ello, este método recurre a subdividir cada período en n partes (en este caso n=10) y decidir en cada momento si el PWM debe estar en alto o bajo, generando los 11 posibles valores que deseamos poder generar de duty.

Por ende, la cuenta de cada cuánto interrumpir, resulta ser:

1000000 / 25000 / 10 = 4uS.

Sé que por ahí lancé bastante código para entender, pero he visto que eres un rápido aprendiz y estoy seguro que terminarás entendiendo el funcionamiento e incluso encontrando posibles errores y mejoras.

Saludos
« Última modificación: 17 de Diciembre de 2013, 20:05:15 por BrunoF »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #33 en: 20 de Diciembre de 2013, 14:08:43 »
Bueno he vuelto  :) he estado un poco ocupado y ademas ya que el año se va a terminar aproveche para formatear mi PC :P jejeje  Año nuevo Virus nuevos jajaja

BrunoF gracias por esas explicaciones he mirado tu codigo muy detallado y lo he analizado, primero que todo he visto que utiliza declaraciones de variables con terminos que desconocia, como: uint8_t inline bueno he buscado sobre ellos y he visto que se trabaja orientado a la parte de c/c++. Mire en el manual de C18 y he reemplazado el Uint8_t por unsigned char "Creo que es lo mismo" el inline si no lo he utilizado por que en el manual de c18 es como una instruccion en .asm y en c/c++ creo que se utiliza  cuando se hace el llamado de la funcion se reemplace todo por el cuerpo de la funcion. NOTA: si esto diciendo cosas que nada tienen que ver me perdonan eso fue lo que he entendio.
Ahora con respecto algunas cosas del codigo tengo ciertas cosas que no entiendo.

Código: [Seleccionar]
void set_pwm_shift(uint8_t phase2Shift, uint8_t phase3Shift)
{
    uint8_t tmp;
 
    tmp = (counter1+ phase2Shift) % 11;
    if(!tmp) tmp++;              //no dejar que valga nunca 0
    counter2 = tmp;
 
    tmp = (counter1+ phase3Shift) % 11;
    if(!tmp) tmp++;              //no dejar que valga nunca 0
    counter3 = tmp;
}

no entiendo la parte del %11 el modulo ese no me queda muy claro.. si me puede explicar esa funcion te lo agradezco


Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #34 en: 20 de Diciembre de 2013, 14:46:58 »
Hola Alvaro,

BrunoF gracias por esas explicaciones he mirado tu codigo muy detallado y lo he analizado, primero que todo he visto que utiliza declaraciones de variables con terminos que desconocia, como: uint8_t inline bueno he buscado sobre ellos y he visto que se trabaja orientado a la parte de c/c++. Mire en el manual de C18 y he reemplazado el Uint8_t por unsigned char "Creo que es lo mismo" el inline si no lo he utilizado por que en el manual de c18 es como una instruccion en .asm y en c/c++ creo que se utiliza  cuando se hace el llamado de la funcion se reemplace todo por el cuerpo de la funcion. NOTA: si esto diciendo cosas que nada tienen que ver me perdonan eso fue lo que he entendio.

como había escrito en el ejemplo de código de arriba, si pones un:

#include <stdint.h>

deberías reconocerte automáticamente los tipos de variables que he utilizado en el código. Personalmente me gusta más usar este tipo de de tipos de datos, porque son mucho más fáciles y fieles de migrar a otros compiladores. Me parece una declaración mucho más explícita. Internamente el stdint.h no es mucho más que un puñado de typedefs que pueden variar de compilador en compilador. Lo importante es que utilizándolo, si quiero que el compilador actual me declare una variable sin signo de 8 bits, hago indistintamente:

uitn8_t myVar;

sin tener que preocuparme por los tipos de datos que el compilador utiliza nativamente.

Por ejemplo,

el C18 podría convertir mi uint8_t a una variable de tipo unsigned char dentro de su stdint.h
mientras que el CCS podría convertira a una variable de tipo unsigned int8 dentro de su stdint.h

Cualquiera sea el caso, yo sólo he pedido que me declaren un uint8_t y luego el compilador en su stdint.h tendrá definidas las equivalencias hacia sus tipos de datos nativos.

Ahora con respecto algunas cosas del codigo tengo ciertas cosas que no entiendo.

Código: [Seleccionar]
void set_pwm_shift(uint8_t phase2Shift, uint8_t phase3Shift)
{
    uint8_t tmp;
 
    tmp = (counter1+ phase2Shift) % 11;
    if(!tmp) tmp++;              //no dejar que valga nunca 0
    counter2 = tmp;
 
    tmp = (counter1+ phase3Shift) % 11;
    if(!tmp) tmp++;              //no dejar que valga nunca 0
    counter3 = tmp;
}

no entiendo la parte del %11 el modulo ese no me queda muy claro.. si me puede explicar esa funcion te lo agradezco

La función set_pwm_shift lo que hace es calcular el phase-shift. Los datos de entrada son los ángulos de desplazamiento (shift) que desea que tenga la fase 2 y 3 con repecto a la fase 1. El rango aceptable de los valores debería ser entre 0 y 10, siendo 0 = 0 y 10 = 2PI.

Si por ejemplo quisiese un phase-shift de 180 grados (PI) de las fases 2 y 3 con repecto a la primera, haría:

set_pwm_shift(5,5);

e internamente lo que hace la función módulo (%) es acotar el resultado del offset entre 0 y 10 (o lo que sería su equivalente en ángulos entre 0 y 2PI) ya que la función módulo devuelve el resto de la división entera. Por ende, cuando uno realiza x % y, el resultado tendrá siempre un valor dentro del intervalo [0;y-1]. En este caso al ser y = 11, el resultado será siempre acotado dentro del intervalo [0,10].

Los acoto porque los valores posibles de los contadores de cada fase son siempre entre 1 y 10 (siempre esquivo el 0, en este caso verificando si el resultado del módulo (el resto) es 0, en cuyo caso lo incremento para que valga 1). Utilizo una variable temporal (tmp) porque hasta no obtener el resultado definitivo, no quiero que suceda justo una interrupción del TMR0 y me agarre con un valor de contador incorrecto. Si hiciese esto (sin utilizar una variable temporal):

    counter2 = (counter1+ phase2Shift) % 11;
    if(!counter2) counter2++;              //no dejar que valga nunca 0


podría suceder que algunas interrupciones del Tmr0 se produjesen justo entre esas dos líneas, y en ese caso, si el resultado del módulo fuese cero, la variable counter2 ingresaría a la subrutina de interr. del Tmr0 con valor 0, que es un valor no deseado por mi, ya que produciría un error en el duty del PWM2 durante esos ciclos de PWM.

Saludos
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #35 en: 20 de Diciembre de 2013, 15:46:49 »
Gracias de nuevo BrunoF con respecto a la directiva #include <stdint.h> creo y me arriesgo a decir esto ya que he visto el manual de C18  que en este compilador no la trae. En XC8 si viene según lo comprobé en el manual el manual.
Si estoy equivocado me lo haces saber.

Exitos :)

Lo que veo en el manual es lo siguiente

Código: [Seleccionar]
[i]An implementation that accepts any stricly conforming program that does not use complex
 types and in which the use of the features specified in the library clause (ANSI '89 Standard clause 7)
 is confined to the contents of the stadard headers <float.h> <iso646.h>.......<stdint.h>[/i]
« Última modificación: 20 de Diciembre de 2013, 15:52:46 por alvaro2043 »

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #36 en: 20 de Diciembre de 2013, 19:22:14 »
Bueno ya he implementado el codigo y ha funcionado perfecto  :-/ esto me va ha servir de patron y espero que para muchos para llevar acabo mas proyectos con PWM por software. Lo que he notado es que el PWM3 no aparece nada en el PIN0 el cual lo tengo para el PWM3  el PWM2 Y PWM1 sale como en el video. 

feature=youtu.be


Código: [Seleccionar]
#pragma config PLLDIV = 2  //Cristal de 8Mhz lo dividimos entre 2 para tener los 4Mhz
#pragma config CPUDIV = OSC1_PLL2  //Los 96Mhz de PLL lo dividimos entre 2 para tener los 48Mhz con lo que vamos a trabajar
#pragma config USBDIV = 2  /////Tomar el reloj para USB desde el PLL- 48Mhz
#pragma config FOSC = HSPLL_HS  //Configurando oscilador interno
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config BORV = 0
#pragma config VREGEN = OFF
#pragma config WDT = OFF
#pragma config WDTPS = 16384
#pragma config MCLRE = OFF
#pragma config LPT1OSC = OFF
#pragma config PBADEN = ON
#pragma config CCP2MX = OFF
#pragma config STVREN = OFF
#pragma config LVP = OFF
#pragma config ICPRT = OFF
#pragma config XINST = OFF
#pragma config DEBUG = OFF
#pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF,CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF,WRT3 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF,EBTR2 = OFF,EBTR3 = OFF

#include <p18f4550.h>
#include <delays.h>


#define PWM1    LATBbits.LATB1
#define PWM2    LATBbits.LATB2
#define PWM3    LATBbits.LATB0

//Tres contadores uno por cada PWM

unsigned char contador1,contador2,contador3;

//Variables que llevan el valor actual del pwm
unsigned char PWM1value,PWM2value,PWM3value;

//Prototipos de Funciones

void set_pwm_duty(unsigned char phase1Value, unsigned char phase2Value, unsigned char phase3Value );
void set_pwm_shift(unsigned char phase2shift,unsigned char phase3shift);


/*-------Interrupción de Alta_Prioridad---------*/
void Interrupt_ISR_TMR0(void);
#pragma code High_vector_Interrupt = 0x08

void High_vector(void){
     _asm goto Interrupt_ISR_TMR0 _endasm
}
#pragma code

#pragma interrupt Interrupt_ISR_TMR0
void  Interrupt_ISR_TMR0 (void)
{
     TMR0L=238;  //Ajustado para que se genere un Interrup cada 4us
     INTCONbits.TMR0IF=0;   
     if(++contador1>10) contador1=1;
     if(++contador2>10) contador2=1;
     if(++contador3>10) contador3=1;

     if(PWM1value >= contador1) PWM1=1; else PWM1=0;
     if(PWM2value >= contador2) PWM2=1; else PWM2=0;
     if(PWM3value >= contador3) PWM3=1; else PWM3=0;
    }



void main(){

   
/*---------Configuracion Oscilador--------*/
    OSCCONbits.SCS1=0;    //Oscilador primario
    OSCCONbits.SCS0=0;

 /*-------Configuracion de pines---------*/
    TRISBbits.RB1=0;     
    LATBbits.LATB1=0;       

    TRISBbits.RB2=0;
    LATBbits.LATB2=0;

    ADCON1=0x0F;   //Todos los pines como digitales

    T0CONbits.TMR0ON=0; //Timero Off
    T0CONbits.T08BIT=1; //Configuracion a 8bits
    T0CONbits.T0CS=0;   //Internal Instruccion
    T0CONbits.T0SE=0;
    T0CONbits.PSA=0;   //Prescaler On

    T0CONbits.T0PS2=0; //Prescaler 1:2
    T0CONbits.T0PS1=0;
    T0CONbits.T0PS0=0;

    RCONbits.IPEN=1;        //Habilitamos la prioridad
    INTCONbits.TMR0IF=0;    //Interrupcion por desbordamiento
    INTCONbits.GIE_GIEH=1;
    INTCONbits.GIEH=1;      //Activamos alta_Prioridad
    INTCONbits.TMR0IE=1;   

    INTCON2bits.TMR0IP=1;  //TMR0 Alta prioridad.

    T0CONbits.TMR0ON=1;    //On Timer0

    //Inicio de contadores de PWM
    contador1=1;
    contador2=1;
    contador3=1;
    set_pwm_duty(1,4,9);
    set_pwm_shift(0,0);


    while(1){

        Delay10KTCYx(10);
        set_pwm_duty(5,5,5);
        set_pwm_shift(3,7);

        Delay10KTCYx(10);
        set_pwm_duty(1,4,9);
        set_pwm_shift(0,0);

    }
}

void set_pwm_duty(unsigned char phase1Value, unsigned char phase2Value, unsigned char phase3Value ){

    PWM1value=phase1Value;
    PWM2value=phase2Value;
    PWM3value=phase3Value;
}

void set_pwm_shift(unsigned char phase2shift,unsigned char phase3shift){

    unsigned char tmp;
    tmp=(contador1+phase2shift)%11;
    if(!tmp) tmp++;
    contador2=tmp;

    tmp=(contador1+phase3shift);
    if(!tmp) tmp++;
    contador3=tmp;

}




Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #37 en: 20 de Diciembre de 2013, 21:08:39 »
Hola Álvaro! Me alegro que funcione. Fíjate que no configuraste como salida el pin b0.

Saludos
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #38 en: 20 de Diciembre de 2013, 21:38:48 »
Hola Álvaro! Me alegro que funcione. Fíjate que no configuraste como salida el pin b0.


Si tienes toda la razon :P jejeje que descuido y lo de la pregunta de  la directiva #include <stdint.h> si viene en el compilador C18 ??

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #39 en: 20 de Diciembre de 2013, 21:57:36 »
Ahora mísmo no tengo instalado el C18. Pero es tan sencillo como colocar la línea y ver si falla al compilar. Si falla es porque evidentemente no viene en el C18.

Saludos.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #40 en: 30 de Diciembre de 2013, 17:01:02 »
Buenas tarde a todos saludos y felices fiesta he estado un poco alejado de todo esto por motivo de la llegada de amigos, familiares etc. Bueno gracias a la ayuda de BrunoF y de otros compañeros poco a poco he ido entendiendo lo que quiero hacer. En esta ocasion quiero por medio de 2 pulsadores conectado a los pines del microcontrolador variar el ancho de pulso. Como el proposito de todo esto es generar las señales para controlar un puente H el ciclo de trabajo maximo que puedo obtener es del 50% de tal forma que las señales de los 2 transistores de la misma rama no conmuten al mismo tiempo. Bueno he utilizado el programa que he hecho anteriormente con la ayuda de Bruno, el problema es que no me quiere funcionar. La logica que tengo en mente y que fue la que supuestamtne implemente es la siguiente:

1- Sabemos que el ciclo de trabajo aumenta con una resolucion del 10%  (Para esta aplicacion el maximo es de 50% Para poder controlar el punte H) por ese motivo lo limito hasta 5 pasos, desde de cumplido estos 5 pasos el siguiente debe arrancar desde 1 y asi sucesivamente.

2- He definido un pin de entrada en donde va un pulsador tambien defini otro contador el cual cumple la siguiente funcion: Cuando se oprime el pulsador el contador debe de aumenter en 1. Este contador se examina en un swicht-case y apartir del valor que tenga aumenta el ciclo de trabajo. Me cause una curiosidad ¿Como puedo solucionar en el caso que alguien tenga por mucho tiempo el pulsador activado  ya que quiero que aumente por cada cambio de estado?

Anexo el codigo.. El cual esta un poco muy prematuro.

Código: [Seleccionar]
#include <p18f4550.h>
#include <delays.h>


#define PWM1    LATBbits.LATB1
#define PWM2    LATBbits.LATB2
#define sw1     LATAbits.LATA0
//Tres contadores uno por cada PWM

unsigned char contador1,contador2,contador;

//Variables que llevan el valor actual del pwm
unsigned char PWM1value,PWM2value=1;

//Prototipos de Funciones

void set_duty(void);

/*-------Interrupción de Alta_Prioridad---------*/
void Interrupt_ISR_TMR0(void);
#pragma code High_vector_Interrupt = 0x08

void High_vector(void){
     _asm goto Interrupt_ISR_TMR0 _endasm
}
#pragma code

#pragma interrupt Interrupt_ISR_TMR0
void  Interrupt_ISR_TMR0 (void)
{
     TMR0L=254; 
     LATBbits.LATB0=!LATBbits.LATB0;
     INTCONbits.TMR0IF=0;
     if(++contador1>10) contador1=1;
     if(++contador2>10) contador2=1;
     

     if(PWM1value >= contador1) PWM1=1; else PWM1=0;
     if(PWM2value >= contador2) PWM2=1; else PWM2=0;
     
    }



void main(){


/*---------Configuracion Oscilador--------*/
    OSCCONbits.SCS1=0;    //Oscilador primario
    OSCCONbits.SCS0=0;

 /*-------Configuracion de pines---------*/
    /*----Salidas---*/
    TRISBbits.RB1=0;
    LATBbits.LATB1=0;

    TRISBbits.RB2=0;
    LATBbits.LATB2=0;

    TRISBbits.RB0=0;
    LATBbits.LATB0=0;

    TRISBbits.RB3=0;
    LATBbits.LATB3=0;
//-----Entradas--------//
    TRISAbits.RA0=1;  //Definido como entrada
   
   
    TRISAbits.RA1=1;  //Definido como entrada
    LATAbits.LATA1=0;
 
  //----------------------//
    ADCON1=0x0F;   //Todos los pines como digitales

   
    T0CONbits.TMR0ON=0; //Timero Off
    T0CONbits.T08BIT=1; //Configuracion a 8bits
    T0CONbits.T0CS=0;   //Internal Instruccion
    T0CONbits.T0SE=0;
    T0CONbits.PSA=0;   //Prescaler On

    T0CONbits.T0PS2=0; //Prescaler 1:2
    T0CONbits.T0PS1=0;
    T0CONbits.T0PS0=0;

    RCONbits.IPEN=1;        //Habilitamos la prioridad
    INTCONbits.TMR0IF=0;    //Interrupcion por desbordamiento
    INTCONbits.GIE_GIEH=1;
    INTCONbits.GIEH=1;      //Activamos alta_Prioridad
    INTCONbits.TMR0IE=1;

    INTCON2bits.TMR0IP=1;  //TMR0 Alta prioridad.

    T0CONbits.TMR0ON=1;    //On Timer0

    //Inicio de contadores de PWM
    contador1=1;
    contador2=1;
   
   
    while(1){

       set_duty();
           
    }
}

void set_duty(void){

    unsigned char cntduty;

    while(!sw1);
                Delay10KTCYx(10); //Retardor de 8.33ms
                cntduty++;
                switch (cntduty){

                    case 1: PWM1value=1; break; //Ciclo de trabajo del 10%
                    case 2: PWM1value=2; break; //Ciclo de trabajo del 20%
                    case 3: PWM1value=3; break; //Ciclo de trabajo del 30%
                    case 4: PWM1value=4; break; //ciclo de trabajo del 40%
                    case 5: PWM1value=5; break; //Cilco de trabajo del 50%
                    default : cntduty=0;

                }

}

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #41 en: 30 de Diciembre de 2013, 17:08:18 »
Hola alvaro,

no te va a ejecutar nunca el código una vez que el Timer interrumpió por primera vez, porque estás precargandolo con el valor 254, que produce que el Timer se desborde inmediatamente y produce que el CPU ni bien sale de la interrupción del Timer, vuelva a ingresar sin ejecutar NUNCA código fuera del Timer.

Por el lado del pulsador, podés hacer:

Código: C#
  1. while(!sw1){
  2.                 Delay10KTCYx(10); //Retardor de 8.33ms
  3.                 cntduty++;
  4.                 switch (cntduty){
  5.  
  6.                     case 1: PWM1value=1; break; //Ciclo de trabajo del 10%
  7.                     case 2: PWM1value=2; break; //Ciclo de trabajo del 20%
  8.                     case 3: PWM1value=3; break; //Ciclo de trabajo del 30%
  9.                     case 4: PWM1value=4; break; //ciclo de trabajo del 40%
  10.                     case 5: PWM1value=5; break; //Cilco de trabajo del 50%
  11.                     default : cntduty=0;
  12.  
  13.                 }
  14.         while(!sw1);
  15.         Delay10KTCYx(10); //Retardo
  16.     }
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #42 en: 30 de Diciembre de 2013, 17:22:54 »
Gracias Bruno osea que no es recomendable precargar el registro TMR0L a un valor cercano del desborde? si es asi aprox cual es el valor máximo que uno puede cargar el timer de tal forma que no se genere ese problema. En los anteriores codigo habiamos cargado el Timer a 238, he decido cambiar ese valor ya que quería aumentar un poco mas la frecuencia de los 25Khz a 32Khz que es lo maximo que se puede generar con esa resolucion.

He visto algo curioso cuando lo simulo en proteus sucede que cuando pulso (SW1) el cual esta conectado a GND y cuando se pulsa ve VCC se queda en VCC por un tiempo considerable y demora en retornar de nuevo a GND no se si es el simulador ya que no lo he probado en lo fisico.

Gracias.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #43 en: 30 de Diciembre de 2013, 18:00:45 »
Gracias Bruno osea que no es recomendable precargar el registro TMR0L a un valor cercano del desborde? si es asi aprox cual es el valor máximo que uno puede cargar el timer de tal forma que no se genere ese problema. En los anteriores codigo habiamos cargado el Timer a 238, he decido cambiar ese valor ya que quería aumentar un poco mas la frecuencia de los 25Khz a 32Khz que es lo maximo que se puede generar con esa resolucion.

  Claro, no puedes dejarlo muy cercano al desborde porque más allá de tu código, hay código agregado por el compilador y por lo tanto no tienes un control preciso de la cantidad de ciclos consumidos y ademas te quedará poco tiempo (si es que sales de la interrupción y no reingresa inmediatamente) para tu programa de ejecución normal (quiero decir, todo aquello que no hagas en la interrupción).


He visto algo curioso cuando lo simulo en proteus sucede que cuando pulso (SW1) el cual esta conectado a GND y cuando se pulsa ve VCC se queda en VCC por un tiempo considerable y demora en retornar de nuevo a GND no se si es el simulador ya que no lo he probado en lo fisico.

Gracias.

  Todo dependerá de cuan cargado está el simulador. Abajo en lo que sería como una barra de estado te avisa si es que está corriendo o no en tiempo real. A su vez también te indica la carga del CPU en porcentaje.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado alvaro2043

  • PIC10
  • *
  • Mensajes: 41
Re: Timer0_PIC18F4550_No_se_que_pasa
« Respuesta #44 en: 02 de Enero de 2014, 18:18:17 »
Feliz año 2014 a todos :) que Dios los bendiga y los mejores deseos :)

Bueno todavia no he podido solucionar el problema de poder variar el ciclo de trabajo con el pulsador he probado el circuito en la protoboard y con mi osciloscopio ver los cambio.. Pero no pasa nada cuando lo oprimo Anexo el codigo. para ver que tengo mal..

Código: [Seleccionar]
#include <p18f4550.h>
#include <delays.h>

/*-----Definicion de estados--------*/

#define ciclo_10    1 //Ciclo del 10%
#define ciclo_20    2 //Ciclo del 20%
#define ciclo_30    3 //Ciclo del 30%
#define ciclo_40    4 //Ciclo del 40%
#define ciclo_50    5 //Ciclo del 50%

/*-----Definicion de pines-----------*/

#define PWM1    LATBbits.LATB0
#define button1 LATAbits.LATA0
/*-------------------------------------*/

unsigned char contador, PwmValue, estado;

/*----Prototipos de funciones----------*/

void set_pwm(unsigned char PwmValue1);
/*-------Interrupción de Alta_Prioridad---------*/
void Interrupt_ISR_TMR0(void);
#pragma code High_vector_Interrupt = 0x08

void High_vector(void){
     _asm goto Interrupt_ISR_TMR0 _endasm
}
#pragma code

#pragma interrupt Interrupt_ISR_TMR0
void  Interrupt_ISR_TMR0 (void)
{
    INTCONbits.TMR0IF=0;    /*Borramos bandera*/
    TMR0L=238;
    if(++contador>10) contador=1;

    if(PwmValue>=contador) PWM1=1; else PWM1=0;
}

void main(){

    estado=ciclo_10;

    TRISB=0x00;
    LATB=0x00;

    TRISAbits.RA0=1; //Como entradas
    //LATAbits.LATA0=0;

/*---------Configuracion Oscilador--------*/

    OSCCONbits.SCS1=0;    //Oscilador primario
    OSCCONbits.SCS0=0;

    ADCON1=0x0F;   //Todos los pines como digitales

    T0CONbits.TMR0ON=0; //Timero Off
    T0CONbits.T08BIT=1; //Configuracion a 8bits
    T0CONbits.T0CS=0;   //Internal Instruccion
    T0CONbits.T0SE=0;
    T0CONbits.PSA=0;   //Prescaler On

    T0CONbits.T0PS2=0; //Prescaler 1:2
    T0CONbits.T0PS1=0;
    T0CONbits.T0PS0=0;

    RCONbits.IPEN=1;        //Habilitamos la prioridad
    INTCONbits.TMR0IF=0;    //Interrupcion por desbordamiento
    INTCONbits.GIE_GIEH=1;
    INTCONbits.GIEH=1;      //Activamos alta_Prioridad
    INTCONbits.TMR0IE=1;

    INTCON2bits.TMR0IP=1;  //TMR0 Alta prioridad.

    T0CONbits.TMR0ON=1;    //On Timer0

    while(1){
        switch(estado){
        case ciclo_10 :
            PwmValue=1;
            while(button1);
            Delay1KTCYx(10);
            while(!button1);
            Delay1KTCYx(10);
            estado=ciclo_20;
            break;
        case ciclo_20 :
            PwmValue=2;
            while(button1);
            Delay1KTCYx(10);
            while(!button1);
            Delay1KTCYx(10);
            estado=ciclo_30;
            break;
        case ciclo_30 :
            PwmValue=3;
            while(button1);
            Delay1KTCYx(10);
            while(!button1);
            Delay1KTCYx(10);
            estado=ciclo_40;
            break;
        case ciclo_40 :
            PwmValue=4;
            while(button1);
            Delay1KTCYx(10);
            while(!button1);
            Delay1KTCYx(10);
            estado=ciclo_50;
        case ciclo_50:
            PwmValue=5;
            while(button1);
            Delay1KTCYx(50);
            while(!button1);
            Delay1KTCYx(50);
            estado=ciclo_10;
            break;


            }


       
    }
}