6 votos

¿Por qué el lugar donde yo claro TMR0IF cambios en el comportamiento del programa?

Estoy programación de un microcontrolador PIC16F877A en C, compilar con Microchip XC8 1.44.

He creado una interrupción de TMR0 para cada 800 microsegundos que explora a través de una matriz de LED, iluminación de cada uno de los 8 LED de columna a través de la configuración de la siguiente manera:

    OPTION_REG = 0x04; // TMR0 prescaler (1:32)
    GIE    = 1;
    TMR0IE = 1;

Y este es mi ISR:

void interrupt isr()
{
    static const uint16_t divs[4] = { 1000, 100, 10, 1 };
    if (TMR0IF)
    {
        PORTB = 0x00; // PORTB is the 8 LED column
        if (i)
        {
            PORTAbits.RA0 = 1; // pin that clocks CD4017 for next column
            __nop(); // give a brief delay just for good measure
            PORTAbits.RA0 = 0;
        }
        else
        {
            PORTAbits.RA1 = 1; // pin that resets CD4017 to first column
            __nop();
            PORTAbits.RA1 = 0;
        }

        // pattern to be displayed
        PORTB = font[i % 8U + 8U * ((c / divs[i / 8U]) % 10U)];
        i = (i + 1U) % 31U; // increment i for next iteration

        TMR0 = TMR0_OFFSET; // 240 for 4MHz crystal for 800us delay according to my calculations (I am bad at calculations)
        TMR0IF = 0;
    }
}

Básicamente c ('contador') llevará a cabo un número entre 0 y 9999, y el 31 de columna de la matriz de LED muestra el uso de los datos en font a dibujar los números.

Ahora, este código funciona a la derecha. Pero si me muevo TMR0IF = 0; al inicio del bloque, algo extraño sucede:

El programa parece ser lenta, como si el reloj se redujo en un factor de 100 o más, y el bucle principal del programa se bloquea y por eso puedo dejar de recibir las señales externas que puedo utilizar para aumentar o restablecer el valor de c, sólo el ISR sigue siendo llamados y mantener la matriz de LED iluminada, pero el parpadeo debido a que el reloj de la gota.

Si me muevo TMR0IF = 0; a la final como en el código anterior aunque, todo parece funcionar normalmente, y el mundo es perfecto. Pero, ¿por qué?

Todo el mundo me vea el código de referencia para el Timer 0 interrumpir el uso conjunto de personas TMR0IF = 0; de inmediato, ¿por qué está causando todo ese molestia en mi código?

13voto

RelaXNow Puntos 1164

El problema básico es que su código de interrupción está tomando más tiempo en ejecutarse que el tiempo entre interrupciones. Esto probablemente debido a dos problemas:

El período de interrupción no es lo que usted piensa que es. La interrupción condición es que se acciona con más frecuencia de lo indicado.

Usted está tomando demasiados ciclos en la rutina de interrupción.

La razón por la que aparece a trabajar cuando se desactive la interrupción de la condición al final de la ISR es que existe entonces algún tiempo para que el primer plano a la ejecución de código antes de la siguiente interrupción. Sin embargo, esa NO es una solución para el problema. Cuando se mueve la limpieza de la interrupción de la condición para el inicio de la ISR en donde debe estar, el ISR lleva tanto tiempo que la siguiente interrupción es de inmediato cuando el ISR extremos. No, esto no desbordamiento de la pila como otra respuesta de reclamos. Sin embargo, no bloquee el primer plano de código de llegar ciclos.

Siempre claro que la interrupción de la condición de la derecha en el comienzo de la rutina de interrupción. Si se utiliza el timer 0 para la interrupción del período de NO establecer TMR0 para un valor fijo de cada interrupción. En su lugar, agregue la cantidad apropiada de cada interrupción. Que manera de no perder el tiempo basado en la interrupción de jitter, latencia.

También, no use el prescaler al agregar un desplazamiento en el temporizador. Si se utiliza el timer 0, el conjunto añadir un offset de cada interrupción para obtener un período específico con el prescaler 1, o utilizar sólo la resultante de libre ejecución período con la falta de unidad del predivisor.

Si desea más arbitrario de interrupción de los períodos, utilice el temporizador 2. Eso es lo que es.

Me doy cuenta de que usted escribió su rutina de interrupción en C. he visto algunos bastante horrible código de la hinchazón debido a que el compilador de C no saber lo que realmente se necesita para ser salvos, y por lo tanto el ahorro de un montón de cosas. Personalmente, escribo PIC 16 de interrupción de las rutinas en ensamblador. También hace que sea más fácil de averiguar lo que está pasando en casos como este, porque no hay ningún compilador entre usted y el hardware.

Me acaba de escanear su ISR código. Usted está haciendo divide en el ISR! No es de extrañar que tomando más tiempo de lo previsto.

Este es un gran ejemplo de por qué en los pequeños microcontroladores como este, compiladores nunca debe ser utilizado como un sustituto para la comprensión de la máquina en el nivel de instrucción. El compilador debe ser sólo un acceso directo para crear un montón de código para usted, pero usted todavía necesita tener una comprensión básica de lo que el código que se es y de lo que la máquina tiene que hacer para poner en práctica lo que pides.

Dicho de otra manera, usted tiene que arquitecto el código, mientras que el pensamiento de la máquina capacidades de formato raw. Una vez hecho eso, el uso de un compilador para generar algunos de los código real para usted puede ser un legítimo de acceso directo. Incluso entonces, el ISR es la rutina que desea la mayoría considere la posibilidad de escribir en ensamblador.

Ir escribir esta interrupción de la rutina en ensamblador. Eso no es porque necesariamente debe ser en ensamblador, pero debido a que usted necesita para aprender la máquina. Ustedes no tienen que estar aquí sin comprender el conjunto de instrucciones y la otra de bajo nivel de capacidades del hardware. Nunca se habría tratado de hacer la división en un ISR si realmente entiende el conjunto de instrucciones.

5voto

user92574 Puntos 13

No creo que usted debe nunca poner TMR0IF=0 (borrar el indicador de interrupción) al principio de su ISR.

Creo que lo que está sucediendo es su rutina ISR está tomando más de 800 nosotros o con su TMR0 se está produciendo más rápido de lo que piensas. Por poner TMR0IF=0 en la parte delantera, que están limpiando la interrupción y permitiendo por otra interrupción de TMR0 para interrumpir la interrupción. El MCU empuja la presente información en la pila, y se llama a la misma interrupción de nuevo. Eventualmente, su pila de desbordamiento y el sistema se bloquee.

  1. Mantener TMR0IF=0 como la última instrucción
  2. El tiempo de su ISR para ver si es menor de 800 nosotros.
  3. Compruebe si TMR0 se está ejecutando en la tasa de pensar.

Yo de momento mis rutinas por la conducción de un GPIO de alta en el inicio y la conducción mismo GPIO de baja antes de salir de la rutina. El uso de una o'scope en que GPIO y usted puede verificar) si el ISR es en realidad menor que 800 us, b) si el TMR0 es realmente llamando a la tasa de pensar.

El ancho de pulso se le indicará la duración de su ISR está tomando. El período que le dirá con qué frecuencia su ISR es que se llama. Si el período de la junta'scope señal es errático, entonces su ISR está tomando más tiempo que el temporizador TMR0 períodos (es decir, es la omisión del TMR0 (períodos)

1voto

kleinempfaenger Puntos 592

La respuesta es ya la dirección en el otro post y comentario (un "MONTÓN" de div, y el ISR a tomar mucho tiempo para hacer las cosas), pero me gustaría señalar que sale como descortés.

Estamos todavía en la Edad de piedra(es broma)? La mayoría de los ejemplo en internet da ejemplo en c, ¿por qué? porque es más fácil de entender y puede ser cambiado libremente, a continuación, un código ensamblador. Seguro, el código escrito en ensamblador es más rápido (tal vez de alguien que se ha pasado un montón de tiempo de codificación con él), pero para una tarea simple, el compilador de hacer un buen trabajo también.

El problema en mi humilde opinión, es la fuente de conocimientos de programación de la op, si se utiliza para desarrollar el software, usted no se da cuenta de cómo muchos de los recursos que el programa está utilizando, porque estás trabajando con un mayor rendimiento de hardware, y no con un limitado pic16.

Div y mod, está seguro de tomar un montón de tiempo para ser ejecutado (en la foto), pero si a optimizar el proceso, tal vez en algún caso es viable. Por ejemplo:

i % 8U -> i&7
i / 8U -> i>>3

Un div y mod, se puede simplificar utilizando la tecla mayús o la lógica de operación (en algunos casos donde el número de mod 2), pero aprender trucos tratando cosas y en algún momento de cometer errores.

Con la carga de trabajo en el isr, es mejor, como se ha sugerido, para establecer un indicador, y en la principal de la actualización de sus datos, pero tratando de mejorar el código, le ayuda en el proyecto en el futuro.

No quiero ser duro, pero todo debe ser evaluado para el ámbito final. En este caso, abordar la carga de trabajo de la foto debe ser de la manera correcta para señalar el problema, escribir en ensamblador lo lograr? Añadiendo más complejidad no resuelve, diciendo por ejemplo: el horno(micro) puede cocinar 1 pizza(n instrucción) cada 10 min(antes de que el ISR se llama de nuevo), pero que están pidiendo a cocinar de 10 de pizza al mismo tiempo, le da probablemente una idea concreta del problema.

Acaba de ser conscientes de lo que usted está utilizando.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X