Interrupt working and Not Working.

Hi guys;

I finish breadboard my "telephone call counter" project. I use two interrupts. One intererupt for counting a phone ring and the other interrupt to "clear" the counter. The project work fine, I use a 7805 for power, an ATmega - Arduino breadboard version, wired it up properly, use an opto-coupler to receive the "rings", use an another Atmega - Arduino breadboard version to simulated a phone call power by a 4.5 V ( 3 X 1.5 V AA battery ), I use a 555 circuit extender to extend the time when it keep on ringing, ( telephone ring 2 second and 4 second no ring, and repeat ) and a reset circuit.

Every things work ok until it hit 37 ( the program use a multiplex mode ). and try to "ring" and wait, no change in number, than I press the clear button, NO CHANGE... What the....????? I keep pressing the clear button , still no change. OK I said, let re-power and reset, use a logic probe to monitor the counting pulse, and to tested, I wait until the state go from LOW to HIGH and to LOW, and " ringing" and repeat, it work until I check the "over" LED ( over 99 ) and it work, and the "clear" work to.

My question is : Why the interrupt ( both of them ) did not work ? And How reliable the ATmega is ?

In my opinion... reliability is about 50 to 80 %...

I will show my schematics and the code later if you guys requested... My project work but at 50 % to 80% reliability because of the interrupts.

And How reliable the ATmega is ?

In my opinion... reliability is about 50 to 80 %...

ATmega about 100% reliable, maybe more. Your code and wiring, unknown reliablity.

Yes, post your code and wiring for help.

Lefty

Ok here the code for the Call counter and the code for the telephone ring simulator.

If my code need to be improve.. well I am open minded...

As for a schematic... give me time, I will do it and share it.. but I don't what format ? eagle, expresspcb... ??

Call Counter code

/*
  size = 1656 bytes

*/

byte ledout[4]={12,11,10,9};
byte digitout[2]={8,7};
byte overnumber=6;

byte i;
byte count2; 

volatile byte count;

void setup()
{
  for (i=0; i<4; i++)
  {
    pinMode(ledout[i], OUTPUT);
  }
  pinMode(digitout[0],OUTPUT);
  pinMode(digitout[1],OUTPUT);
  pinMode(overnumber,OUTPUT);  
  attachInterrupt(0,resetcallnumber,RISING);
  attachInterrupt(1,countthecall, RISING);
  delay(3000);
  count=0;
  digitalWrite(overnumber, LOW);
}  

void loop()
{
  count2=count;
  if (count2<=99)
   {
    displaythecall();
   }
  else
  {
    count=99;
    count2=99;
    digitalWrite(overnumber, HIGH);
    displaythecall();
  }  
}

void displaythecall()
{
  for (i = 0; i < 4; i++)
  {
   digitalWrite (ledout[i], bitRead((count2 % 10),i));
  }
  digitalWrite (digitout[0], LOW);
  digitalWrite (digitout[1], HIGH);
  delay(5);    
  for (i = 0; i < 4; i++)
  {
   digitalWrite (ledout[i], bitRead((count2 / 10),i));
  }
  digitalWrite (digitout[0], HIGH); 
  digitalWrite (digitout[1], LOW);
  delay(5);         
}  

void resetcallnumber()
{
  delay(300);
  count=0;
  digitalWrite(overnumber, LOW);
  return;
} 

void countthecall()
{
 delay(100); 
 count++;
 return; 
}

Telephone Ring simulator

/*
Size = 1258

This program simulate a telephone ring. It connect Digital pin 13
to an opto-coupler ( LED side ) and use Digital pin 12 as an On-Hook 
OFF-Hook. 

Part list :

4N35 Optocoupler or different type
470 ohms resistor ( between pin 13 and the anode LED side of the opto-coupler )
10 K resistor Part of the switch circuit
1 push-on switch or any ON-OFF switch connect to pin 12

Bear in mind to connect the cathode of the LED to the Arduino GND 
Not the other side ( transistor side ) of the optocoupler.

Program by Serge J Desjardins, Toronto, Ontario, Canada 

*/

boolean data = 0; // Init data value to zero

void setup()
// seting up Digital pin 13 OUT and Digital pin  12 IN

{
  pinMode (11, OUTPUT);
  pinMode (12, INPUT);
}

void loop()
{
  data= digitalRead(12);  // Check the switch ON = 1 or OFF = 0
  delay (50); // debounce the switch
  if (data == HIGH ) // the ON-Hook mode
  {
    pulsing ();  // The ringing subroutine
    delay (4000); // the 4 second delay
  }
 else
  {
    digitalWrite (11, LOW); // the OFF-Hook mode
    delay (2000);
  }  
} 

void pulsing()
/*
  The ringing subroutine simulate a 20 Hz signal ( 0.05 second )
 so 0.025 on-time and 0.025 off-time for a duration of 2 second 
 ( is delay (2000) therefor 2000 divide by 50 equal 40 )  
*/

{
 for ( int count=0; count <=40; count++)
  { 
   digitalWrite (11,HIGH);
   delay (25);
   digitalWrite (11, LOW);
   delay (25);
  }
 
}

As for a schematic... give me time, I will do it and share it.. but I don't what format ? eagle, expresspcb... ??

Some just hand draw a neat schematic on paper and take a picture of it.

you can't do any timer functions (i.e. delay) within an interrupt. You should make an interrupt as small as possible, as it interrupts everything else!

void resetcallnumber()
{
  delay(300);
  count=0;
  digitalWrite(overnumber, LOW);
  return;
} 

void countthecall()
{
 delay(100); 
 count++;
 return; 
}

You can't do that. Instead I suggest you do something along the lines of

void resetcallnumber()
{
   count=0; 
} 

void countthecall()
{
 countFlag= true;
} 
in loop()

if (count == 0){
delay(300);
digitalWrite(overnumber, LOW);
}

if (countFlag){
 delay(100); 
 count++;
}

That should work.

@aayotee

Thank for your tip. I will try it. In my program, maybe.. I do agree you have to keep interrupt routine short.

My quick question about Interrupt is : When an interrupt occure, the routine is done and going back, The "Going Back" is my question. "going back" to where in the main program... ??? At begining.. in the middle .. at the end ... or going back anywhere in the main program when the interrupt occure... ??? Anybody has an answer... And how you program an interrupt routine if I want to go at the begining of the function loop(). Which I want in my program.

Still no answer of why the interrupt(s) did not response... I guess is one of those "computer lock-up"...

or going back anywhere in the main program when the interrupt occure... ???

Yes, it returns back to exactly where it was when the interrupt occured.

Lefty

@ retrolefty

Thank for your answer, so how it return to the begining of main loop.. what about the use of return ?

ex:

void myinterrupt ()
{

// do things

}

or 

void my interrupt ()
{

// do things too

return;
}

Any difference ?

No difference, function returns when last statement is performed.

There is no easy method to force a return to the start of your loop() function. Interrupt routine MUST always return to where the interrupt was initated from.

Lefty

So... It WILL return to the spot where in the loop() where the interrupt occure...Mmm.. I need a GOTO statement... this is BASIC not C, so in C no GOTO statement...? ...Bummer .. :stuck_out_tongue:

Yes, C has a goto statment, and it is almost always the wrong way to do something. I suspect the struture of your main loop function is what you need to think about. Possibly you should not be using interrupts at all?

Lefty

Yes, C has a goto statment, and it is almost always the wrong way to do something. I suspect the struture of your main loop function is what you need to think about. Possibly you should not be using interrupts at all?

I begin to agree with you retrolefty, I need to "redesign" the software so in event of an "non responsive" interrupt input - a "lock-up" ... Yep , it back to the "software board" , my circuit, not much change, ( and of course the "decoupling cap"), so it look like in the software side I may be using "polling" techniques... Interrupts make so easy... Bummer again ..

Techone:
Still no answer of why the interrupt(s) did not response... I guess is one of those "computer lock-up"...

the reason your interrupts did not work correctly was because you included timer operations (the delay() function) within the interrupt. I don't think you will need to switch to polling, interrupts will handle what you need.

As for the return statement you included, this isn't necessary for an interrupt function as by definition they don't return anything.

the reason your interrupts did not work correctly was because you included timer operations (the delay() function) within the interrupt. I don't think you will need to switch to polling, interrupts will handle what you need.

Mmm.. sorry to disagree with you... if it was the case, my program will NOT work at all... But it work... 80 %... Therefore a delay() in an interrupt is OK. The delay() in my interrupt is the "debounce" for the push button - "Clear to Zero" or "Soft Reset" When I did turn off my circuit and hock-up a logic probe to the output of the pulse extender ( 555 circuit - pin 3 ) - When LOW, "ring" a HIGH, wait for LOW and "ring"..... My program work until 99 is reach and the "orange" led "over count" is light up...I "soft reset" it and it work ( counter is 00 and the orange LED is off ). The multiplex section work fine also. But when I first test it, ( no monitor ) well it "stuck" at 37... Can't "soft reset" and Can't "count up"... Therefore Interrupt Line Not responding to a HIGH or LOW signal to them ...

Sorry to disagree with you... My opinion. Bear in mind that an "intermittin" problem is harder to find and harder to replicated.
And it is not a PSU problem... I monitor the current for this project... is about 75 mA to 120 mA. I know, it is "Swiging" fluctuated. Maybe of the 7 segment LED multiplexing .

It's not a matter of opinion. From the Arduino reference on using interrupts:

Note
Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

Opps... Me bad... I guess I "mis" read that part... Mmm..NO delay() and no milli()... OK got ya !

That is the cause of the Interrupt Lock-up ? maybe...maybe not...

That is the cause of the Interrupt Lock-up ? maybe...maybe not...

No maybe, no maybe not, it will cause a lock-up. Delay() relies on timer interrupts to count down the time for the delay to 'time out' and move on with next statements. When you enter a interrupt routine all interrupts are disabled, so delay() won't be able to count down and complete, it will just hang and cause a lock-up.

Lefty

So retrolefty, you think that the function delay() in my interrupt routine is the cause of the "non responsive" interrupt input ? OK I agree ( NO delay() & milli() in a interrupt routine ), but why my program did work than ? ... I feel 50/50 here... You know what I mean here...

Anyway retrolefty, I will "re-program" my project, I wonder how I will debouce the push switch... software... or hardware using a 7414 and maybe a Flip-Flop using AND or NAND gates ( S & R ) in conjunction with an another digital output... maybe no interrupt at all...( Man, my programing skill is not great...)

...( Man, my programing skill is not great...)

Mine have pretty much sucked for awhile too, but I am learning. Mostly I read and study as much of others peoples code as I can to understand how the various functions and methods work together. I've learned a lot in three years but still feel I'm a beginner. Hardware is where I feel a lot more comfortable.

Lefty

Software bouncing an interrupt is quite simple. What you want is:

noisy/bouncy trigger -> interrupt - > do something only once in a time defined by your time constant

volatile int iState = 0; //interrupt state
int debounceTime = 100; //debounce time, ms
void setup() {
  attachInterrupt(0,interruptFunction,RISING);
  pinMode(2,INPUT);
}

void loop() {
  if (iState == 1){
    delay(debounceTime)
    if (digitalRead(2) == HIGH) {
      //do something here that required debouncing
      State = 0;
    }
  }
}

void interruptFunction() {
  iState = 1;
}

Basically you are adding two conditions for your action, the triggering of the interrupt, and for that pin to remain high a given time later. You could of course do something more complicated, but I've found this to be quite effective.