I am using Arduino UNO/MEGA, I want to
where the value is 0-1023.
How can I make that ?
Arduino Stack Exchange is a question and answer site for developers of open-source hardware and software that is compatible with Arduino. It only takes a minute to sign up.Sign up to join this community
Section 16, "16-bit Timer/Counter1 with PWM" of Atmel-8271J-AVR- ATmega-Datasheet_11/2015 describes using Timer/Counter-1 for 16-bit PWM, including sample code in both C and assembler. It might take a couple of reads over that section to get familiar with the hardware and learn what else T/C-1 is used for, and that you might have to give up while using it for PWM, but the code is fairly straightforward.
Using this T/C would give you 2-bits more resolution in your PWM output than mapping onto an 8-bit counter, if that is what your project needs.
+1 for the question. Not having needed PWM output for anything more than a demo with my DMM (yet), it hadn't occurred to me to look for a higher resolution until now.
The simplest way is to change your value range to 0-255. You can't change analogWrite's range, since that is fixed in the core software.
analogWrite(5, val >> 2);
>> 2 bit-shifts the value two bits to the right, turning a 10-bit value (0-1023) into an 8-bit value (0-255). It's by far the most efficient way of dividing by 4.
On more complex 32-bit boards, like the Arduino Due, or the chipKIT range of boards, etc, you have the function analogWriteResolution() which can change the range, but that cannot be done on the 8-bit boards.
From what I have read online it looks like the ATMega chips may support higher resolutions for PWM - however there is no support in the core for that. If you need a higher resolution for some specific reason then you will need to program the registers manually yourself and not rely on the Arduino API to do the work for you. For that you will need to consult the datasheet for your chosen chip.
I agree with @Majenko's answer, though here is a more "beginner" friendly method of doing the same.
val = map(val,0,1023,0,255); analogWrite(pin, val);
Not the most efficient, but still...
The other questions so far have correctly addressed one possible meaning of this question, "how can I increase the resolution?" Here's another possible interpretation.
It sounds like you might want to output a higher maximum voltage than what you get from using
analogWrite(pin,255) on the Uno or Mega. This is not possible using the Arduino by itself, because PWM represents a fraction of the maximum output, not an absolute value.
On the Uno and Mega, that maximum output is 5V, so the approximate values come out to:
analogWrite(pin,0); // (0 / 255) * 5V (0% of 5V == 0V) analogWrite(pin,127); // (127 / 255) * 5V (50% of 5V == 2.5V) analogWrite(pin,255); // (255 / 255) * 5V (100% of 5V == 5V)
If you want to make a higher absolute voltage, you will need an external power source and a method of translating the 0-5V output into another voltage range. This is called "level shifting" and there are standalone ICs which can do this job. Motor drivers and H-Bridge devices utilize this principle as well.
If you use some sort of level shifting circuitry, then you can map the analogWrite to a different range, such as 0-20V:
analogWrite(pin,0); // (0 / 255) * 20V (0V) analogWrite(pin,127); // (127 / 255) * 20V (10V) analogWrite(pin,255); // (255 / 255) * 20V (20V)