So far, my sketch is fairly straight forward. Being 200 lines, I don't feel the need to post all of it here, but I'll include the necessary parts. It's basically a single line of math that is giving me an issue.
cycle_time = ((1/frequency)*1000000);
Where frequency is an int that ranges from 400 to 1024 and cycle_time is an int. I've tried splitting it into two lines so it looks like:
ct = 1/frequency;
cycle_time = ct*1000000;
I've tried changing variable types between int, float, and unsigned long between both ways of calculating this, and it always comes back 0. Even the ct line by itself returns 0 when set as a float. 6 or 7 decimal places is more that accurate enough for my needs. I've also tried using
cycle_time = pow(frequency, -1)*1000000
And broke that into two lines as well with the same result. I've verified that frequency is a valid number going in with a Serial.print. Any ideas?
Solution: int frequency, cycle_time; cycle_time = 1000000UL / frequency;
We are assuming for the purposes of this discussion that ..
the number represents the frequency in Hertz; whence t = 1/f in seconds
and you are multiplying by 100000
presumably to get the result in microseconds. (but it SHOULD be 1000000 note extra zero)
1: you need to do the calculation in a way that preserves the resolution. So use
unsigned long cycle_time = 1000000 / frequency
2:
As your DATA is only precise to 0.1% your result can not be more precise than that, and the display SHOULD show it in that way;
A computer will provide the expected result when technically valid data are supplied. In your sketch the 1/frequencey, where frequency varies from 400 - 1024, is not a valid input as 1/frequency will always be evaluted to 0. Therefore, the solution is:
int cycle_time = (1/frequency)*100000UL;
or
float cycle_time = (1.0/frequency)*100000UL;
Serial.println((int)cycle_time);
to get the result in microseconds. (but it SHOULD be 1000000
Thanks johnerrington, in my haste to transpose from my laptop to desktop, I miss counted zeros. I've updated that and the usage of the word double rather than unsigned long.
I hadn't thought about the fact that the 1000000 is larger than what could be stored in a standard int or float. I'll swap that over to UL and simplify the equation to
cycle_time = 1000000UL / frequency;
This looks to be the most simple solution. I'll post my results.
As a side question, when asking for assistance in something this simple, is it better etiquette to post only the necessary code as I did here, or the entire sketch, of nearly 200 lines, which has been properly commented?
The very best would be the smallest sketch that demonstrates the problem. Sometimes in writing the example you will discover the solution and not have to ask.
void setup()
{
Serial.begin(115200);
delay(200);
int frequency, cycle_time;
frequency = 400;
cycle_time = ((1/frequency)*1000000);
Serial.print(cycle_time);
frequency = 1024;
cycle_time = ((1/frequency)*1000000);
Serial.print(cycle_time);
}
void loop() {}
The simplest solution worked perfectly! My loop() now has a valid number to hand off to my pwm() function. so, I'm using:
int frequency, cycle_time;
frequency = (400 to 1000);
cycle_time = 1000000UL / frequency; // Gives cycle period in microseconds
I will take your advice next time johnwasser and put together a small sketch that demonstrates the problem rather than trying to describe it. I was just afraid of getting someone caught up on bad programming outside of the line at issue. Probably putting that line in bold would not be a bad idea.
One last question. Should I include simplified sketches for attempts to solve the issue? Coming here was my last option, not my first. I explored several dozen options of changing the variable types, both in setup and inline with the math as a single line and in two lines. I literally spent hours trying ideas I knew probably would not work, but needed to exclude from being a possible solution. Obviously, I would not include all of the explored option iterations, but maybe the 3 or 4 most extreme from the original code.
Both cycle_time and frequency are int. As the cycle time is in microseconds, going into nanoseconds is unnecessary. In my original post, I said double when I meant unsigned long. That has now been corrected.
If your sketch is proprietary (trade secret) then you should try to produce a small non-secret sketch that reproduces the problem.
If you understand the problem enough to produce a small sketch that reproduces the problem, do that and post it.
If your sketch is not a secret but large and spread across a bunch of files and you don't undertand it enough to produce a small sketch that will demonstrate the problem, pack it all in a .zip file (or other archive format) and upload/attach it.
If your sketch is one file but you don't understand it enough to create a much smaller version that demonstrates the problem, use the IDE 'Tools->Auto Format' and 'Edit->Copy for Forum' and post the whole thing.
These are best practices. Most people try to get away with posting one line or a few lines. This CAN work, especially if an entire function and all of the variable declarations it needs are included.
Working in integers - with a result in microseconds - will be a sensible representation for the precision of the input.
You will still need to scale the result unless the input value (400 - 1024) REALLY DOES represent an input frequency of 400 - 1024Hz.