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
  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Arduino SSD1306 OLED显示屏是一种基于Arduino开发板的显示屏,采用SSD1306驱动芯片,具有高亮度、低功耗、高对比度等特点。它可以用于显示各种信息,如文本、图像、图标等,适用于各种Arduino项目。 ### 回答2: Arduino SSD1306 OLED显示屏是一块高分辨率的单色显示屏,非常适合DIY电子爱好者在自己的项目中使用。与传统的LCD显示屏不同,OLED显示屏具有更快的响应速度、更低的功耗和更高的对比度,同时消耗的电力也更少,在相同的亮度下更加节能,因此在需要使用电池供电的项目中得到广泛应用。Arduino SSD1306 OLED显示屏由OLED屏幕、驱动IC、电容、电阻和其他一些辅助器件组成,通过I2C总线与Arduino板通信。 为了控制这块显示屏,我们需要一个专门编写的程序。在这个程序中,我们可以定义需要显示的内容,包括文本、图形、图标和图像。可以通过设置显示屏坐标和颜色来创建自定义的显示内容。可以使用不同的字体、大小和样式来创建独特的设计。 使用Arduino SSD1306 OLED显示屏的优点不只是它的高效能和易用性,还在于其开放性和扩展性。用户可以使用不同的软件库和驱动程序来创建自己的创新项目,或者使用可用的库和例子来快速上手。对于那些不熟悉编程的用户,也可以使用现成的图形库来轻松地创建复杂的图形和界面。 总的来说,Arduino SSD1306 OLED显示屏是一款多功能的单色显示屏,其灵活性和高效能使其成为DIY电子爱好者的首选。适用于各种类型的项目,包括智能家居、传感器网络、机器人、万花筒、数据可视化和可穿戴设备。 ### 回答3: Arduino ssd1306 oled显示屏是一种非常常见和实用的显示屏,其特点是高亮度、高对比度、低功耗、反应速度快等。这种显示屏采用SSD1306控制芯片,可以通过I2C接口与Arduino连接。SSD1306控制芯片集成了控制器和驱动器,可以通过软件控制屏幕内容。 要使用Arduino ssd1306 oled显示屏,首先需要下载并安装相应的库。在Arduino IDE中打开菜单“工具”-“库管理器”,搜索SSD1306并下载“Adafruit SSD1306”或者“U8g2”库。接下来,连接Arduino ssd1306 oled显示屏到Arduino板上,将VCC连接到5V,GND连接到GND,SDA连接到SDA,SCL连接到SCL。在Arduino IDE中选择正确的板子和端口,并打开一个新的示例程序。如果已安装了U8g2库,可以在示例中找到ssd1306的例子程序进行测试。 在程序中,可以通过调用相应函数来控制显示屏上显示内容,例如显示文本、图形、动画等。可以设置屏幕分辨率、字体大小、对齐方式等缩放和定位属性。可以使用函数来绘制点、线、矩形、圆形、多边形等基本图形,也可以导入和显示位图和动画等多媒体内容。 总的来说,Arduino ssd1306 oled显示屏是一种非常实用和常用的显示屏,可以用于各种跟踪、监控、测量、控制等应用场景。通过简单的硬件和软件设计,可以快速、方便、高效地实现其功能。在今后的开发中,Arduino ssd1306 oled显示屏将会得到更广泛的应用和发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值