Pages: [1]   Go Down
Author Topic: Call random() from interrupt service routine?  (Read 1086 times)
0 Members and 1 Guest are viewing this topic.
Kentucky, US
Offline Offline
Full Member
***
Karma: 1
Posts: 193
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've got a program that responds to AC line zero crosses (an isolated detector drives an Uno D2 pin low at each crossing).  What's the best way to make sure there is a "fresh" pseudo-random number available to the interrupt 0 handler each time it gets called?

Jim
Logged

TC4 Open Source Digital Thermometer and Temperature Controller
http://code.google.com/p/tc4-shield

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 634
Posts: 34547
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It is best to keep interrupt service routines short but nothing to stop you calling the random function.

Random coupled with mains does make me worried, what are you doing?
Logged

Kentucky, US
Offline Offline
Full Member
***
Karma: 1
Posts: 193
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am experimenting with different methods of integral cycle resistive load control using zero cross SSR's.   smiley-eek

Presently, I am using predefined on/off patterns, at half-wave resolution (120Hz), for different output levels.  This works pretty well, but I want to see if random patterns further reduce the flicker.

The general idea is to generate a random number from 0 to 100.  Compare it to the desired duty cycle (75%, for example).  If the random number is less than 75, then the SSR signal is made high and the next half wave becomes an "on" wave.  If the random number is greater than 75, then the next half wave is an "off" wave.  Over a period of a second or two, you would expect something near the desired 75% duty cycle.

Jim
Logged

TC4 Open Source Digital Thermometer and Temperature Controller
http://code.google.com/p/tc4-shield

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you don't call random() from any other part of your code, it should be safe.

However, you probably should just set a flag in the interrupt handler, and pick that flag up in the main() function, and do all your random stuff there, including preparing the next random number.

Also, you can easily generate your own random number genrator using a linear congruential generator, which will be good enough for the use you're suggesting (in fact, a simple table of size 256 might be good enough!)

If your problem is flicker, though, then that won't get better with randomness IMO. You're probably better off just settling on a N:M quantization of on/off distribution. A random distribution might make the noise you may hear from certain fixtures less static, though, and thus maybe make it slightly less unpleasant. It's better to have no noise, though :-)

Here's a function I would use to figure out whether the next is "on" or "off":

Code:
char curVal;
char ratioN; // N >= 0, N <= M
char ratioM; // M > 0, M <= 127

bool getOn() {
  curVal += N;
  if (curVal >= 0) {
    curVal -= M;
    return true;
  }
  return false;
}

Also, you probably don't need 100 steps of control -- try 20-30 steps of control for a pretty smoothly varying system, especially if you're driving things like incandescent lights.

« Last Edit: October 11, 2011, 07:39:57 pm by jwatte » Logged

Kentucky, US
Offline Offline
Full Member
***
Karma: 1
Posts: 193
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Many thanks for the suggestions.  I now have some research to do  smiley-confuse

Jim
Logged

TC4 Open Source Digital Thermometer and Temperature Controller
http://code.google.com/p/tc4-shield

Kentucky, US
Offline Offline
Full Member
***
Karma: 1
Posts: 193
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The N:M quantization works very well.  Thanks again.

I ended up using a resolution of 100 (i.e. M = 100), though I agree that a lower resolution would have probably worked just as well.   Using 100 makes the duty cycle more easily understood by humans.  No real penalty for overkill in this situation.

The short algorithm you posted replaces probably a hundred lines of my old code  smiley-mad

Jim
Logged

TC4 Open Source Digital Thermometer and Temperature Controller
http://code.google.com/p/tc4-shield

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 210
Posts: 13030
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


One small suggestion.  The language standards do not specify if char is signed or unsigned.  Best to be explicit or use a platform independent type...

Quote
int8_t curVal;
int8_t ratioN; // N >= 0, N <= M
int8_t ratioM; // M > 0, M <= 127

bool getOn() {
  curVal += N;
  if (curVal >= 0) {
    curVal -= M;
    return true;
  }
  return false;
}
Logged

Global Moderator
Online Online
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

See:

http://arduino.cc/en/Reference/Char

Quote
The char datatype is a signed type, meaning that it encodes numbers from -128 to 127.
Logged


Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 210
Posts: 13030
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


When I wrote that, I was thinking of the C(++) language standards and future boards.  After reflection I will re-characterize the suggestion as "irrelevant" rather than "small".   smiley-red
Logged

Kentucky, US
Offline Offline
Full Member
***
Karma: 1
Posts: 193
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

FWIW, I implemented it using int16_t.  I'm going to change it to int8_t, I think.

All is not completely well, however. This code, along with code to perform a phase angle delay using timer1, lives inside an ISR for int 0 (I have an external zero cross detector).

In the main loop of the program, I watch for changes on A0 and A1 using analogRead. There are 1-turn pots on those pins. I change the values of ratio_N and phase delay used in the ISR based on the analog readings.

Seemingly randomly, the Arduino locks up once in a while when turning the pots. Way too much code to post here, and could also be related to trying to update an I2C LCD panel too quickly with the changing analog readings (although the same code works perfectly in other applications that do not have the interrupt handler).

Jim

code is here if you are interested.


« Last Edit: October 16, 2011, 08:30:21 am by JimG » Logged

TC4 Open Source Digital Thermometer and Temperature Controller
http://code.google.com/p/tc4-shield

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The short algorithm you posted replaces probably a hundred lines of my old code  smiley-mad

Glad I could help :-) Don't know what to do about your interrupt problem, though.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 210
Posts: 13030
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Seemingly randomly, the Arduino locks up once in a while when turning the pots.

Board?
Logged

Pages: [1]   Go Up
Jump to: