[英]Best way to handle multiple PCINT in AVR
I'm testing some things on a Attiny85 and thought about the best way to handle the interrupt rutine.我正在 Attiny85 上测试一些东西,并考虑了处理中断规则的最佳方法。 I know it is bad to have a lot of code in the interrupt handler, but I'm uncertain of any other ways to do this.我知道在中断处理程序中有很多代码是不好的,但我不确定是否有任何其他方法可以做到这一点。 I want my main program to sleep and wake on PCINT, the PCINT comes from multiple pins (rotary encoder A, b & switch and a receiving UART) so I was thinking just having a lot of code in the handler.我希望我的主程序在 PCINT 上休眠和唤醒,PCINT 来自多个引脚(旋转编码器 A、b 和开关和接收 UART),所以我想在处理程序中有很多代码。
The code to determining which pin caused the interrupt, would look like this确定哪个引脚导致中断的代码如下所示
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}
And then ofc inside each of the if-statements in the interrupt handler, there would be code handling something, like this code, turning on the Timer0然后在中断处理程序中的每个 if 语句中使用 ofc,将有代码处理一些东西,比如这段代码,打开 Timer0
TCNT0 = 0; // Set counter to 0
OCR0A = SERIAL_BIT_TIME; // Call timer interrupt in middle of first bit
position = 0; // Reset position and data
TIMSK |= 1 << OCIE0A; // Enable interrupt for compare register A (timer interrupt)
TIFR |= 1 << OCF0A; // Clear timer interrupt flag to prevent it jumping directly there
PCMSK &= ~(1 << SERIAL_RECEIVE); // Disable pin change interrupt
or with the switch input, the code inside the if-statement would be或者使用 switch 输入,if 语句中的代码将是
if (lightState)
{
dali.transmit(ADDRESS, OFF);
lightState = 0;
}
else
{
dali.transmit(ADDRESS, ON);
lightState = 1;
}
Would this be a dumb solution?这会是一个愚蠢的解决方案吗?
volatile uint8_t flag;
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
gotosleep();
do
{
switch(flag)
{
case 1:
dosomething1();
break;
case 2:
dosomething2();
break;
case 3:
dosomething3();
break;
}
cli();
flag = 0;
sei();
}while(flag);
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
flag = 1;
}
if(changedbits & (1 << PB1))
{
flag = 2;
}
if(changedbits & (1 << PB2))
{
flag = 3;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.