Hogar Flores perennes Temporizador en ejemplos de avr studio. Programación de microcontroladores AVR. Control de salida OC0

Temporizador en ejemplos de avr studio. Programación de microcontroladores AVR. Control de salida OC0

EN Últimamente Cada vez más principiantes se enfrentan al problema de dominar los temporizadores/contadores (en adelante T/C) en la etapa de estudio de los microcontroladores. En este artículo intentaré disipar los temores sobre estos módulos y explicar claramente cómo y con qué se utilizan estos mismos T/S.

Tomaremos como base un libro muy popular entre los desarrolladores de dispositivos MK, escrito por A.V. Evstifeev. Usando los enlaces al final del artículo puede encontrar el proyecto en y el proyecto en. En este artículo analizaremos el funcionamiento del T/S T2 de 8 bits, que forma parte del Atmega8 T/S MK.

Entonces, ¿qué es un temporizador/contador? T/S es uno de los módulos del AVR MK con el que podrás medir determinados periodos de tiempo, organizar PWM y muchas otras tareas. Dependiendo del modelo MK, el número de T/S puede ser 4 o más. Un ejemplo de esto son los MK Atmega640x, 1280x/1281x, 2560x/2561x, que contienen 6 T/S a bordo: dos de 8 bits y cuatro de 16 bits. El Atmega8 MK contiene tres T/S: T0 y T2 con 8 bits, T1 con 16 bits.

Echemos un vistazo más de cerca al microcontrolador T/C T2 Atmega8.

Este temporizador puede funcionar en varios modos: Normal, PWM de fase correcta, CTC (reinicio en caso de coincidencia), PWM rápido. Puedes leer más sobre cada modo en el libro.

Este T/C consta de un registro de control, un registro de conteo, un registro de comparación y un registro de estado de modo asíncrono. El diagrama de bloques de T2 se muestra en la Fig. 1.

Veamos cómo funciona este módulo en teoría. Para que quede más claro para usted, no consideraremos todos los dispositivos innecesarios del temporizador y consideraremos su modo más común: NORMAL. Determinemos por nosotros mismos que el MK está sincronizado desde un oscilador RC interno con una frecuencia de 1 MHz y que el temporizador está configurado para funcionar en modo NORMAL.

Los pulsos de reloj llegan a la entrada clk i\o y entran al preescalador del temporizador. El preescalador se puede configurar, según sus necesidades, para pasar pulsos de reloj directamente o para dividir los pulsos entrantes, pasando solo una determinada parte de ellos. Los pulsos entrantes se pueden dividir en /8, /64, /256, /1024. Dado que nuestro T\S puede funcionar en modo asíncrono, cuando se enciende en este modo, el número de preescaladores aumenta significativamente, pero no los consideraremos por ahora. Desde el preescalador, los pulsos de reloj ingresan a la unidad de control y desde allí ingresan al registro de conteo. El registro de conteo, a su vez, aumenta con cada pulso entrante. El registro de conteo T2 es de 8 bits, por lo que solo puede contar hasta 255. Cuando el registro de conteo se desborda, se restablece a 0 y comienza a contar nuevamente en el mismo ciclo. Además, cuando el registro del contador se desborda, se activa el indicador TOV2 (indicador de interrupción de desbordamiento) del registro TIFR.

Ahora que hemos tocado palabras como REGISTRAR, es hora de familiarizarse con ellas. Para empezar, tocaremos solo aquellos registros con los que trabajaremos directamente, para no llenar el cerebro con información innecesaria.

TCNT2 es un registro de conteo, ya hemos hablado de su funcionamiento.

TCCR2 - registro de control del temporizador.

TIMSK: registro de máscara de interrupción (en Atmega8 este registro es el único para todos los temporizadores).

TIFR - registro de bandera de interrupción (en Atmega8 este registro es el único para todos los temporizadores).

Y ahora sobre cada uno en detalle:

Registro de control TCCR2. Puedes ver el contenido de este registro en la Fig. 2.


Figura 2

Los bits 0-2 son responsables de cronometrar el temporizador. Establecer ciertas combinaciones de estos bits configura el preescalador para un temporizador determinado. Si los tres bits están limpios, el temporizador se apaga.

Los bits 3.6 son responsables del modo de funcionamiento del temporizador.

Los bits 4.5 son necesarios para configurar el comportamiento de la salida OSn (en otras palabras, se utilizan al configurar PWM)

Y el último bit de este registro es el bit 7. Con su ayuda, podemos cambiar a la fuerza el estado del pin OSn.

Registro de máscara de interrupción - TIMSK. Lo vemos en la foto nº 3.

De este registro sólo nos interesan los dos últimos bits, los bits 6 y 7. Con estos bits habilitamos las interrupciones.

El bit 6, si está escrito en él, habilita la interrupción debido al evento "T\C T2 overflow"

Bit 7, si le escribesNitsya, permite interrumpir el evento "Coincidencia del registro de conteo con el registro de comparación"

Registro de bandera de interrupción TIFR. Lo vemos en la foto nº4.

Fig.4

En este registro también nos interesan los dos últimos bits: bits 6 y 7.

Bit 6 - bandera, establecida por el evento "T\C T2 overflow"
Bit 7 - bandera, esta instalado por el evento "Coincidencia del registro de conteo con el registro de comparación"

Estos bits se restablecen automáticamente cuando sale el controlador de interrupciones, pero para estar seguro, puede restablecerlos usted mismo restableciendo estos bits a "0".

Los bits restantes de los registros TIMSK y TIFR son utilizados por T\C T0 y T1. Como ya habrás notado, los bits de estos registros incluso tienen los mismos nombres, con la excepción del número al final del nombre, que indica a qué temporizador se aplica este bit.

Queda por considerar dos tablas simples, a saber: una tabla que describe el control de la señal del reloj (Fig. 6) y una tabla que describe cómo configurar en general un temporizador (Fig. 5).

Escribí anteriormente sobre lo que hay en estas tablas, pero se las presento para mayor claridad.

Ahora hemos terminado con la teoría y es hora de comenzar con la parte práctica. Haré una reserva de inmediato.

LOS RELOJES QUE SE OBTIENEN AL ESTUDIAR ESTE ARTÍCULO NO SON MUY EXACTOS. ESTE ARTÍCULO ESTÁ ORIENTADO A LOS PRINCIPIOS GENERALES DEL TRABAJO CON TEMPORIZADORES.

Abra Studio 6, cree un proyecto y seleccione Atmega8.

Al principio, indicamos la frecuencia del reloj y conectamos las bibliotecas que necesitamos para trabajar.

< avr/io.h >#incluir< avr/interrupt.h >

En la primera línea indicamos la frecuencia. Esto es necesario para que el compilador nos entienda mejor si de repente queremos utilizar las funciones _delay_().

La segunda línea de código incluye la biblioteca con descripción general registros de nuestro MK. También asigna nombres legibles a todos los registros.

La tercera línea incluye una biblioteca para trabajar con vectores de interrupción.

TIMSK |= (1< < TOIE2); TCCR2 |= (1< < CS22)|(1< < CS20); SREG |= (1< < 7);

Esto completa la configuración de nuestro temporizador. Echemos un vistazo más de cerca a las últimas tres líneas de código.

En la primera línea habilitamos las interrupciones para el evento "Desbordamiento del temporizador/contador T2"

Y en la tercera línea habilitamos las interrupciones globalmente. También podría escribirse así:

Asm("sei");

Todo lo que queda es agregar el controlador de interrupciones y el código para nuestro reloj en tiempo real.

ISR (TIMER2_OVF_vect) ( takt++; if (takt>=4)(sek++; takt=0x00;) if (sek>=60) (min++; sek=0x00;) if (min>=60) (hora++; min=0x00 ;) si (hora>=24) (hora=0x00); )

No hay nada complicado ni nuevo para usted en el código que se encuentra en el controlador de interrupciones. Prestemos atención sólo a la variable takt y al número mágico "4". ¿De dónde surgió esta cifra? Echemos un vistazo más de cerca a este punto.

Sabemos que nuestro MK opera desde un oscilador interno con una frecuencia de 1 MHz, el temporizador está sincronizado con un preescalador de \1024, nuestro temporizador puede contar hasta 255. Conociendo estos parámetros, podemos calcular cuántos desbordamientos realizará en 1 segundo

1 000 000 \ 1024 \ 256 = 3,814697.....

Bueno, como estamos aprendiendo a trabajar con temporizadores y no nos fijamos el objetivo de obtener un reloj súper preciso, redondeamos nuestro resultado y obtenemos "4". Aquellos. en 1 segundo el temporizador se desbordará ~4 veces.

¿Por qué dividimos entre 256 si el cronómetro solo cuenta hasta 255? Porque "0" también es un número. Creo que aquí todo está claro.

No olvide que todas las variables deben declararse como globales.

Aquí está la lista completa del programa que obtuvimos.

#definir F_CPU 1000000UL #incluir< avr/io.h >#incluir< avr/interrupt.h >takt de carácter sin firmar = 0; carácter sin firmar sek = 0; carácter sin firmar min=0; hora de carbón sin firmar = 0; ISR (TIMER2_OVF_vect) ( takt++; if (takt>=4)(sek++; takt=0x00;) if (sek>=60) (min++; sek=0x00;) if (min>=60) (hora++; min=0x00 ;) if (hora>=24) (hora=0x00); ) int main(void) ( TIMSK |= (1< < TOIE2); TCCR2 |= (1< < CS22)|(1< < CS20); SREG |= (1< < 7); while(1) { } }

Pero ¿qué pasa con la salida de información al usuario? Y luego a quien le guste. Puede utilizar indicadores de siete segmentos, pantallas gráficas o generadoras de caracteres, etc.

En el archivo encontrará un proyecto con información de visualización de nokia5110, un proyecto en Proteus 7 y eso es todo. archivos necesarios y bibliotecas para el trabajo.

Tenga en cuenta que la biblioteca LCD_5110 para trabajar con la pantalla fue escrita por un participante del foro y proporcionada con su permiso.

En este tutorial hablaremos de temporizadores.

Este tema está directamente relacionado con el tema de la sincronización del microcontrolador. Por eso, te recomiendo que leas el anterior antes de leer esta lección.

Entonces, ¿por qué necesitamos un cronómetro?

Al construir proyectos con microcontroladores, a menudo es necesario medir intervalos de tiempo precisos. Por ejemplo, el deseo de hacer parpadear un LED con una frecuencia determinada o sondear el estado de un botón en los intervalos de tiempo requeridos.

Los cronómetros ayudan a resolver las tareas. Pero los temporizadores del microcontrolador AVR no saben qué es un segundo, un minuto o una hora. Sin embargo, ¡saben muy bien lo que es el tacto! Funcionan precisamente debido a la presencia de sincronización del controlador. Es decir, el temporizador cuenta el número de ciclos del controlador, midiendo así los intervalos de tiempo. Digamos que el controlador funciona a una frecuencia de reloj de 8 MHz, es decir, cuando el temporizador cuente hasta 8.000.000, pasará un segundo, contando hasta 16.000.000, pasarán 2 segundos, y así sucesivamente.

Sin embargo, aquí surge el primer obstáculo. Nuestros registros son de 8 bits, es decir, podemos contar hasta un máximo de 255, y tomando un temporizador de 16 bits, podemos contar hasta un máximo de 65535. Es decir, en un segundo debemos resetear el temporizador. gran cantidad¡una vez! Por supuesto, puedes hacer esto si no tienes nada más que hacer. Pero simplemente medir el tiempo con un microcontrolador potente no es nada interesante; quiero hacer algo más. Aquí es donde el predivisor viene en nuestra ayuda. EN vista general Este intermedio entre el temporizador y la frecuencia del reloj del controlador. El preescalador facilita nuestra tarea al permitirnos dividir la frecuencia del reloj por Cierto número, antes de enviarlo al cronómetro. Es decir, poniendo el preescalador en 8, en 1 segundo nuestro temporizador contará hasta 1.000.000, en lugar de 8.000.000 (Por supuesto, con una frecuencia de reloj del controlador de 8 MHz). Ya es más interesante, ¿no? Y podemos dividir no sólo por 8, sino también por 64 e incluso por 1024.

¡Ahora es el momento de ensamblar el circuito, configurar nuestro temporizador, preescalador y hacer al menos algo útil!

Y hoy fabricaremos "luces de circulación" con LED. Es decir, encenderemos 3 LED uno a uno, con un periodo de 0,75 segundos (Es decir, el tiempo de funcionamiento de un LED es de 0,25 segundos). Armemos el siguiente diagrama:

Calcule usted mismo los valores de las resistencias R 1-R 3.

A continuación, veamos los registros responsables del funcionamiento de los temporizadores. En total, AtMega 8 tiene 3 temporizadores: dos de 8 bits (temporizador 0, temporizador 2) y uno de 16 bits (temporizador 1). Consideraremos el ejemplo del temporizador 1 de 16 bits.

Un par de registros, los registros de 8 bits TCNT 1H y TCNT 1L, juntos forman el registro de 16 bits TCNT 1. Este registro está abierto tanto para escritura como para lectura. Cuando el temporizador 1 está funcionando, el valor de este registro cambia en uno con cada conteo. Es decir, el registro TCNT 1 registra el número de ciclos de reloj que ha contado el temporizador. También podemos escribir aquí cualquier número en el rango del 0 al 2 elevado a la 16ª potencia. En este caso, los ciclos de reloj no se contarán desde 0, sino desde el número que registramos.

El registro TIMSK es responsable de las interrupciones generadas cuando funcionan los temporizadores del microcontrolador. Una interrupción es un controlador de una señal especial que se recibe cuando algo cambia.. Cualquier interrupción del microcontrolador se puede habilitar o deshabilitar. Cuando se produce una interrupción habilitada, se interrumpe el curso del programa principal y se procesa esta señal. Cuando ocurre una interrupción deshabilitada, el flujo del programa no se interrumpe y la interrupción se ignora. El bit TOIE 1 (Habilitación de interrupción de desbordamiento del temporizador 1) es responsable de habilitar la interrupción de desbordamiento del registro de conteo TCNT 1 del temporizador 1. Al escribir 1 en este bit, la interrupción se habilita y al escribir 0, se deshabilita. Esta interrupción es generada por el temporizador 1 cuando alcanza valor máximo registrar TCNT 1. Hablaremos más sobre interrupciones en la próxima lección.

El registro TCCR 1B es responsable de la configuración del temporizador 1. B en este caso Con los bits CS 10-CS 12 configuramos el valor del preescalador según la siguiente tabla.

Los bits restantes no nos interesan por ahora.

También hay un registro TCCR 1A, que le permite configurar otros modos de funcionamiento del temporizador, por ejemplo PWM, pero sobre ellos en un artículo aparte.

Y ahora el código en C:

#definir F_CPU 16000000UL #incluir #incluir uint8_t número=0; ISR(TIMER1_OVF_vect) ( PORTD=(1<2) ( num=0; ) TCNT1=61630;//Valor inicial del temporizador ) int main(void) ( DDRD|=(1<

#definir F_CPU 16000000UL

#incluir

#incluir

uint8_t número = ;

ISR(TIMER1_OVF_vect)

PUERTO = (1<< num ) ;

número++;

si (núm > 2)

número = ;

TCNT1 = 61630; //Valor inicial del temporizador

int principal (vacío)

DDRD |= (1<< PD0 ) | (1 << PD1 ) | (1 << PD2 ) ;

TCCR1B |= (1<< CS12 ) | (1 << CS10 ) ; //Preescalador = 1024

TIMSK |= (1<< TOIE1 ) ; //Habilitar interrupción de desbordamiento del temporizador 1

TCNT1 = 61630; //Valor inicial del temporizador

sí(); //Habilitar interrupciones

mientras(1)

//El bucle principal del programa, está vacío, ya que todo el trabajo está en la interrupción

Código ASM:

Asamblea (x86)

Incluya "m8def.inc" rjmp start .org OVF1addr rjmp TIM1_OVF start: ldi R16,LOW(RamEnd) salida SPL,R16 ldi R16,HIGH(RamEnd) salida SPH,R16 ldi R16,1 ldi R17,0b00000111 salida DDRD,R17 ldi R17,0b00000101 salida TCCR1B,R17 ldi R17,0b11110000 salida TCNT1H,R17 ldi R17,0b10111110 salida TCNT1l,R17 ldi R17,0b00000100 salida TIMSK,R17 sei main_loop: nop rjmp main_loop TIM1_OV F: salida PORTD,R16 lsl R16 cpi R16,8 brlo label_1 ldi R16,1 label_1: ldi R17,0b10111110 salida TCNT1L,R17 ldi R17,0b11110000 salida TCNT1H,R17 reti

Incluir "m8def.inc"

inicio de rjmp

Organización OVF 1 dirección

Rjmp TIM 1_OVF

comenzar :

Ldi R 16, BAJO (RamEnd)

Fuera SPL, R 16

Ldi R 16, ALTO (RamEnd)

Fuera SPH, R 16

Ldi R 16, 1

Ldi R 17, 0b00000111

Fuera DDRD, R 17

Ldi R 17, 0b00000101

Fuera TCCR 1B, R 17

Ldi R 17, 0b11110000

Fuera TCNT 1H, R 17

Ldi R 17, 0b10111110

Una de las ventajas del microcontrolador ATmega8 es su amplia gama de interrupciones diferentes.

Interrumpir es un evento al ocurrir el cual se suspende la ejecución del programa principal y se llama a una función que maneja una interrupción de cierto tipo.

Las interrupciones se dividen en internas y externas. Las fuentes de interrupciones internas incluyen módulos de microcontroladores integrados (temporizadores, transceptor USART, etc.). Las interrupciones externas ocurren cuando llegan señales externas a los pines del microcontrolador (por ejemplo, señales en los pines RESET e INT). La naturaleza de las señales que conducen a la aparición de una interrupción se establece en el registro de control. MCUCR, en particular en los bits - ISC00 (bit 0) e ISC01 (bit 1) para la entrada INT 0; ISC10 (bit2) e ISC11 (bit3) para entrada INT1.

En el microcontrolador ATmega8, cada interrupción tiene su propia vector de interrupción(dirección al comienzo del área de memoria del programa en la que se almacena el comando para saltar a la rutina de interrupción especificada). En mega8, todas las interrupciones tienen la misma prioridad. Si se producen varias interrupciones simultáneamente, la interrupción con el número de vector más bajo se procesará primero.

Vectores de interrupción en Atmega8

DIRECCIÓN fuente de interrupción Descripción
0x0000 REINICIAR Restablecer señal
0x0001 INT0 Solicitud de interrupción externa en la entrada INT0
0x0002 INT1 Solicitud de interrupción externa en la entrada INT1
0x0003 T/C1 Captura del temporizador T/C1
0x0004 T/C1 Coincidir T/C1 Temporizador Comparar Registro A
0x0005 T/C1 Coincide con el registro de comparación B del temporizador T/C1
0x0006 T/C1 Desbordamiento del contador T/C1
0x0007 T/C0 Desbordamiento del contador T/C0
0x0008 SPI Transferencia de datos SPI completada
0x0009 UART El transceptor UART ha completado la recepción de datos.
0x000A UART El registro de datos UART está vacío
0x000B UART Se completa la transmisión de datos mediante el transceptor UART
0x000C ANA_COMP Interrupción del comparador analógico

Gestión de interrupciones

4 registros son responsables de gestionar las interrupciones en ATmega8:

GIMSK(también conocido como GICR): prohibe/habilita interrupciones basadas en señales en las entradas INT0, INT1

GIFR- gestión de todas las interrupciones externas

TIMSK, TIFR- gestión de interrupciones de temporizadores/contadores

Registro GIMSK(GICR)

INTFx=1: ocurrió una interrupción en la entrada INTx. Al ingresar a la rutina de manejo de interrupciones, INTFx se restablece automáticamente al estado de registro. 0

Registro TIMSK

7 6 5 4 3 2 1 0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-

TOIE1=1: Interrupción de desbordamiento T/C1 habilitada

OCIE1A=1: interrupción cuando el registro de comparación A coincide con el contenido del contador T/C1 habilitado

OCIE1B=1: interrupción cuando el registro de comparación B coincide con el contenido del contador T/C1 habilitado

TICIE=1: interrupción habilitada cuando se cumple la condición de captura

TOIE0=1: Interrupción por desbordamiento T/C0 habilitada

Registro TIFR

7 6 5 4 3 2 1 0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-

TOV1=1: Se produjo un desbordamiento de T/C1

OCF1A=1: el registro de comparación A coincidió con el contenido del contador T/C1 permitido

OCF1B=1: el registro de comparación B coincide con el contenido del contador T/C1 permitido

FCI=1: condiciones de captura cumplidas

TOV0=1: Se produjo un desbordamiento de T/C0

Al ingresar a la subrutina de manejo de interrupciones, el indicador de registro TIFR correspondiente a la interrupción se restablece automáticamente al estado de registro. 0

Las interrupciones solo funcionan cuando las interrupciones generales están habilitadas en el registro de estado SREG (bit 7 = 1). Cuando ocurre una interrupción, este bit se restablece automáticamente a 0, deshabilitando las interrupciones posteriores.

En este ejemplo, el pin INT0 está habilitado en el modo de entrada pull-up. Cuando el pin se cortocircuita a tierra usando un botón, se establece un 0 lógico (el borde de la señal cae del voltaje de suministro a 0) y se activa el controlador de interrupciones, encendiendo la bombilla conectada al pin cero del puerto. B

lámpara vacía ON()
{
PUERTO.0=1;
DDRB.0=1;
}

interrumpir vacío text_int0_isr (vacío)
{
lámpara encendida();
}

DDRD.2=0;
PUERTO.2=1;

SREG|= (1 mientras(1) (

El ejemplo anterior también muestra cómo se configuran los vectores de interrupción en Code Vision AVR (interrupt void ext_int0_isr(void)). Los vectores de interrupción se establecen de manera similar para otros casos:

EXT_INT0 2
EXT_INT1 3
TIM2_COMP 4
TIM2_OVF 5
TIM1_CAPT 6
TIM1_COMPA 7
TIM1_COMPB 8
TIM1_OVF 9
TIM0_OVF 10
SPI_STC 11
USART_RXC 12
USART_DRE 13
USART_TXC 14
ADC_INT 15
EE_RDY 16
ANA_COMP 17
TWI 18
SPM_LISTO 19

En esencia, un temporizador de microcontrolador es un contador digital, sólo que "sofisticado". Se suministra una señal de reloj a la entrada del contador, en función de cuyas caídas el contador aumenta su valor. Cuando ocurren eventos (un contador se desborda o su valor coincide con un valor dado), se genera una solicitud de interrupción.

Veamos cómo usar el temporizador T0 en modo Normal. En este modo, el temporizador cuenta desde algún valor inicial del registro de conteo hasta el máximo posible (hasta 255 o 0xFF). Cuando el temporizador T0 cuenta hasta el máximo, en el siguiente ciclo de reloj el registro de conteo TCNT0 se desborda: se reinicia y se establece el indicador TOV0. Si el programa permite interrupciones globalmente (bandera I del registro SREG) y la interrupción de desbordamiento del temporizador T0 (bandera TOIE0 del registro TIMSK), entonces el microcontrolador llamará al controlador correspondiente. Si el valor del registro de conteo coincide con el registro de comparación OCR0, entonces se establece el indicador OCF0 y si la interrupción del evento de coincidencia está habilitada, se iniciará su controlador.

Temporizador T0 en modo Normal

Consideremos un problema práctico: necesitamos sondear un botón cada 20 ms. Frecuencia del microcontrolador 8 MHz, microcontrolador ATmega16.

Lo primero que debe hacer es decidir la elección del coeficiente del preescalador del temporizador y calcular el valor inicial para el registro del contador TCNT0.

El temporizador T0 se puede sincronizar desde la señal de reloj interna del microcontrolador o desde una externa, que se suministra al pin T0. Cuando se opera desde una señal de reloj interno, el usuario puede seleccionar las relaciones de división de frecuencia de esta señal. El temporizador T0 tiene cinco opciones posibles de coeficientes de preescalador: 1, 8, 64, 256, 1024.

Para resolver este problema, razono de la siguiente manera. Si un tic del temporizador T0 tuviera un período de 1 ms, entonces me vendría bien. 20 ciclos de reloj dan 20 ms. ¿Qué coeficiente del preescalador del temporizador le permitirá obtener un período de reloj cercano a 1 ms? Puedes contar.

Frecuencia de reloj del microcontrolador Fcpu = 8000000 Hz
Periodo de reloj del microcontrolador Tcpu = 1/Fcpu
El periodo de reloj del temporizador T0 es igual a Tt0 = (1/Fcpu)/k = k/Fcpu

En k = 1024, el período de reloj del temporizador T0 será igual a Tt0 = 1024/8000000 = 0,128 ms

Este es el período máximo de reloj del temporizador que podemos obtener en nuestras condiciones (Fcpu = 8 MHz). Con probabilidades más bajas, el período será aún más corto.

Bueno, está bien, digamos que un reloj temporizador es de 0,128 ms, ¿el registro de conteo es lo suficientemente ancho como para contar este intervalo de tiempo y cuántos ciclos de reloj tomará? Dividimos el intervalo de tiempo requerido (20 ms) por la duración de un tic del temporizador y obtenemos la respuesta.

n = t/Tto = 20 ms/ 0,128 ms = 156,25

Redondeando al entero más cercano, obtenemos 156 ciclos de reloj. Esto es menor que 255 (el valor máximo del registro de conteo), lo que significa que el registro de conteo TCNT0 es suficiente.

El valor inicial para el registro de conteo TCNT0 se calcula como la diferencia entre el número máximo de ciclos de reloj del temporizador T0 y el requerido, es decir, 256 - 156 = 100. (256 es el número máximo de intervalos de tiempo que cualquier 8- El temporizador de bits puede contar.)

Creo que ahora está claro cómo calcular el valor inicial de TCNT0 para el modo Normal.:

Calculamos el período de un ciclo del temporizador Tt0 = k/Fcpu,
- calcular el número requerido de ciclos de reloj para un intervalo dado n = t/Tto,
- calcular el valor inicial para el registro de conteo TCNT0 = 256 - n.

Puede automatizar este procedimiento mediante macros. Por ejemplo, así:

#definir F_CPU 8000000UL
#define TIME_MS(tiempo, k) (256L - ((tiempo)*(F_CPU))/(1000L*(k)))

Pero con una macro de este tipo hay que tener cuidado, pueden ocurrir errores en ciertos valores de tiempo y k.

Ahora pasemos al código. Para usar el temporizador T0 (y cualquier otro también), debe configurarlo (inicializarlo) y describir el controlador de interrupciones (si se usa).

La inicialización de un temporizador consta de los siguientes pasos:

detener el cronómetro
- configurar el modo Normal en TCCR0 sin inicio,
- establecer el valor inicial TCNT0,
- restablecer banderas en el registro TIFR,
- habilitar la interrupción por desbordamiento en TIMSK,
- configurar el preescalador en TCCR0, es decir, iniciar el temporizador

Es posible realizar variaciones en esta secuencia.

Para nuestra tarea, el código de inicialización se verá así:


/*valor para el registro de conteo*/
#definir T_POLL 100

TCCR0 = 0;
TCCR0 = (0<TCNT0 = T_POLL;
TIF = (1<TIMSK |= (1<TCCR0 |= (1<

La segunda línea de inicialización es esencialmente inútil; se agregó para mayor claridad. Para ver claramente qué modo de temporizador se está configurando.

El reinicio de los indicadores de interrupción en el registro TIFR se realiza escribiendo un 1 en el bit correspondiente. Esta operación debe realizarse sobrescribiendo registros y sin utilizar OR bit a bit. Y es por eso.

Digamos que se establecen dos indicadores de interrupción en el registro TIFR: TOV1 y TOV0. TOV0 necesitamos restablecer. Al configurar el dígito requerido usando OSucede algo como lo siguiente.


//TIFR tiene el valor 0b00000101
//las banderas están configuradas TOV1 y TOV0
//se ejecuta el código TIFR |= (1<
//TIFR se copia a R16
EN R16, 0x38

//en R16 el bit TOV0 está establecido
//aunque ya está instalado
ORI R16, 0x02

//R16 igual a 0b00000101 se escribe en el registro TIFR
SALIDA 0x38, R16

Como resultado, se restablecieron ambas banderas, pero queríamos restablecer una.

Continuemos.

La sintaxis para describir los manejadores de interrupciones es ligeramente diferente para diferentes compiladores. Para IAR'a, el controlador de interrupción del temporizador T0 para el evento de desbordamiento se verá así:



{
TCNT0 = T_POLL;

/*Debería haber un botón de encuesta aquí*/

TIMER0_OVF_vect es la dirección del vector de interrupción de desbordamiento. Se toma de los archivos de encabezado del microcontrolador. En este caso lo tomé del archivo iom16.h.

La primera línea del controlador (TCNT0 = T_POLL;) sobrescribe el registro de conteo y establece su valor inicial. Si no se hace esto, el temporizador continuará contando desde 0. La reescritura del registro de conteo debe realizarse al comienzo del controlador de interrupciones.

Todo el código para nuestra tarea se verá así. (El código se muestra para IAR. Para otros compiladores, debe cambiar los archivos de encabezado y el controlador de interrupciones).

#incluir
#incluir
#incluir

#definir T_POLL 100

int principal (vacío)
{
/*inicializa el temporizador*/

TCCR0 = 0;
TCCR0 = (0<TCNT0 = T_POLL;
TIFR |= (1<TIMSK |= (1<TCCR0 |= (1<

/*inicializa el resto de periféricos*/
DDRB |= (1<

habilitar_interrupt();
mientras(1);

/*controlador de interrupciones T0
por evento de desbordamiento*/
#pragma vector = TIMER0_OVF_vect
__interrumpir vacío TimerT0Ovf(vacío)
{
/*sobrescribiendo el registro de conteo*/
TCNT0 = T_POLL;

/*botón de encuesta*/

/*inversión de PB0 para depuración*/
PUERTO ^= (1<

Control de salida OC0

En modo Normal, el temporizador T0 puede cambiar el estado del pin OC0 cuando el registro de conteo y el registro de comparación coinciden. E incluso sin interrupciones. Las opciones de control están determinadas por los bits COM01 y COM00 del registro TCCR0.

A continuación se muestra un ejemplo de un programa que genera una onda cuadrada en el pin OC0.

#incluir
#incluir

int principal (vacío)
{
/*inicializa el temporizador T0*/

TCCR0 = 0;
TCCR0 = (0<TCNT0 = 0;
OCR0 = 0;
TIMSK = 0;
TCCR0 |= (1<

/*inicializar OC0*/
DDRB |= (1<

Mientras(1);
devolver 0;
}

El pin OS0 cambiará su estado al opuesto cuando el registro de conteo sea cero.

Algunos puntos sobre el uso del temporizador

El controlador de interrupciones del temporizador (y cualquier otro periférico) debe ser lo más corto posible.

Si se redondea el valor calculado para el registro de conteo (o registro de comparación), el temporizador contará el intervalo de tiempo con error.

Y una última cosa. Puede suceder que el procesamiento de una interrupción del temporizador se retrase (por ejemplo, debido a un fallo de otro controlador) y el registro TCNT0 ya cuente varios ciclos de reloj. Si simplemente sobrescribe el valor de TCNT0, la siguiente interrupción se llamará más tarde de lo necesario. Resulta que las interrupciones anteriores (retrasadas) y las nuevas no resistirán el intervalo requerido.

Esta situación se puede solucionar si sobrescribe el registro de conteo de esta manera:

TCNT0 = TCNT0 + valor inicial;

Sumar el valor actual del registro de conteo con el inicializado tendrá en cuenta estos ciclos de reloj adicionales.Realmente hay uno ¡PERO! Si startValue es grande, la operación de suma puede provocar que el registro del contador se desborde.

Por ejemplo, startValue = 250 y el temporizador logró contar hasta 10. Luego, la operación de suma conducirá al siguiente resultado:

10 + 250 = 260

Tomamos 8 dígitos de 260 y obtenemos 4. 4 se escribe en TCNT0.


Temporizadores y contadores para microcontroladores AVR (reloj en tiempo real). Lección 7 de AVR

Cuando todavía estaba empezando a estudiar microcontroladores, quería hacerlo. Sinceramente, quería intentar encender el televisor solo de 7 a 8 en punto, y el resto del tiempo debería haber estado apagado. Hice el dispositivo, pero nunca lo usé...

Todos los microcontroladores AVR tienen varios temporizadores integrados. También se pueden dividir en temporizadores de uso general y un temporizador de vigilancia, que está diseñado para reiniciar el MK cuando se congela.

Los temporizadores de uso general pueden:

  • Reloj de cuarzo externo a 32768 hercios.
  • Contar diferentes intervalos de tiempo
  • Contar pulsos externos en modo contador
  • Generar una señal PWM en ciertos pines MK
  • Generar interrupciones por algún evento, por ejemplo, cuando hay un desbordamiento

Los contadores se pueden cronometrar desde un generador de reloj interno y desde una entrada de conteo. Veamos la funcionalidad del contador temporizador 1 en el microcontrolador atmega8. Inicie CodeVision AVR, cree un nuevo proyecto y acepte la oferta para iniciar Code WizardAVR

Usemos timer2 como ejemplo para implementar un reloj en tiempo real con salida a una pantalla LCD; para esto configuramos el temporizador como se muestra en la captura de pantalla.

aquí configuramos la fuente de reloj externa para el temporizador, como fuente externa usaremos un reloj de cuarzo a 32768 hercios, luego configuraremos el preescalador a 128, es decir, el temporizador funcionará a una frecuencia de 32768/128=256 , y el registro de conteo es de 8 bits (número máximo 255), resulta que se desbordará una vez por segundo, luego marcamos la casilla junto a Interrupción de desbordamiento y hacemos clic en archivo->Generar, guardar y salir.

El asistente de código generó el siguiente código:

#incluir // Interrupción de rutina de servicio de interrupción de desbordamiento del temporizador 2 void timer2_ovf_isr(void) ( ) void main(void) ( // Inicialización de puertos de entrada/salida // Inicialización del puerto B PORTB=0x00; DDRB=0x00; // Inicialización del puerto C PORTC=0x00; DDRC=0x00; // Inicialización del puerto D PORTD=0x00; DDRD=0x00; // Inicialización del temporizador/contador 0 // Fuente del reloj: Reloj del sistema // Valor del reloj: Temporizador 0 detenido TCCR0=0x00; TCNT0=0x00; // Temporizador /Inicialización del contador 1 // Fuente del reloj: Reloj del sistema // Valor del reloj: 125.000 kHz // Modo: PWM rápido superior=00FFh // Salida OC1A: Desconectada // Salida OC1B: Desconectada // Cancelador de ruido: Apagado // Entrada Captura en flanco descendente // Interrupción de desbordamiento del temporizador 1: desactivado // Interrupción de captura de entrada: desactivado // Interrupción de coincidencia de comparación A: desactivado // Interrupción de coincidencia de comparación B: desactivado TCCR1A=0x01; TCCR1B=0x0A; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Inicialización del temporizador/contador 2 // Fuente del reloj: pin TOSC1 // Valor del reloj: PCK2/128 // Modo: Normal top=FFh // Salida OC2: Desconectado ASSR=0x08; TCCR2=0x05; TCNT2=0x00; OCR2=0x00; // Inicialización de interrupciones externas // INT0: desactivado // INT1: desactivado MCUCR=0x00; // Temporizador(es)/Contador(es) Interrupción(es) inicialización TIMSK=0x40; // Inicialización del comparador analógico // Comparador analógico: apagado // Captura de entrada del comparador analógico por temporizador/contador 1: apagado ACSR=0x80; SFIOR=0x00; // La habilitación global interrumpe #asm("sei") mientras (1) ( ); )

#incluir #incluir // Funciones del módulo LCD alfanumérico #asm .equ __lcd_port=0x12 ;PORTD #endasm #include segundo carácter sin firmar = 0; //variable para almacenar segundos unsigned char minute=0; //variable para almacenar minutos unsigned char hour=0; //variable para almacenar horas char lcd_buffer; //búfer variable para salida de pantalla // Interrupción de rutina de servicio de interrupción de desbordamiento de Timer2 void timer2_ovf_isr(void) (if (++segundo==59) //aumenta el número de segundos en 1 y verifica la igualdad 59 (segundo = 0; si (+ +minuto==59) (minuto = 0; if (++hora==59) ( hora = 0; ) ) lcd_clear(); // borra la pantalla antes de mostrar lcd_gotoxy(0,0); // mueve el cursor al punto x=0 y=0 sprintf(lcd_buffer,"%i:%i:%i",hora,minuto,segundo); // crea una línea para la salida lcd_puts(lcd_buffer); // muestra la línea en la pantalla) void main( void) ( // Inicialización del temporizador/contador 2 // Fuente del reloj: pin TOSC1 // Valor del reloj: PCK2/128 // Modo: Normal top=FFh // Salida OC2: Desconectado ASSR=0x08; TCCR2 =0x05; TCNT2=0x00 ; OCR2=0x00; // Inicialización de temporizadores/contadores de interrupciones TIMSK=0x40; // Inicialización del módulo LCD lcd_init(16); // Interrupciones de habilitación global #asm(" sei") mientras que (1 ) ( ); )

El programa está listo, ahora creemos un diagrama en Proteus.

Nuevo en el sitio

>

Más popular