Conhecimento necessário:
[HW] Módulo de Interface do Utilizador,
[AVR] Interrupções, [AVR] Contadores/Temporizadores,
[LIB] Pinos,
[LIB] Temporizadores
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.
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 <homelab/pin.h> #include <homelab/delay.h> #include <homelab/timer.h> #include <avr/interrupt.h> // 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 <homelab/pin.h> #include <homelab/delay.h> #include <homelab/timer.h> #include <avr/interrupt.h> // 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.