On the ATTiny45 data sheets it states that PB5 can be used as a digital IO pin and I want to use it to trigger a pin change interrupt, my only issue is that it is also the reset pin and the moment I connect it to ground to try and trigger an interrupt it resets the ATTiny. Is it possible to use this pin for interrupts and if so how?
Electronic – ATtiny45 pin change interrupt PB5
attinyavrgpioinputinterrupts
Related Solutions
Yes, this is a pretty good application to use interrupts for.
What you are interested in is the external interrupt, but let's break down the general structure of an interrupt first.
If you have enabled a particular interrupt on your system, when that interrupt type occurs, the processor will look up into a table to find the function or service routine to jump to in order to service that particular event.
This function is called an Interrupt Service Routine, or ISR for short. This is a method that you must write.
So let's identify which interrupt you want and which ISR you want to write. To do this, we need to consult the datasheet. The type of interrupt that you're interested in is in the family of interrupts called external interrupts. An excerpt from the ATiny45 datasheet:
9.2 External Interrupts
The External Interrupts are triggered by the INT0 pin or any of the PCINT[5:0] pins. Observe that, if enabled, the interrupts will trigger even if the INT0 or PCINT[5:0] pins are configured as outputs. This feature provides a way of generating a software interrupt. Pin change interrupts PCI will trigger if any enabled PCINT[5:0] pin toggles. The PCMSK Register controls which pins contribute to the pin change interrupts. Pin change interrupts on PCINT[5:0] are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode.
The INT0 interrupts can be triggered by a falling or rising edge or a low level. This is set up as indicated in the specification for the MCU Control Register – MCUCR. When the INT0 interrupt is enabled and is configured as level triggered, the interrupt will trigger as long as the pin is held low. Note that recognition of falling or rising edge interrupts on INT0 requires the presence of an I/O clock, described in “Clock Systems and their Distribution” on page 23.
So they've mentioned some registers of interest here: PCMSK
and MCUCR
PCMSK
controls which pins can trigger the interrupt - so you want to wire up your toggling signal to whichever pin(s) you specify here, and MCUCR
defines how the pins must change in order to trigger the interrupt. In this case, you would probably be interested in configuring your interrupt for Any logical change on INT0 generates an interrupt request.
As outlined in table 9-2 in the document. Continue reading what the registers do in the external interrupt section, they are as follows: MCUCR
, GIMSK
, GIFR
, PCMSK
. The information you want to get out of this is
- How to configure the interrupt (
PCMSK
andMCUCR
) - How to enable or disable the interrupt (
GIMSK
) - How to check its current status (
GIFR
)
Now on to the actual coding. The structure will look something like this (pseudo code):
volatile int i; // volatile because this gets changed in the ISR, so the compiler will know to NOT optimize this when used in loops
int main(void)
{
/* set-up your registers here ... */
/* enable global interrupts */
i = 0;
while (1) {
boundsSafeVectorPrinter(i);
i++;
}
}
ISR(PCINT0_ISR)
{
i = 0;
}
Now whenever a pin change occurs on one of the pins you specified (given that you've set-up all the registers correctly), the ISR(PCINT0_ISR)
routine will be executed.
So how did I know to use ISR(PCINT0_ISR)
? You will need to lookup in whatever definitions file that you are using to see if they have provided the PCINT0_ISR
mapping for you, if not, consult the datasheet again and look at section
9.1 Interrupt Vectors in ATtiny25/45/8
and define it yourself. If you are using avr-gcc, the ISR()
macro is defined here.
I think this covers the basics without giving away too much code. Good luck and have fun!
Pin change interrupts are usually not a good way to detect button actions. This is because mechanical buttons bounce, and you will get lots of meaningless interrupts, and then you still have to do debouncing anyway.
A better way is to have a periodic interrupt, like every 1 ms (1 kHz rate). That's a long time on most processors, so the fraction of time spent in the interrupt will be small. Simply sample the button state every interrupt. Declare a new button state if you have seen the new state 50 ms in a row. 50 ms is longer than most buttons bounce, but is still short enough so that humans won't notice or care about the lag.
Note that this way you can also handle multiple buttons in the same periodic 1 ms interrupt. All you need is one counter for each button.
More on debounce time:
Occasionally, as in this case, someone says 50 ms is too long a debounce time. This is not true for ordinary buttons pressed by humans. It might be a issue perhaps in very timing-critical applications like a stopwatch, but so far I haven't run into one. I did test on this in the early 1980s, and lots of other people have too.
It is true that typical pushbutton bounce time is around 10 ms, with just about all settling by 25 ms. The limiting factor on debounce time is human perception. 50 ms is a bit shorter than where people start to notice a delay when they aren't looking for it. Even then, it takes a much longer time for it to be annoying. It can be possible in some cases for a human to detect a difference between 50 ms and 0 ms delay if they are specifically looking for it, but that is quite different from pushing a button and seeing something happen and not thinking about the delay.
50 ms is therefore a good debounce time because the delay is below the perception limit in ordinary applications, way below the annoyance limit, and well above the bounce time of most switches. I have found switches that did bounce for nearly that long, so you might as well push to the perception limit since there is nothing to loose.
I have done many products with firmware-debounced buttons using 50 ms debounce time. Not once did a customer mention even noticing a delay. They all accepted the buttons as working fine without issue.
Best Answer
Until I checked the ATtiny45 datasheet today I was convinced that you can't program the AVR after programming RSTDSBL in Fuse High Byte. But then I stumbled over this note under Table 6-7 Start-up Times for Internal Calibrated RC Oscillator Clock"
Now it doesn't mention what programming mode is refered to, either High Voltage or SPI. So if your programmer supports it, you may be able to enter the programming mode within 4ms after power up, instead of using the "\$\overline{\text{RESET}}\$-line protocol" (don't know the proper name for it). You should even be able to verify this without programming the RSTDISBL fuse, and just by programming Start Up Times (SUT[1:0] in Fuse Low Byte) for the internal RC osscillator.
Chapter 20 on page 147 and onwards explains various modes for programming of the devices, but fails to mention the RSTDISBL fuse. Seems you need trial-and-error to be 100% sure ...
I personally use Arduino to ISP program AVR's and I suppose one should be able to hack the ArduinoISP sketch to power up the AVR and start the programming handshake within 4ms after that. But I never tried it myself.
Of course you could reset the fuses for your controller using a high voltage programmer like the AVR Dragon. (Dragon apparently isn't able to power cycle the target device, so Dragon won't support programming without utilizing the \$\overline{\text{RESET}}\$-line). On the other hand, Dragon does support HV programming, which solves your problem either way.
Or you could improvise an HV-programmer to reset the default fuses.