Hi, can you please help with something more specific? I have been reading here about SPI ports to be used, about interupts,.. I am a bit confused:
1. does it matter which digital input on an Arduino to use? If so, why and which one?
2. Your proposal sounds good but I would not even go that far; I would just take samples once an hour during 10 or so seconds after a 5 second warm-up and process the results (count number of LOW and HIGH readings and process). What is your take on that?
3. Can you get me some flow chart or sample code or a link to where I can find more specific coding examples or hints?
Thank you, Erik
I don't know Arduino boards specifically, but the basic ATmega has options. You're simply reading a digital pin state. SPI can do that, USART can do that, GPIO can do that.
Serial might be less convenient, because you get bytes out, whereas you might want a unary bit stream. You need to unpack the bytes to get a high-and-low count (which is kind of annoying to write out in C).
The basic operation might be this:
// initialization
uint16_t mark = 0, period = 0;
while (read_pin == 0);
// pin just turned to 1, count 'on' duration
while (read_pin == 1) {
mark++; period++;
delay(SAMPLE_TIME);
}
// pin just turned to 0, count 'off' duration
while (read_pin == 1) {
period++;
delay(SAMPLE_TIME);
}
Repeat this a few times, sum up the marks and periods, and get duty_cycle = (uint16_t)((1 << 16) * mark / period) (for a 0.16 fixed point result).
Note that the above code hangs until an edge is received, and skips through rapidly if edges are much more common than expected. This is a good example of fragile code. Better to use for() to make a fixed duration loop -- it might be 10 second window you mentioned -- and count the occurrence of 1 conditionally.
The DSP method is similar, using accumulator variables that count up the input, but instead of doing a final division, the pin value is added (unconditionally) to the variable, then the variable's value is reduced proportionally each iteration. That is, multiplied by a number slightly less than 1.0 -- the effect is to have a "leaky" accumulator, so that a constant stream of '1's will not make the accumulator eventually overflow, but instead it rises and levels off exponentially, just like the voltage on a capacitor.
Such a loop looks like,
uint32_t accumulator = 0;
const uint32_t GAIN_FACTOR = (1 << 16) * (;
for (NUM_SAMPLES) {
accumulator += read_pin * (1 << 16); // read_pin should return 1 if true, 0 if false (e.g., (PORTA & (1 << PA3)) >> PA3) )
accumulator = (accumulator * GAIN_FACTOR) >> 16; // the first multiplication technically has a 64-bit result.
delay(SAMPLE_TIME); // Check the assembler output if it's doing the right thing
} // or not, and add typecasts as needed. My C is rusty.
Using interrupts, you'd have a counter running in the background (could be a hardware timer-counter) and sample it when an input edge occurs. This gives you the mark and period counts without any extra thinking.
Make sure to filter the input, and prevent additional interrupt events from firing while the interrupt is being serviced (otherwise a nearby RF field will crash the MCU).
Using the timer-counter hardware, I believe you can use the input capture / gating pin to enable or trigger the counter, doing the same thing with almost no CPU involvement at all.
Obviously, the first two options chew CPU constantly, so if you don't need to do anything else, and you can interrupt this process to do other things (like serial or GPIO when reading out the data), that's fine. The latter options can be tacked onto an existing build, assuming that build is, itself, not critical on timing (i.e. it can spare a few clock cycles to service the interrupts), and has the timer(s) and pins free.
The latter options are probably on the advanced side for someone only experienced with Arduino. I would worry about the buginess of the Arduino libraries, as far as being able to support these kinds of functions, too. At that point you might be better off with C in AVR Studio -- less buggy, much steeper learning curve.
Tim