Adding Interrupts

This is my first post and I was not sure if this was more of a programming question or hardware question but anyway here it goes:

I have an arduino pro mini that I am using with a standard 2.4 Ghz RC transmitter and receiver. At the current time, I am using both interrupt pins to read signals coming from the transmitter via the receiver (1 pin for elevator and 1 pin for aileron). Everything is working fine, however, in my code I have a portion that allows my ornithopter to operate autonomously but I can't figure out how to switch from manual mode to autonomous mode. Essentially I need another interrupt pin that I can connect to the receiver so that I can use another channel on my transmitter to switch from manual mode to auto mode. I know that there are only two interrupt pins and thus I am stuck because I don't know of another way to read the signal coming out of the receiver. I want to be able to use one of the sticks on my transmitter to basically signal to the arduino to switch from part of the code to another part of the code. If I was a better computer programmer I might realize that there is an easy way to do this without need an extra pin, but at the current time I am stuck. I hope this question was somewhat understandable and if it was not, I will gladly clarify any part of it.

Thank you

I am not an expert but I am sure that the Atmel chip can generate interrupts on every port. See the data sheet or an internet search would give you an example.

I believe that you may be correct, however, only pins 2 and 3 are "External Interrupts". Which means that I believe only these pins can be configured to trigger an interrupt on a low value, a rising or falling edge, or a change in value. Thus, I am still in need of more assistance on how to do what I described in my original question. Thanks though.

Pin Change Interrupts can be fired on every pin (port, technically), though they only trigger on chang.e

http://www.arduino.cc/playground/Main/PcInt

Seems like this would be useful for you.

Thank you very much Aeturnalus, I looked at the link that you posted and it does appear that it would help me, however since I am still relatively new to arduino code, maybe you could help me a bit more. So lets say that I solder a wire coming from my receiver to a pin on the pro mini (it seems like the code in this link allows both analog and digital pins to support interrupts), so lets say pin 9 which is a digital pin. The signal coming from the receiver is about 1000ms at low, 1500ms at neutral and 2000ms at high. Thus, where in the code that you linked to would I specify pin 9? Or do I simply have to insert this code that has this interrupt "logic" into my own code (I assume before my interrupt routine) and then somewhere (I assume in my interrupt routine) in my code add something about pin 9? Thanks again.

It changes state for over a second? Why not just test the pin with digitalRead every time through loop? You don't have to use interrupts everywhere.

I am very sorry Nick, I meant µs not ms. I always get confused between microseconds and milliseconds.

You can use PCIs, as you only want one mask off all the other pins on the selected port so only one produces an interrupt. Then create an ISR to handle it.


Rob

Hey Rob, as I mentioned, I am quite new to this so I'm a bit confused by what you said. If it would be helpful I can somehow upload the code that I have and maybe someone could help show me where I can insert the code at http://www.arduino.cc/playground/Main/PcInt into my code or some portion of that code into my code.

The code on that link is generic for all pins, way more than you need.

Pin 9 is PORTC pin 1 (second pin) which == PCINT9 (Look at the pinout for the chip in the data sheet and the Duemilanove schematic)

PCINT9 is in the second group of PCIs so you need to enable that in the PCICR reg

PCICR = (1 << PCIE1); // sets the enable flag in the PCICR control register (para 12.2.4 in the data sheet)

This will allow PCIs 8 thru 15 (all the pins on PORTC) but we only want one of them so we need to mask out all the others

PCMSK1 = (1 << PCINT9); (para 12.2.7 in the data sheet)

Actually it’s the other way around, they are all masked by default, we are enabling PCINT9 by writing a 1 into bit 1 of the PCMSK1 reg.

So now the PCI int should be enabled for pin 9. We just need a handler for it.

ISR (PCINT1_vect) {
// your code here
}

To put all that together

void setup() {
  PCICR = (1 << PCIE1); 
  PCMSK1 = (1 << PCINT9);

}

ISR(PCINT1_vect) {
  // your interrupt code here
}

void loop() {

}

Now that’s just from reading the data sheet, I haven’t done it myself.

Hopefully I got all that right, but don’t put money on it :slight_smile:


Rob

Ok so here is my interrupt code:

////////// Start of Interrupt Routines
////////// attach servo signal interrupts to catch signals as they go HIGH then again as they go LOW, then calculate the pulse length.

void rc1_begin() {           // enter function rc1_begin when interrupt pin goes HIGH.
  channel1_startPulse = micros();     // micros() gives the value of the internal clock in microseconds. Store internal clock value as channel1_startPulse
  detachInterrupt(0);  // after recording the value, detach the interrupt from rc1_begin
  attachInterrupt(0, rc1_end, FALLING); // re-attach the interrupt to function rc1_end. This function will be used when the pulse ends (drops in voltage)
}

void rc1_end() {
 channel1_val = micros() - channel1_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue.
 detachInterrupt(0);  // detaches interrupt from this function
 attachInterrupt(0, rc1_begin, RISING);//attaches interrupt to function rc1_begin where it will look for the pulse to go high again
}

//rc2_begin and rc2_end identical to fuctions above. 
void rc2_begin() {
  channel2_startPulse = micros();
  detachInterrupt(1);
  attachInterrupt(1, rc2_end, FALLING);
}

void rc2_end() {
 channel2_val = micros() - channel2_startPulse;
 detachInterrupt(1);
 attachInterrupt(1, rc2_begin, RISING); 
}
/////// End of Interrupt Routines

Now, are you saying I should put my code (above) into your code (below)? Another thing I am confused about is what should I put in my code where it says detachInterrupt()?

void setup() {
  PCICR = (1 << PCIE1); 
  PCMSK1 = (1 << PCINT9);

}

ISR(PCINT1_vect) {
  // your interrupt code here
}

void loop() {

}

Thank you so much, I must zzzz here in USA because it is late but I will attempt this tomorrow and I am sure have more questions.

I'm not sure what you're doing with detachInterrupt there--it's not doing anything useful in particular, that I can see.

Interrupts fire as long as the condition is met, until interrupts are disabled--you don't need to re-attach it every time.

I would forget about all that code until you get the interrupts working. Just try something very simple

void setup() {
	PCICR = (1 << PCIE1); 
	PCMSK1 = (1 << PCINT9);
	Serial.begin (115200);
	
}

ISR(PCINT1_vect) {
  Serial.println ("Yep");
}

void loop() {

}

Get a wire, stick one end into pin 9 and poke the other into GND and/or 5v, see if the interrupt fires. (you may also need a resistor to GND or 5v, but probably not)

Until that works nothing else matters.


Rob

I haven’t ever played with pin change interrupts, but I have a couple of suggestions. First, how quickly do you go through the main loop? Would it be possible to detect this extra pin change with a digitalRead?

Failing that, you could look at a “wired or” configuration for your controls (aileron/elevator). I did some work on making that work here:

http://gammon.com.au/forum/?id=11091

Another approach again would be to wire up the manual/auto input through a 555 timer to “latch” it (set it up in one-shot mode), so that you could detect the change next time you were able to check it (if 1 mS was too fast to pick it up with a digitalRead). Then reset the 555 ready for the next change.