Arduino / Attiny85: Задержка в ISR и манипуляции с портом - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь иметь на выводе инвертированный выход, связанный с другим выходом, воспроизводящим tone(), но есть задержка в 35 мкс при 8 МГц или 158 мкс при 1 МГц.Кажется, есть фиксированная задержка тактового цикла 16us +142, потому что задержка не обратно пропорциональна тактовой частоте.Они очень и очень длинные!Почему?

Это код:

/* Per ATTINY85:
1: I/O5 PB5 A0 RS 
2: I/O3 PB3 A3          - Geiger inverted earphone out
3: I/O4 PB4 A2          - Geiger earphone out
4: GND
5: I/O0 PB0    MOSI SDA - Battery test/Geiger LED out
6: I/O1 PB1    MISO     
7: I/O2 PB2 A1 SCLK SCL INT0 - Geiger probe in (via NPN transistor)
8: Vcc
*/

#include<avr/sleep.h>

byte state;
volatile byte P;
int B;
int Bo;
byte LED=0;
unsigned long t=0;

void particella() 
{
    P=1;
}

ISR(PCINT0_vect)
{
    if (!(PINB & (1<<PB4)))
        PORTB |= (1<<PB3);
    else 
        PORTB &= ~(1<<PB3);
}

void setup()
{
    pinMode(0, OUTPUT); // Al LED.
    pinMode(2, INPUT); // Dal transistor dal tubo Geiger.
    pinMode(2, INPUT_PULLUP); // Pull-up per il collettore del transistor.
    pinMode(4, OUTPUT); // All'auricolare.
    pinMode(3, OUTPUT); // All'auricolare (copia invertita del 4).

    GIMSK = 0x60;    // turns on external and pin change interrupts.
    PCMSK = 0x10;    // turn on interrupts on pin PB4.
    sei();           // set interrupts (enable).

    tone(4,2000,100); // Power on beep
    PORTB|=0b00000001;
    delay(700);
    PORTB&=0b11111110;
    delay(1000);
    readVcc();

    for(byte n=1; n<=state; n++)
    {
        PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
        tone(4,2000,25); // Bip acuto a ogni lampo.
        delay(30);
        PORTB&=0b11111110; //  Spegne il LED su I/O0 = PB0
        delay(250);
    }
    delay(350);

    attachInterrupt(0, particella, FALLING);
}


void loop()
{
    if(P)
    {
        P=0;
        t=millis();
        PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
        LED=1;
        tone(4,1000,5); // Fa TIC nell'auricolare.
    }

    if(millis()-t>=10 && LED==1) 
    {
        LED=0; PORTB&=0b11111110; //  I/O0 = PB0 LED OFF after 10ms.
    }
}

1 Ответ

0 голосов
/ 18 сентября 2018

Есть много задержек перед выполнением кода ISR.

Во-первых, аппаратные задержки. Они задокументированы в таблицах данных и включают время, чтобы заметить и зафиксировать, что входные данные изменились, завершить текущую инструкцию, поместить указатель инструкции в стек и выполнить переход к ISR. enter image description here enter image description here

Далее идут задержки программного обеспечения. Сначала происходит переход от вектора прерывания к адресу IST, затем компилятор помещает серию инструкций в начало ISR, чтобы убедиться, что все регистры сохранены и также имеют правильные ожидаемые значения. Это называется «преамбулой».

https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

Вы не можете ничего сделать с аппаратной задержкой, но вы можете значительно уменьшить программную задержку - особенно для очень простого ISR, подобного вашему. Один из способов - создать «голый» ISR, который будет сохранять только те регистры, которые вы меняете. Для приведенного выше кода вы, вероятно, могли бы получить только изменение одного регистра.

Я думаю, что также возможно выполнить функцию ISR без использования каких-либо регистров данных, используя хитрость записи в регистр PIN, чтобы немного перевернуть. enter image description here

Вы сможете найти более подробную информацию обо всем этом, прибегая к помощи Google, или сообщите здесь, если вам нужно какое-то конкретное руководство по любому из этих пунктов!

Альтернативный подход - использовать встроенный аппаратный инвертированный выход

Timer1 на этом чипе имеет встроенный инвертирующий выход, который будет автоматически выводить инвертированный сигнал, который вы ищете, и между инвертированным и неинвертированным выходами будет намного меньше, чем задержка в 1 цикл (при условии, что вы этого не сделаете) намеренно добавить dead time между переходами).

enter image description here

Это потребует программирования регистров таймера для включения инвертированного выхода, а инвертированные выходы доступны только на определенных выводах, но обычно это не проблема.

...