9 years, 8 months ago.

New mbed user moving from Arduino - Questions about PWM and my code

Just got my first mbed board this week (ST Nucleo F103RB), and I'm trying to port a few things I've learned from the Arduino platform. In particular, I'm looking to replicate PWM functionality I've used on Arduino.

Below are some questions/issues I would like to pose, in addition to asking for review of my code and any alt examples I can be pointed to. This code 'works', but I'm unsure if I'm doing things right, or if I can expand this into the add'l 'Exercises' commented on in my code below.

Thanks a ton in advance! Looking forward to being part of the mbed community!

Issues:

  • Not sure my math, or assumptions on values, are good in code below
  • I am making assumptions based on Arduino and that the AnalogIn pin on Nucleo is 12-bit.
  • LED occasionally flickers when pot is all the way down.
  • Is this the right way to code this Exercise, so I move onto next phases correctly?
  • How can I make my LEDs brighter? 5v or 3v seems to be same brightness.
  • FYI, I'm using a 330 ohm resistor on a red 5mm LED.

include the mbed library with this snippet

#include "mbed.h"

/*

Exercise 1 (current code):
Want to change brightness of standard LED with a 10k pot. 
I plan on building onto this via the add'l exercises below.

Exercise 2:
I will add 2 more pots (3 in total), one each to control Red, Green and Blue of an RGB LED.
Will use pots to adjust amount of each color applied to RGB LED, 
from 0 - 255, in order to create simple color mixer.

Exercise 3
Combine both features into one program. will add 2 more RGB LEDs (3 in total).
Will add a button. In one state, the 3 pots will control RGB color value settings.
In another state, the pots will control the PWM brightness for each of the 3 RGB LED.
Button press cycles Brightness > RGB of LED1 > RGB LED2 > RGB LED3 > Repeat.


*/

// Set pin to read in analog values of pot wiper, 0-4095
AnalogIn potpin(A0);

// Set pin for LED to PWM, so pot can control voltage, and brightness, of LED
PwmOut led(D11);

int main()
{
// Apply analog in reading to PWM out and loop
    while(1) {
        
        // Take analog in value (0-4095) and / by 16 to better map to PWM range of 0-255
        led = potpin/16;
        
        // Picked up from Arduino loops...let it breath a bit before repeating
        wait(0.1);
    }
}

2 Answers

9 years, 8 months ago.

As Erik has already pointed out, all you really need is

while (1) {
led = potpin;
wait(0.1);
}

And it will all work with as much resolution as the hardware can manage.

float potValue = potpin;

is identical to

float potValue = potpin.read();

They both give a value between 0 and 1 correctly scaled for the resolution of the hardware you are using.

If for some reason you want an integer value with the raw bits coming from the ADC then

unsigned int potValue = potpin.read_u16();

will give you a 16 bit value for the analog input voltage. Since on the CPU you are using the ADC is only 12 bit resolution what you will get is the raw ADC value shifted left 4 bits. This is done so that different mbed parts with different resolution ADCs will all give the same range of output values.

On the hardware side your LED is currently only being driven with a PWM that is on 1/16 of the time so it'll get a lot brighter once you make the change.

For setting the brightness of LEDs what you need to pay attention to is the drive current not the voltage. To see how bright you can drive an LED you need to know 4 numbers from the specifications:

The CPU GPIO output voltage (typically close enough to the power supply voltage that you can use that number) The CPU GPIO maximum output current (typically 5mA but for some parts sometimes up to 20mA, Also some parts can handle more current with a low output than with a high output which is why people will wire a pin so that it must go low to turn the LED on.)

The LED forward bias voltage (normally around 1.6V for red & green, often 3V or more for blue) The LED maximum drive current (normally around 20mA)

Take the CPU output voltage and subtract the LED forward bias voltage. That gives you the voltage across the resistor. Divide the voltage across the resistor by the drive current you want, and you get the resistor value you need. Make sure to round the resistor up to the nearest standard value not down.

If you need to get more voltage or current than the CPU can output then you'll need to use an extra transistor to drive the LED.

Having said all of that once you factor in how the LED brightness changes with current and how the human eye sees brightness you can normally barely see the difference between 2-3mA and 20mA,

Accepted Answer

Quote:

will give you a 16 bit value for the analog input voltage. Since on the CPU you are using the ADC is only 12 bit resolution what you will get is the raw ADC value shifted left 4 bits. This is done so that different mbed parts with different resolution ADCs will all give the same range of output values.

Small note: That is supposed to happen, but iirc that is incorrectly done on the Nucleo's, and indeed it just gives the 12-bit value.

posted by Erik - 12 Aug 2014

Well hopefully someone will get around to adding <<4 to the library for the next release. ;-)

posted by Andy A 12 Aug 2014

@ Andy A Thanks for the reply. Very helpful info. A lot more good stuff for me to look into further, as well.

posted by Brand Inman 13 Aug 2014
9 years, 8 months ago.

Both AnalogIn.read (which you do implicitly) and PwmOut.write (which again you use implicitly doing it this way) map from 0 to 1.0. So you can directly apply that.

The pins might not be able to deliver enough current to make it brighter, in that case you need to put a transistor in between (assuming you don't have it yet). Then you can either increase voltage or decrease the resistor.

@ Erik Olieman - Thanks for the reply! I will try that out tonight. So I would need no conversion on either side, as these are both 12-bit pins and/or readings are in same value range?

Everything has been done so many times and documented for Arduino, it was easy to determine if I was doing something right or not. More reading up on C, mbed, GPIO and voltage in general is probably a good idea for me. Thanks again!

posted by Brand Inman 12 Aug 2014

The reading are mapped to the correct range. The ADC is indeed 12-bit, the PWM is max 16-bit, but it depends on the selected period: In contract to Arduino PWM in mbed PWM you can easily change the period (because the resolution is much higher, if you would do it in Arduino you have little resolution left).

In the Handbook you can find standard mbed functions, for some reason it currently says documentation isn't available for PwmOut, but if you click on it it still shows up, for example: https://mbed.org/users/mbed_official/code/mbed/docs/tip/classmbed_1_1PwmOut.html

posted by Erik - 12 Aug 2014