Arduino / Attiny85:ISR和端口操纵的延迟

时间:2018-09-18 08:14:11

标签: arduino interrupt avr isr attiny

我试图在一个引脚上将与另一个播放tone()的输出相关的输出反相,但是有35us @ 8MHz或158us @ 1MHz时钟延迟。似乎有固定的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 :(得分:1)

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寄存器的技巧来翻转ISR功能,而无需使用任何数据寄存器。 enter image description here

您应该可以通过谷歌搜索找到更多有关这方面的信息,如果您需要针对这些方面的任何特定指导,请在此处报告!

另一种方法-使用内置的硬件反向输出

该芯片上的Timer1具有内置的反相输出,该输出将自动输出您要查找的反相信号,并且反相和同相输出之间的延迟要少于1个周期(假设您没有故意在转换之间添加dead time

enter image description here

这将需要对定时器寄存器进行编程以启用反相输出,并且反相输出仅在特定引脚上可用-但这通常不是问题。