Help Understanding Code as well as Fixing Serial Command Errors

Hello everyone,

I am new to the forum so thank you in advance for the assistance here.

I am getting back into programming with arduino and built a POV fidget spinner inspired by an instructable by MakersBox. I am using the SparkFun AVR Pocket Programmer and an ATTiny84 (8MHz internal clock). The code is a bit over my head and I am still working on understanding it. The project uses persistence of vision to display images using 8 LEDs on a custom fidget spinner PCB. The font.h and textAndShapes.h header files (both shown below) store pre-built arrays with the sequence of bytes which turn the 8 LEDs on and off in just the right manner to display shapes and text. I have two questions below.

1. Is anyone able to explain to me how the bytes are actually output to the LEDs in the code? I am not able to figure out where or how that is done.

2. I am getting the below error while compiling and cannot sort out what is going on. It seems that there is an issue with the Serial set of commands. I have included the error below.

c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp: In member function 'void EEPROMClassEx::setMemPool(int, int)':
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:63:3: error: 'Serial' was not declared in this scope
   Serial.println("Cannot change base, addresses have been issued");
   ^~~~~~
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:63:3: note: suggested alternative: 'Stream'
   Serial.println("Cannot change base, addresses have been issued");
   ^~~~~~
   Stream
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:66:3: error: 'Serial' was not declared in this scope
   Serial.println("Cannot change ceiling, below issued addresses");
   ^~~~~~
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:66:3: note: suggested alternative: 'Stream'
   Serial.println("Cannot change ceiling, below issued addresses");
   ^~~~~~
   Stream
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp: In member function 'int EEPROMClassEx::getAddress(int)':
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:89:3: error: 'Serial' was not declared in this scope
   Serial.println("Attempt to write outside of EEPROM memory");
   ^~~~~~
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:89:3: note: suggested alternative: 'Stream'
   Serial.println("Attempt to write outside of EEPROM memory");
   ^~~~~~
   Stream
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp: In member function 'bool EEPROMClassEx::isWriteOk(int)':
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:324:3: error: 'Serial' was not declared in this scope
   Serial.println("Exceeded maximum number of writes");
   ^~~~~~
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:324:3: note: suggested alternative: 'Stream'
   Serial.println("Exceeded maximum number of writes");
   ^~~~~~
   Stream
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:329:3: error: 'Serial' was not declared in this scope
   Serial.println("Attempt to write outside of EEPROM memory");
   ^~~~~~
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:329:3: note: suggested alternative: 'Stream'
   Serial.println("Attempt to write outside of EEPROM memory");
   ^~~~~~
   Stream
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp: In member function 'bool EEPROMClassEx::isReadOk(int)':
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:345:3: error: 'Serial' was not declared in this scope
   Serial.println("Attempt to write outside of EEPROM memory");
   ^~~~~~
c:\Users\Franklin Marquette\Documents\Arduino\libraries\EEPROMEx\EEPROMex.cpp:345:3: note: suggested alternative: 'Stream'
   Serial.println("Attempt to write outside of EEPROM memory");
   ^~~~~~
   Stream

exit status 1

Compilation error: exit status 1

font.h Header File:

///============================================================
 // Arduino Bike POV
 // font.h
 //
 // by Scott Mitchell
 // www.openobject.org
 // Open Source Urbanism
 //
 // Copyright (C) 2008 Scott Mitchell 12-10-2008
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
 // the Free Software Foundation, either version 3 of the License, or
 // (at your option) any later version.
 //
 // This program 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 General Public License for more details.
 //
 // A copy of the GNU General Public License
 // can be found at <http://www.gnu.org/licenses/>.
 //
 // B4.1
 // Last Modified: October 13, 2008
 //============================================================

 // defining the alphabet
 // ascii 7x5 side-feeding characters for led modules
 // adapted from http://www.sxlist.com/TECHREF/datafile/charset/8x6.htm


 // Modified to place data in program memory to save dynamic memory
 // https://playground.arduino.cc/Main/PROGMEM
 // http://www.gammon.com.au/progmem


const char PROGMEM font1[95][5] = {
 {// 
    0b00000000,
    0b00000000,
    0b00000000,
    0b00000000,
    0b00000000 },
 {// !
    0b00000000,
    0b00000000,
    0b11110110,
    0b00000000,
    0b00000000 },
 {// "
    0b00000000,
    0b11100000,
    0b00000000,
    0b11100000,
    0b00000000 },
 {// #
    0b00101000,
    0b11111110,
    0b00101000,
    0b11111110,
    0b00101000 },
 {// $
    0b00000000,
    0b11100000,
    0b00100000,
    0b01111000,
    0b00000000 },
 {// %
    0b11000100,
    0b11001000,
    0b00010000,
    0b00100110,
    0b01000110 },
 {// &
    0b01101100,
    0b10010010,
    0b01101010,
    0b00000100,
    0b00001010 },
 {// '
    0b00000000,
    0b00000000,
    0b11100000,
    0b00000000,
    0b00000000 },
 {// (
    0b00000000,
    0b00111000,
    0b01000100,
    0b10000010,
    0b00000000 },
 {// )
    0b00000000,
    0b10000010,
    0b01000100,
    0b00111000,
    0b00000000 },
 {// *
    0b00101000,
    0b00010000,
    0b01111100,
    0b00010000,
    0b00101000 },
 {// +
    0b00010000,
    0b00010000,
    0b01111100,
    0b00010000,
    0b00010000 },
 {// ,
    0b00000000,
    0b00001010,
    0b00001100,
    0b00000000,
    0b00000000 },
 {// -
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000 },
 {// .
    0b00000000,
    0b00000110,
    0b00000110,
    0b00000000,
    0b00000000 },
 {// /
    0b00000100,
    0b00001000,
    0b00010000,
    0b00100000,
    0b01000000 },
 {// 0
    0b01111100,
    0b10001010,
    0b10010010,
    0b10100010,
    0b01111100 },
 {// 1
    0b00000000,
    0b01000010,
    0b11111110,
    0b00000010,
    0b00000000 },
 {// 2
    0b01000010,
    0b10000110,
    0b10001010,
    0b10010010,
    0b01100010 },
 {// 3
    0b10000100,
    0b10000010,
    0b10100010,
    0b11010010,
    0b10001100 },
 {// 4
    0b00011000,
    0b00101000,
    0b01001000,
    0b11111110,
    0b00001000 },
 {// 5
    0b11100100,
    0b10100010,
    0b10100010,
    0b10100010,
    0b10011100 },
 {// 6
    0b00111100,
    0b01010010,
    0b10010010,
    0b10010010,
    0b00001100 },
 {// 7
    0b10000000,
    0b10001110,
    0b10010000,
    0b10100000,
    0b11000000 },
 {// 8
    0b01101100,
    0b10010010,
    0b10010010,
    0b10010010,
    0b01101100 },
 {// 9
    0b01100000,
    0b10010010,
    0b10010010,
    0b10010100,
    0b01111000 },
 {// :
    0b00000000,
    0b01101100,
    0b01101100,
    0b00000000,
    0b00000000 },
 {// ;
    0b00000000,
    0b01101010,
    0b01101100,
    0b00000000,
    0b00000000 },
 {// <
    0b00010000,
    0b00101000,
    0b01000100,
    0b10000010,
    0b00000000 },
 {// =
    0b00101000,
    0b00101000,
    0b00101000,
    0b00101000,
    0b00101000 },
 {// >
    0b00000000,
    0b10000010,
    0b01000100,
    0b00101000,
    0b00010000 },
 {// ?
    0b01000000,
    0b10000000,
    0b10001010,
    0b10010000,
    0b01100000 },
 {// @
    0b01111100,
    0b10000010,
    0b10111010,
    0b10010010,
    0b01110010 },
 {// A
    0b01111110,
    0b10010000,
    0b10010000,
    0b10010000,
    0b01111110 },
 {// B
    0b11111110,
    0b10010010,
    0b10010010,
    0b10010010,
    0b01101100 },
 {// C
    0b01111100,
    0b10000010,
    0b10000010,
    0b10000010,
    0b01000100 },
 {// D
    0b11111110,
    0b10000010,
    0b10000010,
    0b10000010,
    0b01111100 },
 {// E
    0b11111110,
    0b10010010,
    0b10010010,
    0b10010010,
    0b10000010 },
 {// F
    0b11111110,
    0b10010000,
    0b10010000,
    0b10010000,
    0b10000000 },
 {// G
    0b01111100,
    0b10000010,
    0b10010010,
    0b10010010,
    0b01011110 },
 {// H
    0b11111110,
    0b00010000,
    0b00010000,
    0b00010000,
    0b11111110 },
 {// I
    0b00000000,
    0b10000010,
    0b11111110,
    0b10000010,
    0b00000000 },
 {// J
    0b00000100,
    0b00000010,
    0b10000010,
    0b11111100,
    0b10000000 },
 {// K
    0b11111110,
    0b00010000,
    0b00101000,
    0b01000100,
    0b10000010 },
 {// L
    0b11111110,
    0b00000010,
    0b00000010,
    0b00000010,
    0b00000010 },
 {// M
    0b11111110,
    0b01000000,
    0b00110000,
    0b01000000,
    0b11111110 },
 {// N
    0b11111110,
    0b00100000,
    0b00010000,
    0b00001000,
    0b11111110 },
 {// O
    0b01111100,
    0b10000010,
    0b10000010,
    0b10000010,
    0b01111100 },
 {// P
    0b11111110,
    0b10010000,
    0b10010000,
    0b10010000,
    0b01100000 },
 {// Q
    0b01111100,
    0b10000010,
    0b10001010,
    0b10000100,
    0b01111010 },
 {// R
    0b11111110,
    0b10010000,
    0b10011000,
    0b10010100,
    0b01100010 },
 {// S
    0b01100010,
    0b10010010,
    0b10010010,
    0b10010010,
    0b10001100 },
 {// T
    0b10000000,
    0b10000000,
    0b11111110,
    0b10000000,
    0b10000000 },
 {// U
    0b11111100,
    0b00000010,
    0b00000010,
    0b00000010,
    0b11111100 },
 {// V
    0b11110000,
    0b00001100,
    0b00000010,
    0b00001100,
    0b11110000 },
 {// W
    0b11111100,
    0b00000010,
    0b00001100,
    0b00000010,
    0b11111100 },
 {// X
    0b11000110,
    0b00101000,
    0b00010000,
    0b00101000,
    0b11000110 },
 {// Y
    0b11100000,
    0b00010000,
    0b00001110,
    0b00010000,
    0b11100000 },
 {// Z
    0b10000110,
    0b10001010,
    0b10010010,
    0b10100010,
    0b11000010 },
 {// [
    0b00111100,
    0b01010010,
    0b10010010,
    0b10010100,
    0b01111000 },
 {// \
    0b01000000,
    0b00100000,
    0b00010000,
    0b00001000,
    0b00000100 },
 {// ]
    0b00000000,
    0b10000010,
    0b11111110,
    0b00000000,
    0b00000000 },
 {// ^
    0b00100000,
    0b01000000,
    0b10000000,
    0b01000000,
    0b00100000 },
 {// _
    0b00000010,
    0b00000010,
    0b00000010,
    0b00000010,
    0b00000010 },
 {// `
    0b00000000,
    0b00000000,
    0b11000000,
    0b00100000,
    0b00000000 },
 {// a
    0b00000100,
    0b00101010,
    0b00101010,
    0b00101010,
    0b00011110 },
 {// b
    0b11111110,
    0b00010010,
    0b00100010,
    0b00100010,
    0b00011100 },
 {// c
    0b00011100,
    0b00100010,
    0b00100010,
    0b00100010,
    0b00000100 },
 {// d
    0b00011100,
    0b00100010,
    0b00100010,
    0b00010010,
    0b11111110 },
 {// e
    0b00011100,
    0b00101010,
    0b00101010,
    0b00101010,
    0b00011000 },
 {// f
    0b00010000,
    0b01111110,
    0b10010000,
    0b10000000,
    0b01000000 },
 {// g
    0b00110000,
    0b01001010,
    0b01001010,
    0b01001010,
    0b01111100 },
 {// h
    0b11111110,
    0b00010000,
    0b00100000,
    0b00100000,
    0b00011110 },
 {// i
    0b00000000,
    0b00100010,
    0b10111110,
    0b00000010,
    0b00000000 },
 {// j
    0b00000100,
    0b00000010,
    0b00100010,
    0b10111100,
    0b00000000 },
 {// k
    0b00000000,
    0b11111110,
    0b00001000,
    0b00010100,
    0b00100010 },
 {// l
    0b00000000,
    0b10000010,
    0b11111110,
    0b00000010,
    0b00000000 },
 {// m
    0b00111110,
    0b00100000,
    0b00011000,
    0b00100000,
    0b00011110 },
 {// n
    0b00111110,
    0b00010000,
    0b00100000,
    0b00100000,
    0b00011110 },
 {// o
    0b00011100,
    0b00100010,
    0b00100010,
    0b00100010,
    0b00011100 },
 {// p
    0b00111110,
    0b00101000,
    0b00101000,
    0b00101000,
    0b00010000 },
 {// q
    0b00010000,
    0b00101000,
    0b00101000,
    0b00011000,
    0b00111110 },
 {// r
    0b00111110,
    0b00010000,
    0b00100000,
    0b00100000,
    0b00010000 },
 {// s
    0b00010010,
    0b00101010,
    0b00101010,
    0b00101010,
    0b00000100 },
 {// t
    0b00100000,
    0b11111100,
    0b00100010,
    0b00000010,
    0b00000100 },
 {// u
    0b00111100,
    0b00000010,
    0b00000010,
    0b00000100,
    0b00111110 },
 {// v
    0b00111000,
    0b00000100,
    0b00000010,
    0b00000100,
    0b00111000 },
 {// w
    0b00111100,
    0b00000010,
    0b00001100,
    0b00000010,
    0b00111100 },
 {// x
    0b00100010,
    0b00010100,
    0b00001000,
    0b00010100,
    0b00100010 },
 {// y
    0b00110000,
    0b00001010,
    0b00001010,
    0b00001010,
    0b00111100 },
 {// z
    0b00100010,
    0b00100110,
    0b00101010,
    0b00110010,
    0b00100010 },
 {// {
    0b00000000,
    0b00010000,
    0b01101100,
    0b10000010,
    0b10000010 },
 {// |
    0b00000000,
    0b00000000,
    0b11111110,
    0b00000000,
    0b00000000 },
 {// }
    0b10000010,
    0b10000010,
    0b01101100,
    0b00010000,
    0b00000000 },
 {// ~
    0b00100000,
    0b01000000,
    0b00100000,
    0b00010000,
    0b00100000 }
 };


const char PROGMEM font[95][5] = {
   {0x00,0x00,0x00,0x00,0x00},   //   0x20 32
   {0x00,0x00,0x6f,0x00,0x00},   // ! 0x21 33
   {0x00,0x07,0x00,0x07,0x00},   // " 0x22 34
   {0x14,0x7f,0x14,0x7f,0x14},   // # 0x23 35
   {0x00,0x07,0x04,0x1e,0x00},   // $ 0x24 36
   {0x23,0x13,0x08,0x64,0x62},   // % 0x25 37
   {0x36,0x49,0x56,0x20,0x50},   // & 0x26 38
   {0x00,0x00,0x07,0x00,0x00},   // ' 0x27 39
   {0x00,0x1c,0x22,0x41,0x00},   // ( 0x28 40
   {0x00,0x41,0x22,0x1c,0x00},   // ) 0x29 41
   {0x14,0x08,0x3e,0x08,0x14},   // * 0x2a 42
   {0x08,0x08,0x3e,0x08,0x08},   // + 0x2b 43
   {0x00,0x50,0x30,0x00,0x00},   // , 0x2c 44
   {0x08,0x08,0x08,0x08,0x08},   // - 0x2d 45
   {0x00,0x60,0x60,0x00,0x00},   // . 0x2e 46
   {0x20,0x10,0x08,0x04,0x02},   // / 0x2f 47
   {0x3e,0x51,0x49,0x45,0x3e},   // 0 0x30 48
   {0x00,0x42,0x7f,0x40,0x00},   // 1 0x31 49
   {0x42,0x61,0x51,0x49,0x46},   // 2 0x32 50
   {0x21,0x41,0x45,0x4b,0x31},   // 3 0x33 51
   {0x18,0x14,0x12,0x7f,0x10},   // 4 0x34 52
   {0x27,0x45,0x45,0x45,0x39},   // 5 0x35 53
   {0x3c,0x4a,0x49,0x49,0x30},   // 6 0x36 54
   {0x01,0x71,0x09,0x05,0x03},   // 7 0x37 55
   {0x36,0x49,0x49,0x49,0x36},   // 8 0x38 56
   {0x06,0x49,0x49,0x29,0x1e},   // 9 0x39 57
   {0x00,0x36,0x36,0x00,0x00},   // : 0x3a 58
   {0x00,0x56,0x36,0x00,0x00},   // ; 0x3b 59
   {0x08,0x14,0x22,0x41,0x00},   // < 0x3c 60
   {0x14,0x14,0x14,0x14,0x14},   // = 0x3d 61
   {0x00,0x41,0x22,0x14,0x08},   // > 0x3e 62
   {0x02,0x01,0x51,0x09,0x06},   // ? 0x3f 63
   {0x3e,0x41,0x5d,0x49,0x4e},   // @ 0x40 64
   {0x7e,0x09,0x09,0x09,0x7e},   // A 0x41 65
   {0x7f,0x49,0x49,0x49,0x36},   // B 0x42 66
   {0x3e,0x41,0x41,0x41,0x22},   // C 0x43 67
   {0x7f,0x41,0x41,0x41,0x3e},   // D 0x44 68
   {0x7f,0x49,0x49,0x49,0x41},   // E 0x45 69
   {0x7f,0x09,0x09,0x09,0x01},   // F 0x46 70
   {0x3e,0x41,0x49,0x49,0x7a},   // G 0x47 71
   {0x7f,0x08,0x08,0x08,0x7f},   // H 0x48 72
   {0x00,0x41,0x7f,0x41,0x00},   // I 0x49 73
   {0x20,0x40,0x41,0x3f,0x01},   // J 0x4a 74
   {0x7f,0x08,0x14,0x22,0x41},   // K 0x4b 75
   {0x7f,0x40,0x40,0x40,0x40},   // L 0x4c 76
   {0x7f,0x02,0x0c,0x02,0x7f},   // M 0x4d 77
   {0x7f,0x04,0x08,0x10,0x7f},   // N 0x4e 78
   {0x3e,0x41,0x41,0x41,0x3e},   // O 0x4f 79
   {0x7f,0x09,0x09,0x09,0x06},   // P 0x50 80
   {0x3e,0x41,0x51,0x21,0x5e},   // Q 0x51 81
   {0x7f,0x09,0x19,0x29,0x46},   // R 0x52 82
   {0x46,0x49,0x49,0x49,0x31},   // S 0x53 83
   {0x01,0x01,0x7f,0x01,0x01},   // T 0x54 84
   {0x3f,0x40,0x40,0x40,0x3f},   // U 0x55 85  
   {0x0f,0x30,0x40,0x30,0x0f},   // V 0x56 86
   {0x3f,0x40,0x30,0x40,0x3f},   // W 0x57 87
   {0x63,0x14,0x08,0x14,0x63},   // X 0x58 88
   {0x07,0x08,0x70,0x08,0x07},   // Y 0x59 89
   {0x61,0x51,0x49,0x45,0x43},   // Z 0x5a 90
   {0x3c,0x4a,0x49,0x29,0x1e},   // [ 0x5b 91
   {0x02,0x04,0x08,0x10,0x20},   // \ 0x5c 92
   {0x00,0x41,0x7f,0x00,0x00},   // ] 0x5d 93
   {0x04,0x02,0x01,0x02,0x04},   // ^ 0x5e 94
   {0x40,0x40,0x40,0x40,0x40},   // _ 0x5f 95
   {0x00,0x00,0x03,0x04,0x00},   // ` 0x60 96
   {0x20,0x54,0x54,0x54,0x78},   // a 0x61 97
   {0x7f,0x48,0x44,0x44,0x38},   // b 0x62 98
   {0x38,0x44,0x44,0x44,0x20},   // c 0x63 99
   {0x38,0x44,0x44,0x48,0x7f},   // d 0x64 100
   {0x38,0x54,0x54,0x54,0x18},   // e 0x65 101
   {0x08,0x7e,0x09,0x01,0x02},   // f 0x66 102
   {0x0c,0x52,0x52,0x52,0x3e},   // g 0x67 103
   {0x7f,0x08,0x04,0x04,0x78},   // h 0x68 104
   {0x00,0x44,0x7d,0x40,0x00},   // i 0x69 105
   {0x20,0x40,0x44,0x3d,0x00},   // j 0x6a 106
   {0x00,0x7f,0x10,0x28,0x44},   // k 0x6b 107
   {0x00,0x41,0x7f,0x40,0x00},   // l 0x6c 108
   {0x7c,0x04,0x18,0x04,0x78},   // m 0x6d 109
   {0x7c,0x08,0x04,0x04,0x78},   // n 0x6e 110
   {0x38,0x44,0x44,0x44,0x38},   // o 0x6f 111
   {0x7c,0x14,0x14,0x14,0x08},   // p 0x70 112
   {0x08,0x14,0x14,0x18,0x7c},   // q 0x71 113
   {0x7c,0x08,0x04,0x04,0x08},   // r 0x72 114
   {0x48,0x54,0x54,0x54,0x20},   // s 0x73 115
   {0x04,0x3f,0x44,0x40,0x20},   // t 0x74 116
   {0x3c,0x40,0x40,0x20,0x7c},   // u 0x75 117
   {0x1c,0x20,0x40,0x20,0x1c},   // v 0x76 118
   {0x3c,0x40,0x30,0x40,0x3c},   // w 0x77 119
   {0x44,0x28,0x10,0x28,0x44},   // x 0x78 120
   {0x0c,0x50,0x50,0x50,0x3c},   // y 0x79 121
   {0x44,0x64,0x54,0x4c,0x44},   // z 0x7a 122
   {0x00,0x08,0x36,0x41,0x41},   // { 0x7b 123
   {0x00,0x00,0x7f,0x00,0x00},   // | 0x7c 124
   {0x41,0x41,0x36,0x08,0x00},   // } 0x7d 125
   {0x04,0x02,0x04,0x08,0x04},   // ~ 0x7e 126
 };
 
 /*
 Creative Commons Attribution-Noncommercial-Share Alike 2.5 Australia License
     This page was last modified 14:41, 11 January 2009. This page has been accessed 1,477 times.

     Content is available under Creative Commons Attribution-Noncommercial-Share Alike 2.5 Australia License.
     About Open Source Urbanism
     Disclaimers

    
 Powered by MediaWiki
 */

textAndShapes Header File:

// Place data (except text[]) in program memory to save dynamic memory
// https://playground.arduino.cc/Main/PROGMEM
// http://www.gammon.com.au/progmem

const char text[] = "Hello";
const char string_0[] PROGMEM = "World";

const char string_1[] PROGMEM = "  RPM";   
const char string_2[] PROGMEM = "  SEC";
const char string_3[] PROGMEM = "  REV";
const char string_4[] PROGMEM = " odo";

const char * const string_table[] PROGMEM = {	   // change "string_table" name to suit
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  };

const char PROGMEM shape_1[] = { // heart
  B10000000,
  B01000000,
  B01000000,
  B00100000,
  B00100000,
  B00100000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00100000,
  B00100000,
  B00100000,
  B00100000,
  B01000000,
  B01000000,
  B01000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B01000000,
  B00100000,
  B00010000,
  B00001000,
  B00000100,
  B00000010,
  B00000001,
  B00000001,
  B00000010,
  B00000100,
  B00001000,
  B00010000,
  B00100000,
  B01000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B01000000,
  B01000000,
  B01000000,
  B00100000,
  B00100000,
  B00100000,
  B00100000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00010000,
  B00100000,
  B00100000,
  B00100000,
  B01000000,
  B01000000,
  B10000000,
};

const char PROGMEM shape_SIGMA[] = {
  B00000100,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000110,
  B00000100,
  B00000100,
  B00000100,
  B00000001,
  B00000001,
  B00000011,
  B00000111,
  B00001111,
  B00011111,
  B00111111,
  B01100111,
  B11000111,
  B10000111,
  B10000111,
  B01100111,
  B00010111,
  B00001111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00000111,
  B00001111,
  B00110111,
  B01000111,
  B10000111,
  B10000111,
  B11000111,
  B01100111,
  B00111111,
  B00011111,
  B00001111,
  B00000011,
  B00000011,
  B00000001,
  B00000001,
  B00000000,
  B00000100,
  B00000100,
};
 

const char PROGMEM shape_2[] = { // smile
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10001100,
  B10011110,
  B10011110,
  B10001100,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10001100,
  B10011110,
  B10011110,
  B10001100,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10000000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
  B10001000,
};


 /*
 Creative Commons Attribution-Noncommercial-Share Alike 2.5 Australia License
     This page was last modified 14:41, 11 January 2009. This page has been accessed 1,477 times.

     Content is available under Creative Commons Attribution-Noncommercial-Share Alike 2.5 Australia License.
     About Open Source Urbanism
     Disclaimers

    
 Powered by MediaWiki
 */

Code:

/*

cd C:\Users\MakersBox\Downloads\arduino-1.6.4\hardware\tools\avr\bin
avrdude -C ..\etc\avrdude.conf -P COM8 -b 19200 -c avrisp -p attiny84 -v -e -U lfuse:w:0xE2:m -U hfuse:w:0xD7:m -U efuse:w:0xFf:m  -U flash:w:SMD_spinner_THT_R2b.cpp.hex


Attiny Core:
https://github.com/SpenceKonde/ATTinyCore
Board: Attiny 24/44/84
Pin Mapping: Counter-Clockwise
Chip: Attiny 84
Clock: 8 MHz (internal)

// ATMEL ATTINY84 / ARDUINO
//
//                           +-\/-+
//                     VCC  1|    |14  GND
//             (D  0)  PB0  2|    |13  AREF (D 10)
//             (D  1)  PB1  3|    |12  PA1  (D  9) 
//                     PB3  4|    |11  PA2  (D  8) 
//  PWM  INT0  (D  2)  PB2  5|    |10  PA3  (D  7) 
//  PWM        (D  3)  PA7  6|    |9   PA4  (D  6) 
//  PWM        (D  4)  PA6  7|    |8   PA5  (D  5)        PWM

*/

#include <EEPROMex.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include "font.h"
#include "textAndShapes.h"

// clear and set interup routines
#ifndef cbi
  #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
  #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


const int charHeight = 8;
const int charWidth = 5;
int rows= 8;		                 // Total LED's in a row
bool STATES[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
int LEDS[] = {10, 9, 8, 7, 6, 5, 4, 3};  // Port A
byte magPin = 2;                 // Hall effect sensor, pulled-up, goes low when magnet passes      
byte buttonPin = 0;        


char charArray[6];                       // holds characters to display
unsigned long lastTimeUs;                // time (us) magnet sensed
unsigned long revTimeUs;                 // time (us) of last full rotation
unsigned long dwellTimeUs;               // time (us) between LED changes (based on rotation speed)
volatile unsigned long revolutions = 0;  // track number of revolutions since last start
long totalRevolutions;                   // track total number of revolutions (stored in EEPROM)
bool spinning = true;                    // track reset of time & counts
unsigned long startTimeUs;               // time (us) current spinning started
  
int mode;                                // current operating mode, stored in EEPROM
int modes = 8;                           // number of modes available
  // 0 -> text "Hello World!"
  // 1 -> RPM
  // 2 -> time in seconds
  // 3 -> spin count
  // 4 -> spin count (total)
  // 5 -> "lilly pad" pattern
  // 6 -> shape 1 (heart)
  // 7 -> shape 2 (smile)
  
     

volatile boolean rotationFlag = false;  // modified by ISR

void setup(){
  // setup inputs
  pinMode(buttonPin, INPUT_PULLUP);
  //digitalWrite(buttonPin, HIGH);
  pinMode(magPin, INPUT_PULLUP);
  //digitalWrite(magPin, HIGH);
  
  // setup other LEDs
  for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
    pinMode(LEDS[LED], OUTPUT);
    digitalWrite(LEDS[LED], STATES[LED]);
  }

  // Interupt setting
  GIMSK  = bit (PCIE1);   // Pin change interrupt enable
  PCMSK1 = bit (PCINT10); // Enable interupt on PCINT10 (D2)
  sei();                  // enables interrupts

  // get saved mode from eeprom
  mode = EEPROM.read(0);
  if (mode >= modes) {
    mode = 0; // may be very large first time
  }
  
  // get saved revolution total from eeprom
  totalRevolutions = EEPROMReadlong(1);
  if (totalRevolutions < 0 || totalRevolutions > 999999UL){ // will be -1 first time.
    totalRevolutions = 0;
    EEPROMWritelong(1, 0);
  }

  // show we are alive and what mode is active
  blipLEDs();

  lastTimeUs = micros();
}


void loop(){
  int sigFigs = 5;               // number of significant figures to deplay
  unsigned long curTimeUs;
  int seconds;
  unsigned int rpm;
  
  checkButton();
  if ((micros() - lastTimeUs) > 20000000UL){  // sleep after 20 seconds
    digitalWrite(LEDS[0], HIGH);
    ledsOff();
    system_sleep();
    lastTimeUs = micros();
  }
  if (((micros() - lastTimeUs) > 2000000UL)){ // less than 1 rev / sec
    if (spinning){
      spinning = false;
      totalRevolutions = totalRevolutions + revolutions;
      EEPROMWritelong(1, totalRevolutions);
      revolutions = 0;
      clearArray();
      blipLEDs();
      digitalWrite(LEDS[mode], LOW);
      //system_sleep();
    }
    else {
      //digitalWrite(LEDS[mode], LOW); 
    }
  }

  if (mode == 5){  // lilly pad pattern, show regardles of magnet.
    for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
       digitalWrite(LEDS[LED], HIGH); 
       delay(1); 
       digitalWrite(LEDS[LED], LOW); 
    } 
    for(int LED=(sizeof(LEDS)/sizeof(int))-1; LED >= 0; LED--){
       digitalWrite(LEDS[LED], HIGH); 
       delay(1); 
       digitalWrite(LEDS[LED], LOW); 
    }     
  }

  else if (rotationFlag){ // we are spinning!
    rotationFlag = false;
    if (!spinning){
      spinning = true;
      startTimeUs = micros(); 
    }
    curTimeUs = micros();
    revTimeUs = curTimeUs - lastTimeUs;
    dwellTimeUs = revTimeUs * 3UL / 360UL;   // 3 degrees
    seconds = (curTimeUs - startTimeUs) / 1000000UL;
    rpm = 60000 * 1000 / revTimeUs;
    lastTimeUs = curTimeUs;
    clearArray();    
    if (mode == 0){
      strcpy (charArray, text);
      //sprintf(charArray, "%lu", dwellTimeUs);
    }
    else if (mode == 1){
      sprintf(charArray, "%d", rpm);
      sigFigs = 3;
    }
    else if (mode == 2){
      sprintf(charArray, " %d", seconds);
    }   
    else if (mode == 3){   
      sprintf(charArray, " %lu", revolutions);
    }
    else if (mode == 4){   
      sprintf(charArray, "%lu", totalRevolutions + revolutions);
    }
    else if (mode == 6 || mode ==7){ // shapes 1 or 2
      dwellTimeUs = revTimeUs * 5UL / 360UL;   // 5 degrees
      for(int k=0; k< sizeof(shape_1);k++){
        if (rotationFlag){
          break;
        }
        int i = k + 26; // advancing because of magnet location
        if(i >= sizeof(shape_1)){
          i = i - sizeof(shape_1);
        }
        char b;
        if (mode == 6){
          b = pgm_read_byte_near(&(shape_1[i]));
        }
        else{
          b = pgm_read_byte_near(&(shape_2[i]));          
        }
        //for (int j=0; j<charHeight; j++) {
        //  digitalWrite(LEDS[j], bitRead(b, j));
        //}
        PORTA = b;
        delayMicroseconds(dwellTimeUs);
      }
    }    


    // Text in top half
    if (mode < 5) { 
      int digits = 0;    
      for(int k=0; k< sizeof(charArray); k++){
        char c = charArray[k];
        if (rotationFlag){
          break;
        }
        if(c){
          if(mode==0){
            printLetter(c);
          }
          else{
            if (digits < sigFigs){
              printLetter(c);
              //digits += 1;
            }
            else{
              printLetter('0');
            }
            digits += 1;
          }
        }
      }
      
      // Handle display in lower section
      clearArray();
      if(1 && (revTimeUs < 200000)){
        char * ptr = (char *) pgm_read_word (&string_table[mode]);
        //char buffer [6]; // must be large enough!
        strcpy_P (charArray, ptr);
  
        // wait for it . . .
        while((micros() < (lastTimeUs + revTimeUs / 2 - 5 * dwellTimeUs)) && !rotationFlag){};
        
        // show it
        for (int k=sizeof(charArray)-1; k>=0; k--){
          if (rotationFlag){
            break;
          }
          printLetterLower(charArray[k]);;
        }
      }
    }
  }  
}


ISR(PCINT1_vect){  // Magnet sensed
  if (!digitalRead(magPin)){
    rotationFlag = true;             // Increment volatile variables
    revolutions += 1;
  }
}


void ledsOff(){
  for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
    digitalWrite(LEDS[LED], LOW); 
  }   
}


void dwellDelay(){ // avoid glitch on first rotation having erronious value 
  if (dwellTimeUs > 2000){
    dwellTimeUs = 2000;
  }
  if (dwellTimeUs < 100){
    dwellTimeUs = 100;
  }  
  delayMicroseconds(dwellTimeUs);
}


void printLetter(char ch){
// https://github.com/reger-men/Arduion-POV-clock/blob/master/clock.ino
  // make sure the character is within the alphabet bounds (defined by the font.h file)
  // if it's not, make it a blank character
  if (ch < 32 || ch > 126){
    ch = 32;
    }
  // subtract the space character (converts the ASCII number to the font index number)
  ch -= 32;
  // step through each byte of the character array
  for (int i=0; i<charWidth; i++) {
    char b = pgm_read_byte_near(&(font1[ch][i]));
    //for (int j=0; j<charHeight; j++) {
    //  digitalWrite(LEDS[j], bitRead(b, 7-j));
    //}
    PORTA = b;
    dwellDelay();
  }
  
  //clear the LEDs
  PORTA = 0;
  //for (int i = 0; i < rows; i++){
  //  digitalWrite(LEDS[i] , LOW);
  //}
  dwellDelay();
  dwellDelay();
}


void printLetterLower(char ch){
  // make sure the character is within the alphabet bounds (defined by the font.h file)
  // if it's not, make it a blank character
  if (ch < 32 || ch > 126){
    ch = 32;
    }
  // subtract the space character (converts the ASCII number to the font index number)
  ch -= 32;
  // step through each byte of the character array
  for (int i=charWidth-1; i>-1; i--) {
    char b = pgm_read_byte_near(&(font[ch][i]))<<1;
    PORTA = b;
    //for (int j=0; j<charHeight; j++) {
    //  digitalWrite(LEDS[j+1], bitRead(b, j));
    //}
    dwellDelay();
  }
  //clear the LEDs
  
  for (int i=0; i<rows; i++){
    digitalWrite(LEDS[i], LOW);
  }
  //PORTA = 0;
  // space between letters
  dwellDelay();
  dwellDelay();
}  
 


bool touched(){
  // returns true if touched, false if not.  Light LED until touch released
  bool touchVal = digitalRead(buttonPin);
  if (!touchVal){
    while(!digitalRead(buttonPin)){ // wait till touch release
      delay(10);
      digitalWrite(LEDS[mode], LOW);
    }
    //digitalWrite(LEDS[0], LOW);
    return (true);
  }
  else{
    return (false);
  }
}


void checkButton(){
  // check button for mode change and display current mode
  if (touched()){
    mode += 1;
    if (mode >= modes){
      mode = 0;
    }
    EEPROM.write(0, mode);
    blipLEDs();
  }
}


void blipLEDs(){
  // something to show we are alive
  for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
    digitalWrite(LEDS[LED], HIGH); 
    delay(10); 
    digitalWrite(LEDS[LED], LOW); 
  } 
  for(int LED=sizeof(LEDS)/sizeof(int); LED>mode; LED--){
    digitalWrite(LEDS[LED], HIGH); 
    delay(10); 
    digitalWrite(LEDS[LED], LOW); 
  } 
  digitalWrite(LEDS[mode], HIGH);
}



void EEPROMWritelong(int address, long value)  {
  //This function will write a 4 byte (32bit) long to the eeprom at
  //the specified address to address + 3.
  //https://playground.arduino.cc/Code/EEPROMReadWriteLong

  //Decomposition from a long to 4 bytes by using bitshift.
  //One = Most significant -> Four = Least significant byte
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);

  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}


long EEPROMReadlong(long address){
  //Read the 4 bytes from the eeprom memory.
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);

  //Return the recomposed long by using bitshift.
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}


void clearArray(){
  for(int i=0; i<sizeof(charArray); i++){      // clear array
    charArray[i] = 0;
  }
}


// set system into the sleep state 
// system wakes up when wtchdog is timed out
void system_sleep() {
  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();
  sleep_mode();                        // System sleeps here
  sleep_disable();                     // System continues execution here when watchdog timed out 
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}

Thank you so much!

Franklin

Which board manager are you using?

That code looks like it is expecting ATTinyCore. Which is highly recommended BTW.

1 Like

Thank you so much! Now it compiles. I was using the one described at the site below by David Mellis. What is the difference between the two?

http://highlowtech.org/?p=1695

Also, could you help me understand what the PORTA variable is and how the byte series defined in the header files are actually being output to the LEDs?

Thank you so much!

Hello

This line PORTA = b; will set the states of pins PA0 to PA7, in one operation

1 Like

Completely different. I highly recommend ATTinyCore... I think it is by far the best.

As for PORTA... the GPIO pins are arranged in "ports". Basically a byte, with each bit representing a pin... so a 1/0 will set that pin. It enables you to set multiple pins values at the same time.

1 Like

Thank you both for the help! I am starting to understand this code a lot better as a result.

I attempted to actually upload the code to my board today. As I mentioned, I am using the SparkFun AVR Pocket Programmer and an ATTiny84 (8MHz internal clock). I am connecting to the board via a pogo pin adapter. I have the 'USBTinyISP (ATTinyCore) FAST, for parts running >= 2MHz' programmer selected as this SparkFun tutorial instructed to select the USBTinyISP programmer. If I hook my board up, I am able to load the bootloader and get the done loading message, but it is far too fast. My board does not show as connected nor as having a bootloader installed and as soon as I try and upload code, the IDE just states "Upload error: A programmer is required to upload" (See below for full error).

Sketch uses 6612 bytes (80%) of program storage space. Maximum is 8192 bytes.
Global variables use 232 bytes (45%) of dynamic memory, leaving 280 bytes for local variables. Maximum is 512 bytes.
A programmer is required to upload

I even switched the pogo ISP connector backwards to see what would happen (may have been a dumb idea). The same error message was shown.

Does anyone know what is going on?


On another note, do you know what the meaning of Also, 999999UL or 2000000UL are? Examples are below.

if (((micros() - lastTimeUs) > 2000000UL)){ // less than 1 rev / sec
if ((micros() - lastTimeUs) > 'Also'){ // sleep after 20 seconds
if (totalRevolutions < 0 || totalRevolutions > 999999UL){ // will be -1 first time.

The Also one is particularly odd to me, as if I remove the quotes, the code will not compile and gives me the below error.

C:\Users\Franklin Marquette\Desktop\Jennah Xmas\Fidget Spinner\Instructable\SMD_spinner_THT_R2b\SMD_spinner_THT_R2b.ino: In function 'void loop()':
C:\Users\Franklin Marquette\Desktop\Jennah Xmas\Fidget Spinner\Instructable\SMD_spinner_THT_R2b\SMD_spinner_THT_R2b.ino:120:33: error: 'Also' was not declared in this scope
   if ((micros() - lastTimeUs) > Also){  // sleep after 20 seconds
                                 ^~~~

exit status 1

Compilation error: 'Also' was not declared in this scope

Lastly, in the Arduino.h header file, why are the input, output, and input_pullup values set to these hexadecimals?

> #define INPUT 0x0
> #define OUTPUT 0x1
> #define INPUT_PULLUP 0x2

Thank you!!

Franklin

UL = unsigned long. It it used to ensure the compiler knows that it should leave enough space for an unsigned variable. When dealing with millis()/micros() it is advisable to always use unsigned long for every variable involved.

Is Also defined as a variable? ... it needs to be if you are going to use it in the comparison.

I wouldn't really worry about that. From your (Arduino) perspective you just use INPUT/OUTPUT/INPUT_PULLUP... what happens under the covers is detail that you don't really need to worry about.

Yes.

if (((micros() - lastTimeUs) > 2000000UL))

1 Like

I was able to sort it out :slight_smile:

Okay, thank you!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.