I'm fairly new to Arduino, so forgive any ignorance.
I'm working on a project where I need specific DC voltages ranging from [0, 1] in a 5mV interval. I've gotten this setup with generating a PWM signal with the corresponding voltages duty cycle and then using a low-pass filter to generate the DC value from the PWM. The problem I'm hitting is that it doesn't generate every value I need, i.e. it skips some values. For example, it will output 1v, .995v, and then jump to .975v instead of outputting .990v. I'm starting to think that it's just because of the rounding in the desired voltage -> duty cycle percentage conversion and maybe it's not possible to get all the values I need on this board. Any help/insight that you guys could provide would be much appreciated!
Here's the sketch I've been using:
int PWM_out_pin = 11; // Must be one of 3, 5, 6, 9, 10, or 11
double Veff = 0; //The DC voltage wanted at the output pin
double stepSize = .005;
void setup() {
Serial.begin(9600);
pinMode(PWM_out_pin, OUTPUT);
}
void loop() {
long double PWM_out_level;
for (Veff = 1; Veff >= 0; Veff = Veff - stepSize)
{
PWM_out_level = (255/5)*Veff; // Code logic to set output level
analogWrite( PWM_out_pin, PWM_out_level); // Write the desired voltage to the output pin
delay(5000); // Hold the current voltage for 5 seconds
Serial.println(Veff, 4);
}
}
Think about it: You're only using 51 different values in the analogWrite() function (255/5 is 51). You're never going to get the values you want that way.
Try setting up a resistor divider on the output of your filter to divide by five. That way you can use the full output range (0 to 255).
Next, go down from 255 to 0 in steps of 1, look at the output voltages. That's the best you can do with the Arduino PWM output. Whether it's good enough or not is up to you.
For that sort of precision you should be looking at something like the MCP4821
It is controlled by SPI, and outputs a voltage at 12-bit resolution. That's either between 0 and 2047.5mv at 0.5mV steps, or between 0 and 4095mV at 1mV steps depending on settings.
If you set timer1 to 10 bit mode you'll have 1024 PWM levels available to pins 9 and 10 (it goes up to 16 bits,
but that could make the cycle time very long. You will need to drive the timer1 registers directly to do this,
try searching for "TCCR1A" for posts about this.
There is also a library for more advanced use of timers I believe, it might help.