2

我试图让一个引脚上的输出与另一个播放 a 的输出相关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.
    }
}
4

1 回答 1

1

在执行 ISR 的代码之前有很多延迟。

首先是硬件延迟。这些都记录在数据表中,包括通知和锁定输入更改、完成当前指令、将指令指针压入堆栈以及执行跳转到 ISR 的时间。 在此处输入图像描述 在此处输入图像描述

接下来是软件延迟。首先是从中断向量跳转到 IST 地址,然后编译器会在 ISR 的开头放置一系列指令,以确保所有寄存器都已保存并具有正确的预期值。这被称为“序言”。

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

对于硬件延迟,您无能为力,但您可以显着减少软件延迟 - 特别是对于像您这样的非常简单的 ISR。一种方法是制作仅保存您更改的寄存器的“裸”ISR。对于上面的代码,您可能只需要更改一个寄存器即可。

我认为通过使用写入 PIN 寄存器的技巧来翻转一点,也可以在不使用任何数据寄存器的情况下执行 ISR 功能。 在此处输入图像描述

您应该可以通过谷歌搜索找到有关这一切的更多信息,或者如果您需要有关这些要点的一些具体指导,请在此处报告!

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

这个芯片上的Timer1有一个内置的反相输出,会自动输出你要找的反相信号,而且反相和同相输出之间会有远小于1个周期的延迟(假设你不是故意dead time在过渡)。

在此处输入图像描述

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

于 2018-09-18T15:42:21.937 回答