我试图在一个引脚上将与另一个播放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.
}
}
答案 0 :(得分:1)
ISR的代码执行之前有许多延迟。
首先是硬件延迟。这些都记录在数据表中,包括注意和锁存输入更改,完成当前指令,将指令指针压入堆栈以及执行跳转到ISR的时间。
接下来是软件延迟。首先是从中断向量到IST地址的跳转,然后编译器在ISR的开头放置了一系列指令,以确保所有寄存器都已保存并且具有正确的期望值。这就是所谓的“序言”。
https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
关于硬件延迟,您无能为力,但是您可以大大减少软件延迟-尤其是对于像您这样的非常简单的ISR。一种方法是制作一个“裸” ISR,该ISR仅保存您更改的寄存器。对于上面的代码,您可能只需要更改一个寄存器即可。
我认为也可以通过使用写PIN寄存器的技巧来翻转ISR功能,而无需使用任何数据寄存器。
您应该可以通过谷歌搜索找到更多有关这方面的信息,如果您需要针对这些方面的任何特定指导,请在此处报告!
另一种方法-使用内置的硬件反向输出
该芯片上的Timer1具有内置的反相输出,该输出将自动输出您要查找的反相信号,并且反相和同相输出之间的延迟要少于1个周期(假设您没有故意在转换之间添加dead time
。
这将需要对定时器寄存器进行编程以启用反相输出,并且反相输出仅在特定引脚上可用-但这通常不是问题。