====== Interrupção periódica ======
//Conhecimento necessário:
[HW] [[pt:hardware:homelab:digi]],
[AVR] [[pt:avr:interrupts]], [AVR] [[pt:avr:timers]], \\
[LIB] [[pt:software:homelab:library:pin]],
[LIB] [[pt:software:homelab:library:timer]]//
===== Teoria =====
O objetivo deste capítulo é demonstrar o uso das interrupções no exemplo dos contadores. As interrupções são partes do programa que reagem aos eventos que têm lugar nos microcontroladores. São usadas normalmente para uma resposta rápida a um evento, mas podem também ser usadas para completar vários processos paralelos, acções precisas no tempo e de poupança energética. Por exemplo, é possível fazer um LED piscar com interrupções, de modo a que a freqüência do piscar não dependa do que acontece no programa em execução. Quando a interrupção ocorre a execução do programa principal pára e acontece a verificação da prioridade de interrupção na tabela de vectores de interrupção. Depois disso, dá-se então por concluída a função de interrupção. Depois da interrupção, o programa principal continua a partir do estado onde parou.
===== Prática =====
O programa seguinte mostra como o contador é configurado para fazer uma interrupção. Existem 2 LEDs do módulo de I/O digital no programa. O estado do LED vermelho é alterado periodicamente com uma espera por software; o estado do LED verde é alterado quando ocorrem interrupções. Existe um exercício separado para um LED piscar com espera por software que não é explicado aqui. O objetivo principal é explicar o uso da biblioteca dos contadores e interrupções.
O que se segue mostra o uso de interrupções do controlador xmega. No início do programa, o contador/temporizador de 16 bits E1 é configurado. Em primeiro lugar, o período do temporizador irá ser definido para o valor máximo da função de contagem TC_SetPeriod. O divisor do contador é de 1024 e o valor do período é de 31249, por isso, quando a frequência de relógio é de 32 MHz, o período será exatamente um segundo. Isto é fácil de calcular com seguinte fórmula:
period = (32000000 Hz / 1024 / 1) - 1 = 31249
Depois de permitir que a interrupção atinja o valor máximo do contador 1, uma interrupção deve ser permitida a nível global, o que significa ao longo de todo o microcontrolador. As interrupções globais podem ser ativadas por função sei e proíbidas com cli. Um ficheiro header avr/interrupt.h deve ser incluído na definição da parte do programa dessas funções e interrupções. A parte do programa da interrupção é definida com função macro ISR, cujo parâmetro é o nome do vetor de interrupção. Nesta configuração o valor máximo de interrupção atinjida do vetor do contador 1 é TCE1_OVF_vect. Além disso, para permitir a interrupção global, as prioridades de interrupção devem ser definidas uma a uma, usando o registo XMEGA PMIC.CTRL.
// HomeLab III example of blinking LED with counter interrupt
#include
#include
#include
#include
// Interruption
ISR(TCE1_OVF_vect)
{
// Changing the state of the green LED
pin_toggle(led_green);
}
// Main program
int main(void)
{
// Setting the pins of the LEDs as outputs
pin_setup_output(led_green);
// Setting the period of timer E1
// F_CPU/1024/[aeg] - 1 = periood
// 32000000 / 1024 / 1 - 1 = 31249
TC_SetPeriod(&TCE1, 31249);
// Setting the clock of timer E1 (F_CPU/1024)
TC1_ConfigClockSource(&TCE1, TC_CLKSEL_DIV1024_gc);
// Setting timer E1 to the normal operating mode
TC1_ConfigWGM(&TCE1, TC_WGMODE_NORMAL_gc);
// Enabling high-priority overflow interruptions
TC1_SetOverflowIntLevel(&TCE1,TC_OVFINTLVL_HI_gc);
// Enabling high-priority interruptions
PMIC.CTRL |= PMIC_HILVLEN_bm;
// Enabling global interruption
sei();
// Endless loop
while (1) { }
}
Os exemplos de interrupção são bastante diferentes entre as séries de controladores ATmega (neste exemplo usamos o ATmega2561), porque os temporizadores, em comparação com os controladores da série XMEGA, também são diferentes.
No início do programa, o contador/temporizador de 16 bits 1 foi configurado com a função //timer1_init_ctc//. Com esta função se o contador CTC //clear timer on compare match// tiver sido definido para o modo em que o valor máximo do temporizador não é 216 - 1, mas pode ser selecionado. Neste caso, o valor máximo é fixado para ser igual ao valor do índice do ICR1. O divisor do contador é de 1024 e o valor da ICR1 é 14400, por isso, quando a freqüência de relógio é 14,7456 MHz, o período será exatamente um segundo. Isto é fácil de calcular com seguinte fórmula:
f = 14745600 Hz / 1024 / 14400 = 1
// The HomeLab II example of blinking LED with counter interrupt
#include
#include
#include
#include
// Interruption
ISR(TIMER1_CAPT_vect)
{
// Changing the state of the green LED
pin_toggle(led_green);
}
// Main program
int main(void)
{
// Setting the pins of the LEDs as outputs
pin_setup_output(led_green);
// Seting the timer up in the CTC mode
timer1_init_ctc(
TIMER1_PRESCALE_1024,
TIMER1_CTC_TOP_ICR);
// The maximal value of the timer is 14400, which
// makes the length of the period 1 s
// Formula: 14,7456Mhz / 1024 = 14400
timer1_set_input_capture_value(14400);
// Allowing interruption of achieving the value
timer1_input_capture_interrupt_enable(true);
// Allowing global interruption
sei();
// Endless loop
while (1){ }
}
No início do programa confirma-se que, independentemente do que o microcontrolador está a executar no programa principal, as interrupções ocorrem e o LED verde pisca.