Interrupções. O que é uma interrupção? Como funciona uma interrupção no AVR?

Documentos relacionados
Programação em C no AVR

Mundo Arduino: Vamos começar a programar?

Introdução à Programação em C. Prof. Ricardo Teixeira Tecnologia em Mecatrônica Industrial SENAI

Robótica com Arduino Professor: Paulo Marcos Trentin

Descrição dos pinos de entrada e saída e de funções especiais. Descrição dos modos de acesso: individual e por porto

Sistemas Reativos. Interrupções em microcontroladores (baseado no Atmega328p Arduino Uno)

Plano de Aula. 1 o semestre. Aula número 009 Interrupções. Fazer uso das interrupções externas no Arduíno

Tutorial Proteus 02. Como simular o Arduino no Proteus ISIS utilizando a biblioteca "Emulater" por João Vitor

O que você pode fazer com o Arduino

Programação do Arduino. Parte 1. IDE Wiring

Experimento 6 Conversor analógico digital e comunicação serial

introdução Olá, Após alimentar você deve enviar comandos AT para verificar que o modulo está funcionando e comunicando via serial.

Por Fernando Koyanagi 1

2. Conecte seu Arduino ao computador. 3. Abra as ferramentas da IDE e selecione a porta e a placa que você está utilizando.

Curso introdutório de microcontroladores - Plataforma Arduino

Implementando PWM por soft - um método simples. Por Renie S. Marquet reniemarquet.sites.com.br - versão

Lista de Exercícios A2

Acendendo o Led com Arduino.

Atividade de laboratório 004. Prof: Carlos Eduardo de Brito Novaes 6 de maio de Alunos RA Nome Curso Semestre

MOBILIDADE SUSTENTÁVEL. Luís Martins Duarte Abreu

PRÁTICAS. Microcontroladores: (LT36D) Prof: DaLuz. Práticas - 2º sem Microcontroladores LT36D - 26/04/ :56 1/16

Programação C para Arduino

Plano de Aula. 1 o semestre. Cronômetro Interrupções, Timers. Utilizar interrupções para criar um cronômetro com parciais

Enviando Dados Pela Porta Serial na placa LaunchPad MSP430 Utilizando o ambiente ENERGIA

Arquitetura Von Neumann Dados e instruções são obtidos da mesma forma, simplificando o desenho do microprocessador;

Atividade de laboratório 005. Prof: Carlos Eduardo de Brito Novaes 20 de maio de Alunos RA Nome Curso Semestre

Robótica com Arduino

Revisão Linguagem C Parte 1

MANUALDEGUSTAÇÃO ARDUINO KIT INICIANTE V4.0

- Tarefas Práticas de Programação usando Arduino - Imagem do Robô com Legendas

Tutorial de uso do JbreadBoard

Curso de Arduino. Quais seus principais componentes?

Kit controle remoto IR acionando 3 Led com Arduino

Programação em Linguagem C

Introdução do Arduino para aquisição de dados e controle de instrumentos

Curso de Básico Arduino! Ministrado por: Wellington Cássio Faria Contato:

INTRODUÇÃO A PLATAFORMA ARDUINO. TÁSSIO JOSÉ GONÇALVES GOMES

ANEXO I. O Ambiente de desenvolvimento MpLab IDE v6.62

Binário para Decimal. Binário: = 19. Decimal:

Atividade de laboratório 003. Prof: Carlos Eduardo de Brito Novaes 29 de abril de Alunos RA Nome Curso Semestre

AULA 6 - INTRODUÇÃO AO ARDUINO Revisão de Eletrônica Digital e introdução aos Sistemas Computacionais.

Tutoriais PET-Tele. Introdução à Amostragem de Sinais com o kit Arduino (Versão: A2016M06D21)

Introdução à Plataforma ARDUINO

Características técnicas Baseado no ATMega da empresa AVR, fabricante de micro-controladores em plena ascensão e concorrente do PIC Pode usar ATMega

INTRODUÇÃO: MICROCONTROLADORES

Anatomia do Arduino Bootloader

Plano de Aula. 1 o semestre. Aula número 012 Periféricos Comunicação Serial. Conhecer os princípios de comunicação serial

Arduino: primeiros passos para aprender e configurar.

Sistema Digitais. Bacharelado de Informática UEM DIN - Prof. Elvio 2017

Estrutura Básica da Linguagem Arduino

LIGAR LUZ COM BOTÃO. Projeto 2

1º minicurso de Arduino no IFUSP 4 a 22 de maio de 2015 Prof. Alexandre Suaide

Comunicação RC5 com o dspic Vitor Amadeu Souza

KIT INICIANTE V7 PARA ARDUINO

Missão: Arduino. 3 de Março. Organização

Guia da Placa de desenvolvimento PD Mega16 N1

Aula 23: Noções de Compilação, Montagem, Link-edição, e Interpretação

Arduino Lab 08 Banco de teste para memória RAM HM6116 de 16k

ARDUINO. Profº. Engº. Robson Dias Ramalho

ARDUINO BÁSICO E T A P A 1 O QUE É ARDUINO? Prof. Amadeu Zanon Neto

Projeto 01. Adriano Joaquim de Oliveira Cruz Instituto de Matemática UFRJ 2015 Adriano Cruz. 30 de agosto de 2015

INTRODUÇÃO AO ARDUINO DUE, CANAL DIGITAL, FUNÇÃO DELAY

Cerne Tecnologia e Treinamento

Revisão da Linguagem C Prof. Evandro L. L. Rodrigues

Universidade Federal de Juiz de Fora Laboratório de Eletrônica CEL 037 Página 1 de 6

SEL-433 Aplicação de Microprocessadores I. Prof: Adilson Gonzaga

Introdução. O que é o Arduino?

Comunicação USB com o PIC Vitor Amadeu Souza

Arquitectura de Computadores 2007/2008 2º Semestre 1º Teste (A) - 30/04/2008. Folha de Respostas

Arduino. Gilmar Aquino

- Trabalho Prático de Algoritmos e Programação usando Robô Arduino -

Arquitetura do Microcontrolador Atmega 328

MODBUS COM ARDUINO.

Manual Técnico Módulo de Relê 4 Canais

SEL-614 MICROPROCESSADORES E APLICAÇÕES. Adilson Gonzaga

Sistemas Embarcados:

Sequencial Supermáquina (TEMPORIZAÇÃO SIMPLES)

Universidade Federal do Espírito Santo. Programação I Tipos de Dados Básicos - C Professora: Norminda Luiza

ENG-1450 Microcontroladores e Sistemas Embarcados. Lab03 Execução Experiência 01, Keypad, 7-seg, Exercícios

Disciplina : Microcontroladores AVR

Trabalho Prático Nº3 Porta Paralela

ENG-1450 Microcontroladores e Sistemas Embarcados. Lab02 Apresentação Kit PicGenios Interrupção e Timers

Transcrição:

Interrupções O que é uma interrupção? Irei agora começar a falar de interrupções a partir do mais básico o que é uma interrupção? Uma interrupção é basicamente uma pausa no programa, enquanto o processador trata de outra coisa mais importante. Um exemplo da vida real: http://www.youtube.com/watch?v=a9ep6u0bbra Neste caso a interrupção foi o toque com o pato que interrompeu o discurso. Como funciona uma interrupção no AVR? Nos AVRs, as interrupções têm várias particularidades, pois é necessário activar as interrupções globais, as interrupções particulares e criar uma rotina para lidar com cada interrupção. Cada microcontrolador AVR tem um conjunto de registers cujos bits controlam vários aspectos do seu funcionamento (por exemplo, no tutorial que coloquei no meu primeiro post, estão explicados os que controlam os pinos de INPUT/OUTPUT). O mesmo acontece com as interrupções. No caso do atmega328, o bit I do register SREG controla as interrupções a nível global. Quando o seu valor é 1, estas estão ligadas, e vice-versa. No entanto, há uma instrução mais simples para ligar as interrupções globais do que terem de se lembrar que é no bit I do register SREG, que é simplesmente sei (funciona tanto em assembly como em C, só que em C é uma função incluída no header <avr/interrupt.h>). Depois de ligadas as interrupções globais, ainda é necessário ligar interrupções individuais. Para isso, é necessário encontrar qual o bit que liga certa interrupção (encontra-se na datasheet facilmente na zona dos registers no capítulo acerca da funcionalidade procurada). Depois de ligadas as interrupções globais e particulares, o processador procura por mudanças de estado em bits de certos registers (flags), definidos pelas interrupções individuais. Quando esses bits tornam-se em 1, a interrupção é gerada (independentemente do que esteja a acontecer, o programa pára). Mas falta aqui uma coisa o que acontece quando essa interrupção ocorre? A Interrupt Service Routine (ISR) definida para aquela interrupção é executada. No final disto tudo, a flag fica com o valor 0 novamente, e o programa continua a sua execução a partir do ponto em que estava. Nota: Enquanto o processador está a executar a interrupção, as interrupções globais estão desligadas. Quando acaba-se de executar a interrupção, as interrupções globais são ligadas novamente.

Como lidar com uma interrupção no AVR? Agora que já sabemos como funciona uma interrupção, temos de aprender a programar de forma a lidar com as mesmas. Primeiro, iremos começar por definir o pseudo-código: // Ligar interrupções globais // Definir ISR para lidar com as interrupções particulares ligadas. Para lidar com registos e interrupções, iremos precisar dos seguintes headers: <avr/io.h> e <avr/interrupt.h> (já podemos também adicionar a função main(), e um loop eterno): // Ligar interrupções globais // Definir ISR para lidar com as interrupções particulares ligadas. (como a ISR é uma função, definimos fora do main). Como expliquei anteriormente, ligam-se as interrupções globais através da função sei() // Definir ISR para lidar com as interrupções particulares ligadas. Neste tópico, vamos ignorar as interrupções individuais, pois ainda não falámos de nenhuma

interessante, e vamos concentrar-nos nas ISR. A biblioteca do avr dá-nos uma macro muito útil para definir uma ISR, e tem o nome ISR() (espertos, não são? xd), com um argumento: o nome do vector da interrupção. O vector da interrupção é basicamente o que identifica qual a interrupção com que estamos a lidar. Esta informação encontra-se na página 57 do datasheet que eu tenho (início do capítulo sobre interrupções/capítulo 9), numa tabela, na coluna Source. Por exemplo, no tópico a seguir, vamos lidar com a interrupção que ocorre no pino digital 2. Este pino tem o nome de INT0. Ao olharmos para a tabela, vemos que a source da interrupção é INT0. Para usarmos isto como argumento para a macro ISR, basta adicionar _vect. Assim, o vector é: INT0_vect: (para alguns, esta declaração da função ISR pode ser confusa, pois não tem tipo. No entanto, lembrem-se que é uma macro, e por isso ISR não é realmente o que fica no código final). Nota: Se notarem, alguns dos Vectores na datasheet têm espaços ou vírgulas no nome. Basta substituir esses por _. Por exemplo, para a interrupção gerada quando se recebem dados por serial, temos o seguinte Source: USART, RX. O argumento que usamos para a macro ISR é: USART_RX_vect. Exemplo de interrupção através do pino digital 2 (INT0) Vamos agora fazer algo mais interessante, e codificar uma interrupção. Comecemos com o código do tópico anterior:

Vamos usar para este efeito o pino 2 (podia ser feito com o pino 3 também, com poucas diferenças). O objectivo deste código vai ser mudar o estado de um LED quando se toca num botão ligado ao pino 2. O LED vai estar ligado ao pino digital 4 (PD4). Vamos começar por criar uma variável global, com o estado do pino e inicializar esse pino como output (vai começar desligado) (para mais informações sobre GPIOs, ler o tutorial que pus no primeiro post), e já vamos colocar o código necessário para fazer toggle ao pino na ISR. char output = 0; // Estado do led. DDRD = (1<<PD4); // Inicializar o pino digital 4 como output. PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado. output = ~output; // Alterar o estado PORTD &= ~(1<<PD4); // Desligar o pino isto é necessário para quando o output é 0 se poder desligar. PORTD = ((output&1)<<pd4) // output&1 pois só nos interessa o primeiro bit, assim evitamos mexer nos outros pinos. Agora só nos falta mesmo inicializar a interrupção particular para o INT0.

Ao pesquisarmos na datasheet, podemos observar um pormenor acerca dos interrupts externos INT0 e INT1: eles podem ser ligados por 4 estados diferentes: quando o pino está low, quando o pino transita para high, quando o pino transita para low e quando o pino muda de estado (low-high e vice-versa). Como estamos a usar um botão, o mais fácil é que este ligue o pino à corrente, colocando-o em HIGH. Assim, queremos gerar o interrupt quando o pino transita para HIGH. O estado escolhido para o INT0 está nos bits ISC00 e ISC01 do register EICRA (para o pino INT1, está nesse mesmo register, mas nos bits ISC10 e ISC11). O estado que desejamos corresponde a colocar ambos os bits em 1. Logo, adicionamos isso ao código: char output = 0; // Estado do led. DDRD = (1<<PD4); // Inicializar o pino digital 4 como output. PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado. EICRA = ((1<<ISC00) (1<<ISC01)); // Configurar interrupção no pino INT0 para quando este transita para HIGH output = ~output; // Alterar o estado PORTD &= ~(1<<PD4); // Desligar o pino isto é necessário para quando o output é 0 se poder desligar. PORTD = ((output&1)<<pd4) // output&1 pois só nos interessa o primeiro bit, assim evitamos mexer nos outros pinos. Agora só nos falta mesmo ligar a interrupção associada ao INT0. O bit que controla isto é o INT0 no register EIMSK. Assim, é só modificar o código, e fica completo: char output = 0; // Estado do led.

DDRD = (1<<PD4); // Inicializar o pino digital 4 como output. PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado. EICRA = ((1<<ISC00) (1<<ISC01)); // Configurar interrupção no pino INT0 para quando este transita para HIGH EIMSK = (1<<INT0); output = ~output; // Alterar o estado PORTD &= ~(1<<PD4); // Desligar o pino isto é necessário para quando o output é 0 se poder desligar. PORTD = ((output&1)<<pd4) // output&1 pois só nos interessa o primeiro bit, assim evitamos mexer nos outros pinos. Agora temos um código que, ao clicarmos num botão que liga o pino digital 2 e o pólo positivo, faz toggle do pino digital 4 (nota: visto que não fizemos nada para tratar do bouncing, podem haver resultados inesperados. No entanto, como isto é só para exemplo, não considerámos muito importante). Para experimentarem, podem montar o seguinte circuito: Cuidados a ter na utilização de interrupções Vou deixar aqui duas situações a terem em atenção quando estão a lidar com interrupções: 1. O compilador optimiza bastante o código. Isto quase sempre é uma vantagem, no entanto, por vezes não é. Utilizando o exemplo do tópico anterior, se tivéssemos de aceder a variável output

no código do main(), não estaríamos a aceder ao valor correcto da variável. Isto acontece porque o compilador não considera que podemos aceder à função ISR só com aquele código, logo apenas carrega a variável da memória ram para os registers uma vez, e depois não actualiza o seu valor, que é alterado na ISR. Para resolver isto, dizemos ao código que a variável output é volatile, declarando-a assim: volatile char output; Isto indica ao compilador que a variável pode ser alterada de formas inesperadas, e por isso deve sempre actualizar o seu valor da ram. 2. O processador AVR do Arduino funciona a 8 bits. Isto quer dizer que ele só pode lidar com 8 bits de cada vez. Não pode, por exemplo, carregar um int da memória numa só instrução, pois estes têm 16 bits. Mas as interrupções podem ocorrer em qualquer parte do programa logo o que pensam que acontece se tirarmos a primeira metade de um inteiro da memória, e antes de tirarmos a segunda metade ocorrer uma interrupção que altere essa variável? Resultados não previsíveis obviamente Logo, o que podemos fazer para evitar isto? O que podemos fazer é desligar interrupções nesses blocos de código que não podem ser perturbados (nota: se estiverem a carregar um char não deve haver problemas, visto ter apenas 8 bits). Isto é feito facilmente com a função cli() (também no header <avr/interrupt.h>). Depois do código efectuado, basta ligar novamente as interrupções com sei(). Por exemplo: //... int i,j; for(;;) { cli(); j = i; // o i é alterado numa interrupção // //... E com isto acabamos a base das interrupções. Decidi começar com estas, pois nos próximos tutoriais, explicarei as interrupções individuais de várias funcionalidades.