#include #include #include #include #include "marquee.h" #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // The pins for I2C are defined by the Wire-library. // On an arduino UNO: A4(SDA), A5(SCL) // On an arduino MEGA 2560: 20(SDA), 21(SCL) // On an arduino LEONARDO: 2(SDA), 3(SCL), ... #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #define LOGO_HEIGHT 30 #define LOGO_WIDTH 30 // 'logoN', 30x30px const unsigned char epd_bitmap_logoN [] PROGMEM = { 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x2a, 0x10, 0x00, 0x00, 0x51, 0x08, 0x00, 0x00, 0xb8, 0x44, 0x00, 0x00, 0x32, 0x22, 0x00, 0x02, 0x70, 0x89, 0x00, 0x04, 0xa3, 0x34, 0x80, 0x08, 0x7f, 0x7f, 0x40, 0x11, 0x67, 0xf7, 0xa0, 0x22, 0x37, 0xb1, 0x70, 0x40, 0x9f, 0xf0, 0x28, 0x84, 0x7c, 0xfa, 0x44, 0x89, 0x7c, 0xf8, 0x84, 0x50, 0x3f, 0xe4, 0x08, 0x3a, 0x27, 0xb1, 0x10, 0x17, 0xaf, 0xda, 0x20, 0x0b, 0xfb, 0xf8, 0x40, 0x04, 0xb3, 0x14, 0x80, 0x02, 0x44, 0x39, 0x00, 0x01, 0x11, 0x12, 0x00, 0x00, 0x88, 0x74, 0x00, 0x00, 0x42, 0x28, 0x00, 0x00, 0x21, 0x50, 0x00, 0x00, 0x10, 0xe0, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00 }; marquee_t* marquee; void setup() { Serial.begin(9600); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } write_logo(); delay(1000); marquee = malloc(sizeof(marquee_t)); *marquee = make_marquee("Nat King Cole - Sweet Loraine"); } void loop() { //check for serial messages if (Serial.available() > 0) { int r = 0; char* bytesRead = malloc(sizeof(char) * 128); //read until null while (1) { int sa = Serial.available(); if (sa > 0) { r += Serial.readBytes(bytesRead + r, sa); if (bytesRead[r-1] == '\n') { bytesRead[r-1] = '\0'; break; } } delay(50); } handle_serial_msg(bytesRead); free(bytesRead); } write_marquee(marquee); if (marquee->scrolledBy == 0) { delay(1000); } //check if message needs to be scrolled if (marquee->doesScroll) { scroll_marquee(marquee, 2); } delay(1); } //serial messages start with one byte to identify message type //messages are null terminated void handle_serial_msg(char* bytesRead) { //control messages if (bytesRead[0] == 'c') { display.ssd1306_command(bytesRead[1] == '0' ? SSD1306_DISPLAYOFF : SSD1306_DISPLAYON); } //marquee messages else if (bytesRead[0] == 'm') { *marquee = make_marquee(bytesRead + 1); } } void write_marquee(marquee_t* marquee) { display.clearDisplay(); //draw chars //default char size is 5x8, so our char size is 20x32. //therefore, the maximum number of whole characters to be displayed is 6. //iterate over string for (int i = 0; i < marquee->textLength; i++) { //multiply by 21 for 20 character pixels and 1 space pixel int charX = (i * 21) - marquee->scrolledBy; if (charX > -20 && charX < 128) { display.drawChar(charX, 0, marquee->text[i], SSD1306_WHITE, SSD1306_BLACK, 4); } } display.display(); } void write_logo() { display.clearDisplay(); display.drawBitmap( (display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, epd_bitmap_logoN, LOGO_WIDTH, LOGO_HEIGHT, 1); display.display(); delay(1000); }