Arduino Nano + SSD1306 OLED 进阶(二)( 时钟设计-带动画效果DS3231)

硬件组成
Arduino Nano 或 UNO, SSD1306 I2C总线,DS3231模块。
外加两个按键,用来设置时钟和日期,一个蜂鸣器。
根据自己的板子可以调整按键的连接位置。
在这里插入图片描述

本文例程使用Adafruit_SSD1306 库文件。

使用 Adafruit_SSD1306 库文件的时候,需要注意两点:

一是编译的时候可能提示如下错误:

Line 53 and 54 #if (SSD1306_LCDHEIGHT != 64) and # error (“Height incorrect, please fix Adafruit_SSD1306.h!”)

这个是头文件里宏定义不对,需要改动两个地方:
找到 Adafruit_SSD1306.h

  1. #define SSD1306_128_64 //这一行有效
  2. // #define SSD1306_128_32
  3. // #define SSD1306_96_16

在你的应用程序里,添加下面这句

#define SSD1306_LCDHEIGHT 64

注意是添加到这个前面

#if (SSD1306_LCDHEIGHT != 64)
#error(“Height incorrect, please fix Adafruit_SSD1306.h!”);
#endif

二是编译的时候可能提示缺少DS3231的头文件,可以把头文件跟时钟程序保存在同一个路径下,如果没有sd3231的头文件,可以下载整个工程文件

点我下载工程文件
包含GFX和SSD1306库,以及DS3231的头文件,函数文件。

运行效果:
在这里插入图片描述
由于刷新率的原因,图片中看着有条黑线,实际肉眼观测是看不到的。

主程序代码如下

#include <SPI.h> //Library for Adafruit communication to OLED display
#include <Wire.h> //I2C communication library
#include "ds3231.h" //Real Time Clock library
#include <Adafruit_GFX.h> //Graphics library
#include <Adafruit_SSD1306.h> //OLED display library
#include <EEPROM.h> //This library allows reading and writing to the EEPROM

//Uncomment ONE of the following three lines to define the behavior of pin 10 when alarm is activated
#define beeper //Uncomment if 5 volt continuous tone beeper or buzzer is connected to pin 10 (5 Hz output)
//#define speaker //Uncomment if speaker is connected to pin 10 through 1 microfarad capacitor and 100 ohm resistor in series (1480 Hz at 5 Hz output)
//#define voltage //Uncomment if pin 10 is connected to alarm device requiring steady output while alarm is activated

//Uncomment following line to enable display dimming between 10 PM and 5 AM
//#define dimming

#define OLED_RESET 4 //Define reset for OLED display
Adafruit_SSD1306 display(OLED_RESET); //Reset OLED display

#define SSD1306_LCDHEIGHT 64

//Check for proper display size - required
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

unsigned long prev, interval = 100; //Variables for display/clock update rate
byte flash = 0; //Flag for display flashing - toggle once per update interval
byte mode = 0; //Mode for time and date setting
int tempset; //Temporary variable for setting time/date
int framecount = 3; //Framecounter for animation. Initialized to last frame to start animation at first frame
int framecount2 = 0; //Counter for number of display update periods - for timing display image changes
int imagecounter = 4; //Counter for display of new static image - Initialized to 4 to start static image display at beginning
uint8_t secset = 0; //Index for second RTC setting
uint8_t minset = 1; //Index for minute RTC setting
uint8_t hourset = 2; //Index for hour RTC setting
uint8_t wdayset = 3; //Index for weekday RTC setting
uint8_t mdayset = 4; //Index for date RTC setting
uint8_t monset = 5; //Index for month RTC setting
uint8_t yearset = 6; //Index for year RTC setting

//Alarm time variables
uint8_t wake_HOUR = 0;
uint8_t wake_MINUTE = 0;
uint8_t wake_SECOND = 0;
uint8_t wake_SET = 1; //Default alarm to ON in case of power failure or reset
int beepcount = 0; //Variable for number of 100ms intervals since alarm started sounding
const int alarmEE = 0; //EEPROM alarm status storage location


//First animation frame image
static const unsigned char PROGMEM frame_000[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x01, 0xCC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0xCE, 0x0F, 0x8C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0xC7, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0xC0, 0x00, 0x00, 0x1D, 0x83, 0xFF, 0x06, 0x38, 0x00, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x0F,
0xFF, 0x81, 0xFB, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x05, 0xC0, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
0x33, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x07, 0xFE, 0x03, 0xE2, 0x00, 0x33, 0x80, 0x00,
0x00, 0x00, 0x00, 0x07, 0xC0, 0x1F, 0x0E, 0x00, 0x63, 0x80, 0xE1, 0x80, 0x00, 0x00, 0x00, 0x00,
0x07, 0x40, 0x7F, 0x8E, 0x00, 0x23, 0x80, 0x79, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xE7,
0x84, 0x00, 0x27, 0x04, 0x39, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x06, 0xE1, 0xC7, 0x00, 0x1F, 0xE7,
0x0E, 0x38, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE3, 0x80, 0x00, 0x1E, 0x07, 0x1E, 0x10, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x03, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x03, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xBE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00,
0x01, 0x9C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x1D, 0xFF, 0x00,
0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xFF, 0xF3, 0xC0, 0x00, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0xF8, 0x79, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0xE0, 0x79, 0xE0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x01, 0xC0, 0x7F, 0xE0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x80, 0x3F,
0xE0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x01, 0x80, 0x0F, 0x60, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00, 0x06, 0x7B, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x03, 0x80, 0x00, 0x00,
0x00, 0x1F, 0xFE, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0xFB, 0x04,
0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x1F, 0xFB, 0x00, 0x00, 0x01, 0xC0,
0x07, 0xC0, 0x00, 0x00, 0x70, 0x00, 0x7F, 0xFE, 0x1E, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0xC0, 0x00,
0x00, 0x3D, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x0D, 0xF1,
0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x06, 0xC0, 0xF8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//Second animation frame image
static const unsigned char PROGMEM frame_001[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07,
0xFF, 0xFF, 0x83, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x03,
0xC0, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x03, 0xF0, 0x78, 0x07, 0x03, 0xFF, 0xCC, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x1F, 0xE0, 0x78, 0x01, 0x83, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x3F, 0x80, 0x38, 0xE0, 0x30, 0x00, 0xC7, 0x3E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xE0, 0xF0,
0xE0, 0x00, 0x00, 0xC6, 0x04, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xF9, 0xC0, 0x00, 0x00, 0x38,
0x06, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xDF, 0x80, 0x00, 0x00, 0x7F, 0x9F, 0x01, 0xCC,
0xE0, 0x00, 0x00, 0x00, 0x07, 0xDF, 0x00, 0x00, 0x00, 0x01, 0x9C, 0x07, 0x8F, 0xE0, 0x00, 0x00,
0x00, 0x01, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x32, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0xD9, 0xCF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x40, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
0x0C, 0x39, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x7F, 0xFF, 0x80,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x7F, 0xEF, 0xC0, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xFC, 0x0F, 0xF0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x01, 0xC0, 0x0F, 0xF0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x01, 0x80, 0x0F, 0xF0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x07,
0xF0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x30, 0x03, 0x00, 0x07, 0xD0, 0x00, 0x02,
0x70, 0x00, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x03, 0x00, 0x01, 0xB0, 0x00, 0x03, 0xFF, 0x80, 0x00,
0x00, 0x0C, 0xFE, 0xF0, 0x01, 0x80, 0x00, 0x30, 0x00, 0x03, 0x83, 0xF3, 0xFF, 0xFF, 0xFE, 0xE0,
0x00, 0x01, 0x80, 0x00, 0x70, 0x00, 0x00, 0x00, 0x77, 0xFF, 0xFC, 0x07, 0x60, 0x00, 0x01, 0xF8,
0x0D, 0xF0, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xBF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//Third animation frame image
static const unsigned char PROGMEM frame_002[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1F, 0x80, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x3F,
0xFF, 0xFC, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x81, 0xFE, 0x0F, 0x1F, 0xC3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xC7, 0x9E, 0x0F, 0x03, 0xC1, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x09, 0xFE, 0x1E, 0x0E, 0x0F, 0x01, 0xE0, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0xF0, 0x0C, 0x06, 0x03, 0x81, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE0,
0x00, 0x00, 0x01, 0xC1, 0xBF, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x00,
0xC2, 0x3F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x37, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3F, 0xC3, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x1C, 0x03, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x23, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61,
0xC7, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE1, 0xC4, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x40, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
0x3F, 0x33, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x3F, 0xFB, 0x00,
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7D, 0xFF, 0x80, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xE0, 0x0D, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x01, 0x80, 0x1E, 0x70, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x01, 0x80, 0x1E, 0xF0, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x1F,
0xF0, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x07, 0xF0, 0x00, 0x00,
0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xEF, 0xC0, 0x00,
0x00, 0x00, 0x03, 0x80, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x3D, 0xFF, 0x3C, 0x00, 0x00, 0x03,
0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x00, 0x3C, 0x0F, 0xBF, 0xFF, 0x81, 0xFB, 0x00, 0x01, 0xB0,
0x00, 0xC0, 0x00, 0x00, 0x08, 0x01, 0xB0, 0x3F, 0x9F, 0xFD, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
0x00, 0x00, 0x00, 0xF0, 0x00, 0xD8, 0x0D, 0x80, 0x00, 0xE7, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0xD8, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//Fourth animation frame image
static const unsigned char PROGMEM frame_003[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x0F, 0xE6, 0x73, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7E, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7E, 0x00, 0x0F, 0xDE, 0x1F, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x7E,
0x1E, 0x03, 0xC1, 0xC0, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0xFE, 0x1E, 0x00, 0xC1,
0xF8, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x83, 0xDE, 0x1C, 0x00, 0x41, 0xBF, 0xE6, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1F, 0xC7, 0x0E, 0x00, 0x3E, 0x67, 0xF7, 0x86, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0xFE, 0x00, 0x00, 0x07, 0x86, 0x26, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x78,
0x00, 0x00, 0x01, 0x87, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xF0, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x3D, 0x00, 0xC6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x18, 0x03, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x01, 0xE3, 0xC7, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x33, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x31,
0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
0x1F, 0x1D, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x3F, 0xFF, 0x80,
0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x38, 0x3F, 0x80, 0x00, 0x00, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x30, 0x1E, 0xE0, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x00, 0x60, 0x1E, 0xE0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
0x00, 0x60, 0x1E, 0xF0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x00, 0xC0, 0x1F,
0xF0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x0F, 0xE0, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x01, 0xE0, 0x00, 0x00, 0x07, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x01, 0xC4, 0x06, 0x70, 0x00, 0x0E,
0x00, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE7, 0xFE, 0x7E, 0x60, 0x1C, 0x00, 0x00, 0x30,
0x01, 0xC0, 0x00, 0x00, 0x00, 0x73, 0xE3, 0xB6, 0x7F, 0xD8, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00,
0x00, 0x00, 0x3E, 0x01, 0xF6, 0x61, 0xD8, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x0E,
0x00, 0x03, 0x60, 0x68, 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x38, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//Pusheen Teacup static image
static const unsigned char PROGMEM pusheen_teacup[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0xE6, 0x0C, 0x61, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xC7, 0xFC, 0x3F, 0xFF, 0xC0, 0x00, 0x00,
0x00, 0x83, 0xF8, 0x3E, 0x3D, 0xF0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x38, 0xF8, 0x00, 0x00,
0x0F, 0x80, 0x00, 0x3C, 0x00, 0xFC, 0x00, 0x00, 0x3F, 0x9C, 0xC7, 0x3F, 0x00, 0x6E, 0x00, 0x00,
0x0F, 0x1C, 0xE7, 0x3D, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x1D, 0xF3, 0x1E, 0x00, 0x03, 0x80, 0x00,
0x13, 0x01, 0x80, 0x02, 0x00, 0x01, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00,
0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xC0,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xE0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xC4,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xC4, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xC6,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC6, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC4,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x88,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x38,
0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x70, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0x80, 0xC0,
0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x07, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x06, 0x3E, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
0x00, 0x07, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x00,
0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//Pusheen Artist static image
static const unsigned char PROGMEM pusheen_artist[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x37, 0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x33, 0xFC,
0xCF, 0x80, 0x00, 0x00, 0x00, 0x63, 0xF8, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x60, 0xF0, 0x41, 0xF8,
0x00, 0x00, 0x00, 0xC0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0xCE, 0x00, 0x00,
0x0F, 0xDC, 0xC6, 0x00, 0x0F, 0x00, 0x00, 0x03, 0x9C, 0xCE, 0x7C, 0x0F, 0x80, 0x00, 0x0F, 0x8F,
0xEE, 0x1C, 0x01, 0x80, 0x00, 0x0F, 0x00, 0x60, 0x60, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x70,
0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0xC0, 0x00, 0x02, 0x00, 0x00, 0x18, 0x00, 0xC0,
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x06,
0x00, 0x00, 0x00, 0x00, 0x60, 0x07, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0xFA, 0x00, 0x00,
0x00, 0x00, 0xDC, 0x07, 0xFA, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x06, 0xFB, 0x00, 0x00, 0x00, 0x00,
0xDE, 0x04, 0xCF, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x04, 0xCD, 0x80, 0x00, 0x00, 0x01, 0xFE, 0x04,
0xE9, 0xC0, 0x00, 0x00, 0x03, 0xFE, 0x07, 0xF8, 0xE0, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFE,
0x00, 0x00, 0x0F, 0xF8, 0x00, 0x0F, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x7C, 0x01, 0xFF, 0xCF,
0xF8, 0x00, 0x38, 0x60, 0x00, 0xF7, 0xFF, 0xE0, 0x00, 0x7C, 0x70, 0x00, 0x03, 0x01, 0x80, 0x00,
0x7C, 0x38, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x7C, 0x1C, 0x00, 0x3C, 0x18, 0x0F, 0xC0, 0x6C, 0x07,
0x00, 0xF0, 0xFF, 0x8F, 0xFF, 0x6C, 0x03, 0x83, 0xC1, 0xCB, 0xC7, 0xFF, 0x6C, 0x01, 0xEF, 0x03,
0x1E, 0xF7, 0xFF, 0x3C, 0x10, 0x7C, 0x03, 0xD7, 0xF0, 0x00, 0x00, 0x3C, 0x10, 0x07, 0xFD, 0xD8,
0x00, 0x00, 0x2E, 0x00, 0x07, 0xE1, 0xD8, 0x00, 0x00, 0x3F, 0x00, 0x07, 0xE3, 0x98, 0x00, 0x00,
0x1F, 0x0F, 0x86, 0xC7, 0x38, 0x00, 0x00, 0x00, 0x3F, 0x86, 0x77, 0x70, 0x00, 0x00, 0x00, 0x7F,
0x86, 0xF7, 0xE0, 0x00, 0x00, 0x00, 0x7F, 0x03, 0xF1, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00
};

//Pusheen Scooter static image
static const unsigned char PROGMEM pusheen_scooter[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x66, 0x03, 0x80, 0x00, 0x00, 0x0C, 0xC3, 0x07, 0xC0, 0x00, 0x00, 0x0F, 0x83,
0xFC, 0xC0, 0x00, 0x00, 0x3B, 0x83, 0xF8, 0x40, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x7C, 0x00, 0x00,
0x07, 0x38, 0x00, 0xFC, 0x00, 0x00, 0x06, 0x39, 0x80, 0xFC, 0x00, 0x00, 0x0C, 0x03, 0xCC, 0x7C,
0x00, 0x00, 0x08, 0x00, 0xCC, 0x47, 0x80, 0x00, 0x18, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x18, 0x00,
0x00, 0x07, 0xF0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x30, 0x00, 0x00, 0x00, 0x7C, 0x00,
0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00,
0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x30, 0x00,
0x00, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00,
0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x03, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x78, 0x00, 0x00, 0x03, 0xFC, 0x03, 0xFF,
0x00, 0x00, 0x07, 0xFE, 0x01, 0xFB, 0xC1, 0xC0, 0x1F, 0xFE, 0x01, 0x60, 0x79, 0xE0, 0x7B, 0xF8,
0x03, 0x60, 0x1F, 0xFF, 0xE0, 0x00, 0x03, 0x20, 0x1F, 0xFF, 0x80, 0x00, 0x02, 0x30, 0x1F, 0xFF,
0xC0, 0x00, 0x02, 0x30, 0x1F, 0xFF, 0x80, 0x00, 0x1E, 0x18, 0x18, 0x01, 0x80, 0x1E, 0x38, 0x0C,
0x30, 0x01, 0x86, 0x3E, 0x6F, 0xEC, 0x30, 0xF8, 0xCF, 0x3A, 0x5C, 0x64, 0x61, 0xDC, 0xDF, 0xBE,
0x7F, 0xFF, 0xE7, 0xFE, 0x5F, 0x9E, 0x7C, 0x78, 0x07, 0x8F, 0x4F, 0x00, 0x7B, 0xAF, 0xFF, 0x77,
0xCE, 0x00, 0x1B, 0xA5, 0xFB, 0x75, 0xC0, 0x00, 0x19, 0x20, 0x03, 0x24, 0x00, 0x00, 0x0C, 0x60,
0x01, 0x8C, 0x00, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//Pusheen Cookie static image
static const unsigned char PROGMEM pusheen_cookie[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x80, 0x73, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0xC0, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, 0xFF, 0x81, 0x00,
0x00, 0x00, 0x00, 0x1E, 0xC0, 0x6F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x6D, 0x01, 0x9E,
0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0xF6, 0x80, 0x00, 0x01, 0xC0,
0x00, 0x00, 0x00, 0x1F, 0x07, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x3B, 0x07, 0x04, 0x3C, 0xFF,
0x00, 0x00, 0x00, 0x70, 0x07, 0x0C, 0x3C, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x7F, 0x18, 0x40,
0x00, 0x00, 0x03, 0x80, 0x00, 0xE1, 0xC0, 0x40, 0x00, 0x00, 0x07, 0x00, 0x01, 0xC3, 0x60, 0x60,
0x00, 0x00, 0x0C, 0x00, 0x03, 0x83, 0x30, 0x60, 0x00, 0x00, 0x18, 0x00, 0x03, 0x32, 0x30, 0x60,
0x00, 0x00, 0x30, 0x00, 0x01, 0x30, 0x30, 0x20, 0x00, 0x00, 0x60, 0x00, 0x01, 0x87, 0x30, 0x20,
0x00, 0x00, 0xC0, 0x00, 0x01, 0x87, 0x70, 0x20, 0x00, 0x01, 0x80, 0x00, 0x00, 0xF7, 0xF0, 0x20,
0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x30, 0x00, 0x03, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x30,
0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x00, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x60, 0x00, 0x08, 0x00, 0xE7, 0xBE, 0x00, 0x00, 0x60,
0x00, 0x08, 0x01, 0xBF, 0xF7, 0x00, 0x00, 0x60, 0x00, 0x08, 0x03, 0x60, 0x1D, 0xE0, 0x00, 0x40,
0x00, 0x0C, 0x03, 0xC0, 0x06, 0xF0, 0x00, 0xC0, 0x00, 0x04, 0x07, 0x80, 0x00, 0x10, 0x00, 0xC0,
0x1F, 0xFE, 0x07, 0x80, 0x00, 0x90, 0x01, 0x80, 0x7E, 0x6E, 0x07, 0x00, 0x00, 0x90, 0x01, 0xC0,
0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x9F, 0xFF, 0xC0, 0x7F, 0xE0, 0x05, 0x00, 0x00, 0x9F, 0xFF, 0xC0,
0x00, 0x00, 0x05, 0x00, 0x00, 0x97, 0x80, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x9F, 0x80, 0x00,
0x00, 0x00, 0x07, 0x80, 0x00, 0xBD, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0x80, 0x00, 0xB3, 0x80, 0x0C,
0x00, 0x00, 0x03, 0xC0, 0x06, 0x31, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0x77, 0xBD, 0xE3, 0x30, 0x00,
0x00, 0x00, 0x01, 0xDF, 0xFF, 0x03, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00
};

//Pusheen Marshmallow static image
static const unsigned char PROGMEM pusheen_marshmallow[] =
{
    
    
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x80, 0x00, 0x00, 0x00, 0x1E, 0x07, 0xC7,
0xF0, 0x00, 0x00, 0x36, 0x0C, 0xDF, 0xF8, 0x00, 0x00, 0x33, 0x7C, 0x79, 0xDE, 0x00, 0x00, 0x63,
0xF8, 0x63, 0xDF, 0x00, 0x00, 0x41, 0xF0, 0x1E, 0x1F, 0x00, 0x0F, 0xC0, 0x00, 0x3C, 0x1D, 0x80,
0x1F, 0xC0, 0x00, 0x30, 0x01, 0xC0, 0x00, 0xD8, 0x01, 0xBE, 0x00, 0xC0, 0x0F, 0x9E, 0x67, 0x00,
0x00, 0x60, 0x1D, 0x8E, 0x70, 0x00, 0x00, 0x60, 0x01, 0x80, 0x60, 0x00, 0x00, 0x60, 0x01, 0x80,
0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30,
0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x80, 0x00, 0x00, 0x00, 0x30, 0x0F, 0xC0, 0x00, 0x00,
0x00, 0x38, 0x0C, 0xE0, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x38, 0x00, 0x00, 0x02, 0x66, 0x30, 0x7E,
0x00, 0x00, 0x0F, 0xE6, 0x30, 0x67, 0x80, 0x00, 0x1F, 0xC2, 0x20, 0x21, 0xF8, 0x00, 0x7F, 0x83,
0x60, 0x30, 0x3F, 0xFF, 0xEE, 0x03, 0x60, 0x30, 0x03, 0xFF, 0xFC, 0x03, 0x40, 0x30, 0x00, 0x00,
0x78, 0x01, 0x40, 0x30, 0x00, 0x00, 0x70, 0x01, 0xC0, 0x10, 0x00, 0x00, 0x70, 0x01, 0xC0, 0x10,
0x00, 0x00, 0x60, 0x01, 0xC0, 0x10, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x10, 0x00, 0x00, 0x00, 0x01,
0xC0, 0x10, 0x00, 0x00, 0x00, 0x01, 0x80, 0x10, 0x00, 0x00, 0x00, 0x01, 0x80, 0x10, 0x00, 0x00,
0x00, 0x01, 0x80, 0x10, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x30, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x30,
0x00, 0x00, 0x00, 0x01, 0xC0, 0x30, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x20, 0x00, 0x00, 0x00, 0x03,
0x40, 0x60, 0x00, 0x00, 0x00, 0x03, 0x60, 0x60, 0x00, 0x00, 0x00, 0x03, 0x60, 0xC0, 0x00, 0x00,
0x00, 0x02, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x06, 0x39, 0x80, 0x00, 0x00, 0x00, 0x06, 0x1C, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8
};


void setup()
{
    
    
Serial.begin(9600); //Initialize serial port, if needed (not used)
Wire.begin(); //Initializw I2C communication library
DS3231_init(0x00); //Initialize Real Time Clock for 1Hz square wave output (no RTC alarms on output pin)

pinMode(8, INPUT); //Set pin for time/date mode button to input
digitalWrite(8, HIGH); //Turn on pullup resistors

pinMode(9, INPUT); //Set pin for time/date set button to input
digitalWrite(9, HIGH); //Turn on pullup resistors

pinMode(10, OUTPUT); //Set pin for external alarm indicator output
digitalWrite(10, LOW); //Initialize external alarm to off state

//Read stored alarm set status and initialize to on at first run or on error  
wake_SET = EEPROM.read(alarmEE);
if (wake_SET != 0 && wake_SET != 1){
    
    
  wake_SET = 1;
  EEPROM.write(alarmEE, wake_SET);}
    
    
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64 OLED display)
display.setTextSize(1); //Set default font size to the smalles
display.setTextColor(WHITE); //Set font to display color on black background
display.dim(0); //Set display to full brightness
display.invertDisplay(0); //Set display to normal video
// init done
}

void loop()
{
    
    
char tempF[6]; //Local variable to store converted temperature reading from Real Time Clock module
float temperature; //Intermediate temperature variable to convert Celsius to Farenheit
unsigned long now = millis(); //Local variable set to current value of Arduino internal millisecond run-time timer
struct ts t; //Structure for retrieving and storing time and date data from real time clock

//Draw and update display every refresh period (100ms)
if ((now - prev > interval)) {
    
     //Determine whether to start a time and screen update
  framecount2 = framecount2 + 1; //Update counter of refresh periods
  if(framecount2 > 300){
    
    
    framecount2 = 0; //Wrap the refresh period counter to 0 after 300 updates, 
    mode = 0; //Reset mode to normal every cycle unless setting buttons pressed to reset cycle counter
    }
  if(flash == 0){
    
    flash = 1;}else{
    
    flash = 0;} //Toggle flash flag for cursor blinking later
  DS3231_get(&t); //Get time and date and save in t structure 
  get_alarm(); //Retrieve current alarm setting

  #if defined(dimming)
  if(t.hour >= 22 || t.hour < 5){
    
    display.dim(1);} //Dim the display between 10 PM and 5 AM
    else {
    
    display.dim(0);} //Otherwise set display to full brightness
  #endif

  #if defined(beeper)
  digitalWrite(10, LOW); //Turn off external alarm every cycle - no effect if alarm not on
  #endif
  
  #if defined(speaker)
  note(0,0); //Turn off external alarm beep every cycle - no effect if alarm not on
  #endif

  #if defined(voltage)
  if(!DS3231_triggered_a1()){
    
    digitalWrite(10, LOW);} //Turn off external alarm for flashing only if RTC alarm flag clear
  #endif
  
  display.invertDisplay(0); //Return display to normal after alarm stops - no effect if alarm not on
  
  //Force a temperature conversion if one is not in progress for rapid update and better clock accuracy
  //Maintain 1Hz square wave output
  if((DS3231_get_addr(0x0E) & 0x20) == 0){
    
    DS3231_init(0x20);} //Check conversion in process flag
  temperature = DS3231_get_treg(); //Get temperature from real time clock
  temperature = (temperature * 1.8) + 32.0; // Convert Celsius to Fahrenheit
  dtostrf(temperature, 5, 1, tempF); //Convert temperature to string for display

  display.clearDisplay(); //Clear display buffer from last refresh

//NOTE: Alarm indicators are overwritten in display buffer if full-screen animation is displayed, so no check for that  
  if (mode <= 7){
    
     //Alarm indicators and actions in normal and time set display mode only
  if (wake_SET){
    
     //Display alarm on indicator if alarm turned on
    display.setCursor(80, 8); //Position text cursor for alarm on indicator
    display.print("*"); //Print character between time and temperature if alarm on
  }
  }

  if(wake_SET && DS3231_triggered_a1()){
    
     //Display/sound alarm if enabled and triggered
      beepcount = beepcount + 1;
      if(beepcount <= 600){
    
     //Sound alarm for 60 seconds
        if(!flash){
    
     //Flash display and sound interrupted beeper
        display.invertDisplay(1); //Flash inverse video display at 5 Hz

        #if defined(speaker)
        note(6, 6); //Sound external alarm if alarm triggered, regardless of mode (1480 Hz)on pin 10
        #endif

        #if defined(beeper)
        digitalWrite(10, HIGH); //Flash external alarm if alarm triggered, regardless of mode
        #endif

        #if defined(voltage)
        digitalWrite(10, HIGH); //Turn on external alarm if alarm triggered, regardless of mode
        #endif
        
        }
      }
      else{
    
    beepcount = 0; DS3231_clear_a1f();} //If alarm has sounded for 1 minute, reset alarm timer counter and alarm flag
  }
 
  if (mode <=7){
    
             
  display.setCursor(92,8); //Set cursor for temperature display
  display.print(tempF); //Send temperature to display buffer
  display.drawCircle(124,8,2,WHITE); //Draw degree symbol after temperature

//DO NOT CHANGE CURSOR POSITIONING OF TIME AND DATE TEXT FIELDS OR TIME/DATE SET CURSOR WON'T MATCH!!!     
  display.setCursor(0,0); //Position cursor for day-of-week display
  printDay(t.wday); //Lookup day of week string from retrieved RTC data and write to display buffer
        
  printMonth(t.mon); //Lookup month string from retrieved RTC data and write to display buffer
        
  if(t.mday<10){
    
    display.print("0");} //Add leading zero to date display if date is single-digit
  display.print(t.mday); //Write date to display buffer
  display.print(", "); //Write spaces and comma between date and year
        
  display.print(t.year); //Write year to display buffer
        
  display.setCursor(0, 8); //Position text cursor for time display
        
  //RTC is operated in 24-hour mode and conversion to 12-hour mode done here, in software
  if(t.hour == 0){
    
    display.print("12");} //Convert zero hour for 12-hour display
    else if(t.hour < 13 && t.hour >= 10){
    
    display.print(t.hour);} //Just display hour if double digit hour
        else if(t.hour < 10){
    
    display.print(" "); display.print(t.hour);} //If single digit hour, add leading space
        else if(t.hour >= 13 && t.hour >= 22){
    
    display.print(t.hour-12);} //If double digit and PM, convert 24 to 12 hour
        else{
    
    display.print(" "); display.print(t.hour-12);} //If single digit and PM, convert to 12 hour and add leading space
        
        display.print(":"); //Display hour-minute separator
        if(t.min<10){
    
    display.print("0");} //Add leading zero if single-digit minute
        display.print(t.min); //Display retrieved minutes
        
        display.print(":"); //Display minute-seconds separator
        if(t.sec<10){
    
    display.print("0");} //Add leading zero for single-digit seconds
        display.print(t.sec); //Display retrieved seconds
        
        if(t.hour < 12){
    
    display.print(" AM");} //Display AM indicator, as needed
        else{
    
    display.print(" PM");} //Display PM indicator, as needed
        
        
  if(framecount2 > 50 ){
    
     //Display analog clock for 250 of 300 frames in frame cycle
    // Now draw the clock face
    display.drawCircle(display.width()/2+30, display.height()/2 + 8, 20, WHITE); //Draw and position clock outer circle
    //display.fillCircle(display.width()/2+25, display.height()/2 + 8, 20, WHITE); //Fill circle only if displaying inverted colors
    if(flash){
    
    display.drawCircle(display.width()/2+30, display.height()/2 + 8, 2, WHITE);} //Draw, position and blink tiny inner circle
    display.drawRect(71,17,47,47,WHITE); //Draw box around clock

    //Position and draw hour tick marks
    for( int z=0; z < 360;z= z + 30 ){
    
    
    //Begin at 0° and stop at 360°
      float angle = z ;
      angle=(angle/57.29577951) ; //Convert degrees to radians
      int x2=(94+(sin(angle)*20));
      int y2=(40-(cos(angle)*20));
      int x3=(94+(sin(angle)*(20-5)));
      int y3=(40-(cos(angle)*(20-5)));
      display.drawLine(x2,y2,x3,y3,WHITE);
    }
  
    //Position and display second hand
    float angle = t.sec * 6 ; //Retrieve stored seconds and apply
    angle=(angle/57.29577951) ; //Convert degrees to radians  
    int x3=(94+(sin(angle)*(20)));
    int y3=(40-(cos(angle)*(20)));
    display.drawLine(94,40,x3,y3,WHITE);

   //Position and display minute hand
    angle = t.min * 6; //Retrieve stored minutes and apply
    angle=(angle/57.29577951) ; //Convert degrees to radians  
    x3=(94+(sin(angle)*(20-3)));
    y3=(40-(cos(angle)*(20-3)));
    display.drawLine(94,40,x3,y3,WHITE);

    //Position and display hour hand
    angle = t.hour * 30 + int((t.min / 12) * 6); //Retrieve stored hour and minutes and apply
    angle=(angle/57.29577951) ; //Convert degrees to radians  
    x3=(94+(sin(angle)*(20-11)));
    y3=(40-(cos(angle)*(20-11)));
    display.drawLine(94,40,x3,y3,WHITE);
  }

  if(framecount2 > 50){
    
     //Display static image for 250 of 300 frames
    if(framecount2 == 51){
    
     //Increment the image to be displayed once per 300 frames
      imagecounter = imagecounter + 1; //Advance the image counter
    }
    display.fillRect(0,16,64,48,WHITE); //Draw "white" background for static image display on left half of screen
    if(imagecounter > 4){
    
    imagecounter = 0;} //Roll over the image counter after all images have sequenced
    if(imagecounter == 0){
    
    display.drawBitmap(0, 16, pusheen_teacup, 64, 48, BLACK);} //Position and draw static bitmap
    if(imagecounter == 1){
    
    display.drawBitmap(5, 16, pusheen_artist, 56, 48, BLACK);} //Position and draw static bitmap
    if(imagecounter == 2){
    
    display.drawBitmap(10, 16, pusheen_scooter, 48, 48, BLACK);} //Position and draw static bitmap
    if(imagecounter == 3){
    
    display.drawBitmap(0, 16, pusheen_cookie, 64, 48, BLACK);} //Position and draw static bitmap
    if(imagecounter == 4){
    
    display.drawBitmap(10, 16, pusheen_marshmallow, 48, 48, BLACK);} //Position and draw static bitmap 
  }
  
    //Animated Pusheen
  framecount = framecount + 1; //Increment frame counter on each display update (5Hz frame rate on animation)
  if(framecount > 3){
    
    framecount = 0;} //Roll over frames after 4-frame animation plays
  if(framecount2 <= 50){
    
     //Display animation for 50 of 300 frames of display frame counter
    display.fillRect(0,16,128,48,WHITE); //Set "white" baxkground for animation
    if(framecount == 0){
    
    display.drawBitmap(10, 16, frame_000, 104, 48, BLACK);} //Display frame 1
    if(framecount == 1){
    
    display.drawBitmap(10, 16, frame_001, 104, 48, BLACK);} //Display frame 2 on next display update
    if(framecount == 2){
    
    display.drawBitmap(10, 16, frame_002, 104, 48, BLACK);} //Display frame 3 on next display update
    if(framecount == 3){
    
    display.drawBitmap(10, 16, frame_003, 104, 48, BLACK);} //Display frame 4 on next display update
    }
  }
  
      if (mode > 7){
    
     
      display.setCursor(0, 0); //Position text cursor
      display.print("Alarm Set: ");
      if(wake_SET){
    
    display.print("ON");}else{
    
    display.print("OFF");}
      display.setCursor(0, 8); //Position text cursor for time display
        
      //RTC is operated in 24-hour mode and conversion to 12-hour mode done here, in software
      if(wake_HOUR == 0){
    
    display.print("12");} //Convert zero hour for 12-hour display
        else if(wake_HOUR < 13 && wake_HOUR >= 10){
    
    display.print(wake_HOUR);} //Just display hour if double digit hour
            else if(wake_HOUR < 10){
    
    display.print(" "); display.print(wake_HOUR);} //If single digit hour, add leading space
            else if(wake_HOUR >= 13 && wake_HOUR >= 22){
    
    display.print(wake_HOUR-12);} //If double digit and PM, convert 24 to 12 hour
            else{
    
    display.print(" "); display.print(wake_HOUR-12);} //If single digit and PM, convert to 12 hour and add leading space
        
            display.print(":"); //Display hour-minute separator
            if(wake_MINUTE<10){
    
    display.print("0");} //Add leading zero if single-digit minute
            display.print(wake_MINUTE); //Display retrieved minutes
        
            display.print(":"); //Display minute-seconds separator
            if(wake_SECOND<10){
    
    display.print("0");} //Add leading zero for single-digit seconds
            display.print(wake_SECOND); //Display retrieved seconds
        
            if(wake_HOUR < 12){
    
    display.print(" AM");} //Display AM indicator, as needed
            else{
    
    display.print(" PM");} //Display PM indicator, as needed
    }
    
    
//Time/Date setting button processing and cursor flashing
//CURSOR COORDINATES ARE SET TO MATCH TIME/DATE FIELD - DO NOT CHANGE!!
//Digital and analog time/date display updates with new settings at 5Hz as settings are changed
  switch(mode)
  {
    
    
    case 0: break;
    case 1: //Day-of-week setting
      if(flash){
    
    display.drawRect(0,0,18,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = t.wday; //Get the current weekday and save in temporary variable
        tempset = tempset + 1; //Increment the day at 5Hz rate
        if(tempset > 7){
    
    tempset = 1;} //Roll over after 7 days
        t.wday = tempset; //After each update, write the day back to the time structure
        set_rtc_field(t, wdayset); //Write the set field only back to the real time clock module after each update
      }
      break;
    case 2: //Month setting
      if(flash){
    
    display.drawRect(24,0,18,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = t.mon; //Get the current month and save in temporary variable
        tempset = tempset + 1; //Increment the month at 5Hz rate
        if(tempset > 12){
    
    tempset = 1;} //Roll over after 12 months
        t.mon = tempset; //After each update, write the month back to the time structure
        set_rtc_field(t, monset); //Write the set field only back to the real time clock module after each update
      }
      break;
    case 3: //Date setting
      if(flash){
    
    display.drawRect(48,0,12,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = t.mday; //Get the current date and save in temporary variable
        tempset = tempset + 1; //Increment the date at 5Hz rate
        //(RTC allows incorrect date setting for months < 31 days, but will use correct date rollover for subsequent months.
        if(tempset > 31){
    
    tempset = 1;} //Roll over after 31 days
        t.mday = tempset; //After each update, write the date back to the time structure 
        set_rtc_field(t, mdayset); //Write the set field only back to the real time clock module after each update
      }
      break;
    case 4: //Year setting
      if(flash){
    
    display.drawRect(72,0,24,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = t.year; //Get the current year and save in temporary variable
        tempset = tempset + 1; //Increment the year at 5Hz rate
        //RTC allows setting from 1900, but range limited here to 2000 to 2099
        if(tempset > 2099){
    
    tempset = 2000;} //Roll over after 2099 to 2000
        t.year = tempset; //After each update, write the year back to the time structure
        set_rtc_field(t, yearset); //Write the set field only back to the real time clock module after each update
      } 
      break;
    case 5: //Hour setting
      if(flash){
    
    display.drawRect(0,8,12,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = t.hour; //Get the current hour and save in temporary variable
        tempset = tempset + 1; //Increment the hour at 5Hz rate
        if(tempset > 23){
    
    tempset = 0;} //Roll over hour after 23rd hour (setting done in 24-hour mode)
        t.hour = tempset; //After each update, write the hour back to the time structure
        set_rtc_field(t, hourset); //Write the set field only back to the real time clock module after each update
      }
      break;
    case 6: //Minute setting
      if(flash){
    
    display.drawRect(18,8,12,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = t.min; //Get the current minute and save in temporary variable
        tempset = tempset + 1; //Increment the minute at 5Hz rate
        if(tempset > 59){
    
    tempset = 0;} //Roll over minute to zero after 59th minute
        t.min = tempset; //After each update, write the minute back to the time structure
        set_rtc_field(t, minset); //Write the set field only back to the real time clock module after each update
      }
      break;
      
     //Set clock + 1 minute, then press and hold to freeze second setting.
     //Release button at 00 seconds to synchronize clock to external time source.
    case 7: //Second synchronization
      if(flash){
    
    display.drawRect(36,8,12,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Reset second to zero at 5Hz rate if button held down
        t.sec = 0; //After each update, write the zeroed second back to the time structure
        set_rtc_field(t, secset); //Write the set field only back to the real time clock module after each update
      }
      break;
                 
    case 8: //Alarm hour setting
      if(flash){
    
    display.drawRect(0,8,12,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = wake_HOUR; //Get the current hour and save in temporary variable
        tempset = tempset + 1; //Increment the hour at 5Hz rate
        if(tempset > 23){
    
    tempset = 0;} //Roll over hour after 23rd hour (setting done in 24-hour mode)
        wake_HOUR = tempset; //After each update, write the hour back to the alarm variable
        set_alarm(); //Write the alarm setting back to the RTC after each update
      }
    break;
       
    case 9: //Alarm minute setting
      if(flash){
    
    display.drawRect(18,8,12,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        tempset = wake_MINUTE; //Get the current minute and save in temporary variable
        tempset = tempset + 1; //Increment the minute at 5Hz rate
        if(tempset > 59){
    
    tempset = 0;} //Roll over minute to zero after 59th minute
        wake_MINUTE = tempset; //After each update, write the minute back to the alarm variable
        set_alarm(); //Write the alarm setting back to the RTC after each update
      }
    break;
    
     case 10: //Alarm enable/disable
      if(flash){
    
    display.drawRect(66,0,18,8,WHITE);} //Display rectangle cursor every other display update (5Hz blink)
      if(!digitalRead(9) && (!flash)){
    
     //Update setting at 5Hz rate if button held down
        if(wake_SET){
    
    wake_SET = 0;}else{
    
    wake_SET = 1;} //Toggle alarm on/of variable at 5 Hz
        EEPROM.write(alarmEE, wake_SET); //Save alarm enable setting to EEPROM
      }
    break;
  }
        
prev = now; //Reset variables for display and time update rate
display.display(); //Display the constructed frame buffer for this framecount
    }
    
//Clock setting mode set - outside time/display update processing for faster button response
if(!digitalRead(8)){
    
     //Read setting mode button
  delay(25); //100ms debounce time to avoid accidental triggering on button bump
  if(!digitalRead(8)){
    
     //Activate setting mode change after 100ms button press
    mode = mode + 1; //Increment the time setting mode on each button press
    framecount2 = 0;  //Reset cycle counter if button pressed to delay auto return to normal mode
    if(mode > 10){
    
    mode = 0;} //Roll the mode setting after 7th mode
    while(!digitalRead(8)){
    
    } //Wait for button release (freezes all display processing and time updates while button held, but RTC continues to keep time)
  }
 }
 
 if(!digitalRead(9)){
    
     //Reset alarm flag if set button pressed
   delay(25); //25ms debounce time
   if(!digitalRead(9)){
    
    
    DS3231_clear_a1f(); //Clear alarm flag if set button pressed - insures alarm reset when turning alarm on
    beepcount = 0; //Reset alarm timeout counter if alarm stopped by pushing button
    framecount2 = 0; //Reset cycle counter if button pressed to delay auto return to normal mode
    }
 }
}


//Function to display month string from numerical month argument
void printMonth(int month)
{
    
    
  switch(month)
  {
    
    
    case 1: display.print("Jan ");break;
    case 2: display.print("Feb ");break;
    case 3: display.print("Mar ");break;
    case 4: display.print("Apr ");break;
    case 5: display.print("May ");break;
    case 6: display.print("Jun ");break;
    case 7: display.print("Jul ");break;
    case 8: display.print("Aug ");break;
    case 9: display.print("Sep ");break;
    case 10: display.print("Oct ");break;
    case 11: display.print("Nov ");break;
    case 12: display.print("Dec ");break;
    default: display.print("--- ");break; //Display dashes if error - avoids scrambling display
  } 
}


//Function to display day-of-week string from numerical day-of-week argument
void printDay(int day)
{
    
    
  switch(day)
  {
    
    
    case 1: display.print("Mon ");break;
    case 2: display.print("Tue ");break;
    case 3: display.print("Wed ");break;
    case 4: display.print("Thu ");break;
    case 5: display.print("Fri ");break;
    case 6: display.print("Sat ");break;
    case 7: display.print("Sun ");break;
    default: display.print("--- ");break; //Display dashes if error - avoids scrambling display
  } 
}

//Subroutine to adjust a single date/time field in the RTC
void set_rtc_field(struct ts t,  uint8_t index)
{
    
    
    uint8_t century;

    if (t.year > 2000) {
    
    
        century = 0x80;
        t.year_s = t.year - 2000;
    } else {
    
    
        century = 0;
        t.year_s = t.year - 1900;
    }

    uint8_t TimeDate[7] = {
    
     t.sec, t.min, t.hour, t.wday, t.mday, t.mon, t.year_s };

    Wire.beginTransmission(DS3231_I2C_ADDR);
    Wire.write(index);
        TimeDate[index] = dectobcd(TimeDate[index]);
        if (index == 5){
    
    TimeDate[5] += century;}
        Wire.write(TimeDate[index]);
    Wire.endTransmission();
    
    //Adjust the month setting, per data sheet, if the year is changed
    if (index == 6){
    
    
      Wire.beginTransmission(DS3231_I2C_ADDR);
      Wire.write(5);
      TimeDate[5] = dectobcd(TimeDate[5]);
      TimeDate[5] += century;
      Wire.write(TimeDate[5]);
      Wire.endTransmission();
    } 
}


//Subroutine to set alarm 1
void set_alarm()
{
    
    

    // flags define what calendar component to be checked against the current time in order
    // to trigger the alarm - see datasheet
    // A1M1 (seconds) (0 to enable, 1 to disable)
    // A1M2 (minutes) (0 to enable, 1 to disable)
    // A1M3 (hour)    (0 to enable, 1 to disable) 
    // A1M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    byte flags[5] = {
    
     0, 0, 0, 1, 1 }; //Set alarm to trigger every 24 hours on time match

    // set Alarm1
    DS3231_set_a1(0, wake_MINUTE, wake_HOUR, 0, flags); //Set alarm 1 RTC registers

}

//Subroutine to get alarm 1
void get_alarm()
{
    
    
    uint8_t n[4];
    uint8_t t[4];               //second,minute,hour,day
    uint8_t f[5];               // flags
    uint8_t i;

    Wire.beginTransmission(DS3231_I2C_ADDR);
    Wire.write(DS3231_ALARM1_ADDR);
    Wire.endTransmission();

    Wire.requestFrom(DS3231_I2C_ADDR, 4);

    for (i = 0; i <= 3; i++) {
    
    
        n[i] = Wire.read();
        f[i] = (n[i] & 0x80) >> 7;
        t[i] = bcdtodec(n[i] & 0x7F);
    }

    f[4] = (n[3] & 0x40) >> 6;
    t[3] = bcdtodec(n[3] & 0x3F);
    
    wake_SECOND = t[0];
    wake_MINUTE = t[1];
    wake_HOUR = t[2];
}

#if defined(__AVR_ATmega32U4__) && defined(speaker)
//Subroutine for low overhead beep for alarm speaker on pin 10, ATmega32U4
const uint8_t scale[] PROGMEM = {
    
    239,225,213,201,190,179,169,159,150,142,134,127};

void note (int n, int octave) {
    
    
  DDRB = DDRB | 1<<DDB6;                     // PB6 (Arduino D10) as output
  TCCR4A = 0<<COM4A0 | 1<<COM4B0;            // Toggle OC4B on match
  int prescaler = 10 - (octave + n/12);
  if (prescaler<1 || prescaler>9) prescaler = 0;
  OCR4C = pgm_read_byte(&scale[n % 12]);
  TCCR4B = prescaler<<CS40;
}

#elif !defined(__AVR_ATmega32U4__) && defined(speaker)
//Subroutine for low overhead beep for alarm speaker on pin 10, ATmega328
const uint8_t scale[] PROGMEM = {
    
    239,225,213,201,190,179,169,159,150,142,134,127};

void note (int n, int octave) {
    
    
  DDRD = DDRD | 1<<DDD3;                     // PD3 (Arduino D3) as output
  TCCR2A = 0<<COM2A0 | 1<<COM2B0 | 2<<WGM20; // Toggle OC2B on match
  int prescaler = 9 - (octave + n/12);
  if (prescaler<3 || prescaler>6) prescaler = 0;
  OCR2A = pgm_read_byte(&scale[n % 12]);
  TCCR2B = 0<<WGM22 | prescaler<<CS20;
}
#endif

猜你喜欢

转载自blog.csdn.net/malcolm_110/article/details/106928419