Super Bowl L(ed)

With the kick-off of Super Bowl L between the Carolina Panters and the Denver Broncos a few hours away I decided to show the ultimate team spirit and blink my NodeMCU and RGB LED in the colors of Broncos Country: orange and blue. It makes for an excellent opportunity to get some hands on experience with Pulse-Width Modulation and NodeMCU's PWM module before the big game kick-off.1

A common method to 'mix' a custom color of a RGB LED is by controlling the brightness of each of the individual three colors. The brightness of a LED can be controlled by adjusting the duty cycle.

If we dim all three colors in equal amounts, the result will be white light. Red equally mixed with green will gets us yellow. From a Bronco's perspective I mix the following RGB recipe: set red fully on, and green 50% brightness and blue off will get us an orange color.

NodeMCU's PWM module provides a set of commands that do exactly this.

config.lua

First we need to define the pins which are connected to the respective RGB legs respectively. A separate config.lua script contains all variables that are relevant for adjustments. See code snippet below.

-[[
config.lua | Tiest van Gool

Global variables definitions for usage across various lua scripts  
--]]

--NodeMCU Pin Definitions
PIN_R = 1 --GPIO5 Red  
PIN_G = 2 --GPIO4 Green  
PIN_B = 5 --GPIO14 Blue

-- Status Message
print("Global variables loaded")  

pwm.lua

Controlling the brightness of the RGB LED using the PWM module is realized here. Lets examine this script a little closer. In order to accomplish the blinking I have defined 3 different routines:

  • The initialization routine rgb_init sets the RGB pins to PWN mode with the command pwm.setup(). Once activated pwm.start() enables detection of the waveform on the GPIOs.
  • The routine rgb_duty mixes the actual color of the LED by adjusting the duty cycles pwm.setduty(). The parameter color is evaluated to determine what color to output. A duty value of 0 turns the pin to full brightness while 1023 is off.
  • Lastly the rgb_toggle routine alternates the LED color from orange to blue. The parameter color is alternated and passed on to the routine rgb_duty for the color adjustment.

At the end the script toggles the color value from orange (3) to blue (2) in a 2 second interval leveraging a modified Blink! script as described in this post.

--[[
pwm_blink.lua | Tiest van Gool

Serves as actual init file to enable testing and debugging during initialization mode.  
--]]

-- Load global user-defined variables'
dofile("config.lua")

-- Initialization routine for RGB LED pins'
function rgb_init(freq, duty)  
  -- Configure PWM (freq, 50% duty cycle[512/1023])  
  pwm.setup(PIN_R, freq, duty)     -- Red
  pwm.setup(PIN_G, freq, duty)     -- Green
  pwm.setup(PIN_B, freq, duty)     -- Blue

  --Start the PWM on the pins (Defaults to white)
  pwm.start(PIN_R)
  pwm.start(PIN_G)
  pwm.start(PIN_B)
end

-- Routine to set color of RGB LED based on local variable
-- Default set color to orange or white
function rgb_duty(color)  
  if color == 0 then
    -- RED COLOR
    pwm.setduty(PIN_R, 0)
    pwm.setduty(PIN_G, 1023)
    pwm.setduty(PIN_B, 1023)
  elseif color == 1 then 
   -- GREEN COLOR
    pwm.setduty(PIN_R, 1023)
    pwm.setduty(PIN_G, 0)
    pwm.setduty(PIN_B, 1023)
  elseif color == 2 then
    -- BLUE COLOR
    pwm.setduty(PIN_R, 1023)
    pwm.setduty(PIN_G, 1023)
    pwm.setduty(PIN_B, 0)
  elseif color == 3 then
    -- ORANGE COLOR
    pwm.setduty(PIN_R, 0)
    pwm.setduty(PIN_G, 512)
    pwm.setduty(PIN_B, 1023)
  else
    -- WHITE COLOR
    pwm.setduty(PIN_R, 0)
    pwm.setduty(PIN_G, 0)
    pwm.setduty(PIN_B, 0)
  end
end

-- LED Initialization
rgb_init(100, 1023)  
print("LED Initialized")  
color = 2  
print("Blue color")

-- Routine to toggle color of LED Orange and Blue
function rgb_toggle ()  
  -- BLUE COLOR
  if color == 2 then
    print("color 2 - BLUE")
    color = 3
    rgb_duty(color) -- Turn LED Orange
  -- ORANGE COLOR
  elseif color == 3 then
    print("color 3 - ORANGE")
    color = 2
    rgb_duty(color) -- Turn LED Blue
  else
    print("color X - WHITE")
    color = 3
    rgb_duty(color) -- Turn LED White
  end
end

-- Create interval for toggling color
tmr.alarm(0, 2000, 1, rgb_toggle)  

init.lua

NodeMCU uses init.lua as the auto executable which is invoked upon boot-up. The script below calls the init_broncos.lua. It contains a 10 second delay to allow for cancelling the excution in the situation of an error in order to interrupt and endless loop.

--[[
init.lua | Tiest van Gool

Init.lua is automatically executed on bootup of the NodeMCU. This launcher file loads the actual init_XYZ file only when everything has been tested and debugged.  
A 15 second delay has been added in case of error and enable abort.  
--]]


-- Set local variable
FileToExecute="pwm.lua"

-- Set timer to abort initialization of actual program
print("You have 15 second to enter file.remove('init.lua') to abort")  
tmr.alarm(0, 15000, 0, function()  
  print("Executing: ".. FileToExecute)
  dofile(FileToExecute)
end)  

Once the scripts are uploaded onto the NodeMCU your RGB LED should be proudly blinking in the colors of the Denver Broncos: orange/blue. We've successfully mixed colors by leveraging the PWM module and duty cycles.

Update 2/07: The Denver Broncos have won Super Bowl 50 with 24 - 10 where the defense dominated Cam and the Panthers.

[^n] Republished and modified based on my original blog post created on February 7th 2016.

Tiest van Gool

Boulder, CO

comments powered by Disqus