diff options
Diffstat (limited to 'source/arduino/analogwrite.rst')
-rw-r--r-- | source/arduino/analogwrite.rst | 223 |
1 files changed, 134 insertions, 89 deletions
diff --git a/source/arduino/analogwrite.rst b/source/arduino/analogwrite.rst index 64ecd5b..d04f485 100644 --- a/source/arduino/analogwrite.rst +++ b/source/arduino/analogwrite.rst @@ -1,116 +1,161 @@ +.. highlight:: cpp + .. _arduino-analogwrite: analogWrite() ============= -TODO - -In libmaple, analogWrite is just a convenience alias for -:ref:`pwmWrite`. This is because PWM is not true analog output (i.e., -is not the output of a DAC), so the name was badly-chosen; however, -for the sake of compatibility, the alias was provided. - -.. doxygenfunction:: pwmWrite - -Description ------------ - -Writes an analog value -(`PWM wave <http://arduino.cc/en/Tutorial/PWM>`_) to a pin. Can be -used to light a LED at varying brightnesses or drive a motor at -various speeds. After a call to **analogWrite()**, the pin will -generate a steady square wave of the specified duty cycle until the -next call to **analogWrite()** (or a call to **digitalRead()** or -**digitalWrite()** on the same pin). The frequency of the PWM -signal is approximately 490 Hz. - - - -On most Arduino boards (those with the ATmega168 or ATmega328), -this function works on pins 3, 5, 6, 9, 10, and 11. On the Arduino -Mega, it works on pins 2 through 13. Older Arduino boards with an -ATmega8 only support analogWrite() on pins 9, 10, and 11. You do -not need to call pinMode() to set the pin as an output before -calling analogWrite(). - - - -The *analogWrite* function has nothing whatsoever to do with the -analog pins or the *analogRead* function. - - - -Syntax ------- - -analogWrite(pin, value) - - - -Parameters ----------- - -pin: the pin to write to. - - - -value: the duty cycle: between 0 (always off) and 255 (always on). - - - -Returns -------- +.. note:: + + On the Maple, calling analogWrite() is the same as calling + :ref:`wirish-pwmwrite`\ ; see that function's documentation for more + information. + + This is because PWM is not true analog output (i.e., is not the + output of a `DAC + <http://en.wikipedia.org/wiki/Digital-to-analog_converter>`_\ ), so + the function is badly named. For instance, **analogWrite() has + absolutely nothing to do with** :ref:`arduino-analogread`\ , which + is potentially confusing. + + The alias of analogWrite() to pwmWrite() is provided (sigh) for the + sake of compatibility with Arduino, but we recommend using + :ref:`wirish-pwmwrite` when writing new software, for clarity. + +.. contents:: Contents + :local: + +Arduino Compatibility +--------------------- + +There are a few important differences between Arduino's `analogWrite() +<http://arduino.cc/en/Reference/AnalogWrite>`_ and Maple's +:ref:`wirish-pwmwrite` that you should keep in mind. In each case, we +have some recommendations you can use to help converting from Arduino +to Maple. + +Difference 1: Duty cycle range is different +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first and most important difference is that the largest possible +value for the duty cycle is much bigger on the Maple. Using Arduino's +analogWrite(), the duty cycle ranges between 0--255 (always off -- +always on)\ [#fbytemax]_\ . Using Maple's pwmWrite(), the duty cycle +ranges from 0--65,535 by default\ [#fuint16max]_\ . + +This is a good thing! The greater range of values on the Maple gives +you much more precise control over the duty cycle of your PWM output. + +If you're porting code from the Arduino and want a quick-and-dirty +fix, one solution is to :ref:`map <arduino-map>` the argument to +analogWrite into the right range:: + + // Arduino code: + analogWrite(pin, duty); + + // Becomes Maple code: + analogWrite(pin, map(duty, 0, 255, 0, 65535)); + +This will convert values in the range 0-255 to values in the range +0--65,635, which is the correct default range for all of the timers +which control PWM output. See the :ref:`timers reference <timers>` +for more information. + +Another fix is to consult the :ref:`pin mapping mega table +<pin-mapping-mega table>` to find the timer which controls PWM on the +pin you're using, then set that Timer's overflow to 255. Subsequent +calls to analogWrite() should work as on the Arduino (with the same +loss of precision). Note, however, that that affects the overflow for +the **entire timer**, so other code relying on that timer (such as any +:ref:`interrupts <arduino-attachinterrupt>` the timer controls) will +likely need to be modified as well. + +Difference 2: You must use pinMode() to set up PWM +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The second difference is that on the Maple, you **must** set up the pin +for PWM output using :ref:`arduino-pinmode`\ , with argument ``PWM``. +This should just be one extra line of code in your +:ref:`arduino-setup` function. Example:: + + void setup() { + // set up pin 9 for PWM + pinMode(9, PWM); + } -nothing +This also means that you can't later call :ref:`arduino-digitalread` +or :ref:`arduino-digitalwrite` on that pin (unless some time in +between, you use pinMode() to reconfigure that pin for ``INPUT`` or +``OUTPUT``; see the :ref:`arduino-pinmode` page for more information). +Difference 3: No PWM on pin 10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On the Maple, the pins which support PWM are: 0, 1, 2, 3, 5, 6, 7, 8, +9, 11, 12, and 14, or twelve pins in total. That is at least as +*many* PWM pins as any Arduino board, but there are differences in +*which* pins support it. -Notes and Known Issues ----------------------- +* On **most Arduino boards** (those with the ATmega168 or ATmega328; + this includes the **Arduino Uno**), this function works on pins 3, + 5, 6, 9, 10, and 11, or six pins total. Note that these boards + support PWM on pin 10, while Maple does not. -The PWM outputs generated on pins 5 and 6 will have -higher-than-expected duty cycles. This is because of interactions -with the millis() and delay() functions, which share the same -internal timer used to generate those PWM outputs. This will be -noticed mostly on low duty-cycle settings (e.g 0 - 10) and may -result in a value of 0 not fully turning off the output on pins 5 -and 6. +* On the **Arduino Mega**, PWM works on pins 2 through 13, or twelve pins + total. Note that this board supports PWM on pins 4, 10, and 13, + while the Maple does not. Maple supports PWM on pins 0, 1, and 14, + which the Mega does not, making the total number of pins supporting + PWM equal on these boards. +* **Older Arduino boards** with an ATmega8 only support analogWrite() on + pins 9, 10, and 11. Maple does not support PWM on pin 10. +In all cases, Arduino boards support PWM on pin 10, unlike Maple. We +did our best to make PWM as pin-compatible as possible; however, +circuit layout constraints prevented us from achieving perfect +compatibility. -Example -------- +The "safest" pins to use for PWM output are pins 9 and 11. These pins +work on any Arduino board and on Maple. The "safe" pins, which work +on most recent Arduino boards, the Arduino Mega and the Maple, are +pins 3, 5, 6, 9, and 11. Thus, if you want your project to be as +portable as possible between Maple and Arduino, we recommend using the +"safest" pins first, then the "safe" pins, as necessary. -Sets the output to the LED proportional to the value read from the -potentiometer. +Difference 4: PWM frequency +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The frequency of the PWM signal (i.e., the frequency of a complete +on/off cycle) on the Arduino is approximately 490 Hz. +On the Maple, the frequency is configurable, defaulting to about 1100 +Hz, or 1.1 KHz. This is because the PWM frequency is the frequency of +the timer which controls PWM output on the particular pin (\ +:ref:`the PWM tutorial has the details <pwm>`\ ). -:: +If your application absolutely requires Arduino's PWM frequency (it +probably doesn't), then the steps are: - - int ledPin = 9; // LED connected to digital pin 9 - int analogPin = 3; // potentiometer connected to analog pin 3 - int val = 0; // variable to store the read value - - void setup() - { - pinMode(ledPin, OUTPUT); // sets the pin as output - } - - void loop() - { - val = analogRead(analogPin); // read the input pin - analogWrite(ledPin, val / 4); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255 - } +1. Figure out which timer controls PWM output on your pin (\ :ref:`this table <pwm-timer-table>` is your friend here). Let's say it's ``Timern``\ , where ``n`` is some number 1, 2, 3, or 4. +2. Call ``Timern.setPeriod(2041)``\ . This will set the timer's period to approximately 2041 microseconds, which is a frequency of approximately 490 Hz. +Be aware that this will change the period for the **entire timer**\ , +and will affect anything else in your program that depends on that +timer. One example is :ref:`interrupts <timers-attachinterrupt>`\ . +You've been :ref:`warned <timers-pwm-conflicts>`\ . See also -------- +- :ref:`Maple PWM tutorial <pwm>` -- `analogRead <http://arduino.cc/en/Reference/AnalogRead>`_\ () -- `Tutorial: PWM <http://arduino.cc/en/Tutorial/PWM>`_ +.. rubric:: Footnotes +.. [#fbytemax] This is because the value for the duty cycle on Arduino + must fit in 1 byte of memory, and an unsigned (i.e., nonnegative) + integer with size 1 byte can hold the values between 0 and 255. +.. [#fuint16max] This is because the value for the duty cycle on the + Maple uses 2 bytes of memory, and an unsigned (i.e., nonnegative) + integer with size 2 bytes can hold the values between 0 and 65,535. |