Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

PwmSample


  • Please log in to reply
19 replies to this topic

#1 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 16 August 2010 - 07:12 AM

Hi Netduino fans,

Here's a little sample that uses a PWM pin to control the brightness of an LED. I like to call it PwmSample, for lack of a better name. B)

What it does:
When you press and hold the pushbutton, a connected LED will gradually brighten and dim. If you release the pushbutton, the LED stays at its current brightness. Pushing the button again will resume the brighten/dim cycle from the current value.

How it works:
This sample combines several techniques from the previous samples. It uses an InterruptPort for the pushbutton input; the SwitchInterruptHandler() method is called when the InterruptPort detects a rising or falling edge due to the pushbutton.

The sample also uses a Timer callback to do the actual LED brightness control. Every 20 milliseconds, the PwmTimerCallback() method is called. This method checks whether the pushbutton is closed (the buttonState variable). If so, then it increments (or decrements) the PWM pin's duty cycle.

Circuit:
Note that you'll need to connect an external LED to the Netduino board (it won't work with the built-in LED, since it's not connected to a PWM-enabled pin).

I used Digital Pin 5 in the sample; you can use any PWM-enabled pin (5, 6, 9, or 10), but make sure to change the Pin definition on line 34.

I don't have a schematic editor handy, but the circuit is simple enough. Just connect one end of a 100-ohm resistor to Digital Pin 5. Connect the other end of the resistor to the anode (+) lead of your LED. Then connect the cathode (-) lead of the LED to one of the GND pins on the Netduino Power header.

Here's the code:
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace PwmSample
{
    public class Program
    {
        const int pwmPeriod = 20;
        const uint MaxDutyCyle = 100;

        static bool buttonState;
        static int pwmDutyCycle;
        static int pwmIncrement;
        static InterruptPort button;
        static PWM led;

        public static void Main()
        {
            pwmDutyCycle = 0;
            pwmIncrement = 1;
            buttonState = false;

            // NOTE: You will need to connect an LED to Digital Pin 5 on the Netduino board.
            // Use a 100-ohm (brown-black-brown) resistor between the LED anode (+) and Digital Pin 5.
            // Connect the LED cathode (-) to one of the GND pins on the Power header.
            //
            // You can use any other PWM-enabled pin (5, 6, 9 or 10), but also remember to change
            // the Pin parameter in the PWM constructor below.

            led = new PWM(Pins.GPIO_PIN_D5);

            button = new InterruptPort(
                Pins.ONBOARD_SW1,
                false,
                Port.ResistorMode.Disabled,
                Port.InterruptMode.InterruptEdgeBoth);

            // Bind the interrupt handler to the pin's interrupt event.
            button.OnInterrupt += new NativeEventHandler(SwitchInterruptHandler);

            // Create a System.Threading.Timer instance and pass it the timer callback method.
            Timer pwmTimer = new Timer(
                new TimerCallback(PwmTimerCallback),
                null,
                pwmPeriod,
                pwmPeriod);

            Thread.Sleep(Timeout.Infinite);
        }

        public static void PwmTimerCallback(Object obj)
        {
            // Only change the LED brightness when the button is pushed (true).
            if (true == buttonState)
            {
                // Set the pin's new duty cycle.
                pwmDutyCycle += pwmIncrement;
                led.SetDutyCycle((uint)pwmDutyCycle);

                Debug.Print(pwmDutyCycle.ToString());

                if ((MaxDutyCyle == pwmDutyCycle) || (0 == pwmDutyCycle))
                {
                    // The duty cycle has hit the min or max value.
                    // Start ramping in the other direction.
                    pwmIncrement = -pwmIncrement;
                }
            }
        }

        public static void SwitchInterruptHandler(UInt32 data1, UInt32 data2, DateTime time)
        {
            button.DisableInterrupt();

            buttonState = (0 == data2);

            button.EnableInterrupt();
        }

    }
}

Thanks,
~ David ~

#2 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 16 August 2010 - 08:13 AM

Nice usage of interrupt handler parameter (data2) to get the pin/button state.

#3 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 16 August 2010 - 08:22 AM

Just out of curiosity, do you plan to extend PWM control to compensate the LED brightness non-linearity?

#4 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 16 August 2010 - 03:05 PM

Just out of curiosity, do you plan to extend PWM control to compensate the LED brightness non-linearity?


Was that a question for dab or the Netduino team?

Either way, what are you looking for in particular?

#5 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 16 August 2010 - 03:44 PM

Was that a question for dab or the Netduino team?

For dab.

Either way, what are you looking for in particular?

It was meant as a hint for further improvement or different version. When you control LED linearly (i.e. dutyCycle += c, in this case c = 1), the brightness does not scale linearly with duty cycle: there is almost no change in brightness for low values, then it increases relatively fast and again there are small changes for values around maximum duty cycle. This is caused by LED characteristics and the way how a human eye perceives brightness. Thus, usually an exponential or quadratic function is used for compensation (correction).

#6 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 16 August 2010 - 03:48 PM

For dab.


Okay, super. And good point regarding LED brightness. It's funny how things like that seem as though they should be nice and linear...but then the real world realities give us fun excuses to adjust things :)

#7 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 16 August 2010 - 04:14 PM

Just out of curiosity, do you plan to extend PWM control to compensate the LED brightness non-linearity?


Hi CW2,

Thanks for the suggestion - I think that would be a good follow-on sample. For the time being, I just wanted to create something equivalent to the Arduino "Fading" sample, but showcase some of the Netduino / NETMF features (like timer callbacks, and a "real" Sleep() function).

The Arduino sample also just folows a linear PWM ramp, which as you mention, doesn't correspond to a linear brightness at the LED :)

A more advanced exercise might use a lookup table to compensate for the non-linear response of the LED.

BTW, does anybody happen to know what the response curve of a typical LED looks like? I'm curious if it's a logarithmic function (like audio), or if it's something completely different.
Thanks,
~ David ~

#8 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 16 August 2010 - 04:20 PM

Nice usage of interrupt handler parameter (data2) to get the pin/button state.

Thanks, Chris. To give credit where it's due, I plagiarized copied that from the Event Handlers tutorial.

TBH, I couldn't find much in the way of documentation of how data1 and data2 are used in the callback. The .NETMF documentation mentions that data1 is the port, and data2 is the state, but "state" in this context was a little unclear. Apparently it refers to the logic state of the pin that generated the interrupt, but having that documented explicitly might be a good thing ;)
Thanks,
~ David ~

#9 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 16 August 2010 - 04:28 PM

For the time being, I just wanted to create something equivalent to the Arduino "Fading" sample, but showcase some of the Netduino / NETMF features (like timer callbacks, and a "real" Sleep() function).

I understand the purpose of the sample; IMHO you did it very well - the interrupt/event-driven mechanism is nicely demonstrated.

#10 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 16 August 2010 - 04:30 PM

TBH, I couldn't find much in the way of documentation of how data1 and data2 are used in the callback. The .NETMF documentation mentions that data1 is the port, and data2 is the state, but "state" in this context was a little unclear. Apparently it refers to the logic state of the pin that generated the interrupt, but having that documented explicitly might be a good thing ;)


You are correct. Here are the details (which we'll have to be sure to include in our future "introduction to Netduino" text).

data1: pin number
You can compare this to a Netduino pin using something like this (or a switch statement):
if (data 1 == (uint)Pins.GPIO_###)

data2: state
For interrupt ports:
0 = 0V (GND, or logic "low")
1 = 3.3V (or logic "high")

As far as state goes, I usually use if(data == 0) for "logic low" and if(data != 0) or if(data > 0) for "logic high".

Chris

#11 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 18 August 2010 - 08:36 AM

A more advanced exercise might use a lookup table to compensate for the non-linear response of the LED.

BTW, does anybody happen to know what the response curve of a typical LED looks like? I'm curious if it's a logarithmic function (like audio), or if it's something completely different.


I did a little research to answer my own question. B)

It appears that LEDs have a gamma relationship between the voltage and perceived brightness. I found this application note that explains it nicely:

http://www.maxim-ic....dex.mvp/id/3667

So, I've posted an updated version of the PwmSample (under the "PwmGamma" topic in this forum) that uses a LUT (lookup table) to implement the gamma correction.

The PwmGamma sample ramps the LED brightness in a way that looks more linear (still not perfect, but much better than before).
Thanks,
~ David ~

#12 FastEddy

FastEddy

    New Member

  • Members
  • Pip
  • 5 posts

Posted 14 September 2010 - 03:52 AM

Start debugging and: "An unhandled exception of type 'System.NotSupportedException' occurred in SecretLabs.NETMF.Hardware.dll" Line34 led = new PWM(Pins.GPIO_PIN_D5); Must be doing something stupid :(

#13 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 14 September 2010 - 03:58 AM

Start debugging and: "An unhandled exception of type 'System.NotSupportedException' occurred in SecretLabs.NETMF.Hardware.dll"


Hi FastEddy,

Three quick questions:
1. Which version of the firmware are you using?
2. Have you reflashed your unit or compiled your own firmware?
3. Does PWM work for you on pins 6, 9, and 10?

It might also be helpful to post your full code...

Chris

#14 FastEddy

FastEddy

    New Member

  • Members
  • Pip
  • 5 posts

Posted 14 September 2010 - 08:02 AM

Chris, 3. I tried Pin6 - same result 2. Bog standard, received from Amazon a week ago (I have not changed the firmware that came on it) and ... 1. With the software from the Download page here Wrote, compiled and loaded blinky "Hello World" just fine. Code cut-and-paste directly from this thread (typed it in myself the first time then re-tried from scratch with C&P). I have Arduino and STM8S Discovery working for some months but a noob on the Netduino. Thanks for your help...

#15 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 14 September 2010 - 08:14 AM

FastEddy, Could you zip the solution folder up and attach it here? Chris

#16 FastEddy

FastEddy

    New Member

  • Members
  • Pip
  • 5 posts

Posted 14 September 2010 - 08:45 AM

Here it is...

Attached Files



#17 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 14 September 2010 - 07:48 PM

Hi FastEddy, Okay, easy solution for this one... Right now, the Visual Studio solution is set up to deploy to the Microsoft Emulator. To use PWM, you'll need to deploy to the actual hardware. To do this: 1. Go to the Projects menu and select your Project's properties (bottom menu option) 2. In the left side of the properties pane, click on ".NET Micro Framework" 3. Select a transport of "USB" and a device of "Netduino..." 4. Close the properties pane. 5. Run your Netduino app Please let us know how that works for you... Chris

#18 FastEddy

FastEddy

    New Member

  • Members
  • Pip
  • 5 posts

Posted 15 September 2010 - 12:46 AM

Hah... I knew it -- noob mistake! Thanks, Chris

#19 FastEddy

FastEddy

    New Member

  • Members
  • Pip
  • 5 posts

Posted 15 September 2010 - 03:44 AM

Oooooooooooooo... button-controlled fading. Pretty! Now to get my head around the code and get it doing something useful. dab, thanks for publishing useful example. How do you suggest I get a relevant basic command reference? I hate reading (and writing) documentation as much as the next guy but there are times when it really helps... The community (including me ;) ) would probably benefit enormously from some pointers on how to research the command syntax.

#20 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 22 September 2010 - 05:15 AM

Oooooooooooooo... button-controlled fading. Pretty!

Now to get my head around the code and get it doing something useful.

dab, thanks for publishing useful example. How do you suggest I get a relevant basic command reference? I hate reading (and writing) documentation as much as the next guy but there are times when it really helps...

The community (including me ;) ) would probably benefit enormously from some pointers on how to research the command syntax.


Hi FastEddy,

Thanks for the kind words - I'm glad you find the sample code helpful B).

You raise a good point about getting up to speed on the technology. I consider myself pretty much a newbie to C# and the .NET framework (until relatively recently, I was a C++/Win32 API kind of guy).

For me, the biggest challenge is the .NET framework itself. It's huge (even .NETMF), and a lot of classes aren't very discoverable. I always find myself thinking "I know there's a class/method to do 'x', but where?".

Here are some things I've found helpful:

  • Sample code. Find something here in the Project showcase that looks interesting to you, get the source code, and play with it. Look up the classes / methods that you're not familiar with. Try making small changes to the code and see what happens. Don't be afraid to experiment.
  • Online documentation. Currently, the best available documentation is at the MSDN library site. But be aware that even that is sometimes wrong, or slightly out-of-date for the .NETMF libraries.
  • Books. There are a couple of books that I've found sort of useful. One is "Embedded Programming with the .NET Micro Framework", by Donald Thompson and Rob Miles. The other is "Expert .NET Micro Framework" by Jens Kuhner. Both of these are a bit dated, but have some useful sample code. There's also quite a bit of stuff in both books that I didn't find that useful, but they're worth reading for a couple of chapters (I'd recommend borrowing them if you can find a library that has them, or buy used copies).
  • Community. Right here is a good resource - it's a fairly small (but growing) community, and people I've seen are eager to share and swap advice and ideas. And the Secret Labs folks here are also super-helpful.

I hope that helps get you started.
Thanks,
~ David ~




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.