Autor Tema: XC8 + Flag Timer 1 + proteus  (Leído 5572 veces)

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

Desconectado JMKaltenmeier

  • PIC10
  • *
  • Mensajes: 31
XC8 + Flag Timer 1 + proteus
« en: 21 de Abril de 2020, 11:15:16 »
Tengo un inconveniente. Quiero hacer un código que cambia el registro de TMR1 para temporizar diferentes tiempos!.
Cuando desborda el timer, el flag se pone en 1, eso pasa y lo simulo cuando uso este codigo:
Código: [Seleccionar]
#include <xc.h>
#include <pic18f2550.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define _XTAL_FREQ 48000000 //para usar el Delay

unsigned int tiempo_on_us = 100;


void main(void)
{
   
   //PORTB
    TRISBbits.RB4=0;   
   //TIMER1
    T1CON=0b10110000;//prescale 8
    TMR1=0x00;
    T1CONbits.TMR1ON=1; //enciendo el timer
   
   
   
    while (1)
    {
        TMR1=65536 - ((tiempo_on_us*48)/(4*8));//100us
        do{
           
            PORTBbits.RB4=1;
       
        }while(PIR1bits.TMR1IF == 0);
        PIR1bits.TMR1IF = 0;
        PORTBbits.RB4=0;
        __delay_us(100);
    }
   
 };

pero por ejemplo cuando cambio el valor de la variable "tiempo_on_us" dentro del main. ya el flag nunca se pone en uno, El registro TMR1 se carga con el valor correcto y empieza a temporizar, llega a la cuenta maxima, desborda, pero el flag no se pone en 1, por lo que no sale del bucle . Ejemplo si simulo el siguiente codigo, que simplemente cambio el valor de la variable dentro del main.

Código: [Seleccionar]
#include <xc.h>
#include <pic18f2550.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define _XTAL_FREQ 48000000 //para usar el Delay

unsigned int tiempo_on_us = 100;


void main(void)
{
   
   //PORTB
    TRISBbits.RB4=0;   
   //TIMER1
    T1CON=0b10110000;//prescale 8
    TMR1=0x00;
    T1CONbits.TMR1ON=1; //enciendo el timer
   
    tiempo_on_us = 50;
   
    while (1)
    {
        TMR1=65536 - ((tiempo_on_us*48)/(4*8));//100us
        do{
           
            PORTBbits.RB4=1;
       
        }while(PIR1bits.TMR1IF == 0);
        PIR1bits.TMR1IF = 0;
        PORTBbits.RB4=0;
        __delay_us(100);
    }
   
 };


Cargar el timer de esta manera: TMR1=65536 - ((tiempo_on_us*48)/(4*8)); no me parece un buen metodo, pero no se como hacer para variar la temporzacion al valor que yo quiera. Necesito hacer esto para otro codigo, por lo que PWM lo descarte.

Desconectado Eduardo2

  • PIC24H
  • ******
  • Mensajes: 1004
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #1 en: 21 de Abril de 2020, 12:35:50 »
............
pero por ejemplo cuando cambio el valor de la variable "tiempo_on_us" dentro del main. ya el flag nunca se pone en uno, El registro TMR1 se carga con el valor correcto y empieza a temporizar, llega a la cuenta maxima, desborda, pero el flag no se pone en 1, por lo que no sale del bucle . Ejemplo si simulo el siguiente codigo, que simplemente cambio el valor de la variable dentro del main.

Código: [Seleccionar]
#include <xc.h>
#include <pic18f2550.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define _XTAL_FREQ 48000000 //para usar el Delay

unsigned int tiempo_on_us = 100;


void main(void)
{
   
   //PORTB
    TRISBbits.RB4=0;   
   //TIMER1
    T1CON=0b10110000;//prescale 8
    TMR1=0x00;
    T1CONbits.TMR1ON=1; //enciendo el timer
   
    tiempo_on_us = 50;
   
    while (1)
    {
        TMR1=65536 - ((tiempo_on_us*48)/(4*8));//100us
        do{
           
            PORTBbits.RB4=1;
       
        }while(PIR1bits.TMR1IF == 0);
        PIR1bits.TMR1IF = 0;
        PORTBbits.RB4=0;
        __delay_us(100);
    }
   
 };

Es raro,  yo copypego ese código y sale lo mas bien del bucle.  Tal vez convendría comprobar que esté en 1 al entrar.

Citar
Cargar el timer de esta manera: TMR1=65536 - ((tiempo_on_us*48)/(4*8)); no me parece un buen metodo, pero no se como hacer para variar la temporzacion al valor que yo quiera. Necesito hacer esto para otro codigo, por lo que PWM lo descarte.

A mi tampoco,  hacer ese cálculo repetidamente no tiene sentido y te suma 6uS al  Toff.  Mejor cargá directamente la cuenta de TMR1.

Código: [Seleccionar]
   ....................
    tiempo_on_us = 50 ;
    tiempo_on_tics = 0x10000-(tiempo_on_us*48)/(4*8) ;
    while (1)
    {
        TMR1 = tiempo_on_tics ;
        PORTBbits.RB4 = 1 ;
        while(PIR1bits.TMR1IF == 0);
        PIR1bits.TMR1IF = 0;
        PORTBbits.RB4   = 0;
        __delay_us(100);
    }

No querés usar PWM, OK   ¿Pero por qué tampoco interrupciones?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #2 en: 21 de Abril de 2020, 12:59:37 »
Si el problema es optimización, entonces:

Código: C
  1. 0xFFFF - ((((tiempo_on_us << 1) + tiempo_on_us) >> 1)) + 1)

Una multiplicación por 3, una division por 2 y luego la resta. Si... ocupa unos cuantos ciclos, pero seguramente sea mucho menos que los ciclos de una division por 32.
Queda 3/2 por que 48/32 son fracciones equivalentes.
Y luego reducido el numero del comienzo que llevaria a ocupar numeros de 32 bits. Para que se maneje en 16...

Esto en el caso que realmente necesite hacer este calculo..... Sino lo usa como antes.

No lo compile pero ASM seguramente deberia llevar 4 para hacer lo del 3/2 y sumarle 1, luego la resta de 16bits, que serian 6 mas aproximadamente. un total de 15/20 ciclos. Por las dudas.
« Última modificación: 21 de Abril de 2020, 13:02:01 por KILLERJC »

Desconectado Eduardo2

  • PIC24H
  • ******
  • Mensajes: 1004
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #3 en: 21 de Abril de 2020, 15:52:16 »
Por otro lado... ¿Para que usás el timer en modo bloqueante? 
Para eso hacé un retardo con un bucle for.  No es lo mismo que el timer, pero del modo en que lo estás usando da igual. Incluso podés hacer variable el T_off.

Código: [Seleccionar]
#define delay_for(x) for(unsigned int nnnn=x;nnnn>0;nnnn--)

void main(void)
{
unsigned int N_on,N_off ;

   //PORTB
    TRISBbits.RB4=0;

    tiempo_on_us =  50 ;
    tiempo_off_us = 100 ;

    N_on  = tiempo_on_us *4/3  ; // Es la variable que realmente tenés que modificar
    N_off = tiempo_off_us *4/3 ; // Idem

    while (1)
    {
        PORTBbits.RB4 = 1 ;
        delay_for(N_on) ;

        PORTBbits.RB4   = 0;
        delay_for(N_off) ;
    }
 };

Desconectado JMKaltenmeier

  • PIC10
  • *
  • Mensajes: 31
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #4 en: 21 de Abril de 2020, 17:03:17 »
Hola Eduardo2. Comienzo contestándote para la segunda respuesta
Citar
Por otro lado... ¿Para que usás el timer en modo bloqueante?
Para eso hacé un retardo con un bucle for.  No es lo mismo que el timer, pero del modo en que lo estás usando da igual. Incluso podés hacer variable el T_off.
El tema es este, el codigo que puse es un breve programa para ver porque el flag no se pone en alto cuando desborda el timer.
Yo en realidad estoy implementando otro programa que genera una secuencia de pulsos bipolares, con ancho de pulso, tiempo muerto, y frecuencia variable. todos los tiempos esos lo genero con el TIMER1, la idea es que un usuario pueda modificar esto a gusto, por lo que debería modificar la carga del registro cada vez que quiera variar uno de estos paramentos.
Por eso que queiro cargar al registro con una variable y no con un valor fijo. La idea que cuando se produzca una interrupción (ejemplo con un pulsador), cambie el valor de esa variable y luego modifique el valor registro TMR1.
Ahora eso es en el programa principal, lo que sucedía era esto: Cuando yo carga de manera fija el registro TMR1 para los diferentes paramentros, o con el primer metodo de inicializar una variable fuera del "void main (Void)" todo andaba bien, el timer desbordaba y el flag se ponia en uno, todo muy lindo, podía ver la secuencia de pulsos bipolares en Proteus. Luego cuando modificaba una variable ya el flag del timer nunca se ponía en uno aunque este desbordara!!!, lo que digo que sucede con el segundo programa cuando digo que no sale del bucle "do while".


Citar
Es raro,  yo copypego ese código y sale lo mas bien del bucle.  Tal vez convendría comprobar que esté en 1 al entrar.
Te muestro imagen 1, sin modificar la variable
imagen 2, modificando la variable
No me doy cuenta que xq pasa esto, yo tengo entendio que ese flag siempre se pone en uno cuando desborda el timer, es como automático, pareciera que algo lo bloquea. Yo vi la simulación haciendo un debugger con el VSM de proteus, es mas lo estoy corriendo en "tiempo real" con proteus mientras voy linea por linea moviendome en MPLABX. Veo como se van modificando los registros tanto en Proteus  y Mplab x, y es exactamente lo mismo, no es que en Mplabx si se pone en alto, pero en proteus no. Estoy utilizando la herrmienta Proteus VSM viewer.

Citar
A mi tampoco,  hacer ese cálculo repetidamente no tiene sentido y te suma 6uS al  Toff.  Mejor cargá directamente la cuenta de TMR1
Exacto, alguna idea de como hacer lo que quiero sin utilizar una formula asi?. Ejemplo, que venga un flaco, ponga con un teclado, quiero 200us, joya temporiza 200us, pero luego ponga 50us y temporice 50us. Como que me veo obligado a utilizar una variable que modifique el registro según la formula para temporizar el valor adecuado.


Citar
No querés usar PWM, OK   ¿Pero por qué tampoco interrupciones?
Voy a usar interrupciones, pero no del modulo Timer...No es necesario según la esencialidad del programa. Para lo unico que voy a usar las interrupciones es para modificar el registro TMR1, ejemplo con un pulsador, conectado al puerto B.



Hola KILLERJC, el problema en principio no es de optimizacion, puse esa cuenta como para salir del paso y ver por que carajo no se pone en alto el flag. Obviamente comprobé que el registro luego de esa cuenta tenga e valor que yo pretendo. En principio no importa que tome mas o menos ciclos en hacerla.
En principio no es importante que tome varios ciclos en cargar el registro, quiero que se ponga el Flag en uno para hacer lo que yo quiero.
Luego si, voy a intentar optimizar eso lo mejor posible



Desconectado Eduardo2

  • PIC24H
  • ******
  • Mensajes: 1004
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #5 en: 21 de Abril de 2020, 18:43:44 »
...Te muestro imagen 1, sin modificar la variable
imagen 2, modificando la variable
No me doy cuenta que xq pasa esto, yo tengo entendio que ese flag siempre se pone en uno cuando desborda el timer, es como automático, pareciera que algo lo bloquea. Yo vi la simulación haciendo un debugger con el VSM de proteus, es mas lo estoy corriendo en "tiempo real" con proteus mientras voy linea por linea moviendome en MPLABX. Veo como se van modificando los registros tanto en Proteus  y Mplab x, y es exactamente lo mismo, no es que en Mplabx si se pone en alto, pero en proteus no. Estoy utilizando la herrmienta Proteus VSM viewer.

Tu simulación dura 1ms y la salida recíen cambia despues de 43.5ms

 

* 2550_43.jpg
(108.23 kB, 800x342 - visto 392 veces)


Hay que analizar por qué la 1er cuenta es tan alta.

Citar
Exacto, alguna idea de como hacer lo que quiero sin utilizar una formula asi?. Ejemplo, que venga un flaco, ponga con un teclado, quiero 200us, joya temporiza 200us, pero luego ponga 50us y temporice 50us. Como que me veo obligado a utilizar una variable que modifique el registro según la formula para temporizar el valor adecuado.

Es que al número que ingresó el flaco (50)  , antes de terminar la interrupción hacés: 
N_tmr = 65536-numero_del_flaco*3/2 ;  // 3/2 = 48/(4*8)
y es N_tmr  con lo que reiniciás el TMR1 dentro del bucle.


---------------------------------------------------------------------------------------------------------

Revisando me encuentro con que si a TMR1 lo inicio fuera del loop, algo sin sentido porque lo hace dos líneas despues:
Código: [Seleccionar]
void main(void)
{
   //PORTB
    TRISBbits.RB4=0;
   //TIMER1
    T1CON=0b10110000;//prescale 8
    TMR1=0x00;
    T1CONbits.TMR1ON=1; //enciendo el timer

    tiempo_on_us = 50;
    TMR1=65536 - ((tiempo_on_us*48)/(4*8));   //<<<<<<<<<<<<  Línea "inútil"
    while (1)
    {
        TMR1=65536 - ((tiempo_on_us*48)/(4*8));//100us
        do{
......................

Con esa línea simula correctamente, la sacás y vuelve a demorar 43.6ms en arrancar.

No se si lo probaste ya físicamente, porque huele a bug del Proteus.   Con este sería el tercero con que me encuentro.


« Última modificación: 21 de Abril de 2020, 19:57:45 por Eduardo2 »

Desconectado JMKaltenmeier

  • PIC10
  • *
  • Mensajes: 31
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #6 en: 21 de Abril de 2020, 20:17:04 »
Hola Eduardo2. Me corta las piernas si llega a ser bug de proteus!. Luego lo voy a probar físicamente, creo que en mi casa tengo las cosas necesarias en casa. Tuve que descargar el  proteus 8.9, ya que versiones anteriores también tenían bug con los comparadores analógicos de este PIC, cosa que también los necesito ajajaj.
Probe exactamente el mismo codigo con el TIMER0 jajaja, con este empieza luego de 5.3ms.
Voy a probar que onda con el modulo CPP en modo Compare, Creo que puedo hacer exactamente lo mismo, con el flag que se pone en alto del modulo, al compararse con el valor del registro TMR1. Espero que no ande mal, si no me corta las piernas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #7 en: 21 de Abril de 2020, 20:27:20 »
Citar
Con esa línea simula correctamente, la sacás y vuelve a demorar 43.6ms en arrancar.

Suena a una optimizacion... Apenas puedo lo pruebo en mi PC.

Desconectado JMKaltenmeier

  • PIC10
  • *
  • Mensajes: 31
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #8 en: 21 de Abril de 2020, 20:42:26 »
Haciendo esto anda Bien. Puedo cambar la variable, cambia el ancho del pulso, todo Bien, Pero dentro del While(1), Me va a joder la vida si la cambbio dentro de una interrupcion, xq no va a andar.
(pase a TIMER0, luego pruebo lo mismo con TIMER1)

Citar
#define _XTAL_FREQ 48000000 //para usar el Delay

unsigned int tiempo_on_us = 100;
unsigned int CTimer;
   

void main(void)
{  //PORTB
    TRISBbits.RB4=0;   
   //TIMER1
    T0CON=0b00001010;//prescale 8
    TMR0=0x00;
    T0CONbits.TMR0ON=1; //enciendo el timer
    //tiempo_on_us = 50;
    //CTimer=65536 - tiempo_on_us*(3/2);//100us
    //TMR0=CTimer;
    while (1)
    {
        tiempo_on_us = 5000;
         CTimer=65536 - tiempo_on_us*(3/2);//100us
        TMR0=CTimer;
        do{
           
            PORTBbits.RB4=1;
       
        }while(INTCONbits.TMR0IF == 0);
        INTCONbits.TMR0IF = 0;
        PORTBbits.RB4=0;
        __delay_us(100);
    }
   
 };




Desconectado JMKaltenmeier

  • PIC10
  • *
  • Mensajes: 31
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #9 en: 21 de Abril de 2020, 20:48:06 »
Sin embargo si hago esto, anda mal tambien!.
 
Código: [Seleccionar]
void main(void)
{  //PORTB
    TRISBbits.RB4=0;   
   //TIMER1
    T0CON=0b00001010;//prescale 8
    TMR0=0x00;
    T0CONbits.TMR0ON=1; //enciendo el timer
    //tiempo_on_us = 50;
    //CTimer=65536 - tiempo_on_us*(3/2);//100us
    //TMR0=CTimer;
    while (1)
    {
        tiempo_on_us = tiempo_on_us + 100;
         CTimer=65536 - tiempo_on_us*(3/2);//100us
        TMR0=CTimer;
        do{
           
            PORTBbits.RB4=1;
       
        }while(INTCONbits.TMR0IF == 0);
        INTCONbits.TMR0IF = 0;
        PORTBbits.RB4=0;
        __delay_us(100);
    }

Desconectado uZYNQ

  • PIC16
  • ***
  • Mensajes: 123
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #10 en: 21 de Abril de 2020, 20:56:46 »
Cargar el timer de esta manera: TMR1=65536 - ((tiempo_on_us*48)/(4*8)); no me parece un buen metodo, pero no se como hacer para variar la temporzacion al valor que yo quiera. Necesito hacer esto para otro codigo, por lo que PWM lo descarte.
Porque descartas el PWM?? EL PIC18F2550 tiene un modulo EPWM (mejorado) que te permite hacer lo que quieres! Incluso para señales complementarias ya tiene el tiempo muerto programable. Se ajusta la frecuencia con un registro (PR2) y el ciclo de trabajo se actualiza en otro registro (CCP1L). Este modulo es utilizado para control de motores y convertidores de potencia. otros como el PIC18F4431 tiene tres modulos EPWM utilizado mucho para control de motores trifasicos.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #11 en: 21 de Abril de 2020, 21:22:57 »
Ahi lo probe, y en el simulador del MPLAB, me funciona correctamente, tengo XC8 1.43

Desconectado Eduardo2

  • PIC24H
  • ******
  • Mensajes: 1004
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #12 en: 22 de Abril de 2020, 02:43:41 »

Misterio resuelto (creo :) )


En la configuración de Timer1:  T1CON=0b10110000
está activado el bit7  RD16

    RD16: 16-Bit Read/Write Mode Enable bit
    1 = Enables register read/write of Timer3 in one 16-bit operation
    0 = Enables register read/write of Timer3 in two 8-bit operations

En este caso, primero debe escribirse TMR1H, que no se carga en el registro sino en un buffer.
Luego se debe escribir TMR1L, que activa la carga simultánea del buffer a TMR1H.

¿Que pasa si se hace al revés? 
Al escribir 1ro TMR1L, en TMR1H se carga lo que tenía el buffer y lo que se escribe TMR1H permanece abandonado en el buffer hasta la próxima escritura de TMR1L 


¿Que pasaba acá?

Cuando se carga una constante, por ejemplo TMR1=0x0000;
XC8 genera (en assembler :) )
Código: [Seleccionar]
    TMR1H = 0 ;
    TMR1L = 0 ;   

Todo Ok, pero cuando se trata de una variable de 16 bits, ej: TMR1 = Nh_Nl
genera:
Código: [Seleccionar]
    TMR1L = Nl ;
    TMR1H = Nh ;

Cambia el orden !!!!  Nh queda boyando en el buffer y lo que fue a TMR1H es el valor que había antes.


En la 1er versión del programa, como unsigned int tiempo_on_us = 100 ;  no se volvía a tocar XC8 la trataba como constante --> cargaba en el orden correcto.   

Pero despues, con tiempo_on_us = 50 ;  ya se trataba como variable y te la cargaba al revés. 
Entonces, en el 1er ciclo, en lugar de cargarse 0xFF1E en TMR1 se cargaba 0x001E (overflow en ~43ms) , pues 0x00 era el contenido del buffer y 0xFF quedaba esperando.
Para el segundo ciclo siempre se cargaba 0xFF, por eso parecía andar bien.


Solución:  Usar el macro WRITETIMER1(x) que siempre te carga los registros en el orden correcto.
Código: [Seleccionar]
    WRITETIMER1(65536 - (tiempo_on_us*3/2) ) ;       
Microchip es conciente de la cagada pero en lugar de arreglar el problema te hace un macro  :(   
   

Desconectado JMKaltenmeier

  • PIC10
  • *
  • Mensajes: 31
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #13 en: 22 de Abril de 2020, 09:00:33 »
hola uZYNQ
Citar
Porque descartas el PWM?? EL PIC18F2550 tiene un modulo EPWM (mejorado) que te permite hacer lo que quieres! Incluso para señales complementarias ya tiene el tiempo muerto programable. Se ajusta la frecuencia con un registro (PR2) y el ciclo de trabajo se actualiza en otro registro (CCP1L). Este modulo es utilizado para control de motores y convertidores de potencia. otros como el PIC18F4431 tiene tres modulos EPWM utilizado mucho para control de motores trifasicos.
Simplemente no veia la utilidad para la aplicacion de establecer solo tiempos. Estoy tratando de establecer tiempos precisos para una generación de pulsos bipolares. hay dos tiempos muertos y un tiempo igual para el pulso + y -. Es necesario que los tiempos para el pulso + y - sean IGUALES, por eso que el codigo para tratar eso lo hago en ASM. El hecho de setear estos tres tiempos, me parece mas practico y preciso que utilizar un PWM. El EPWM no esta para los disp PIC18F4550/4455?.

hola KILLERJC
Citar
Ahi lo probe, y en el simulador del MPLAB, me funciona correctamente, tengo XC8 1.43
Yo no utilice el simulador de MPLAB, directamente uso la herramienta de VSM... Creo que deberia ser lo mismo. Te pregunto, cual es el motivo por el cual no actualizas el XC8?


hola Eduardo2.
Citar
Misterio resuelto (creo :) )
Tiene toda la pinta que si, ahi lo probe, y en principio anda....Voy a ver que onda en la otra aplicación. Estoy seguro que nunca me hubiera dado cuenta jajaaj, ya estaba negado jajajaja

Desconectado uZYNQ

  • PIC16
  • ***
  • Mensajes: 123
Re:XC8 + Flag Timer 1 + proteus
« Respuesta #14 en: 22 de Abril de 2020, 09:17:03 »

 El EPWM no esta para los disp PIC18F4550/4455?.


Si claro que tienen el EPWM, Los PIC18F4550/4455 son iguales a los PIC18F2550/2455 pero con un puerto adicional y encapsulado de 40 pines en vez de 28.


 

anything