Como crio uma interrupção do timer com o Arduino?

9

Estou tentando criar um atraso de tempo com o Arduino. Eu gostaria de usar a função interrupts (), porque é uma interrupção interna.

Exemplo: digamos, eu gostaria de acender e apagar uma luz, apenas com o tempo da interrupção.

Há um código de amostra, mas ele usa interrupções externas (attachInterrupt ()). Eu gostaria de continuar usando as interrupções internas.

Aleatório
fonte
2
Eu acho que o ponto que também Kortuk mostrou é que attachInterrupt é uma coisa abstrata, você não está anexando qualquer componente externo :)
clabacchio
Este artigo pode ajudá-lo. engblaze.com/…
Seth Archer Brown

Respostas:

10

O blog de Noah Stahl tem um exemplo de piscar de um LED com o Timer2 . Com isso e a planilha de dados, você poderá adaptá-lo à interrupção que desejar usar - ou seja, a interrupção cuja função normal você mais pode desistir ou deseja modificar. Timer2 é geralmente usado para algumas funções PWM.

Seu exemplo cita o ATmega2560; Posso confirmar que ele funciona com um ATmega328p também. Veja em seu site exemplos mais úteis de interrupção do Arduino.

Editar:

Aqui está minha versão levemente editada - principalmente nos comentários - do código de Noé. Chame Timer2init () da função setup do Arduino () depois de inicializar qualquer estrutura de dados ou hardware relacionado, porque o tempo - e a interrupção - começarão assim que você o fizer.

F / ex, usei-o para multiplexar uma tela de 3 dígitos e 7 segmentos, então, antes de inicializar o timer, inicializei os registros de E / S da tela e apaguei os dados da tela no local em que o ISR a procuraria.

Há uma tabela nos comentários de alguns dados úteis de tempo da folha de dados e meus próprios cálculos de referência para configurar outro esquema de tempo.

A macro ISR () cuida da criação de código de entrada e saída de interrupção para um ISR, em vez da entrada e saída de uma função normal, e de vinculá-lo ao vetor de interrupção apropriado. O restante dessa função é 1) o código a ser executado a cada interrupção e 2) o código de código para redefinir o timer para a próxima interrupção.

Conforme escrito, isso deve aparecer em um esboço .pde ou .ino (ou em um arquivo .cpp, se você usar eclipse, f / ex). O esboço precisa # definir LEDPIN, e setup () precisa chamar Timer2init (). A função loop pode estar vazia ou não; o LED deve começar a piscar no download (bem, literalmente, depois que Timer2init () for chamado).

/*
 * From sample interrupt code published by Noah Stahl on his blog, at:
 * http://arduinomega.blogspot.com/p/arduino-code.html
 * 
 */


/*** FUNC

Name:           Timer2init

Function:       Init timer 2 to interrupt periodically. Call this from 
                the Arduino setup() function.

Description:    The pre-scaler and the timer count divide the timer-counter
                clock frequency to give a timer overflow interrupt rate:

                Interrupt rate =  16MHz / (prescaler * (255 - TCNT2))

        TCCR2B[b2:0]   Prescaler    Freq [KHz], Period [usec] after prescale
          0x0            (TC stopped)     0         0
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000


Parameters: void

Returns:    void

FUNC ***/

void Timer2init() {

    // Setup Timer2 overflow to fire every 8ms (125Hz)
    //   period [sec] = (1 / f_clock [sec]) * prescale * (255-count)
    //                  (1/16000000)  * 1024 * (255-130) = .008 sec


    TCCR2B = 0x00;        // Disable Timer2 while we set it up

    TCNT2  = 130;         // Reset Timer Count  (255-130) = execute ev 125-th T/C clock
    TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
    TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
    TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
    TCCR2B = 0x07;        // Timer2 Control Reg B: Timer Prescaler set to 1024
}



/*** FUNC

Name:       Timer2 ISR

Function:   Handles the Timer2-overflow interrupt

Description:    Maintains the 7-segment display

Parameters: void

Returns:    void

FUNC ***/

ISR(TIMER2_OVF_vect) {
    static unsigned int led_state = 0; // LED state

    led_state = !led_state;         // toggles the LED state
    digitalWrite(TOGGLE_PIN, led_state);

    TCNT2 = 130;     // reset timer ct to 130 out of 255
    TIFR2 = 0x00;    // timer2 int flag reg: clear timer overflow flag
};
JRobert
fonte
(@Kortuk: O comentário a que você se refere foi minha observação de vários comentaristas aqui e não foi direcionado a você pessoalmente e foi desnecessário. Peço desculpas e removi-o.) Eu ampliei minha resposta conforme sugerido e espero que seja agora não apenas demonstrativo, mas instrutivo também. Ele inclui comentários que escrevi no código para meu próprio uso (ou seja: se eu puder entendê-los daqui a seis meses, alguém também poderá), além de algumas instruções "como usar" no responda. Obrigado por suas sugestões.
JRobert
Observe que pré-escalas de 32 e 128 não estão disponíveis para timer0 e timer1 (pelo menos com atmega328).
tuupola
É bom saber - obrigado. Eu uso isso para Timer2 (até agora) e é basicamente um drop-in.
JRobert
5

A função attachInterrupt () na verdade está anexando uma interrupção a uma alteração de estado externa em um pino, não possui outras opções.

Na mesma página, as opções de modo estão listadas como:

O modo define quando a interrupção deve ser acionada. Quatro constantes são predefinidos como valores válidos:

  • LOW para acionar a interrupção sempre que o pino estiver baixo,
  • CHANGE para acionar a interrupção sempre que o pino mudar de valor
  • ELEVANDO para disparar quando o pino passa de baixo para alto,
  • CAINDO quando o pino passa de alto a baixo.

Desculpe ser o portador de más notícias, essa é uma das primeiras coisas que procurei também.

Kortuk
fonte
Eu acho que ele quer dizer que ele quer usar um timer interno, em vez de um dispositivo externo ... mas eu não sei Arduino muito bem, então eu não posso dizer se é possível
clabacchio
@clabacchio, estou dizendo que a única opção é usar um gatilho externo, não há função de timer interno.
21412 Kortuk
Ah, que bom :) mas pelo menos as placas do Arduino possuem temporizadores?
clabacchio
Sim, é assim que eles realizam coisas como atraso.
Kortuk
11
@ icarus74 O ATMega328 realmente tem 3 temporizadores (um é 16b e dois são 8b), mas todos são usados ​​pelo Arduino. Um é usado para funções como delay () e millis () e os três são usados ​​para PWM (você pode encontrar mais informações na função 'init ()', arquivo 'cablagem.c' no Arduino IDE).
92812 vasco
2

Este artigo sobre PWM esclarecerá muitas dúvidas sobre o uso de temporizadores do Arduino. Existem dois temporizadores de 8 bits e um temporizador de 16 bits no Arduino. Não existe uma API de alto nível para conectar a função ISR diretamente aos timers, que é fornecida com o Arduino SDK (ou seja, como uma biblioteca padrão), mas um método de nível um pouco inferior para definir Registros de Função Especial e bit-aritmética / operações sobre eles. No entanto, existe uma biblioteca contribuída pelo usuário chamada Timer one .

icarus74
fonte
Na verdade, existem várias combinações de cronômetros diferentes possíveis, dependendo de qual Arduino está sendo referido. A resposta é enganosa.
Aparentemente So
@SeeminglySo, gostaria de elaborar? Se você está falando sobre o hardware do Arduino, observe que a resposta está no contexto da pergunta e também no momento em que a pergunta é feita.
precisa saber é o seguinte
O Arduino Mega (baseado no ATmega1280) foi lançado em 26 de março de 2009 e o Mega 2560 (ATmega2560) foi lançado em 24 de setembro de 2010, ambos muito antes de essa pergunta ser feita. Ambos os microcontroladores têm mais do que o temporizador / contador 2x 8 bits e 1x 16 bits especificado na resposta.
Aparentemente So
A maioria das interações que eu já vi até agora tem uma referência inequívoca ao Arduino, como Duemilanove ou Uno, ou seja, as placas baseadas na série 328. Outras placas sempre foram explicitamente qualificadas pela série uP no. ou Mega, Nano, Micro etc. De qualquer forma, aceitarei humildemente a correção. Nesse contexto, um esclarecimento é melhor.
precisa saber é o seguinte
1

O Arduino está usando todos os três temporizadores no ATMega328. Timer1(16 bits) é usado para funções como delay()e millis()e para a saída de PWM nos pinos 5 e 6. Os outros dois temporizadores - Timer0e Timer2são utilizados para a saída de PWM sobre os pinos 3, 9, 10, 11.

Portanto, não há função do Arduino para interrupção do timer. Mas, existe um jeito. Você pode usar este código para ativar a interrupção do timer em Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

void setup() {
  // Enable Timer2 interrupt.
  TIMSK2 = (0<<OCIE2A) | (1<<TOIE2);
}

void loop() {
  // Your main loop.
}

Eu escrevi esse código sem testar, por isso é possível que tenha cometido um erro. Nesse caso, verifique a folha de dados, p.156 .

Se você deseja alterar a frequência do temporizador (pré-calibrador), basta alterar o registro TCCR2A. Para obter mais informações, consulte a página 153 da folha de dados. Mas se você alterar a frequência do temporizador, também altera a frequência do sinal PWM nos dois pinos de saída!

vasco
fonte
AFAIK no ATmega328 Timer0e Timer2são 8 bits e somente Timer116 bits.
tuupola
Não, isso não está correto. É o Timer0, não o Timer1, usado para delay () e millis () e para a saída PWM nos pinos 5 e 6. O Timer0 é um timer de 8 bits. Veja, por exemplo, Temporizadores e interrupções do Arduino .
Peter Mortensen