ArduinoLibs
|
00001 /* 00002 * Copyright (C) 2012 Southern Storm Software, Pty Ltd. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00020 * DEALINGS IN THE SOFTWARE. 00021 */ 00022 00023 #include "Charlieplex.h" 00024 #if defined(ARDUINO) && ARDUINO >= 100 00025 #include <Arduino.h> 00026 #else 00027 #include <WProgram.h> 00028 #endif 00029 #include <stdlib.h> 00030 #include <string.h> 00031 00121 Charlieplex::Charlieplex(const uint8_t *pins, uint8_t numPins) 00122 : _count(((int)numPins) * (numPins - 1)) 00123 , _lastTime(micros()) 00124 , _currentIndex(-1) 00125 , _pwmPhase(0xC0) 00126 { 00127 // Determine the best hold time for 50 Hz refresh when all LED's 00128 // are lit. Divide it again by 4 (to get 200 Hz) to manage the 00129 // simulated PWM in refresh(). 00130 _holdTime = 20000 / _count / 4; 00131 00132 // Allocate the pin arrays and populate them. Doing this now makes 00133 // refresh() more efficient later, at the expense of some memory. 00134 _pins1 = (uint8_t *)malloc(_count); 00135 _pins2 = (uint8_t *)malloc(_count); 00136 int n = 0; 00137 for (uint8_t pass = 1; pass < numPins; ++pass) { 00138 for (uint8_t pin = 0; pin < (numPins - pass); ++pin) { 00139 _pins1[n] = _pins2[n + 1] = pins[pin]; 00140 _pins2[n] = _pins1[n + 1] = pins[pin + pass]; 00141 n += 2; 00142 } 00143 } 00144 00145 // Allocate space for the LED value array and zero it. 00146 _values = (uint8_t *)malloc(_count); 00147 memset(_values, 0, _count); 00148 00149 // Start with all pins configured as floating inputs (all LED's off). 00150 for (uint8_t pin = 0; pin < numPins; ++pin) { 00151 digitalWrite(pins[pin], LOW); 00152 pinMode(pins[pin], INPUT); 00153 } 00154 } 00155 00159 Charlieplex::~Charlieplex() 00160 { 00161 free(_pins1); 00162 free(_pins2); 00163 free(_values); 00164 } 00165 00277 void Charlieplex::loop() 00278 { 00279 unsigned long us = micros(); 00280 if ((us - _lastTime) >= _holdTime) { 00281 _lastTime = us; 00282 refresh(); 00283 } 00284 } 00285 00296 void Charlieplex::refresh() 00297 { 00298 // Find the next LED to be lit. 00299 int prevIndex = _currentIndex; 00300 int limit = _count; 00301 while (limit >= 0) { 00302 _currentIndex = (_currentIndex + 1) % _count; 00303 if (_values[_currentIndex] != 0) 00304 break; 00305 --limit; 00306 } 00307 if (limit < 0) { 00308 // No LED's are lit. Turn off the previous LED and exit. 00309 if (prevIndex != -1) { 00310 digitalWrite(_pins1[prevIndex], LOW); 00311 digitalWrite(_pins2[prevIndex], LOW); 00312 pinMode(_pins1[prevIndex], INPUT); 00313 pinMode(_pins2[prevIndex], INPUT); 00314 } 00315 _currentIndex = -1; 00316 return; 00317 } 00318 00319 // Light the current LED. 00320 uint8_t value = _values[_currentIndex]; 00321 uint8_t pin1 = _pins1[_currentIndex]; 00322 uint8_t pin2 = _pins2[_currentIndex]; 00323 _pwmPhase += 0x40; 00324 if (prevIndex != _currentIndex) { 00325 // Turn off the previous LED. 00326 if (prevIndex != -1) { 00327 digitalWrite(_pins1[prevIndex], LOW); 00328 digitalWrite(_pins2[prevIndex], LOW); 00329 pinMode(_pins1[prevIndex], INPUT); 00330 pinMode(_pins2[prevIndex], INPUT); 00331 } 00332 00333 // We simulate PWM using a phase counter because analogWrite() 00334 // combined with holdTime() causes too much flickering if more 00335 // than one LED is lit. This reduces the PWM resolution to 1 in 4. 00336 pinMode(pin1, OUTPUT); 00337 pinMode(pin2, OUTPUT); 00338 if (value > _pwmPhase) 00339 digitalWrite(pin1, HIGH); 00340 else 00341 digitalWrite(pin1, LOW); 00342 } else { 00343 // Same LED as previous. Since there is only a single LED 00344 // that is lit, we can use analogWrite() to set the PWM state. 00345 if (value == 255) 00346 digitalWrite(pin1, HIGH); 00347 else 00348 analogWrite(pin1, value); 00349 } 00350 }