PWM: emulating analog pins with your Arduino board

PWM signals

With the digital and analog pins, which you can use on your Arduino board, you can receive or send electrical signals to control or obtain data from your electronic projects. In addition, there are other very interesting signals on this type of boards, and those are the PWM, that can emulate an analog signal without being really analog. That is to say, they are digital pins that can act in a similar way (that not equal) to an analog signal.

This type of signals are very practical for when you not only want to use digital HIGH and LOW signals, that is, 1 or 0, ON and OFF, but you want to go further and describe signals that are a little more complex. For example, you can modulate the speed of a DC motor, or the light intensity of a light, for a solenoid, etc.

Analogical vs. digital system

Electronic circuits can be divided into two large families or categories: digital and analogue. When talking about digital electronics, we are using magnitudes with discrete values, that is, a binary system represented by electrical signals of a low or high voltage to interpret the state of those bits that are handled. On the other hand, when it is a question of an analogical circuit, we are using magnitudes with continuous values.

Within the digital systems, we can find at the same time those of the combinational type and those of the sequential type. That is to say, the first ones are those in which the output of the system only depends on the state of the inputs. On the other hand, in the sequential ones, memory elements are included, and the output will depend on the current state of the inputs and the previous state stored.

In the case of the analogs there are not these two big groups or variants, since here they are continuous signals that will always depend on the current signal of the system. For example, in a loudspeaker, the signal supplied to it will depend on the sound you want to play. Same with a microphone, which will generate an analog signal depending on the sound it is receiving. You have probably also seen this with many other sensors that we have described in this blog and that act with analog signals (and therefore it was necessary to create a formula so that the values in the Arduino IDE sketches could be calculated or conditioned later) .

These characteristics of both make some have their advantages and disadvantages, as is usual in almost everything. For example, digitals are usually cheaper, faster, easier to develop, easier to store information, more accurate, programmable, not as vulnerable to the effects of noise, etc. But it is also true that with the analog ones you can operate with more complex signals.

For example, a digital Hall Effect sensor can only detect the presence or absence of a nearby magnetic field. On the other hand, an analogue Hall Effect sensor can do that and also determine the density of that magnetic field thanks to an analogue signal it generates at its output. Knowing how to interpret this signal of higher or lower voltage, one can easily know this magnitude. Other examples are a multitude of natural magnitudes that can be measured quantitatively with an analog system, such as temperature, time, pressure, distance, sound, etc.

Analog vs. digital signal

That said, an analog signal will be an electrical voltage or current that varies over time and continuously. If represented on a graph, the analog signal would be a single frequency sine wave.

As for the digital signal, it is a voltage that varies in a staggered manner with respect to time. That is, if it is represented in a graph, it will be a stepped signal that does not vary continuously, but changes by steps or in discrete increments.

You should know that there are circuits to switch from an analog signal to a digital signal or vice versa. These converters are known as DAC (Digital-to-Analog Converter) and ADC (Analog-to-Digital Converter). And they are very common in many devices that we use nowadays, such as TV, computers, etc. With them you can convert the digital signals that these devices use at an electronic level to work with other peripherals or parts that work in analog.

For example, a speaker or microphone with analog signals that works with a sound card, or digital graphics cards that had the famous RAMDAC chip for analog monitor ports . In Arduino, this kind of converters are also used for multiple projects, as we will see…

What is PWM?

duty cycle grafica

Although PWM (Pulse-Width Modulation) has a digital basis, the shape of its signal resembles a somewhat “square” analog signal. It allows, by means of digital pulses, to vary the signal to emulate an analog system as I mentioned before. In fact, if you look at the name, it already gives you clues of what it does, through the width of the digital pulses.

This is beneficial for Arduino since there are many automatisms or electronic components that you can add to your projects that are not capable of providing an authentic analog signal, but use this PWM to operate. Nor can they use a discrete analog signal, i.e. one that goes into voltage jumps to resemble a digital one. What they can do is use a digital output -Vcc or Vcc of digital type to generate this peculiar signal .

Therefore, PWM is a kind of “trick” with which Arduino and other systems can interoperate with this type of signals that do not become completely analog or conventional digital. To make it possible, they keep a digital output active for a specific time or off, depending on the interest at each moment. This is far from what would be a digital clock signal or binary code to use, whose pulses have an equal width.

In your projects with Arduino you can check this kind of PWM signals in which a constant frequency of pulse firings is maintained over time, but the width of these pulses is varied. In fact, it is called Duty Cycle when a signal is kept on high in relation to the total cycle. Therefore, Duty Cycle is provided in %.

Remember that in a PWM you do not work as in an analog signal, between several voltage values and fluctuating between them. In the case of PWM it is a square signal in the digital style and whose maximum value is Vcc. For example, if you work with a 3V power supply, you can give 3V or 0V pulses, but not 1V or other intermediate value as it would happen in a real analogical one. What would vary in that case is the width of the pulse, that we can maintain it a 30% in that value Vcc high, or a 60% to give more power, etc.

But be careful, because if a device supports a limit Vcc and it is exceeded with PWM, it can be damaged. So it would be always necessary to respect the values of the datasheets provided by the manufacturers. In addition, in some devices such as DC motors, relays, electromagnets, etc., a withdrawal of the voltage after a Duty Cycle can mean that inductive loads can generate damage. That is why the appropriate protections must be implemented.

PWM in Arduino

 

Arduino bus I2C

Now that you know how it works, let’s look at the concrete case of PWM within the Arduino world…

PWM: pinout in Arduino

In Arduino boards you can find several pins that implement hardware PWM. You can identify them on the PCB itself because they have a ~(virgin) symbol along with the pin number. You could also do it by software in Arduino’s code, but that would overload the microcontroller, something absurd when you can do it natively and by hardware…

  • Arduino UNO, Mini and Nano: it has 6 8-bit PWM outputs on pins 3, 5, 6, 9, 10 and 11, which will have that ~ right in front of the number.
  • Arduino Mega: on this most powerful Arduino board you have 15 8-bit PWM outputs. They are on pins 2 to 13 and 44 to 46.
  • Arduino Due: in this case there are 13 PWM outputs also of 8 bits. They are on pins 2 to 13, plus two other analog outputs discretized by DAC with 12-bit resolution.

When you talk about 8-bit or 12-bit resolution, etc., in this type of PWM output, you are referring to the room for manoeuvre you have. With 8 bits you have 256 levels among which you can vary, and the 12 bits go up to 4096 levels.

Control with Timers

For hardware PWM control, Arduino will use the Timers for this. Each Timer present can serve 2 or 3 PWM outputs. A comparison log for each output complements this system so that when the time reaches the value of the log the state or value of the output is changed to stop those Duty Cycles. Even if there are two outputs controlled by the same Timer, both can have different Duty Cycles, although they share the same frequency.

In the case of the Timers associated with each PWM pin will vary depending on the type of Arduino board you have:

  • Arduino UNO, Mini and Nano:
    • Timer0 – 5 and 6
    • Timer1 – 9 and 10
    • Timer2 – 3 and 11
  • Arduino Mega:
    • Timer0 – 4 and 13
    • Timer1 – 11 and 12
    • Timer2 – 9 and 10
    • Timer3 – 2, 3 and 5
    • Timer4 – 6, 7 and 8
    • Timer5 – 44, 45 and 46

The preset register will divide by a whole number the time and the Timer does the rest for the control of each of the associated PWM outputs. If you change the value of the register you can alter the frequency. The frequencies will also be different according to the Timer and the board:

  • Arduino ONE, Mini and Nano:
    • Timer0: allows prescales of 1, 8, 64, 256 and 1024. The frequency is 62.5 Khz.
    • Timer1: with prescales of 1, 8, 64, 256 and 1024. With a frequency of 31.25 KHz.
    • Timer2: the same as Timer1, only that it adds a prescale also of 32 and 128 in addition to the previous ones.
  • Arduino Mega:
    • Timer0, 1, 2: same as the previous ones.
    • Timer3, 4, and 5: with frequency of 31.25 Khz and prescales of 1, 8, 64, 256 and 1024.

Incompatibilities and conflicts

The timer associated to the outputs is not only used for this function, but also for others. Therefore, if they are being used by another function you must choose between one or the other, you can’t be using both at the same time. For example, these are some of the incompatibilities you can find in your projects:

  • Servo library: when you use servomotors, intensive use of timers is made, so it could generate conflicts. Specifically, use Timer1 for UNO, Nano and Mini, that is, you cannot use pins 9 and 10 while you are using a sketch with that library. In Mega it will depend on the amount of servos…
  • SPI: if you use SPI communication on the Arduino board, you are using pin 11 for the MOSI function. That’s why you can’t use that PWM pin.
  • Tone: this function uses the Timer2 to operate. So if it is used, you are disabling pins 3 and 11 (or 9 and 10 for Mega).

Practical test with Arduino

Arduino PWM scheme with LED

If you want to see how PWM works in Arduino, the best thing you can do is to connect the measuring tips of a voltmeter or polymeter (depending on the voltage measurement) between the PWM pin you have chosen to use and the ground or GND pin of the Arduino board. That way, on the screen of the measuring device you will be able to see how the voltage is varying with an output that is digital thanks to this PWM trick.

You can replace the voltmeter/polimeter by an LED to see how the light intensity varies, by a DC motor, or by any other element you want. I have simplified it in the scheme with Fritzing with an LED just like that, but you should know that it can represent the tips of a polymer as well…

If you use an LED, remember the resistance at the cathode and GND.

For the source code to control the Arduino board microcontroller to make everything work, you should insert this in Arduino IDE (in this case I used the PWM 6 pin of Arduino UNO):


const int analogOutPin = 6;
byte outputValue = 0;
 
void setup()
{
   Serial.begin(9600);
   pinMode(ledPIN , OUTPUT);
 
   bitSet(DDRB, 5); // LED or voltmeter
   bitSet(PCICR, PCIE0);
   bitSet(PCMSK0, PCINT3);
}
 
void loop()
{
   if (Serial.available()>0)
   {
      if(outputValue >= '0' && outputValue <= '9')
      {
         outputValue = Serial.read(); // We read
         outputValue -= '0'; // Subtract '0' to convert to a number
         outputValue *= 25; // Multiply x25 to get a scale of 0 to 250
         analogWrite(ledPIN , outputValue);
      }
   }
}
 
ISR(PCINT0_vect)
{
   if(bitRead(PINB, 3))
   {
      bitSet(PORTB, 5); // LED on
   }
   else
   {
      bitClear(PORTB, 5); // LED off
   }
}

Leave a Comment

*

*