Autor Tema: Precision timer0 pic18f4550  (Leído 3126 veces)

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

Desconectado jesus524

  • PIC10
  • *
  • Mensajes: 3
Precision timer0 pic18f4550
« en: 28 de Octubre de 2019, 04:34:05 »
Buen dia! Tengo un problema con el timer0 del pic18f4550.
Estoy haciendo un proyecto para usar 2 servomotores con el timer0 pero tengo el problema que no es preciso!
Configure el timer0 para cada 20 ms e hice para que de alto en 1ms y bajo en 19ms y no es preciso... En alto lo hace a 870us

Podrian ayudarme por favor? Gracias!

Citar
//Este es un comentario
//Bits de configuracion o directivas de preprocesador
//#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
//#pragma config CPUDIV = OSC2_PLL3// System Clock Postscaler Selection bits ([Primary Oscillator Src: /2][96 MHz PLL Src: /3])
#pragma config FOSC = XT_XT  // Oscillator Selection bits (XT oscillator, PLL enabled (XTPLL))
#pragma config PWRT = ON        // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOR = OFF        // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)

#include <xc.h>
#define _XTAL_FREQ 4000000UL   //Frecuencia de trabajo actual

unsigned int temporal = 0;

unsigned int servo = 1;     // Servos para seleccionar Servo1 = 1 / Servo2 = 0

//ANGULOS ACTUALES DE LOS SERVO 1 Y 2

unsigned int ang_servo1 = 1000;
unsigned int ang_servo2 = 1000;

unsigned int val_min = 1000;
unsigned int val_max = 2000;

void Configurar_TMR0(void){
    INTCONbits.GIE = 0;
    T0CON = 0x88;//1000 0100
    INTCONbits.TMR0IE = 1; // Permitir el desbordamiento del Timer0
    INTCONbits.GIE = 1;
}

void ingresoTmr0(unsigned int tiempo){  //1000
    temporal = (65535 - tiempo);
    TMR0L = temporal;
    temporal = (65535 - tiempo);
    TMR0H = temporal >>8;
    T0CONbits.TMR0ON = 1;
}

void Configurar_Puertos(void){
    ADCON1 = 0x0F;
    TRISBbits.RB0 = 1;      //BOTON PARA IZQUIERDA DEL SERVO 1
    TRISBbits.RB1 = 1;      //BOTON PARA DERECHA DEL SERVO 1
    TRISBbits.RB2 = 1;      //BOTON PARA IZQUIERDA DEL SERVO 2
    TRISBbits.RB3 = 1;      //BOTON PARA DERECHA DEL SERVO 2
   
    TRISEbits.RE0 = 0;      //SERVO 1
    TRISEbits.RE1 = 0;      //SERVO 2
}

void main(void){

    Configurar_TMR0();
    Configurar_Puertos();
    T0CONbits.TMR0ON = 0;
   
    //ESTABLECER UN VALOR INICIAL
    //SERVO 1 EN BAJO
   
   
   
    while(1){
        //PARA EL SERVO 1 IZQUIERDA
        if(PORTBbits.RB0 == 1){     //ANG_SERVO1 = 1000
            __delay_ms(15);
            if(ang_servo1 == val_min){
                ang_servo1 = val_min;   
                servo = 1;
            }
            else{
                ang_servo1 = ang_servo1 - 50;
                servo = 1;
            }
        }
        //PARA EL SERVO 1 DERECHA
        if(PORTBbits.RB1 == 1){
            __delay_ms(15);
            if(ang_servo1 == val_max){
                ang_servo1 = val_max;
                servo = 1;
            }
            else{
                ang_servo1 = ang_servo1 + 50;
                servo = 1;
            }
        }
        //PARA EL SERVO2 IZQUIERDA
        if(PORTBbits.RB2 == 1){
            __delay_ms(15);
            if(ang_servo2 > val_min){
              ang_servo2 = ang_servo2 - 50;
              servo = 0; 
            }
            else{
                ang_servo2 = val_min;
                servo = 0;
            }
           
        }
        //PARA EL SERVO2 DERECHA
        if(PORTBbits.RB3 == 1){
            __delay_ms(15);
            if(ang_servo2 < val_max){
                ang_servo2 = ang_servo2 + 50;
                servo = 0;
            }
            else{
                ang_servo2 = val_max;
                servo = 0;
            }
        }
    }
}

//IMAGINANDO QUE INGRESE 1000

void __interrupt (high_priority) Tmr0ISR(void){
    if(INTCONbits.TMR0IF){     
        switch(servo){
            case 1:
                if(PORTEbits.RE0){
                    ingresoTmr0(ang_servo1);
                    LATEbits.LE0 = 0;
                }
                else{
                    ingresoTmr0(20000-ang_servo1);
                    LATEbits.LE0 = 1;
                }
                INTCONbits.TMR0IF = 0;
                //CONTO 2ms (ESTANDO EN BAJO) / SALTA A LA INTERRUPCION Y AHORA CUENTA
                //19ms (ESTANDO EN ALTO)
                break;
            case 0:
                if(PORTEbits.RE1){
                    ingresoTmr0(ang_servo2);
                    LATEbits.LE1 = 0;
                }
                else{
                    ingresoTmr0(20000-ang_servo2);
                    LATEbits.LE1 = 1;
                }
                INTCONbits.TMR0IF = 0;
                break;
               
        }
       
    }
}

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Precision timer0 pic18f4550
« Respuesta #1 en: 28 de Octubre de 2019, 07:16:24 »
Un problema que veo sin siquiera ponerme a pensar en el codigo es:

- Estas usando el Timer 0 como si fuera de 16 bits.

temporal = (65535 - tiempo);
    TMR0L = temporal;

Y no lo iniciaste como 16 bits... Es decir cambiar el bit: T08BIT: Timer0 8-Bit/16-Bit Control bit
inicia en 1 lo cual lo esta como 8 bits.

Desconectado jesus524

  • PIC10
  • *
  • Mensajes: 3
Re:Precision timer0 pic18f4550
« Respuesta #2 en: 28 de Octubre de 2019, 10:14:58 »
Gracias por responder! Pero el bit T08BIT si lo tengo configurado como 16 bits en la
Citar
void Configurar_TMR0(void){
esta el T0CON configurado como 10001000

Un problema que veo sin siquiera ponerme a pensar en el codigo es:

- Estas usando el Timer 0 como si fuera de 16 bits.

temporal = (65535 - tiempo);
    TMR0L = temporal;

Y no lo iniciaste como 16 bits... Es decir cambiar el bit: T08BIT: Timer0 8-Bit/16-Bit Control bit
inicia en 1 lo cual lo esta como 8 bits.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Precision timer0 pic18f4550
« Respuesta #3 en: 28 de Octubre de 2019, 15:55:02 »
Perdon no lo vi. Ahora mirando el codigo encuentro varios problemas.

Código: C
  1. if(ang_servo1 == val_min){
  2.                 ang_servo1 = val_min;  
  3.                 servo = 1;
  4.             }
  5.             else{
  6.                 ang_servo1 = ang_servo1 - 50;
  7.                 servo = 1;
  8.             }

Por que no directamente

Código: C
  1. if(PORTBbits.RB0 == 1){     //ANG_SERVO1 = 1000
  2.             while(PORTBbits.RB0);
  3.             ang_servo1 = ang_servo1 - 50;
  4.             if(ang_servo1 < val_min) ang_servo1 = val_min;

Es decir, Decremento y verifico si me pase... Asi con todos los botones.

Y finalmente la interrupcion.

Hacer un switch case es un desastre.... Por lo tanto, considero que deberias buscar otra aproximacion.

Deberias en ves de usar el valor del timer, deberia tener una interrupcion fija, de unos 0,1ms por ejemplo
Entonces 10 veces es el minimo (1ms)
Y 20 veces es el maximo (2ms)

Esto hace que tu interrupcion sea la siguiente:

Código: C
  1. void __interrupt (high_priority) Tmr0ISR(void){
  2.     if(INTCONbits.TMR0IF){    
  3.         ingresoTmr0(valorpara0.1ms);
  4.         INTCONbits.TMR0IF = 0;
  5.         if(continterrupciones > ang_servo1) LATEbits.LE0 = 0;
  6.         if(continterrupciones > ang_servo2) LATEbits.LE1 = 0;
  7.         if(++continterrupciones > 200) {
  8.                 continterrupciones = 0;
  9.                 LATEbits.LE0 = 1;
  10.                 LATEbits.LE1 = 1;
  11.         }
  12.     }
  13. }

Y cargas en ang_servox un valor entre 10 y 20...

Por supuesto esto no tiene demasiados pasos, ya que tenemos 10 pasos para dar. Podes achicar mas la interrupcion.
Ademas como el tiempo es fijo, podrias usar el CCP en modo Compare, para que se auto-recargue, lo que si vas a necesitar usar el Timer 1

Desconectado jesus524

  • PIC10
  • *
  • Mensajes: 3
Re:Precision timer0 pic18f4550
« Respuesta #4 en: 29 de Octubre de 2019, 16:27:44 »
Gracias por responder!

Hice un codigo mas sencillo y pues da lo mismo... le di 2 ms en alto y 18ms en bajo, pero no es precisio, me da 1.88 ms en alto

#pragma config PLLDIV = 0       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC2_PLL3// System Clock Postscaler Selection bits ([Primary Oscillator Src: /2][96 MHz PLL Src: /3])
#pragma config FOSC = XTPLL_XT  // Oscillator Selection bits (XT oscillator, PLL enabled (XTPLL))
#pragma config PWRT = ON        // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOR = OFF        // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)

#include <xc.h>
#define _XTAL_FREQ 32000000UL   //Frecuencia de trabajo actual


unsigned int servo = 1;
unsigned int ang_servo1 = 2000;
unsigned int estado = 0;

void ingresoTmr0(unsigned int tiempo){
    TMR0L = (65535 - tiempo);
    TMR0H = (65535 - tiempo) >> 8;
}

void main(void){
    ADCON1 = 0x0F;              //Todos los RXy en digitales
    TRISEbits.RE0 = 0;
    INTCONbits.GIE = 1;
    INTCONbits.TMR0IE = 1;
    T0CON = 0x82;
    while(1){
    }   
}


void __interrupt (high_priority) Tmr0ISR(void){
    if(estado == 0){
        estado = 1;
        LATEbits.LE0 = 0;
        TMR0L = 63535;
        TMR0H = 63535>>8;
               
    }
    else{
        estado = 0;
        LATEbits.LE0 = 1;
        TMR0L = 47535;
        TMR0H = 47535>>8;
    }
    INTCONbits.T0IF = 0;
}

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Precision timer0 pic18f4550
« Respuesta #5 en: 29 de Octubre de 2019, 21:19:06 »
Citar
Hice un codigo mas sencillo y pues da lo mismo... le di 2 ms en alto y 18ms en bajo, pero no es precisio, me da 1.88 ms en alto

Y eso es lo que me da el simulador del MPLAB X:
Código: [Seleccionar]
Target halted. Stopwatch cycle count = 15041 (1,880125 ms)
Los problemas son:
- Al entrar en la interrupcion se sigue contando, eso ya es un error de tiempo
- Hasta que cambias el valor del timer, seguis aumentando el error. Por eso es lo primero que haces.

De todas formas NO es bueno... Por eso recomiendo el uso del Timer1 + CCP

Código: C
  1. #pragma config PLLDIV = 0       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
  2. #pragma config CPUDIV = OSC1_PLL2
  3. #pragma config FOSC = XT_XT
  4. #pragma config PWRT = ON        // Power-up Timer Enable bit (PWRT enabled)
  5. #pragma config BOR = OFF        // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
  6. #pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting 2.05V)
  7. #pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
  8. #pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
  9. #pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
  10. #pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
  11. #pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
  12. #pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
  13. #pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
  14.  
  15. #include <xc.h>
  16. #define _XTAL_FREQ 4000000UL   //Frecuencia de trabajo actual
  17.  
  18.  
  19. void main(void){
  20.    
  21.     ADCON1 = 0x0F;              //Todos los RXy en digitales
  22.     LATEbits.LE0 = 0;
  23.     TRISEbits.RE0 = 0;
  24.    
  25.     // Configuracion del timer 1
  26.     // Preescaler 1:1
  27.     T1CON = 0;
  28.    
  29.     // Configuracion del CCP - Compare
  30.     // Cargo para 2ms -> 2000
  31.     CCP1CON = 0x0B;
  32.     CCPR1 = 2000;
  33.    
  34.     // Activo Timer 1
  35.     T1CONbits.TMR1ON = 1;
  36.     LATEbits.LE0 = 1;
  37.    
  38.     // Activo interrupciones
  39.     PIR1bits.CCP1IF = 0;
  40.     PIE1bits.CCP1IE = 1;
  41.     INTCONbits.PEIE = 1;
  42.     INTCONbits.GIE = 1;
  43.    
  44.    
  45.     while(1){
  46.     }  
  47. }
  48.  
  49.  
  50. void __interrupt (high_priority) ISR(void){
  51.     if(PIR1bits.CCP1IF){
  52.         PIR1bits.CCP1IF = 0;
  53.         if(CCPR1 == 2000) {
  54.             CCPR1 = 18000;
  55.             LATEbits.LE0 = 0;
  56.         } else {
  57.             CCPR1 = 2000;
  58.             LATEbits.LE0 = 1;
  59.         }
  60.     }
  61. }


Respuesta del simulador:
Citar
Target halted. Stopwatch cycle count = 18002 (18,002 ms)
Target halted. Stopwatch cycle count = 2001 (2,001 ms)
Target halted. Stopwatch cycle count = 18000 (18 ms)
Target halted. Stopwatch cycle count = 2001 (2,001 ms)
Target halted. Stopwatch cycle count = 18002 (18,002 ms)
Target halted. Stopwatch cycle count = 2001 (2,001 ms)
Target halted. Stopwatch cycle count = 18000 (18 ms)
Target halted. Stopwatch cycle count = 2001 (2,001 ms)
Target halted. Stopwatch cycle count = 18002 (18,002 ms)
Target halted. Stopwatch cycle count = 2001 (2,001 ms)
Target halted. Stopwatch cycle count = 18000 (18 ms)
Target halted. Stopwatch cycle count = 2001 (2,001 ms)


Igual esta forma como te comentaba es COMPLICADA para manejar dos o mas servomotores, y te conviene usar el acercamiento que te propuse antes para facilitarte la vida.

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3206
Re:Precision timer0 pic18f4550
« Respuesta #6 en: 03 de Noviembre de 2019, 18:30:06 »

Por supuesto esto no tiene demasiados pasos, ya que tenemos 10 pasos para dar. Podes achicar mas la interrupcion.


Estoy haciendo un control de 4 servos, para radio-control y desconozco cuantos pasos serían aceptables, la idea no es para un avión (ya que una emisora casera podría ser peligrosa) ni para un coche o barco de competición donde 10 pasos puede ser poco, si no para algún robot, coche o barco casero para entretenerse un rato.

Saludos!!!
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Precision timer0 pic18f4550
« Respuesta #7 en: 03 de Noviembre de 2019, 19:06:16 »
Es que depende del grado de movimiento que quieras tener. Recorda que entre 1ms y 2ms, cubririas 180º con el servomotor. Asi que 10 pasos implica que cada paso es de 18º.
Otro tema es que ese movimiento luego mediante algun aparejo o reduccion con engranajes tenga mucha menos amplitud. Por eso digo que depende mucho de la aplicacion.

Por supuesto podes hacerlo mas fino al paso. Con un micro de 48Mhz como el propuesto acá podrias hacer pasos de 1.8º sin problemas, si tenes uno mas rapido mejor, y si tenes algun otro micro con mas PWMs para descargarte del software seria lo ideal.

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3206
Re:Precision timer0 pic18f4550
« Respuesta #8 en: 03 de Noviembre de 2019, 19:41:31 »
OK KILLERJC, el PIC16F684 tiene 4 PWM, a ver si saco un rato y aplico el código que pusiste a los 4 PWM.

Saludos!!!
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Precision timer0 pic18f4550
« Respuesta #9 en: 03 de Noviembre de 2019, 20:04:23 »
OK KILLERJC, el PIC16F684 tiene 4 PWM, a ver si saco un rato y aplico el código que pusiste a los 4 PWM.

Saludos!!!

Ojo que no estoy usando el modulo PWM (solo el PWM), estoy usando el CCP en modo Compare. Ese PIC tiene 1 solo PWM con 4 salidas, no 4 PWM independientes, Y si queres muchas salidas mas y liberar el micro, podes poner algo como el PCA9685, que tenes modulos a bajo precio "Arduino"

Desconectado bytedaniel

  • PIC10
  • *
  • Mensajes: 3
Re:Precision timer0 pic18f4550
« Respuesta #10 en: 05 de Noviembre de 2019, 09:47:46 »
Ese si que tiene más salidas.

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3206
Re:Precision timer0 pic18f4550
« Respuesta #11 en: 05 de Noviembre de 2019, 15:48:26 »
OK KILLERJC, el PIC16F684 tiene 4 PWM, a ver si saco un rato y aplico el código que pusiste a los 4 PWM.

Saludos!!!

Ojo que no estoy usando el modulo PWM (solo el PWM), estoy usando el CCP en modo Compare. Ese PIC tiene 1 solo PWM con 4 salidas, no 4 PWM independientes, Y si queres muchas salidas mas y liberar el micro, podes poner algo como el PCA9685, que tenes modulos a bajo precio "Arduino"

OK, no me había fijado en ese detalle, quizás sea más fácil irse a uno más rápido y hacerlo por software, como el PIC16F1847 que funciona hasta con 32MHz.

Saludos!!!
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡