Pages: [1]   Go Down
Author Topic: timer help  (Read 1094 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 94
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I need some help setting up a timer that runs an ISR once per second so that i can send a serial message out once per second.
I have read the article at the following link but i am still a little lost. i don't understand bit shifting and hex very well which is probably a huge part of my problem

http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/

here are some of my questions

should i be using timer1 or timer 2?
which prescaler do i choose when wanting an interrupt once per second?
how do i set the prescaler you recommend?
how do i enable the ISR?
is there a more readable way to do timer stuff kind of like the attachInterrupt function?
like maybe something like enableTimer1(interval, handlerfunction)

if anybody knows of a sample program or tutorial or an article for real simple timer usage please let me know

some background...

i need to debounce a reed switch in my main loop and then send the time between pulses out in a serial message once per second.

Thanks
Jeff
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6250
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jeff, are you sure you need an ISR? It may be better to use the millis timer. Can you say a little more about the pulses you want to measure.  Are they synchronized in some way to the messages you want to send? What is the minimum and maximum period of the pulses. Can more than one pulse occur between messages? What do you want to send if a pulse occurs in the middle of a message.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 94
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i'm about 99% sure that i need to use a timer interrupt. i have a anemometer with a reed switch that gives one pulse per revolution. 1 pulse/second is equal to 2.5 mph wind speed.

i was going to find some debounce code and run that in the main loop to calculate time between pulses. (1000ms/timeBetweenPulses(ms)) x 2.5 = Windspeed(MPH)

the timer interrupt is to be used to faithfully send a message to my software on the computer once every second that contains the time between pulses and a few other bits of info. the software on the computer needs to get a message from the board once per second and update the display.

i don't know how else to make sure that a message goes out every second while the debounce code is running.

i can't use delay(1000) because that stops the debounce operation.

Any ideas are very much appreciated.

if after reading this you agree about the timer, can you help me out with the timer stuff

Thanks
Jeff
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6250
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jeff, happy to help you out with the timer but I wonder it would be better for you to use interrupts to do the pulse counting and use the millis function to handle the one seconds intervals between messages. Perhaps I am missing something but it seems that the highest priority task is to accurately time the rotation so this would be a good candidate for interrupt handing. And I think the code is simpler if you use an interrupt for rotation sensing and a simple delay for message timing.

If  I understand your requirements, the minimum time between pulses  would be at least 20ms (150mph) and the maximum would be around 5 seconds (0.5 mph). anything less than 20ms would be ignored as noise, anything 5 seconds or more would be considered 0 mph.  Is that what you are thinking?

If so, then consider the following pseudocode for the attachInterrupt handler :
-----
  In the handler, if the pulse has gone high, store the current millis() value in a startPulse variable

If the pulse goes low, calculate the duration from startPulse to the millis() time now

If this is less than 20 ms, the pulse is noise and  is ignored
But if its 20 ms or more then store the current millis() value as currentRotationTime

(Except for the very first rotation at startup, i.e. a rotation counter  equals zero )  the time for one rotation is the difference between the previousRotationTime and the currentRotationTime

Store the rotation duration (currentRotationTime – prevRotationTime) in an array so it can be accessed from the main loop.  But I would think you might as  well convert the duration to mph here so you could store the value as a byte

Save the currentRotationTime as prevRotationTime

Increment a rotation counter

(note that the duration calculations need to detect overflow )

--- Psuedocode for loop ---

delay 1000 ms

calculate the average or peak of the values stored and send via serial port

---   end of psuedocode ---

I have some code that simplifies calculation of moving average and peak values that I can post if this would be of help
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 94
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi and thanks for helping me out on this one.
this is exactly how i originally wrote my program when the sensor was a hall effect sensor. unfortunately, and it is out of my control. i now have to make it work with a reed switch and it is failing because of the bounce in the reed switch.  i am unaware of away to accurately debounce the reed switch in the interrupt. what makes me think it is failing is that when i know the wind is somewhere between 10-20mph i'll have a max gust reading of 150mph or so which i know is not correct. i feel like i need to have the main loop do the debounce by polling the pin(which has the pullup resistor turned on) and when it detects an edge do a 50 microsecond delay and then check if it is still LOW, if it is then record the time then wait for next edge record the time and do the math as you suggested. then i would like to at an accurately spaced 1 second interval send the data to the computer. the reason to use the boards clock for the 1 second interval is that i feel that it will be more accurate than a software timer that is at the mercy of all kinds of other things going on in the users computer. my display needs to update once per second and the board very nicely gives me a data available event once per second. this is of course when i was doing what you suggested and had a nice little delay(1000) in the main loop and was getting time between pulses in my interrupt handler.

also here is the math stuff. anything longer than 2500 milliseconds(1.0MPH) is garbage and anything faster than 12-13 milliseconds is not needed. (1000/2500)*2.5 or (1000/12)*2.5

i don't know how else to explain the bogus readings with the reed switch other than bounce.

I am still open to any suggestions that you may have.

also as a side project i also need this whole thing to work as a field data logger sending data to a usb flash drive and my preliminary tests on that show some random bad writes and my guess is that an interrupt is happening during a write that is causing the write message to get screwed up. so the thought there was to have a all the disk communication happen in a timer interrupt so that there is no interrupts to interrupt the writing to disk. so i feel like no matter what i need to learn how to use timers. what are your thoughts on this?

also besides trying to get this project off the ground i am very interested in learning about micro controller programing and i feel that learning the ins and outs of timers is just another area that i should know

below is a sample of my attachInterrupt Handler

Code:
void pulse_detect()
{
  thetime = millis();
  if (thetime - lastpulse >= 13) //this is my debounce check
  {
    timediff = (thetime - lastpulse);
    lastpulse = thetime;
    count++;
  }
  else
  {
   if (thetime - lastpulse < 0 ) // this is an attempt to deal with the millis() rollover problem every nine hours
   {
// record the time for the next pulse to measure against but don't do the math because it won't make sense
     lastpulse = thetime;
    count++;
   }
  }

}

thanks for your help
Jeff
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6250
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jeff, thanks for providing that background, it does help me to understand the context. I am not sure what is the best way for me to help.

On the one hand, I have a strong aversion to encouraging anyone to create code that spends a significant amount of time in an interrupt handler.
On the other hand, I do understand your desire to become familiar with AVR timers.
And it is your project, and I am curious to see how it goes.

I am hoping that a timer expert will step up and assist you so I can watch from the sidelines  smiley-wink
If not then I will try to help.
« Last Edit: March 18, 2008, 12:00:13 pm by mem » Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 94
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i'm curious. do you think that sending a small serial message(12 bytes or less) during the interrupt is a long time?
i do agree with you that interrupts should get in and get out fast.

also side question...

do you know what the max value of millis() is right before it rolls over to 0?

i want to try and do some math to deal with roll over

thanks again
Jeff
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6250
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There is a function here to handle the rollover: http://www.faludi.com/2007/12/18/arduino-millis-rollover-handling/

I use a different approach. I modified the millis interrupt in wiring.c and use a counter that is incremented every second. This rolls over in about 70 years.

Code:
volatile static unsigned int mscounter;
volatile static unsigned int correction;      
volatile unsigned long _time;  // this is the seconds counter

SIGNAL(SIG_OVERFLOW0)
{
   timer0_overflow_count++;
   ++correction; // used to increment the counter on average every 976.5625 overflows      
   if( ++mscounter >= 976)        
      if( (correction >= 143)||(mscounter >= 977) )
      {
            mscounter = 0;
             _time++;
       }
}


Serial send time may depend on baud rate but I would guess that it would be in the order of a few milliseconds. I am not sure how fast hardwar serial is.  Try a test using millis to see if it is more than a millisecond.

« Last Edit: March 18, 2008, 12:31:32 pm by mem » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
do you know what the max value of millis() is right before it rolls over to 0?
I believe 9h 32m 39.737s (0x20C49B9 milliseconds) is followed by zero.

The following code in wiring.c should generate a millis() that has 0xFFFFFFFF followed by zero, which means that integer arithmetic will work correctly during the rollover -

#define CLOCK_CYCLES_PER_MILLISECOND (F_CPU / 1000UL)
#define NUMBER_OF_CLOCK_CYCLES_PER_TIMER0_OVERFLOW 16384UL
 
volatile unsigned long millis;
unsigned long clock_ticks;
 
SIGNAL(SIG_OVERFLOW0)
{
  clock_ticks += NUMBER_OF_CLOCK_CYCLES_PER_TIMER0_OVERFLOW;
  while (clock_ticks >= CLOCK_CYCLES_PER_MILLISECOND) {
    millis++;
    clock_ticks -= CLOCK_CYCLES_PER_MILLISECOND;
  }
}
 
unsigned long millis()
{
  unsigned long return_val;
  cli(); // disable interrupts so that the value of millis cannot update while we are reading it
  return_val = millis;
  sei(); // re-enable interrupts
  return return_val;
}

Have a look at this post http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1205949448/0 for more on this
Logged

Pages: [1]   Go Up
Jump to: