Configuración del oscilador interno PIC12F1822

1

Estoy tratando de configurar el oscilador interno en mi PIC para que oscile a 16MHz y estoy tratando de probar si está funcionando correctamente parpadeando un LED. Como lo entiendo, cada comando toma 4 ciclos de reloj para ejecutarse, y tengo dos declaraciones en mi bucle while. Incremento mi contador y tengo una instrucción if para verificar si el contador ha alcanzado 4000000 todavía. Si lo ha alcanzado, entonces cambia el LED y reinicia el contador.

Si tanto el incremento como la instrucción toman 4 ciclos de reloj para ejecutarse, eso significa que el LED debería alternar aproximadamente una vez cada 2 segundos, ya que debería tomar aproximadamente 32000000 ciclos de reloj para i igual a 4000000. Sin embargo, mi LED solo está alternando una vez cada 20 segundos ¿Podría alguien decirme qué estoy haciendo mal o qué no entiendo?

// PIC12F1822 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>


#include <stdio.h>
#include <stdlib.h>

/*
 * 
 */
int main(int argc, char** argv) {
    OSCCONbits.SCS=0b11;//needs to be 1x for high frequency oscillator
    OSCCONbits.IRCF = 0b1111; //sets to 16MHz
    unsigned long i=0x0;
    TRISA=0X00; //portA as an output
    PORTA=0X00; //LED off
    while (1)
    {
        i++;//increment counter
        if (i>4000000) //is time to toggle?
        {
            i=0; //reset counter
            PORTA=~PORTA; //toggle LED
        }


    }
        return (EXIT_SUCCESS);
}
    

1 respuesta

2

En un PIC de 8 bits la mayoría , las instrucciones del código de máquina requieren 4 relojes para ejecutarse. Pero su programa está escrito en C, no en código de máquina. Una sola instrucción C puede compilar en cualquier cosa, desde cero instrucciones hasta todo el espacio de memoria disponible, dependiendo del código de máquina que el compilador decida que se requiere para implementarlo.

El código en su bucle while(1) se compila en este (XC8 V1.37, modo 'libre'): -

42:                    while (1)
   7FD    2FE0     GOTO 0x7e0
43:                    {
44:                        i++;//increment counter
   7E0    3001     MOVLW 0x1
   7E1    07F4     ADDWF 0x74, F
   7E2    3000     MOVLW 0
   7E3    3DF5     ADDWFC 0x75, F
   7E4    3000     MOVLW 0
   7E5    3DF6     ADDWFC 0x76, F
   7E6    3000     MOVLW 0
   7E7    3DF7     ADDWFC 0x77, F
45:                        if (i>4000000) //is time to toggle?
   7E8    0877     MOVF 0x77, W
   7E9    1D03     BTFSS 0x3, 0x2
   7EA    2FF3     GOTO 0x7f3
   7EB    3001     MOVLW 0x1
   7EC    0274     SUBWF 0x74, W
   7ED    3009     MOVLW 0x9
   7EE    3B75     SUBWFB 0x75, W
   7EF    303D     MOVLW 0x3d
   7F0    3B76     SUBWFB 0x76, W
   7F1    1C03     BTFSS 0x3, 0
   7F2    2FE0     GOTO 0x7e0
46:                        {
47:                            i=0; //reset counter
   7F3    3000     MOVLW 0
   7F4    00F7     MOVWF 0x77
   7F5    3000     MOVLW 0
   7F6    00F6     MOVWF 0x76
   7F7    3000     MOVLW 0
   7F8    00F5     MOVWF 0x75
   7F9    3000     MOVLW 0
   7FA    00F4     MOVWF 0x74
48:                            PORTA=~PORTA; //toggle LED
   7FB    0020     MOVLB 0

Entonces, la única instrucción i++ dio como resultado 8 instrucciones de código de máquina. Con i redefinido como char en lugar de long solo se generan 4 instrucciones. La misma operación en el ensamblador solo puede requerir 1 instrucción.

Algunas instrucciones de código de máquina requieren más de 1 ciclo de CPU (4 relojes) para ejecutarse. BTFSS (archivo de prueba de bits, omitir si está configurado) siempre toma 2 ciclos, incluso cuando se omite la siguiente instrucción. GOTO también toma 2 ciclos, pero BTFSS seguido de GOTO solo toma 3 ciclos.

Los PIC solo tienen un canal de instrucciones 1, por lo que el tiempo es muy predecible. Aun así, calcular el tiempo de ejecución preciso de un programa complejo de código de máquina no es fácil. Hacerlo desde fuentes de alto nivel es prácticamente imposible.

Si desea una sincronización precisa, sus opciones son: -

  1. 'ajustar' el bucle de retardo (y darse cuenta de que cualquier cambio puede romperlo)

  2. Escribir en ensamblador

  3. Use un temporizador de hardware

La opción 3 es la mejor opción si desea un código confiable, escalable y mantenible.

    
respondido por el Bruce Abbott

Lea otras preguntas en las etiquetas