Upload
others
View
10
Download
0
Embed Size (px)
Citation preview
– Sistemas Reativos –
Interrupções em microcontroladores
(baseado no Atmega328p – Arduino Uno)
Noemi [email protected]
Adriano [email protected]
Interrupção no Microcontrolador
● Mecanismo para interromper a execução do programa principal.
– Desvia a execução para um endereço especial.
– Retorna para a execução principal exatamente no local que foi interrompido.
● Amplamente utilizado em microcontroladores e CPUs convencionais.
● Equivale a um evento primário em sistemas reativos.
Tipos
● Externa– Pinos digitais – INT0, INT1
– Barramento – PC0, PC1, PC2
● Interna– Temporizadores e Watchdog Time-out
– Interface de comunicação – USART, SPI, TWI
– Outros – Conversor A/D, EEPROM
Execução da interrupção
Execuçãoda rotinaprincipal
Execuçãoda rotina deinterrupção
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
101 102 103 104
Evento de Interrupção
PC = 101
PC = 9
PC → Program Counter
Mudança de contexto
Execuçãoda rotinaprincipal
Execuçãoda rotina deinterrupção
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
101 102 103 104
Evento de Interrupção
PC = 101
PC = 9
Registador A = 10
Registador A = -5
Registador A = -5
Mudança de contexto
Execuçãoda rotinaprincipal
Execuçãoda rotina deinterrupção
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
101 102 103 104
Evento de Interrupção
PC = 101
PC = 9
Registador A = 10Salva A → Temp
Registador A = -5
Recupera A ← TEMPRegistador A = 10
Mudança de contexto
● No ponto de vista do microcontrolador – No início de uma interrupção, o programa deve
salvar os registradores de interesse.
– No final da interrupção, o programa deve restaurar os registradores de interesse.
● Suporte do compilador AVR-GCC – Ao utilizar o suporte de interrupção do AVR-
GCC, o compilador providencia a manutenção dos registradores.
– ISR(xxx_vect){ …... }
1 Reset 2 External Interrupt Request 0 (pin D2) (INT0_vect) 3 External Interrupt Request 1 (pin D3) (INT1_vect) 4 Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect) 5 Pin Change Interrupt Request 1 (pins A0 to A5) (PCINT1_vect) 6 Pin Change Interrupt Request 2 (pins D0 to D7) (PCINT2_vect) 7 Watchdog Time-out Interrupt (WDT_vect) 8 Timer/Counter2 Compare Match A (TIMER2_COMPA_vect) 9 Timer/Counter2 Compare Match B (TIMER2_COMPB_vect)10 Timer/Counter2 Overflow (TIMER2_OVF_vect)11 Timer/Counter1 Capture Event (TIMER1_CAPT_vect)12 Timer/Counter1 Compare Match A (TIMER1_COMPA_vect)13 Timer/Counter1 Compare Match B (TIMER1_COMPB_vect)14 Timer/Counter1 Overflow (TIMER1_OVF_vect)15 Timer/Counter0 Compare Match A (TIMER0_COMPA_vect)16 Timer/Counter0 Compare Match B (TIMER0_COMPB_vect)17 Timer/Counter0 Overflow (TIMER0_OVF_vect)18 SPI Serial Transfer Complete (SPI_STC_vect)19 USART Rx Complete (USART_RX_vect)20 USART, Data Register Empty (USART_UDRE_vect)21 USART, Tx Complete (USART_TX_vect)22 ADC Conversion Complete (ADC_vect)23 EEPROM Ready (EE_READY_vect)24 Analog Comparator (ANALOG_COMP_vect)25 2-wire Serial Interface (I2C) (TWI_vect)26 Store Program Memory Ready (SPM_READY_vect)
ATmega328InterruptVector
ATmega328InterruptVector
Vantagens e desvantagens
● Orientado a eventos● Manutenção de contexto● Máquina de estado● Tempo de resposta● Longas execuções● Execução da Interrupção x Tarefas do usuário● Etc...
Usando uma interrupção
● Preparação– Configurar pinos
– Configurar interrupção
– Habilitar a interrupção
● Tratador– Função a ser executada na interrupção
INT0 e INT1
● Pinos digitais: D2 e D3
● Configurar como input e, se necessário, o pull-up.
● Pode-se configurar o tipo de transição:
– LOW to trigger the interrupt whenever the pin is low,
– CHANGE to trigger the interrupt whenever the pin changes value
– RISING to trigger when the pin goes from low to high,
– FALLING for when the pin goes from high to low.
INT0 – AVR-GCC
Preparação INT0:
• DDRD = 1<<PD2; // Set PD2 as input (INT0)
• GICR = 1<<INT0; // Enable INT0
• MCUCR = 1<<ISC01 | 1<<ISC00; // Trigger INT0 on rising edge
• sei(); //Enable Global Interrupt
Tratador INT0
● ISR(INT0_vect){ // Tratador Int0
...
}
INT0 – Arduinohttps://www.arduino.cc/en/Reference/AttachInterrupt
Preparação INT0:
• // Set pin 2 as input (INT0) on rising edge
• attachInterrupt(digitalPinToInterrupt(2), myHandler, RISING);
Tratador INT0
● void myHandler(){ // Tratador Int0
}
Comandos especiais
● interrupts (); ou sei (); => Enable interrupts
● noInterrupts (); ou cli(); => Disable interrupts
Cuidados com as otimizações do compilador
● Otimizações durante a compilação pode simplificar o código e até remover trechos aparentemente desnecessários.
● Cuidado especial no contexto da interrupção.
char X;
void myHandler(){ X = PORTB; …. código que não usa o X … PORTB = 20;}
char X;
void myHandler(){ X = PORTB; …. código que não usa o X … PORTB = 20;}
Volatile
● Força a geração do código quando for escrever na variável.
● Muito importante no contexto da interrupção.● Definição interna para PORTB
– (*(volatile uint8_t *)((0x18) + 0x20))
● Como fazer com X?volatile char X;
void myFunction(){ X = PORTB; ….
Pin change interrupt (PCINT)
● Uma única interrupção para um grupos de pinos da mesma porta.
● Qualquer alteração em um pino gera uma interrupção do tipo PCINTx. (CHANGE mode)
● Precisa ler a porta e identificar qual foi o pino (comparar com a última interrupção).
● É possível “mascarar” somente alguns bits da porta.● Não tem suporte de attachInterrupt(). ● Grupos de pinos
– ISR (PCINT0_vect) pin change interrupt for D8 to D13– ISR (PCINT1_vect) pin change interrupt for A0 to A5– ISR (PCINT2_vect) pin change interrupt for D0 to D7
Facilitadorhttp://playground.arduino.cc/Main/PinChangeInterrupt
● Executa a configuração para um pino por vez
void pciSetup(byte pin){ // enable pin *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // clear any outstanding interrupt (Interrupt Flag) PCIFR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group (Interrupt Control) PCICR |= bit (digitalPinToPCICRbit(pin)); }● Usar a mesma rotina para tratar um grupo
– pciSetup(7); e pciSetup(8); => ISR (PCINT0_vect)
– pciSetup(A0); => ISR (PCINT1_vect)
Agendador de tarefas
● Possíveis problemas se a rotina do usuário estiver dentro da chamada da interrupção.
– Longa execução
– Bloqueios
● Como fazer para a rotina do usuário não ficar dentro da chamada da interrupção???
– “Agendador de tarefas” - Task Scheduler
– Fila de execução.
– Comando “post” para incluir tarefa.
Tarefa Interrupção – Parte A
● Refazer a parte das chaves da tarefa 3, event_driven.ino, agora usando interrupções no lugar do loop.
● Para os botões do MultiFunction Shield deve-se usar a interrupção de Pin Change A1..A3 (PCINT1_vect).
Tarefa Interrupção – Parte BTarefa Extra
● Refazer a parte dos temporizadores da tarefa 3, event_driven.ino.
● Utilizar o serviço de timers disponibilizado na aula. TimerService (.h e .c)
● Esse serviço usa interrupções internamente para executar callbacks do usuário.
Tarefa Interrupção – Parte CTarefa Extra
● Alterar o controle de execução da Tarefa 3 (já com o uso de interrupções) para agendar as execuções fora da rotina de interrupção, usar o componente Scheduler.
● Esse componente controla a execução das tarefas (callback) solicitadas de forma a ficarem fora da rotina de interrupção.
Biblioteca TimerServiceIncluir TimerService.h e TimerService.C
● Implementa #MAX_TIMERS timers.● Utiliza um float para programar tempos em
segundos, com precisão de milisegundos.● Permite até 2.147.483,648 segundos => 24,86
dias.● Quando finalizar o tempo, irá executar a função
passada como Callback.● Pode ser cancelado.● Pode ser consultado se está ativo ou não.
Biblioteca TimerServiceDetalhes em TimerService.h
/* Instantiate TimerService */
TimerService();
/* Initialize internal timer must be called in setup() */
void init();
/* Set the timer delay starts immediately * id: Timer id 0 .. (MAX_TIMERS1) * dl: Counter in seconds (float point) precision in milliseconds * cb: Callback function to be called when the timer fired */
boolean set(uint8_t id, float dl, cbTimer cb);
/* Return true if the time is running, otherwise returns false * id: Timer id 0 .. (MAX_TIMERS1) */
boolean isRunning(uint8_t id);
/* Clear the timer counting and the cb function registration. * id: Timer id 0 .. (MAX_TIMERS1) */
void stop(uint8_t id);
Exemplo TimerService
TimerService myTimer; // Cria objeto Timer
void led2(){ // Callback a ser executada digitalWrite(led2Pin, digitalRead(led2Pin)^1);}
void setup() { myTimer.init(); // Inicializa o objeto Timer // Configura o Timer0 com 5seg para execuar led2 myTimer.set(0,5.0,led2); }void loop(){}
Biblioteca SchedulerIncluir Scheduler.h e Scheduler.c
● Implementa uma lista com a quantidade #MAX_SLOTS de slots para tarefas.
● A callback de uma tarefa deve ser inserida num slot específico.
● O loop do scheduler deixa a CPU no modo Sleep até que aconteça uma interrupção de timer ou pinos.
● O loop “varre” a lista a procura de slot ativos e executa uma Callback por vez. A execução da tarefa libera o slot.
● A sequência de execução é a ordem dos slots e não a ordem de inserção.
● Não é possível inserir tarefas em slots ainda ocupados.● Se não existir tarefas pendentes, o loop volta para o
estado Sleep.
Biblioteca SchedulerDetalhes em Scheduler.h
/* Instantiate Scheduler */Scheduler();
/* Post a Task in a specific slot. Return false if exists a task. * slot: Slot id * cb: Callback function */boolean post(uint8_t slot, cbTask cb);
/* Initialize internal slots must be called from setup() */void init(); /* Main schedule loop. Must be called from loop(). * Executes all pending tasks and goes to sleep mode. * The system awake on any interruption. */void loop();
Exemplo Scheduler
Scheduler taskCtl; // Cria objeto Scheduler
void led2(){ // Callback a ser executada digitalWrite(led2Pin, digitalRead(led2Pin)^1);}
void setup(){ taskCtl.init(); // Inicializa objeto Scheduler // Posta a task led2 para execução no slot 0 taskCtl.post(0,led2); }
void loop(){ // Executa as tasks pendentes ou “dorme” até uma interrupção taskCtl.loop(); }