Interrupções

As interrupções no AVR podem ser causadas por contadores, interfaces de comunicação, conversores de analógico para digital, comparadores, pinos especiais de entradas-saídas bem como por várias outras funções, dependendo do controlador. Uma interrupção pode ser autorizada ou desautorizada pela unidade que a gera. Independentemente da interrupção ser autorizada ou não, existe um campo de 1-bit (flag, sinalizador, de interrupção) no controlador correspondente, que adquire o valor verdadeiro quando se verifica uma condição de interrupção. Se a flag de interrupção for alterada para verdadeira e a interrupção é permitida, o controlador inicia a execução do código especificado para tal interrupção.

Cada interrupção do microcontrolador AVR encontra-se ligada a um evento específico. Cada evento tem uma flag no registo de estados, que marca a ocorrência do evento. Os eventos encontram-se ligados aos registos de mascara das interrupções e aos bits que a estas correspondem. Se a interrupção do evento não tiver uma mascara definida, quando tal evento se verifica, o processador para por alguns ciclos de executar o programa em curso e inicia a execução do programa relacionado com tal interrupção. Depois de executado programa correspondente à interrupção, o processador recomeça o programa principal entretanto em pausa.

Exemplo

Para usar as interrupções do AVR na biblioteca LibC, é necessário incluir “interrupt.h”. O código executado aquando da interrupção é escrito depois da palavra-chave “ISR”. Os eventos são também ligados a mascara de registo e aos bits correspondentes. O texto entre as aspas depois de “ISR” é o nome da interrupção. Segue-se o exemplo em C:

#include <avr/interrupt.h>
 
ISR(XXX_vect)
{
	// nada faz
}

O registo de estado e controlo SREG permite o controlo global de todas as interrupções. A opção de permitir ou não todas as interrupções de uma vez existe para permitir a proteção de dados. Uma vez que as interrupções quebram a execução do programa principal, alguns dos dados em uso por este programa principal podem ser descartados ou corrompidos neste processo. Estas situações podem ser evitadas facilmente através da desativação de todas as interrupções antes de iniciar o processamento dos preciosos dados. A desativação global de interrupções é fácil, se poder ser executada através de um único registo (SREG). Depois e executada a parte critica do programa, as interrupções podem facilmente ser novamente ativadas, passando a ser executadas todas as interrupções que venham a ocorrer.

 

Exemplo

Vamos supor que existe uma variável de 16 bits no programa, que é tanto é alterada por uma interrupção do programa principal como pelo programa de uma interrupção, sendo depois o valor desta variável fornecido a outra variável:

#include <avr/interrupt.h>
 
// variáveis globais de 16 bits x e y
unsigned short x, y;
 
// variáveis globais de 16 bits x e y
ISR(XXX_vect)
{
	x = 0x3333;
}
 
int main()
{
	// da um valor a x
	x = 0x1111;
 
	// ativa globalmente as interrupções  
	sei();
 
	// atribui o valor de x a y
	y = x;	
}

O programa em si é muito simples – primeiro, é atribuído o valor de 0x1111 a variável x e mais tarde, este valor é atribuído a variável y. Se ocorrer uma interrupção entre estas duas operações, x obterá o valor de 0x3333. Logicamente, a variável y poderá vir a ter dois valores diferentes no final do programa, no entanto num AVR de 8 bits existe uma terceira opção. Isto porque numa arquitetura de 8-bits são necessários dois ciclos para transportar 16-bits de dados pelo que uma interrupção na hora errada pode corromper a integridade dos dados.

Consequentemente, y poderá vir a ter o valor de 0x1111 ou 0x3333, mas poderá também vir a ter o valor de 0x3311 no final do programa. Para evitar este terceiro resultado, indesejado, devem ser desativadas todas as interrupções temporariamente antes de realizar tais operações por mais um ciclo.

	// desativa globalmente as interrupções
	cli();
 
	// da o valor de x a f
	y = x;
 
	// ativa globalmente as interrupções
	sei();