khoih-prog / TimerInterrupt

This library enables you to use Interrupt from Hardware Timers on an Arduino, such as Nano, UNO, Mega, etc. It now supports 16 ISR-based timers, while consuming only 1 hardware Timer. Timers' interval is very long (ulong millisecs). The most important feature is they're ISR-based timers. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks.
MIT License
98 stars 11 forks source link

One Step Timer #29

Closed freetoair closed 2 years ago

freetoair commented 2 years ago

I'd like to know what the problem is, probably in my code, but I've tried everything I know, and no luck. I'm trying to write a One shoot timer, but it doesn't work. Look at this code, if you can help me.``

/****************************************************************************************************************************
 * examples/Argument_Simple.ino
 * For Arduino AVR boards
 * Written by Khoi Hoang
 * 
 * Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt
 * Licensed under MIT license
 * Version: v1.0.2
 *
 * Now we can use these new 16 ISR-based timers, while consuming only 1 hardware Timer.
 * Their independently-selected, maximum interval is practically unlimited (limited only by unsigned long miliseconds)
 * The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
 * Therefore, their executions are not blocked by bad-behaving functions / tasks.
 * This important feature is absolutely necessary for mission-critical tasks.
 * 
 * Notes:
 * Special design is necessary to share data between interrupt code and the rest of your program.
 * Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume 
 * variable can not spontaneously change. Because your function may change variables while your program is using them, 
 * the compiler needs this hint. But volatile alone is often not enough.
 * When accessing shared variables, usually interrupts must be disabled. Even with volatile, 
 * if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. 
 * If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled 
 * or the entire sequence of your code which accesses the data.
 *
 * Version Modified By   Date      Comments
 * ------- -----------  ---------- -----------
 *  1.0.0   K Hoang      23/11/2019 Initial coding
 *  1.0.1   K Hoang      25/11/2019 New release fixing compiler error
 *  1.0.2   K.Hoang      28/11/2019 Permit up to 16 super-long-time, super-accurate ISR-based timers to avoid being blocked
 *****************************************************************************************************************************/
//These define's must be placed at the beginning before #include "TimerInterrupt.h"
#define TIMER_INTERRUPT_DEBUG      0

#define USE_TIMER_1     true
#define USE_TIMER_2     false
#define USE_TIMER_3     false
#define USE_TIMER_4     false
#define USE_TIMER_5     false

#include "TimerInterrupt.h"

unsigned int outputPin1 = LED_BUILTIN;
unsigned int outputPin2 = A0;
volatile int counter = 0;
uint16_t shot = 5;

void TimerHandler1(unsigned int outputPin = LED_BUILTIN)
{
  static bool toggle1 = false;
  static bool started = false;

  if (!started)
  {
    started = true;
    pinMode(outputPin, OUTPUT);
  }

  //timer interrupt toggles pin outputPin, default LED_BUILTIN
  Serial.println("pin1 = " + String(outputPin) + " address: " + String((uint32_t) &outputPin) );
  digitalWrite(outputPin, toggle1);
  toggle1 = !toggle1;
  counter ++;
}

#define TIMER1_INTERVAL_MS    1000 

void setup()
{
  Serial.begin(115200);
  Serial.println("\nStarting");

  // Timer0 is used for micros(), millis(), delay(), etc and can't be used
  // Select Timer 1-2 for UNO, 0-5 for MEGA
  // Timer 2 is 8-bit timer, only for higher frequency 

  ITimer1.init();

  // Using ATmega328 used in UNO => 16MHz CPU clock , 
  // For 16-bit timer 1, 3, 4 and 5, set frequency from 0.2385 to some KHz
  // For 8-bit timer 2 (prescaler up to 1024, set frequency from 61.5Hz to some KHz

  if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS, TimerHandler1, outputPin1))
  {
    Serial.println("Starting  ITimer1 OK, millis() = " + String(millis()));
    Serial.println("OutputPin1 = " + String(outputPin1) + ", address = " + String((uint32_t) &outputPin1) );
  }
  else
    Serial.println("Can't set ITimer1. Select another freq. or timer");

}

void loop()
{ 
  if (counter == shot){
    ITimer1.disableTimer() ; 
//    ITimer1.detachInterrupt() ; 
  }
}

Yes, I know the total number of serviced IRQ requests is 5, but the first 3 are undefined. I saw that on the oscilloscope, and I can't find a reason why that is.

khoih-prog commented 2 years ago

HI @freetoair

If your use-case is different from normal, you have to read the open source code, then you'll understand what to use.

For example Duration = 0 or not specified => run indefinitely

// Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
template<typename TArg>
bool attachInterruptInterval(unsigned long interval, void (*callback)(TArg), TArg params, unsigned long duration = 0)

Yes, I know the total number of serviced IRQ requests is 5, but the first 3 are undefined. I saw that on the oscilloscope, and I can't find a reason why that is.

Using Hardware TimerInterrupt requires better knowledge and skills, so I'll leave the question for you to find out.


Finally, if it's not an issue or bug of the library, post on Discussions to ask for help, not here. Also you have to follow the minimum request of specifying

as specified in Issue: Bug report

It seems that you use very old library version v1.0.2, while current version is v1.8.0

Continue doing this way will get you blocked from posting in the library issues/discussions

Good Luck,

freetoair commented 2 years ago

Ok, thanks for the recommendation. I have updated the library, but unfortunately still without success. It doesn't matter, I solved the problem with a few commands in assembler. I apologize for posting my problem in the wrong place.

regards, freetoair

khoih-prog commented 2 years ago

It's great that you found out your way. No apology needed. I was just a little bit hard to make it easier for other users to search and post the possible bug.

If you feel necessary, thru your experience, it's better to add that kind of example for other users. I'll do as I don't know if the use-case is popular or difficult to write.

You can also make a PR if you'd like.

Regards,

freetoair commented 2 years ago

Of course I will share my experience. For now I'm testing the code, when I'm sure it works correctly I'll post it. The solution is not directly related to your library, it is more an example for using AVR timer1 counters as one shoot timer. If it can help someone why not post it.

regards, freetoair