Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
BlinkenLights
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
UCC
BlinkenLights
Commits
d9e5da97
Commit
d9e5da97
authored
Jan 25, 2014
by
Mitchell Pomery
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial Commit
Code so far.
parents
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
2948 additions
and
0 deletions
+2948
-0
.gitattributes
.gitattributes
+22
-0
.gitignore
.gitignore
+215
-0
BlinkenLights.ino
BlinkenLights.ino
+391
-0
libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp
libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp
+932
-0
libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h
libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h
+91
-0
libraries/Webduino/WebServer.h
libraries/Webduino/WebServer.h
+1262
-0
libraries/Webduino/keywords.txt
libraries/Webduino/keywords.txt
+35
-0
No files found.
.gitattributes
0 → 100644
View file @
d9e5da97
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
.gitignore
0 → 100644
View file @
d9e5da97
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
BlinkenLights.ino
0 → 100644
View file @
d9e5da97
/*
BlinkenLights
by Mitchell Pomery [BG3] with help from Andrew Adamson [BOB]
modified 20 Jan 2014
*/
///TODO: Vary light pattern randomly
///TODO: Make run when no network is present
///TODO: Recover when network reappears
#include <Ethernet.h> // Needed For Reasons
#include <WebServer.h> // Lets us easily do web requests
#include <SPI.h> // Needed to control Lights
#include <Adafruit_NeoPixel.h> // Controls the Lights
#define STRIPLENGTH 42 // Number of LED's in light strip
#define PIN 6 // Pin that the LED strip is attached to
#define PREFIX "" // Document root for our pages
#define PORT 80 // Web Server Port
#define NAMELEN 8 // Max variable length in request
#define VALUELEN 256 // Max value from request
#define WIDTH // How many LEDs wide our array is
#define HEIGHT // How many LEDs high our array is
// Used to store the LED's values
struct
led
{
char
red
;
char
green
;
char
blue
;
};
int
position
=
0
;
// led array
struct
led
ledArray
[
STRIPLENGTH
];
char
brightness
=
(
char
)
128
;
static
uint8_t
mac
[]
=
{
0xC0
,
0xCA
,
0xC0
,
0x1A
,
0x19
,
0x82
};
// C0CA C01A 1982
IPAddress
ip
(
130
,
95
,
13
,
96
);
int
lightOption
=
0
;
// Set up our light strip
Adafruit_NeoPixel
strip
=
Adafruit_NeoPixel
(
STRIPLENGTH
,
PIN
,
NEO_GRB
+
NEO_KHZ800
);
// Set up our webserver
WebServer
webserver
(
PREFIX
,
80
);
// showArray
void
showArray
()
{
for
(
int
i
=
0
;
i
<
STRIPLENGTH
;
i
++
)
{
strip
.
setPixelColor
(
i
,
(
int
)
ledArray
[
i
].
red
,
(
int
)
ledArray
[
i
].
green
,
(
int
)
ledArray
[
i
].
blue
);
}
strip
.
show
();
}
// setLED
void
setLED
(
int
pos
,
int
red
,
int
green
,
int
blue
)
{
ledArray
[
pos
].
red
=
red
;
ledArray
[
pos
].
green
=
green
;
ledArray
[
pos
].
blue
=
blue
;
}
// Sets the light sequence to one that is predefined
void
webSetSequence
(
WebServer
&
server
,
WebServer
::
ConnectionType
type
,
char
*
url_tail
,
bool
tail_complete
)
{
URLPARAM_RESULT
rc
;
char
name
[
NAMELEN
];
char
value
[
VALUELEN
];
server
.
httpSuccess
();
// Kill the connection before doing anything if all they want is the head
if
(
type
==
WebServer
::
HEAD
)
{
return
;
}
else
if
(
type
==
WebServer
::
POST
)
{
while
(
server
.
readPOSTparam
(
name
,
NAMELEN
,
value
,
VALUELEN
))
{
//Serial.print(name);
//Serial.print(" = ");
//Serial.println(value);
//if (name == "seq") {
// lightOption = value;
//}
}
}
else
if
(
type
==
WebServer
::
GET
)
{
//WebServer::POST
if
(
strlen
(
url_tail
))
{
while
(
strlen
(
url_tail
))
{
rc
=
server
.
nextURLparam
(
&
url_tail
,
name
,
NAMELEN
,
value
,
VALUELEN
);
if
(
rc
!=
URLPARAM_EOS
)
{
//Serial.println(name);
//Serial.println(value);
if
(
String
(
name
).
equals
(
"seq"
))
{
lightOption
=
atoi
(
value
);
server
.
print
(
lightOption
);
}
}
}
}
///TODO: Get ?seq=X and set lightOption to X
}
else
{
server
.
print
(
"Unknown"
);
}
}
void
webSetLED
(
WebServer
&
server
,
WebServer
::
ConnectionType
type
,
char
*
url_tail
,
bool
tail_complete
)
{
URLPARAM_RESULT
rc
;
char
name
[
NAMELEN
];
char
value
[
VALUELEN
];
int
xPos
=
-
1
;
int
yPos
=
-
1
;
int
r
=
-
1
;
int
g
=
-
1
;
int
b
=
-
1
;
server
.
httpSuccess
();
// Kill the connection before doing anything if all they want is the head
if
(
type
==
WebServer
::
HEAD
)
{
return
;
}
else
if
(
type
==
WebServer
::
POST
)
{
while
(
server
.
readPOSTparam
(
name
,
NAMELEN
,
value
,
VALUELEN
))
{
//Serial.print(name);
//Serial.print(" = ");
//Serial.println(value);
//if (name == "seq") {
// lightOption = value;
//}
}
}
else
if
(
type
==
WebServer
::
GET
)
{
//WebServer::POST
if
(
strlen
(
url_tail
))
{
while
(
strlen
(
url_tail
))
{
rc
=
server
.
nextURLparam
(
&
url_tail
,
name
,
NAMELEN
,
value
,
VALUELEN
);
if
(
rc
!=
URLPARAM_EOS
)
{
//Serial.println(name);
//Serial.println(value);
if
(
String
(
name
).
equals
(
"x"
))
{
xPos
=
atoi
(
value
);
}
else
if
(
String
(
name
).
equals
(
"y"
))
{
yPos
=
atoi
(
value
);
}
else
if
(
String
(
name
).
equals
(
"r"
))
{
r
=
atoi
(
value
);
}
else
if
(
String
(
name
).
equals
(
"g"
))
{
g
=
atoi
(
value
);
}
else
if
(
String
(
name
).
equals
(
"b"
))
{
b
=
atoi
(
value
);
}
}
}
}
}
else
{
server
.
print
(
"Unknown"
);
}
//Serial.println(xPos);
//Serial.println(yPos);
//Serial.println(r);
//Serial.println(g);
//Serial.println(b);
if
(
xPos
!=
-
1
&&
yPos
!=
-
1
&&
r
!=
-
1
&&
g
!=
-
1
&&
b
!=
-
1
)
{
setLED
(
xPos
,
r
,
g
,
b
);
}
}
void
webSetBrightness
(
WebServer
&
server
,
WebServer
::
ConnectionType
type
,
char
*
url_tail
,
bool
tail_complete
)
{
URLPARAM_RESULT
rc
;
char
name
[
NAMELEN
];
char
value
[
VALUELEN
];
int
xPos
=
-
1
;
int
yPos
=
-
1
;
int
r
=
-
1
;
int
g
=
-
1
;
int
b
=
-
1
;
server
.
httpSuccess
();
// Kill the connection before doing anything if all they want is the head
if
(
type
==
WebServer
::
HEAD
)
{
return
;
}
else
if
(
type
==
WebServer
::
POST
)
{
while
(
server
.
readPOSTparam
(
name
,
NAMELEN
,
value
,
VALUELEN
))
{
//Serial.print(name);
//Serial.print(" = ");
//Serial.println(value);
//if (name == "seq") {
// lightOption = value;
//}
}
}
else
if
(
type
==
WebServer
::
GET
)
{
//WebServer::POST
if
(
strlen
(
url_tail
))
{
while
(
strlen
(
url_tail
))
{
rc
=
server
.
nextURLparam
(
&
url_tail
,
name
,
NAMELEN
,
value
,
VALUELEN
);
if
(
rc
!=
URLPARAM_EOS
)
{
//Serial.println(name);
//Serial.println(value);
if
(
String
(
name
).
equals
(
"brightness"
))
{
strip
.
setBrightness
(
atoi
(
value
));
}
}
}
}
}
else
{
server
.
print
(
"Unknown"
);
}
}
// Fill the dots one after the other with a color
void
colorWipe
(
uint32_t
c
,
uint8_t
wait
)
{
for
(
uint16_t
i
=
0
;
i
<
strip
.
numPixels
();
i
++
)
{
strip
.
setPixelColor
(
i
,
c
);
strip
.
show
();
delay
(
wait
);
}
}
void
rainbow
(
uint8_t
wait
)
{
uint16_t
i
,
j
;
for
(
i
=
0
;
i
<
strip
.
numPixels
();
i
++
)
{
strip
.
setPixelColor
(
i
,
Wheel
((
i
+
position
)
&
255
));
}
strip
.
show
();
delay
(
wait
);
position
++
;
}
// Slightly different, this makes the rainbow equally distributed throughout
void
rainbowCycle
(
uint8_t
wait
)
{
uint16_t
i
,
j
;
for
(
j
=
0
;
j
<
256
*
5
;
j
++
)
{
// 5 cycles of all colors on wheel
for
(
i
=
0
;
i
<
strip
.
numPixels
();
i
++
)
{
strip
.
setPixelColor
(
i
,
Wheel
(((
i
*
256
/
strip
.
numPixels
())
+
j
)
&
255
));
}
strip
.
show
();
delay
(
wait
);
}
}
//Theatre-style crawling lights.
void
theaterChase
(
uint32_t
c
,
uint8_t
wait
)
{
for
(
int
j
=
0
;
j
<
10
;
j
++
)
{
//do 10 cycles of chasing
for
(
int
q
=
0
;
q
<
3
;
q
++
)
{
for
(
int
i
=
0
;
i
<
strip
.
numPixels
();
i
=
i
+
3
)
{
strip
.
setPixelColor
(
i
+
q
,
c
);
//turn every third pixel on
}
strip
.
show
();
delay
(
wait
);
for
(
int
i
=
0
;
i
<
strip
.
numPixels
();
i
=
i
+
3
)
{
strip
.
setPixelColor
(
i
+
q
,
0
);
//turn every third pixel off
}
}
}
}
//Theatre-style crawling lights with rainbow effect
void
theaterChaseRainbow
(
uint8_t
wait
)
{
for
(
int
j
=
0
;
j
<
256
;
j
++
)
{
// cycle all 256 colors in the wheel
for
(
int
q
=
0
;
q
<
3
;
q
++
)
{
for
(
int
i
=
0
;
i
<
strip
.
numPixels
();
i
=
i
+
3
)
{
strip
.
setPixelColor
(
i
+
q
,
Wheel
(
(
i
+
j
)
%
255
));
//turn every third pixel on
}
strip
.
show
();
delay
(
wait
);
for
(
int
i
=
0
;
i
<
strip
.
numPixels
();
i
=
i
+
3
)
{
strip
.
setPixelColor
(
i
+
q
,
0
);
//turn every third pixel off
}
}
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t
Wheel
(
byte
WheelPos
)
{
if
(
WheelPos
<
85
)
{
return
strip
.
Color
(
WheelPos
*
3
,
255
-
WheelPos
*
3
,
0
);
}
else
if
(
WheelPos
<
170
)
{
WheelPos
-=
85
;
return
strip
.
Color
(
255
-
WheelPos
*
3
,
0
,
WheelPos
*
3
);
}
else
{
WheelPos
-=
170
;
return
strip
.
Color
(
0
,
WheelPos
*
3
,
255
-
WheelPos
*
3
);
}
}
void
setup
()
{
// Open //Serial communications and wait for port to open:
//Serial.begin(9600);
//while (!//Serial) {
//; // wait for //Serial port to connect. Needed for Leonardo only
//}
//Serial.println("//Serial Port Opened");
// start the Ethernet connection and the server:
//Serial.println("Starting Ethernet");
Ethernet
.
begin
(
mac
,
ip
);
//Serial.println("Setting Up Server");
webserver
.
setDefaultCommand
(
&
webSetSequence
);
webserver
.
addCommand
(
"custom"
,
&
webSetSequence
);
webserver
.
addCommand
(
"individual"
,
&
webSetLED
);
webserver
.
addCommand
(
"brightness"
,
&
webSetBrightness
);
//Serial.println("Starting Server");
webserver
.
begin
();
//Serial.print("server is at ");
//Serial.println(Ethernet.localIP());
// Initialize our LED Array
for
(
int
i
=
0
;
i
<
STRIPLENGTH
;
i
++
)
{
ledArray
[
i
].
red
=
(
char
)
128
;
ledArray
[
i
].
green
=
(
char
)
128
;
ledArray
[
i
].
blue
=
(
char
)
128
;
}
// Start Lights
strip
.
begin
();
//strip.show();
strip
.
setBrightness
(
32
);
showArray
();
}
void
loop
()
{
// process incoming connections one at a time forever
char
buff
[
64
];
int
len
=
64
;
webserver
.
processConnection
(
buff
,
&
len
);
position
=
position
%
256
;
rainbow
(
10
);
// Run our light sequence after checking for we requests
/*switch (lightOption) {
case 0:
break;
case 1:
colorWipe(strip.Color(255, 0, 0), 50); // Red
break;
case 2:
colorWipe(strip.Color(0, 255, 0), 50); // Green
break;
case 3:
colorWipe(strip.Color(0, 0, 255), 50); // Blue
break;
case 4:
theaterChase(strip.Color(127, 127, 127), 50); // White
break;
case 5:
theaterChase(strip.Color(127, 0, 0), 50); // Red
break;
case 6:
theaterChase(strip.Color( 0, 0, 127), 50); // Blue
break;
case 7:
rainbow(100);
break;
case 8:
rainbowCycle(20);
break;
case 9:
theaterChaseRainbow(50);
break;
default:
lightOption = 7;
break;
}*/
showArray
();
}
libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp
0 → 100644
View file @
d9e5da97
/*-------------------------------------------------------------------------
Arduino library to control a wide variety of WS2811- and WS2812-based RGB
LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips.
Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega
MCUs, with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide
output on PORTB and PORTD, while 16 MHz chips can handle most output pins
(possible exception with upper PORT registers on the Arduino Mega).
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries,
contributions by PJRC and other members of the open source community.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing products
from Adafruit!
-------------------------------------------------------------------------
This file is part of the Adafruit NeoPixel library.
NeoPixel is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#include "Adafruit_NeoPixel.h"
Adafruit_NeoPixel
::
Adafruit_NeoPixel
(
uint16_t
n
,
uint8_t
p
,
uint8_t
t
)
:
numLEDs
(
n
),
numBytes
(
n
*
3
),
pin
(
p
),
pixels
(
NULL
)
#if defined(NEO_RGB) || defined(NEO_KHZ400)
,
type
(
t
)
#endif
#ifdef __AVR__
,
port
(
portOutputRegister
(
digitalPinToPort
(
p
))),
pinMask
(
digitalPinToBitMask
(
p
))
#endif
{
if
((
pixels
=
(
uint8_t
*
)
malloc
(
numBytes
)))
{
memset
(
pixels
,
0
,
numBytes
);
}
}
Adafruit_NeoPixel
::~
Adafruit_NeoPixel
()
{
if
(
pixels
)
free
(
pixels
);
pinMode
(
pin
,
INPUT
);
}
void
Adafruit_NeoPixel
::
begin
(
void
)
{
pinMode
(
pin
,
OUTPUT
);
digitalWrite
(
pin
,
LOW
);
}
void
Adafruit_NeoPixel
::
show
(
void
)
{
if
(
!
pixels
)
return
;
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while
((
micros
()
-
endTime
)
<
50L
);
// endTime is a private member (rather than global var) so that mutliple
// instances on different pins can be quickly issued in succession (each
// instance doesn't delay the next).
// In order to make this code runtime-configurable to work with any pin,
// SBI/CBI instructions are eschewed in favor of full PORT writes via the
// OUT or ST instructions. It relies on two facts: that peripheral
// functions (such as PWM) take precedence on output pins, so our PORT-
// wide writes won't interfere, and that interrupts are globally disabled
// while data is being issued to the LEDs, so no other code will be
// accessing the PORT. The code takes an initial 'snapshot' of the PORT
// state, computes 'pin high' and 'pin low' values, and writes these back
// to the PORT register as needed.
noInterrupts
();
// Need 100% focus on instruction timing
#ifdef __AVR__
volatile
uint16_t
i
=
numBytes
;
// Loop counter
volatile
uint8_t
*
ptr
=
pixels
,
// Pointer to next byte
b
=
*
ptr
++
,
// Current byte value
hi
,
// PORT w/output bit set high
lo
;
// PORT w/output bit set low
// Hand-tuned assembly code issues data to the LED drivers at a specific
// rate. There's separate code for different CPU speeds (8, 12, 16 MHz)
// for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The
// datastream timing for the LED drivers allows a little wiggle room each
// way (listed in the datasheets), so the conditions for compiling each
// case are set up for a range of frequencies rather than just the exact
// 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on
// devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based
// on the datasheet figures and have not been extensively tested outside
// the canonical 8/12/16 MHz speeds; there's no guarantee these will work
// close to the extremes (or possibly they could be pushed further).
// Keep in mind only one CPU speed case actually gets compiled; the
// resulting program isn't as massive as it might look from source here.
// 8 MHz(ish) AVR ---------------------------------------------------------
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL)
#ifdef NEO_KHZ400
if
((
type
&
NEO_SPDMASK
)
==
NEO_KHZ800
)
{
// 800 KHz bitstream
#endif
volatile
uint8_t
n1
,
n2
=
0
;
// First, next bits out
// Squeezing an 800 KHz stream out of an 8 MHz chip requires code
// specific to each PORT register. At present this is only written
// to work with pins on PORTD or PORTB, the most likely use case --
// this covers all the pins on the Adafruit Flora and the bulk of
// digital pins on the Arduino Pro 8 MHz (keep in mind, this code
// doesn't even get compiled for 16 MHz boards like the Uno, Mega,
// Leonardo, etc., so don't bother extending this out of hand).
// Additional PORTs could be added if you really need them, just
// duplicate the else and loop and change the PORT. Each add'l
// PORT will require about 150(ish) bytes of program space.