Made MD* libraries (Parola, MAX72XX) project specific, to be able to use the newest software version from github.

This commit is contained in:
2019-02-01 15:21:58 +01:00
parent fe9f25c856
commit c7547144d2
761 changed files with 108577 additions and 2 deletions

View 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);
};

View 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

View 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();
}