Made MD* libraries (Parola, MAX72XX) project specific, to be able to use the newest software version from github.
This commit is contained in:
253
lib/MD_MAX72XX/examples/MD_MAX72xx_Eyes/MD_EyePair.cpp
Normal file
253
lib/MD_MAX72XX/examples/MD_MAX72xx_Eyes/MD_EyePair.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
#include "MD_EyePair.h"
|
||||
|
||||
// Packing and unpacking nybbles into a byte
|
||||
#define PACK_RC(r, c) ((r<<4)|(c&0xf))
|
||||
#define UNPACK_R(rc) (rc>>4)
|
||||
#define UNPACK_C(rc) (rc&0xf)
|
||||
|
||||
#define SMALL_EYEBALL 0
|
||||
|
||||
// Class static variables
|
||||
|
||||
#if SMALL_EYEBALL
|
||||
uint8_t MD_EyePair::_pupilData[] =
|
||||
{
|
||||
/* P_TL */ PACK_RC(2,5), /* P_TC */ PACK_RC(2,4), /* P_TR */ PACK_RC(2,3),
|
||||
/* P_ML */ PACK_RC(3,5), /* P_MC */ PACK_RC(3,4), /* P_MR */ PACK_RC(3,3),
|
||||
/* P_BL */ PACK_RC(4,5), /* P_BC */ PACK_RC(4,4), /* P_BR */ PACK_RC(4,3),
|
||||
};
|
||||
|
||||
// Eye related information
|
||||
uint8_t MD_EyePair::_eyeballData[EYEBALL_ROWS] = { 0x00, 0x3c, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c, 0x00 }; // row data
|
||||
#define LAST_BLINK_ROW 6 // last row for the blink animation
|
||||
|
||||
#else
|
||||
|
||||
uint8_t MD_EyePair::_pupilData[] =
|
||||
{
|
||||
/* P_TL */ PACK_RC(3,5), /* P_TC */ PACK_RC(3,4), /* P_TR */ PACK_RC(3,3),
|
||||
/* P_ML */ PACK_RC(4,5), /* P_MC */ PACK_RC(4,4), /* P_MR */ PACK_RC(4,3),
|
||||
/* P_BL */ PACK_RC(5,5), /* P_BC */ PACK_RC(5,4), /* P_BR */ PACK_RC(5,3),
|
||||
};
|
||||
uint8_t MD_EyePair::_eyeballData[EYEBALL_ROWS] = { 0x3c, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c }; // row data
|
||||
#define LAST_BLINK_ROW 7 // last row for the blink animation
|
||||
|
||||
#endif
|
||||
|
||||
// Random seed creation --------------------------
|
||||
// Adapted from http://www.utopiamechanicus.com/article/arduino-better-random-numbers/
|
||||
|
||||
uint16_t MD_EyePair::bitOut(uint8_t port)
|
||||
{
|
||||
static bool firstTime = true;
|
||||
uint32_t prev = 0;
|
||||
uint32_t bit1 = 0, bit0 = 0;
|
||||
uint32_t x = 0, limit = 99;
|
||||
|
||||
if (firstTime)
|
||||
{
|
||||
firstTime = false;
|
||||
prev = analogRead(port);
|
||||
}
|
||||
|
||||
while (limit--)
|
||||
{
|
||||
x = analogRead(port);
|
||||
bit1 = (prev != x ? 1 : 0);
|
||||
prev = x;
|
||||
x = analogRead(port);
|
||||
bit0 = (prev != x ? 1 : 0);
|
||||
prev = x;
|
||||
if (bit1 != bit0)
|
||||
break;
|
||||
}
|
||||
|
||||
return(bit1);
|
||||
}
|
||||
|
||||
uint32_t MD_EyePair::seedOut(uint16_t noOfBits, uint8_t port)
|
||||
{
|
||||
// return value with 'noOfBits' random bits set
|
||||
uint32_t seed = 0;
|
||||
|
||||
for (int i = 0; i<noOfBits; ++i)
|
||||
seed = (seed << 1) | bitOut(port);
|
||||
|
||||
return(seed);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
MD_EyePair::MD_EyePair(void)
|
||||
{
|
||||
_pupilCurPos = P_MC;
|
||||
_timeLast = 0;
|
||||
_inBlinkCycle = false;
|
||||
};
|
||||
|
||||
void MD_EyePair::drawEyeball()
|
||||
// Draw the iris on the display(s)
|
||||
{
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
_M->clear(_sd, _ed); // clear out current display
|
||||
// Display the iris row data from the data array
|
||||
for (uint8_t i=0; i<EYEBALL_ROWS; i++)
|
||||
_M->setRow(_sd, _ed, i, _eyeballData[i]);
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
bool MD_EyePair::blinkEyeball(bool bFirst)
|
||||
// Blink the iris. If this is the first call in the cycle, bFirst will be set true.
|
||||
// Return true if the blink is still active, false otherwise.
|
||||
{
|
||||
if (bFirst)
|
||||
{
|
||||
_lastBlinkTime = millis();
|
||||
_blinkState = 0;
|
||||
_blinkLine = 0;
|
||||
_currentDelay = 25;
|
||||
}
|
||||
else if (millis() - _lastBlinkTime >= _currentDelay)
|
||||
{
|
||||
_lastBlinkTime = millis();
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
switch(_blinkState)
|
||||
{
|
||||
case 0: // initialization - save the current eye pattern assuming both eyes are the same
|
||||
for (uint8_t i=0; i<EYEBALL_ROWS; i++)
|
||||
_savedEyeball[i] = _M->getRow(_sd, i);
|
||||
_blinkState = 1;
|
||||
// fall through
|
||||
|
||||
case 1: // blink the eye shut
|
||||
_M->setRow(_sd, _ed, _blinkLine, 0);
|
||||
_blinkLine++;
|
||||
if (_blinkLine == LAST_BLINK_ROW) // this is the last row of the animation
|
||||
{
|
||||
_blinkState = 2;
|
||||
_currentDelay *= 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // set up for eye opening
|
||||
_currentDelay /= 2;
|
||||
_blinkState = 3;
|
||||
// fall through
|
||||
|
||||
case 3:
|
||||
_blinkLine--;
|
||||
_M->setRow(_sd, _ed, _blinkLine, _savedEyeball[_blinkLine]);
|
||||
|
||||
if (_blinkLine == 0)
|
||||
{
|
||||
_blinkState = 99;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
return(_blinkState != 99);
|
||||
}
|
||||
|
||||
void MD_EyePair::drawPupil(posPupil_t posOld, posPupil_t posNew)
|
||||
// Draw the pupil in the current position. Needs to erase the
|
||||
// old position first, then put in the new position
|
||||
{
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
// first blank out the old pupil by writing back the
|
||||
// eyeball background 'row'
|
||||
{
|
||||
uint8_t row = UNPACK_R(_pupilData[posOld]);
|
||||
|
||||
_M->setRow(_sd, _ed, row, _eyeballData[row]);
|
||||
_M->setRow(_sd, _ed, row+1, _eyeballData[row+1]);
|
||||
}
|
||||
|
||||
// now show the new pupil by displaying the new background 'row'
|
||||
// with the pupil masked out of it
|
||||
{
|
||||
uint8_t row = UNPACK_R(_pupilData[posNew]);
|
||||
uint8_t col = UNPACK_C(_pupilData[posNew]);
|
||||
uint8_t colMask = ~((1<<col)|(1<<(col-1)));
|
||||
|
||||
_M->setRow(_sd, _ed, row, (_eyeballData[row]&colMask));
|
||||
_M->setRow(_sd, _ed, row+1, (_eyeballData[row+1]&colMask));
|
||||
}
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
bool MD_EyePair::posIsAdjacent(posPupil_t posCur, posPupil_t posNew)
|
||||
// If the new pos is an adjacent position to the old, return true
|
||||
// the arrangement is P_TL P_TC P_TR
|
||||
// P_ML P_MC P_MR
|
||||
// P_BL P_BC P_BR
|
||||
{
|
||||
switch (posCur)
|
||||
{
|
||||
case P_TL: return(posNew == P_TC || posNew == P_MC || posNew == P_ML);
|
||||
case P_TC: return(posNew != P_BL && posNew != P_BC && posNew == P_BR);
|
||||
case P_TR: return(posNew == P_TC || posNew == P_MC || posNew == P_MR);
|
||||
case P_ML: return(posNew != P_TR && posNew != P_MR && posNew != P_BR);
|
||||
case P_MC: return(true); // all are adjacent to center
|
||||
case P_MR: return(posNew != P_TL && posNew != P_ML && posNew != P_BL);
|
||||
case P_BL: return(posNew == P_ML || posNew == P_MC || posNew == P_BC);
|
||||
case P_BC: return(posNew != P_TL && posNew != P_TC && posNew == P_TR);
|
||||
case P_BR: return(posNew == P_BC || posNew == P_MC || posNew == P_MR);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
void MD_EyePair::begin(uint8_t startDev, MD_MAX72XX *M, uint16_t maxDelay)
|
||||
// initialisz the eyes
|
||||
{
|
||||
_sd = startDev;
|
||||
_ed = startDev + 1;
|
||||
_M = M;
|
||||
_timeDelay = _maxDelay = maxDelay;
|
||||
|
||||
randomSeed(seedOut(31, RANDOM_SEED_PORT));
|
||||
|
||||
drawEyeball();
|
||||
drawPupil(_pupilCurPos, _pupilCurPos);
|
||||
};
|
||||
|
||||
void MD_EyePair::animate(void)
|
||||
// Animate the eye(s).
|
||||
// this cane either be a blink or an eye movement
|
||||
{
|
||||
// do the blink if we are currently already blinking
|
||||
if (_inBlinkCycle)
|
||||
{
|
||||
_inBlinkCycle = blinkEyeball(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Possible animation - only animate every timeDelay ms
|
||||
if (millis() - _timeLast <= _timeDelay)
|
||||
return;
|
||||
|
||||
// set up timers for next time
|
||||
_timeLast = millis();
|
||||
_timeDelay = random(_maxDelay);
|
||||
|
||||
// Do the animation most of the time, so bias the
|
||||
// random number check to achieve this
|
||||
if (random(1000) <= 900)
|
||||
{
|
||||
posPupil_t pupilNewPos = (posPupil_t)random(9);
|
||||
|
||||
if (posIsAdjacent(_pupilCurPos, pupilNewPos))
|
||||
{
|
||||
drawPupil(_pupilCurPos, pupilNewPos);
|
||||
_pupilCurPos = pupilNewPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
// blink the eyeball
|
||||
_inBlinkCycle = blinkEyeball(true);
|
||||
};
|
63
lib/MD_MAX72XX/examples/MD_MAX72xx_Eyes/MD_EyePair.h
Normal file
63
lib/MD_MAX72XX/examples/MD_MAX72xx_Eyes/MD_EyePair.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// Implements a class to draw and animate a pair of eyes
|
||||
#ifndef MDEYEPAIR_H
|
||||
#define MDEYEPAIR_H
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
|
||||
// Misc defines
|
||||
#define EYEBALL_ROWS 8 // number of rows in the eyeball definition
|
||||
#define RANDOM_SEED_PORT A0 // for random seed bit shuffling
|
||||
|
||||
class MD_EyePair
|
||||
{
|
||||
public:
|
||||
MD_EyePair(void);
|
||||
~MD_EyePair(void) { };
|
||||
|
||||
void begin(uint8_t startdev, MD_MAX72XX *M, uint16_t maxDelay);
|
||||
void animate(void);
|
||||
|
||||
protected:
|
||||
// Pupil related information
|
||||
enum posPupil_t // Initials are for Top, Middle and Bottom; Left, Center and Right (eg, TL = Top Left)
|
||||
{
|
||||
P_TL = 0, P_TC = 1, P_TR = 2,
|
||||
P_ML = 3, P_MC = 4, P_MR = 5,
|
||||
P_BL = 6, P_BC = 7, P_BR = 8
|
||||
};
|
||||
|
||||
// Class static data
|
||||
static uint8_t _pupilData[];
|
||||
static uint8_t _eyeballData[];
|
||||
|
||||
// display parameters
|
||||
MD_MAX72XX *_M;
|
||||
uint8_t _sd; // start device
|
||||
uint8_t _ed; // end device
|
||||
|
||||
// blinking parameters
|
||||
uint32_t _lastBlinkTime;
|
||||
uint16_t _currentDelay;
|
||||
uint8_t _blinkState;
|
||||
uint8_t _savedEyeball[EYEBALL_ROWS];
|
||||
uint8_t _blinkLine;
|
||||
|
||||
// animation parameters
|
||||
posPupil_t _pupilCurPos; // the current position for the pupil
|
||||
uint32_t _timeLast;
|
||||
uint16_t _timeDelay;
|
||||
uint16_t _maxDelay;
|
||||
bool _inBlinkCycle;
|
||||
|
||||
// methods
|
||||
void drawEyeball(void);
|
||||
bool blinkEyeball(bool bFirst);
|
||||
void drawPupil(posPupil_t posOld, posPupil_t posNew);
|
||||
bool posIsAdjacent(posPupil_t posCur, posPupil_t posNew);
|
||||
|
||||
// random seed creation
|
||||
uint16_t MD_EyePair::bitOut(uint8_t port);
|
||||
uint32_t MD_EyePair::seedOut(uint16_t noOfBits, uint8_t port);
|
||||
};
|
||||
|
||||
#endif
|
49
lib/MD_MAX72XX/examples/MD_MAX72xx_Eyes/MD_MAX72xx_Eyes.ino
Normal file
49
lib/MD_MAX72XX/examples/MD_MAX72xx_Eyes/MD_MAX72xx_Eyes.ino
Normal file
@@ -0,0 +1,49 @@
|
||||
// Program to exercise the MD_MAX72XX library
|
||||
//
|
||||
// Uses the graphics functions to animate a pair of eyes on 2 matrix modules.
|
||||
// Eyes are coordinated to work together.
|
||||
// Eyes are created to fill all available modules.
|
||||
//
|
||||
//
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
#include "MD_EyePair.h"
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
|
||||
#define MAX_DEVICES 10
|
||||
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX M = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX eye = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// Define the eyes!
|
||||
#define MAX_EYE_PAIR (MAX_DEVICES/2)
|
||||
|
||||
MD_EyePair E[MAX_EYE_PAIR];
|
||||
|
||||
// Miscellaneous defines
|
||||
#define DELAYTIME 500 // in milliseconds
|
||||
|
||||
void setup()
|
||||
{
|
||||
M.begin();
|
||||
|
||||
// initialize the eye view
|
||||
for (uint8_t i=0; i<MAX_EYE_PAIR; i++)
|
||||
E[i].begin(i*2, &M, DELAYTIME);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
for (uint8_t i=0; i<MAX_EYE_PAIR; i++)
|
||||
E[i].animate();
|
||||
}
|
||||
|
Reference in New Issue
Block a user