Você está na página 1de 6

Interrupes no Arduino: uma breve anlise

Escrito por Gabriel Yoshiaki Hotta em 2013/12/17, sugestes, correes, comentrios, etc, podem ser enviadas para anoxya@gmail.com

Requisitos
Este artigo supe que o leitor j possui o conhecimento bsico sobre interrupes: o que uma interrupo, como trata-las (attachInterrupt() e detachInterrupt()). Tambm recomendado o conhecimento bsico da linguagem Assembly para melhor compreenso, embora no seja estritamente necessrio.

Introduo
Interrupes no Arduino so simples de usar e na maioria das vezes no precisamos nos preocupar com muitos detalhes. Entretanto, quando passam a ser utilizadas vrias interrupes, caractersticas importantes e que no so to evidentes passam a possuir grande relevncia. Uma delas a prioridade das interrupes, bem como a necessidade de interrupes aninhadas (nested interruptions). Pouco material sobre o assunto est disponvel, e de forma dispersa e fragmentada. Este artigo tenta reunir informaes sobre o tema, boa parte do material se baseia na traduo/interpretao do Datasheet.

Terminologia
Capturar interrupo: tratamento de um evento associado a uma interrupo. Condio de interrupo: circunstancias na qual uma interrupo deve ser efetuada. Habilitao de interrupo: circunstancias na qual o processador capaz de efetuar a captura de uma interrupo. Rotina de interrupo: conjunto de comandos/instrues que sero executados quando houver captura de interrupo.

Os tipos de interrupo
Existem basicamente dois tipos de interrupo. O primeiro tipo capturado por um evento que seta o respectivo bit na "Flag Interrupt". Quando isso acontece a rotina de interrupo associada executada e o bit na "Flag Interrupt" limpo (zerado). Se durante a execuo da rotina de interrupo houver uma nova condio de interrupo, o bit ser novamente setado e manter seu valor at a interrupo ser novamente habilitada (tambm possvel limpar o bit explicitamente dentro da rotina, impedindo a execuo posterior da rotina de interrupo). O segundo tipo de interrupo capturado to logo a condio de interrupo esteja presente, elas no utilizam necessariamente a "Flag Interrupt". Se a condio de interrupo

surgir e desaparecer antes da interrupo estar habilitada a rotina de interrupo associada no ser executada. Se duas ou mais condies de interrupo ocorrerem simultaneamente haver uma prioridade de execuo entre as interrupes. Ao sair de uma rotina de interrupo o AVR ir retornar ao programa principal e executar uma instruo antes de executar a prxima rotina de interrupo. Ou seja, se houver duas condies de interrupo, a rotina de interrupo da primeira (com maior prioridade) ser executada, em seguida uma, e somente uma, instruo do programa principal ser executado e apenas depois disso a segunda rotina de interrupo ser executada. O "Status Register" no automaticamente armazenado ao entrar em uma rotina de interrupo, nem restaurado ao sair da Rotina de interrupo. Cabe ao programador faze-lo caso seja do seu interesse.

Prioridade de interrupes
A prioridade de execues dada pela posio no "Interruption Vector", quanto menor a posio ocupada, maior a prioridade. Para o ATmega2560 (usado no Arduino Mega 2560, em outros modelos deve-se consultar o respectivo Datasheet) temos a seguinte tabela:

Interrupes aninhadas (nested interruptions)


Quando uma interrupo capturada a flag de interrupo global "SREG" zerada, desabilitando todas interrupes.

Ao sair de uma rotina de interrupo executada a instruo "RETI" que reabilita as interrupes. Este o comportamento desejado na maioria das vezes, pois espera o termino de uma rotina de interrupo para, em seguida, executar uma outra rotina de interrupo. Entretanto, se o programador desejar pode-se reabilitar a captura de interrupo dentro de uma rotina de interrupo. A isso d-se o nome de interrupes aninhadas (nested interruptions). Para habilitar interrupes aninhadas o programador deve explicitamente utilizar a instruo responsvel por habilitar interrupes: sei(). Note ainda que o uso incorreto pode acarretar em infinitas interrupes recursivas. Ainda h outro porm, mesmo utilizado a instruo "sei()" no incio de uma rotina de interrupo ainda permanecem algumas instrues geradas pelo compilador antes da instruo Assembly "SEI", ou seja, algumas poucas instrues ainda so executadas com a interrupo desativada. O cdigo em C
ISR(TIM0_OVF_vect) { sei(); //do nothing }

Gera o seguinte cdigo assembly:


PUSH PUSH IN PUSH CLR SEI POP OUT POP POP RETI R1 R0 R0, 0x3F R0 R1 R0 0x3F, R0 R0 R1 ; retorna ao programa principal ; ; ; ; ; ; \ | | interrupcao ainda desativada | / <<-- reabilita interrupcoes globais

Melhor forma de utilizar a instruo SEI


A avr-libc permite a insero da instruo "SEI" antes de qualquer instruo na rotina de interrupo atravs da seguinte declarao: ISR(XXX_vect, ISR_NOBLOCK) { } onde XXX_vect uma interrupo valida no vetor de interrupes. Por exemplo, o seguinte cdigo C
ISR(TIM0_OVF_vect, ISR_NOBLOCK) { //do nothing }

Gera o cdigo Assembly


SEI PUSH PUSH IN PUSH CLR POP OUT POP POP RETI ; <<-- habilita interrupcoes globais R1 R0 R0, 0x3F R0 R1 R0 0x3F, R0 R0 R1 ; retorna ao programa principal

Fontes
Datasheet do ATmega2560 http://www.carlosdelfino.eti.br/eletronica/item/89-prioridade-dasinterrup%C3%A7%C3%B5es-em-microcontroladores-atmega http://stackoverflow.com/questions/5111393/do-interrupts-interrupt-other-interrupts-onarduino http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html http://ucexperiment.wordpress.com/2013/05/20/nested-interrupts/

Você também pode gostar