Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* necessary libraries, ensure they are
- installed in Arduino IDE before uploading */
- #include <MD_Parola.h>
- #include <MD_MAX72xx.h>
- #include <SPI.h>
- #include <CircularBuffer.h>
- #define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW // change if using PAROLA_HW or other LED hardware, incorrect setting can cause orientation issues
- /* settings: */
- const byte MAX_DEVICES = 1; // number of LED modules, should always be one in this setup - unsure if more would work with no issues
- const byte CLK_PIN = 13; // LED's CLK pin
- const byte DATA_PIN = 11; // LED's DATA pin
- const byte CS_PIN = 10; // LED's CS pin
- const byte NUM_GEARS = 7; // how many gears are used - must match the number of gear characters in GearChars array
- const uint8_t BUFFER_SIZE = 4; // set number of stored previous gear states - 4 used here used to detect 'sequence' such as 1-2-1-2, which can then be acted upon
- const char GearChars[NUM_GEARS] = {'P', 'R', 'N', 'D', '3', '2', '1'}; // layout here from left to right should match gear order on vehicle from top to bottom/start to finish
- const uint8_t Hall[] = { 3, 4, 5, 6, 7, 8 }; // sensor pins in the same order as GearChars array - 'Park' position is assumed to not have a sensor and so first pin is "R"
- const char StartupText[] = {"Startup Text"}; // text scrolled upon boot
- const char ANIM_SEQUENCE[BUFFER_SIZE] = {'D', 'N', 'D', 'N'}; // sequence of gears necessary to activate animation (i.e. D-N-D-N), must be same length as BUFFER_SIZE
- //const char DEBUG_SEQUENCE = {'1', '2', '1', '2'}; // sequence of gears necessary to activate DEBUG mode (i.e. 1-2-1-2), must be same length as BUFFER_SIZE
- const uint8_t SCROLL_SPEED = 75; // speed that StartupText is scrolled, number is milliseconds between frame updates
- const byte BRIGHTNESS = 4; // set brightness of LEDs (0-15), can replace with potentiometer-derived value
- const uint8_t DEBUG_MODE = 0; // set to 1 to enable debugging via Serial (baud)
- const uint8_t DEBUG_READS = BUFFER_SIZE; // number of readings in debug mode, recommended to match buffer size or larger
- const int DEBUG_DELAY = 3000; // delay between debug readings in milliseconds (3 seconds by default)
- const int BAUD_SPEED = 9600; // set baud rate here for Serial communication
- const int8_t NUM_LOOPS = NUM_GEARS - 1; // used for loop counting etc when starting with 0
- MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // creates display instance using given settings
- /* Sprite definitions - stored in RAM/PROGMEM to save memory */
- const uint8_t F_PMAN = 6;
- const uint8_t W_PMAN = 8;
- const uint8_t PROGMEM pacman[F_PMAN * W_PMAN] = // gobbling pacman animation
- {
- 0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c,
- 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
- 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
- 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c,
- 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
- 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
- };
- const uint8_t F_PMANGHOST = 6;
- const uint8_t W_PMANGHOST = 18;
- static const uint8_t PROGMEM pacmanghost[F_PMANGHOST * W_PMANGHOST] = // ghost pursued by pacman
- {
- 0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
- 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
- 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
- 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe,
- 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe,
- 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe,
- };
- const uint8_t F_SAILBOAT = 1;
- const uint8_t W_SAILBOAT = 11;
- const uint8_t PROGMEM sailboat[F_SAILBOAT * W_SAILBOAT] = // sail boat
- {
- 0x10, 0x30, 0x58, 0x94, 0x92, 0x9f, 0x92, 0x94, 0x98, 0x50, 0x30,
- };
- const uint8_t F_STEAMBOAT = 2;
- const uint8_t W_STEAMBOAT = 11;
- const uint8_t PROGMEM steamboat[F_STEAMBOAT * W_STEAMBOAT] = // steam boat
- {
- 0x10, 0x30, 0x50, 0x9c, 0x9e, 0x90, 0x91, 0x9c, 0x9d, 0x90, 0x71,
- 0x10, 0x30, 0x50, 0x9c, 0x9c, 0x91, 0x90, 0x9d, 0x9e, 0x91, 0x70,
- };
- const uint8_t F_HEART = 5;
- const uint8_t W_HEART = 9;
- const uint8_t PROGMEM beatingheart[F_HEART * W_HEART] = // beating heart
- {
- 0x0e, 0x11, 0x21, 0x42, 0x84, 0x42, 0x21, 0x11, 0x0e,
- 0x0e, 0x1f, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x1f, 0x0e,
- 0x0e, 0x1f, 0x3f, 0x7e, 0xfc, 0x7e, 0x3f, 0x1f, 0x0e,
- 0x0e, 0x1f, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x1f, 0x0e,
- 0x0e, 0x11, 0x21, 0x42, 0x84, 0x42, 0x21, 0x11, 0x0e,
- };
- const uint8_t F_INVADER = 2;
- const uint8_t W_INVADER = 10;
- const uint8_t PROGMEM spaceinvader[F_INVADER * W_INVADER] = // space invader
- {
- 0x0e, 0x98, 0x7d, 0x36, 0x3c, 0x3c, 0x36, 0x7d, 0x98, 0x0e,
- 0x70, 0x18, 0x7d, 0xb6, 0x3c, 0x3c, 0xb6, 0x7d, 0x18, 0x70,
- };
- const uint8_t F_FIRE = 2;
- const uint8_t W_FIRE = 11;
- const uint8_t PROGMEM fire[F_FIRE * W_FIRE] = // fire
- {
- 0x7e, 0xab, 0x54, 0x28, 0x52, 0x24, 0x40, 0x18, 0x04, 0x10, 0x08,
- 0x7e, 0xd5, 0x2a, 0x14, 0x24, 0x0a, 0x30, 0x04, 0x28, 0x08, 0x10,
- };
- const uint8_t F_WALKER = 5;
- const uint8_t W_WALKER = 7;
- const uint8_t PROGMEM walker[F_WALKER * W_WALKER] = // walking stick figure
- {
- 0x00, 0x48, 0x77, 0x1f, 0x1c, 0x94, 0x68,
- 0x00, 0x90, 0xee, 0x3e, 0x38, 0x28, 0xd0,
- 0x00, 0x00, 0xae, 0xfe, 0x38, 0x28, 0x40,
- 0x00, 0x00, 0x2e, 0xbe, 0xf8, 0x00, 0x00,
- 0x00, 0x10, 0x6e, 0x3e, 0xb8, 0xe8, 0x00,
- };
- /* Struct used for sprite settings. */
- struct
- {
- const uint8_t *data;
- uint8_t width;
- uint8_t frames;
- }
- sprite[] =
- {
- { fire, W_FIRE, F_FIRE },
- { pacman, W_PMAN, F_PMAN },
- { walker, W_WALKER, F_WALKER },
- { beatingheart, W_HEART, F_HEART },
- { sailboat, W_SAILBOAT, F_SAILBOAT },
- { spaceinvader, W_INVADER, F_INVADER },
- { steamboat, W_STEAMBOAT, F_STEAMBOAT },
- { pacmanghost, W_PMANGHOST, F_PMANGHOST }
- };
- /* variables will change: */
- int8_t currentGear;
- CircularBuffer<byte, BUFFER_SIZE> previousGears; // a buffer to store previous gear positions
- void setup() {
- hallSetup(); // initialise sensors
- displaySetup(); // initialise display
- currentGear = 0; // set current gear to 'Parked' position until first sensor read to establish known state
- previousGears.push(currentGear); // push 'Park' {"P"} position to buffer also, which is translated to *char via GearChars[0]
- if (DEBUG_MODE == 1) { // check if DEBUG_MODE is enabled, and runs debugFunction() if TRUE
- Serial.begin(BAUD_SPEED);
- debugFunction();
- }
- }
- void loop() {
- currentGear = getGear(); // read hall effect sensors and calculate current gear position
- displayGear(currentGear); // display the current gear, with appropriate animation if different from previous gear
- checkHistory(); // checks gear history for defined sequences and calls relevant functions
- }
- /* writes 4 (or DEBUG_READS) lots of readings from
- all sensors to Serial, with a delay to allow changing
- gear, and fills & prints buffer, for debugging purposes */
- void debugFunction() {
- String buf = "";
- String bufChars = "";
- for (int8_t i = 0; i < DEBUG_READS; i++) {
- delay(DEBUG_DELAY); // wait to allow gear changing/hall sensor/magnet position changes
- for (int8_t x = 0; x < NUM_LOOPS; x++) { // loop through all sensors and print values to Serial
- Serial.println(
- String(x + 1) +
- "| Digital: " +
- String(digitalRead(Hall[x])) +
- " Analogue: " +
- String(analogRead(Hall[x]))
- );
- }
- previousGears.push(GearChars[random(NUM_LOOPS)]); // push pseudorandom GearChar values to buffer
- buf = buf + previousGears.last(); // add current gear in numeric form to a string for printing to Serial
- bufChars = bufChars + GearChars[previousGears.last()]; // add current gear in char form to a string for printing to Serial
- }
- Serial.println("Buffer contents: " + buf); // ...print buffer contents, to Serial...
- while (true); // puts arduino into an infinite loop, reboot to start again
- }
- /* initialize the hall effect sensor pins as inputs: */
- void hallSetup() {
- for (int8_t i = 0; i < NUM_LOOPS; i++) {
- pinMode(Hall[i], INPUT);
- }
- }
- /* setup LED display */
- void displaySetup() {
- P.begin(); // initialise display
- P.setIntensity(BRIGHTNESS); // set display intensity/brightness
- P.displayClear();
- P.displayScroll(StartupText, PA_LEFT, PA_SCROLL_LEFT, SCROLL_SPEED); // display message on startup
- while (!P.displayAnimate()) // play animation once until complete
- ;
- P.displayReset();
- P.displayClear();
- }
- /* loop through sensors until LOW reading detected */
- int8_t getGear() {
- int8_t gear = NUM_LOOPS;
- while ((gear) && (digitalRead(Hall[gear - 1]))) {
- gear--;
- }
- return gear;
- }
- /* displays current gear on LED, checks if animations
- should be used depending on previous gear value */
- void displayGear(int8_t gearValue) {
- char curGearChar[2] = {GearChars[gearValue]}; // convert gearValue to c-string character for display purposes by pulling from null terminated array using pointers
- if (gearValue == previousGears.last()) { // if current gear is same as previous, simply print
- P.displayText(curGearChar, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT); // set display settings
- P.displayAnimate(); // display appropriate character
- }
- else if ((previousGears.last() < gearValue)) { // if the previous gear is situated to the left of current gear (in char array) then scroll down
- P.displayText(
- curGearChar, PA_CENTER, SCROLL_SPEED, 1, PA_SCROLL_DOWN, PA_NO_EFFECT // set scrolling text settings
- );
- while (!P.displayAnimate()) // play once animation until complete
- ;
- previousGears.push(gearValue); // push current gear to buffer as it is different
- } else { // if the previous gear is not situated left (i.e. is to the right of current gear in char array) then scroll up
- P.displayText(
- curGearChar, PA_CENTER, SCROLL_SPEED, 1, PA_SCROLL_UP, PA_NO_EFFECT
- );
- while (!P.displayAnimate())
- ;
- previousGears.push(gearValue); // push current gear to buffer as it is different
- }
- }
- /* WIP */
- /* checks for given sequence of gear changes and calls other functions as required */
- void checkHistory() {
- if (previousGears.isFull()) {
- char gearHistory[BUFFER_SIZE]; // create new char array from history for comparison
- for (int8_t i = 0; i < BUFFER_SIZE; i++) { // loop to populate array with char equivalents
- gearHistory[i] = GearChars[previousGears[i]];
- }
- if (checkArrays(gearHistory, ANIM_SEQUENCE, BUFFER_SIZE) == true) { // compares the two arrays; if buffer history matches ANIM_SEQUENCE, then display animation
- displayAnimation(random(ARRAY_SIZE(sprite) - 1)); // selects and displays random animation from struct array
- }
- }
- }
- /* compares 2 char arrays and returns boolean result */
- boolean checkArrays(char arrayA[], char arrayB[], long numItems) {
- boolean match = true;
- long i = 0;
- while (i < numItems && match) {
- match = (arrayA[i] == arrayB[i]);
- i++;
- }
- return match;
- }
- /* displays selected animation */
- void displayAnimation(byte selection) {
- char curGearChar[2] = {GearChars[previousGears.last()]};
- P.displayReset();
- P.displayClear();
- P.setSpriteData(
- sprite[selection].data, sprite[selection].width, sprite[selection].frames, // entry sprite
- sprite[selection].data, sprite[selection].width, sprite[selection].frames // exit sprite
- );
- P.displayText(
- curGearChar, PA_CENTER, SCROLL_SPEED, 1, PA_SPRITE, PA_SPRITE // set animation settings
- );
- while (!P.displayAnimate()) // play animation once until complete
- ;
- }
Advertisement
Add Comment
Please, Sign In to add comment