Newbie question regarding interrupts

Hi,

This is my first post here… so hello and hope I have done this post properly, according to the posting rules.

I’m a newbie to Arduino and I’m an old assembler dude who is very familiar with 8080/85, Z80, 6800 and 6502 hardware/software, but I am keen to get into the Arduino.

I have a simple project that I am building to allow an Arduino to countdown in seconds, using the Timer1 interrupt, and display hours and minutes on 3 x 7 segment LED displays. At then end of the time period the relay is switched off. It will also have 2 push buttons. Button A will activate the unit, where it will commence counting down. If I hit Button A during the countdown it will set back to the start again. Button B is to stop counting immediately, and thereby de-activate the relay.

To make sure I got my interrupt timing working I am sending the values to my PC via serial print. Once I get that sorted I can then add the LED displays and button, with the subsequent code.

The code I am using is below, and I do apologise if it is rubbish, but I am still learning. My issue is, when the countdown goes to 0, I expect the serial print to say “0:0:0” for hours, minutes and seconds, respectively, followed by “Timer Expired” message. However, I don’t get this. I do if I comment out the “noInterrupts” line, but then the thing keeps counting down. Can someone point out what I have done wrong.

I am using Arduino 1.8.1 running on a PC with Windows10, and using an Arduino UNO.

The TimerOne library I got from an example in “Exploring the Arduino” book by Jeremy Blum.

regards
River

// Timer1 interrupt using seconds countdown
  // to derive hours and minutes
 
  #include <TimerOne.h>
  
  unsigned int start_count = 5;  // Initial count in seconds
  int flag = 0;                  // Interrupt flag
  int end_flag = 0;              // Flag for printing "Timer Expired" just once
  unsigned int hour;             // hours
  unsigned int minute;           // minutes
  unsigned int second;           // seconds
   
void setup() {
  // put your setup code here, to run once:
 end_flag = 0;                   // Clear flag for "Timer Expired" routine
 Serial.begin(9600);             // Set up serial port
 Serial.print("\n");             // Send carriage return
 Timer1.initialize(1000000);     // Intialise Timer1 for 1 second interrupt
 Timer1.attachInterrupt(CountDown);  // Activate Timer1 and interrupts
}

void loop() 
{
  // Execute uppon each timer interrupt 
  if (flag == 1)                 // Execute serial prints if interrupt flag is set
  {
    Serial.print(start_count);   // serial print intial countdown of seconds
    Serial.print(" - ");         // and hours:minutes:seconds
    Serial.print(hour);          // and followed by carriage return
    Serial.print(":");
    Serial.print(minute);
    Serial.print(":");
    Serial.print(second);
    Serial.print("\n");
   
    start_count = start_count - 1;  // Decrement seconds counter
    
    flag = 0;                    // clear interrupt flag so only above is printed once
                                 // per interrupt
  }

  if (start_count == 65535 && end_flag == 0) // Kludge to determine when decremented beyond
                                             // 0 seconds remaining
  {
    Serial.print("\n");                      // print carriage return
    Serial.print("Timer Expired");           // and "Timer Expired" message
    end_flag = 1;                            // Set flag so "Timer Expired" is omnly printed once
    
    noInterrupts();                          // Time expired so disable interrupts
  }
}

void CountDown()                                        // Timer1 expired interrupt service routine
{
  hour = start_count / 3600;                            // derive remaining hours
  minute = (start_count % 3600) / 60;                   // derive remaining minutes
  second = start_count - (hour * 3600) - (minute * 60); // derive remaining seconds
  flag = 1;                                             // Set interrupt flag
}

Hello,

river: I have a simple project that I am building to allow an Arduino to countdown in seconds, using the Timer1 interrupt...

Why? Blink-without-delay is a far better choice.

Why?... because I don't know better, and didn't know what to search for such a thing. I'll go look for it. Thanks.

These are a good place to start... https://www.gammon.com.au/blink http://forum.arduino.cc/index.php?topic=76140.0 http://forum.arduino.cc/index.php?topic=223286.0

"flag" should be volatile.

http://www.gammon.com.au/interrupts

hour, minute and second should also be volatile.

Pete

Never do this

    noInterrupts();                          // Time expired so disable interrupts

It stops ALL interrupts !

Mark

There is nothing wrong (or unusual) about using noInterrupts() but it should be followed very very quickly by interrupts() to turn them back on.

But it will probably be a lot simpler not to use interrupts at all in this project. The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing. It may help with understanding the technique.

...R

Hi,

Thanks for your replies. Much appreciated.

I have gone and checked some of the links and, by using the sample code from Robin2, I got a LED flashing without "delay", and I understand the logic on how it works. I can build up on this now, with a clearer understanding.

Many thanks to the other posters regarding interrupts, volatile and other links - which I will read up on and check out.

To give some clarity about my project.... I have a nice audio-visual room, which has an AV amp and a nice old school stereo amp (restoration/repair old amplifiers is one of my hobbies). They need to share the same sets of speakers, and by default the speakers connect to the AV amp. I could use or build a speaker switch to select the speakers between the 2 amps, but that seems crude and too simple, so I decided to use an Arduino.

The concept is to have the Arduino activate a set of relays to switch the speakers to the stereo amp, with 3 x 7seg LED displays, which count down minutes from 8:00 to 0:00 (8 hours). When at 0:00 the relays are de-energised, which means the speakers will then connect to the AV amp, and the LED display to go blank. The Arduino has 2 buttons. Pressing Button A activates the relays and starts the time at 8:00, and therefore connects the speakers to the stereo amp. Button B de-activates the relays and the LED display will go off and speakers will be connected to the AV amp.

The whole "timing" thing I am doing is to count down and display minutes remaining, with the ability of the Arduino to still be able to check for buttons.

Hopefully, when I get this done, I can progress onto more adventurous Arduino projects.

regards River

Thank you for the follow-up.

Skip the relay - look at an analog mux chip.

Mark

Hi,

Haven’t looked into analog mux’s yet. May do so at a later stage but first I’ll use relays, especially as the amps push out 150W RMS.

Anyway, I was quite industrious today, did a lot of reading and experimenting and now have some code which uses “milli()” to decrement at one second intervals, and display this on an SPI 4-digit, 7-seg display. When the count reaches zero the relay (current code uses LedPin 13) goes off.

I need to add the buttons and also convert count to time (initial value will be 28800 for 8hours in seconds), but I’m pretty chuffed at what I got done so far. It may be a simple thing and no doubt poor coding for you guys, but for me it’s good progress.

Thanks for your assistance :slight_smile:

/* Speaker Relay
 *  
 * Application using Arduino UNO to switch relays to connect 
 * speakers between 2 amplifiers.
 * 
 * Button A switches on the relays and commences a countdown
 * from 8hrs, displaying hours & minutes on a 4-digit 7-segment
 * LED display. If Button A is pressed during the count down, it 
 * will start back at 8 hours.
 * 
 * Button B cancels the count down, blanks the display and deactivates
 * the relays
 * 
 * Button pins are :-
 *     Pin 9 - Button A
 *     Pin 8 - Button B
 * 
 * The display is controlled via SPI, using the following pins :-
 *     Pin 12 - MSI (data in)
 *     Pin 11 - SCK (clock)
 *     Pin 10 - CS (select) *  
 *  The display is the "Serial 7-seg Display" from Mikroelektronika
 *  
 *  A small slave relay provides power for the 4 large speaker relays.
 *  Slave relay pin is...
 *     Pin 7 - Slave Relay
 *     
 *  The count down is acheived by using "milli()" function, and checking
 *  expired time. RTC accuracy is not required for this application.
 *  
 *  
 * Modification History
 * ===============================================================
 * Date     | Vers | Comments
 * 26/02/17 | 100  | Initial version - uses LED Pin13 to emulate relay
 * 
 * 
 * 
 * 
 */

// --- LIBRARIES
#include <LedControl.h>

// --- CONSTANTS
const int LEDpin = 13;         // Emulate relay on/off
const int timeInterval = 1000; // 1 second time interval

// --- VARIABLES
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
int ctr = 9999;                  // Countdown in seconds

// --- DECLARATIONS
LedControl lc = LedControl(12,11,10,1);  // Setup SPI display

void setup() {
  // Set up code - run once
  pinMode (LEDpin, OUTPUT);    // Output for Relay
  digitalWrite(LEDpin, HIGH);  // Relay energised
  
  lc.shutdown(0,false);        // Initialise display
  lc.setIntensity(0,1);        
  lc.clearDisplay(0);           
}

void loop()
{
  // Mainline code
  currentMillis = millis();    // Get current run time in millisecs

  if (currentMillis - previousMillis >= timeInterval)
  {
    previousMillis += timeInterval;  // Keep track of expired millisecs
    ctr = ctr - 1;                   // Decremenr remaining time 1 second
  }
  ShowTimer(ctr);                    // Display remaining time

  if (ctr == 0)                      // if counter expired
  {
    digitalWrite(LEDpin,LOW);        // De-activate relay
  }
}

void ShowTimer(int v)               // Display count down
{
  int ones;                        
  int tens;
  int hundreds;
  int thousands;

  ones=v%10;                        // Derive values to display
  v=v/10;
  tens=v%10;
  v=v/10;
  hundreds=v%10;
  v=v/10;
  thousands = v; 

  lc.setDigit(0,3,(byte)thousands,false); // Display the countdown
  lc.setDigit(0,2,(byte)hundreds,false);
  lc.setDigit(0,1,(byte)tens,false);
  lc.setDigit(0,0,(byte)ones,false);
}

regards
River

Analog multiplexers: http://www.gammon.com.au/forum/?id=11976

Hi,

Thanks for the link. I'll check it out :)