PIC12F675 Timer0 se detiene al cabo de un rato

0

Bueno, estoy usando MPLAB X y básicamente estoy tratando de lograr un UART de software para este pequeño PIC que se ejecuta a 4 MHZ. Al principio lo intenté con retrasos porque se ha dicho que incluso a 4 MHZ, podría alcanzar los 9600 bps (que es lo que necesito, nada menos), pero por alguna razón no pude alcanzar los 1200 bps. He leído que los temporizadores son mucho más precisos, así que empecé a buscar en Google y salí con este código de ejemplo para parpadear un LED:

#define _XTAL_FREQ 4000000

// Configuration Bits
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

#define LED GP2

#include <xc.h>

unsigned int count = 0;

void interrupt ISR() {
  count++;           // Interrupt causes count to be incremented by 1
  if(count == 18) {
   LED = ~LED;       // Toggle LED every sec
   count = 0;
  }
  TMR0 = 192;        // TMR0 returns to its initial value
  INTCONbits.T0IF = 0;  // Bit T0IF is cleared so that the interrupt could reoccur
}

void main(void) {
    ANSEL = 0;
    ADCON0 = 0;
    CMCON = 0x07;
    VRCON = 0;
    TRISIO = 0b111011;
    GPIO = 0b000100;

    OPTION_REG = 0x07; // Prescaler (1:256) is assigned to the timer TMR0
    TMR0 = 192;          // Timer T0 counts from 192 to 255
    INTCON = 0xA0;     // Enable interrupt TMR0 and Global Interrupts 

    while (1) {
        // No code here
    }

    return;
}

Establecí TMR0 en 192 porque eso es 3/4 de 255, por lo que el LED parpadearía cada cuarto de segundo. Cuando lo programé y lo probé, pude ver el parpadeo del LED varias veces y luego seguir encendido. A veces parpadeaba 10 veces, algunas solo 3 y luego se quedaban. Lo extraño es que se mantiene encendido porque también podría mantenerse apagado. Tal vez tenga algo que ver con el problema. Si pudieras señalarme en cualquier lugar, realmente lo apreciaría.

EDITAR:

Aquí hay una foto de la configuración de PIC. Dejé esa resistencia de 10k de GP4 a tierra porque la estaba usando para otro código ahora que recuerdo. También había un cable proveniente de ese pin que flotaba alrededor.

Tal vez esa resistencia podría haber traído problemas.

    
pregunta Joaquin Guevara

3 respuestas

2

Terminó siendo un problema de hardware. Al colocar el LED directamente entre el pin de salida y la GND, la corriente sería de aproximadamente 16.5 mA, lo que llevaría al MCU al límite, al menos este pequeño en particular. Aparentemente, el PIC se detiene debido a algún mecanismo de seguridad o simplemente un error dentro del PIC. No estoy seguro porque cuando cargué un código de parpadeo con retrasos en lugar de Timer0, funcionó bien. El problema es que una resistencia en serie debe colocarse en serie con el LED, aunque debe tenerse en cuenta que incluso 10 mA es casi lo mismo que toda la MCU puede proporcionar entre sus pines.

Aquí hay una foto de ella trabajando SIN el condensador de desacoplamiento, como una demostración de que el problema fue el exceso de dibujo actual, pero debería usarse siempre de todos modos ya que reduce el ruido y le ahorrará futuros dolores de cabeza al depurar el PIC.

    
respondido por el Joaquin Guevara
1

Para obtener una interrupción periódica confiable utilizando el temporizador 0, debe agregar en cada interrupción, no volver a cargarla. De esta manera se cancelan la latencia de interrupción y la posible fluctuación de fase.

El procesador está funcionando a 4 MHz, por lo que la velocidad de reloj de la instrucción es de 1 MHz. Eso significa que hay 104 ciclos de instrucciones por intervalo de bits a 9600 baudios. Eso es suficiente para implementar un firmware UART, aunque con una sobrecarga de compilador desconocida en el camino, realmente no sabes lo que está sucediendo. Definitivamente codificaría la rutina de interrupción en el ensamblador. Realice las tareas de UART tan pronto como pueda después de la interrupción, para reducir el jitter. Agregue al temporizador 0 después de eso, ya que es independiente de jitter.

Dado que los detalles sobre qué agregar al temporizador 0 son un poco difíciles, utilizo una macro para eso. Esto es de mi archivo STD.INS.ASPIC disponible como parte de mi entorno de desarrollo PIC :

;********************
;
;   Macro TIMER0_PER cy
;
;   Update timer 0 so that it next wraps CY cycles from the previous wrap.  This
;   can be useful in a timer 0 interrupt routine to set the exact number of
;   cycles until the next timer 0 interrupt.  Timer 0 is assumed to be running
;   from the instruction clock.  The appropriate value is added into timer 0,
;   so this macro does not need to be invoked a fixed delay after the last
;   timer 0 wrap.  CY must be a constant.
;
;   The timer sets its interrupt flag when counting from 255, which wraps back
;   to 0.  If left alone, the timer therefore has a period of 256 instruction
;   cycles.  When adding a value into the timer, the increment is lost during
;   the add instruction, and the timer is not incremented for two additional
;   cycles when the TMR0 register is written to.  This effectively adds 3 more
;   cycles to the timer 0 wrap period.  These additional cycles are taken
;   into account in computing the value to add to TMR0.
;
timer0_per macro cy
         dbankif tmr0
         movlw   256 + 3 - (cy)
         addwf   tmr0
         endm

Por supuesto, hay formas obvias y fáciles de resolver este problema general:

  1. Usa un PIC con un UART.

  2. Use el temporizador 2, ya que tiene un registro de período incorporado.

respondido por el Olin Lathrop
0
  

el PIC se detiene debido a algún mecanismo de seguridad

Has salido bor. He utilizado una configuración similar con éxito, pero no bor.

Tu código de temporizador también se puede mejorar. Para mantener la precisión a largo plazo, intente no cargar la compensación repetidamente.

Editar: cuando se carga en el contador del temporizador, se destruye el valor que puede haber acumulado desde la reinversión, ya sea en el contador del temporizador o en el prescaler.

Por lo tanto, la mejor manera de obtener precisión a largo plazo en un temporizador como el timer0 es nunca volver a cargarlo una vez que se inicie.

Me gusta esto

TMR0 = -TMR_PR; // LOAD UP TMRPR LSB.   .... Obtener el temporizador 0 en marcha.

en el ist   Si (TMR_PR)     TMR_PR - = 0X100; // actualizar tmrpr, asumiendo 8 bits tmr0.   de lo contrario, TMR_PR ha caducado.

Lo que hace es que, independientemente de la duración del período de tiempo deseado, el contador solo se vuelve a cargar una vez, desde el principio.

Pero su problema es improbable, el problema del temporizador aquí. Entonces, en lugar de pensar que es lo que piensas, publica tus rutinas de Hart suave y deja que otras personas te ayuden.

    
respondido por el dannyf

Lea otras preguntas en las etiquetas