====== 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.