From c15ecfa48e45e5475b31d109254d0f35c80470b6 Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Wed, 12 Jun 2024 02:27:48 +0100 Subject: basic functionality done --- .gitignore | 1 + bind_serial.sh | 6 + disp_proj.ino | 404 ++++++++++----------------------------------------------- marquee.c | 20 +++ marquee.h | 18 +++ upload.sh | 1 + 6 files changed, 118 insertions(+), 332 deletions(-) create mode 100644 .gitignore create mode 100755 bind_serial.sh create mode 100644 marquee.c create mode 100644 marquee.h mode change 100644 => 100755 upload.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/bind_serial.sh b/bind_serial.sh new file mode 100755 index 0000000..cc3e5c1 --- /dev/null +++ b/bind_serial.sh @@ -0,0 +1,6 @@ +PORT=$(arduino-cli board list | grep dev | grep -o '^\S*') +if [ -z $PORT ]; +then + return "Failed to find board" +fi +arduino-cli monitor -p $PORT diff --git a/disp_proj.ino b/disp_proj.ino index 4d0259d..0c16b94 100644 --- a/disp_proj.ino +++ b/disp_proj.ino @@ -1,27 +1,8 @@ -/************************************************************************** - This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - - This example is for a 128x32 pixel display using I2C to communicate - 3 pins are required to interface (two I2C and one reset). - - Adafruit invests time and resources providing this open - source code, please support Adafruit and open-source - hardware by purchasing products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries, - with contributions from the open source community. - BSD license, check license.txt for more information - All text above, and the splash screen below must be - included in any redistribution. - **************************************************************************/ - #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 @@ -35,8 +16,6 @@ #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 NUMFLAKES 10 // Number of snowflakes in the animation example - #define LOGO_HEIGHT 30 #define LOGO_WIDTH 30 @@ -52,275 +31,82 @@ const unsigned char epd_bitmap_logoN [] PROGMEM = { 0x00, 0x04, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00 }; - -static const unsigned char PROGMEM logo_bmp[] = -{ 0b00000000, 0b11000000, - 0b00000001, 0b11000000, - 0b00000001, 0b11000000, - 0b00000011, 0b11100000, - 0b11110011, 0b11100000, - 0b11111110, 0b11111000, - 0b01111110, 0b11111111, - 0b00110011, 0b10011111, - 0b00011111, 0b11111100, - 0b00001101, 0b01110000, - 0b00011011, 0b10100000, - 0b00111111, 0b11100000, - 0b00111111, 0b11110000, - 0b01111100, 0b11110000, - 0b01110000, 0b01110000, - 0b00000000, 0b00110000 }; +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 - } - - testdrawbitmap(); // Draw a small bitmap image + 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() { -} - -void testdrawline() { - int16_t i; - - display.clearDisplay(); // Clear display buffer - - for(i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE); - display.display(); - delay(1); - } - for(i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=0; i0; i-=3) { - // The INVERSE color is used so circles alternate white/black - display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE); - display.display(); // Update screen with each newly-drawn circle - delay(1); - } - - delay(2000); -} - -void testdrawroundrect(void) { - display.clearDisplay(); - - for(int16_t i=0; i0; i-=5) { - // The INVERSE color is used so triangles alternate white/black - display.fillTriangle( - display.width()/2 , display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, SSD1306_INVERSE); - display.display(); - delay(1); - } - - delay(2000); -} - -void testdrawchar(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(SSD1306_WHITE); // Draw white text - display.setCursor(0, 0); // Start at top-left corner - display.cp437(true); // Use full 256 char 'Code Page 437' font - - // Not all the characters will fit on the display. This is normal. - // Library will draw what it can and the rest will be clipped. - for(int16_t i=0; i<256; i++) { - if(i == '\n') display.write(' '); - else display.write(i); - } - - display.display(); - delay(2000); -} - -void testdrawstyles(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(SSD1306_WHITE); // Draw white text - display.setCursor(0,0); // Start at top-left corner - display.println(F("Hello, world!")); - - display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text - display.println(3.141592); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(SSD1306_WHITE); - display.print(F("0x")); display.println(0xDEADBEEF, HEX); - - display.display(); - delay(2000); -} - -void testscrolltext(void) { - display.clearDisplay(); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(SSD1306_WHITE); - display.setCursor(10, 0); - display.println(F("scroll")); - display.display(); // Show initial text - delay(100); - - // Scroll in various directions, pausing in-between: - display.startscrollright(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrollleft(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrolldiagright(0x00, 0x07); - delay(2000); - display.startscrolldiagleft(0x00, 0x07); - delay(2000); - display.stopscroll(); - delay(1000); -} - -void testdrawbitmap(void) { + //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( @@ -330,49 +116,3 @@ void testdrawbitmap(void) { display.display(); delay(1000); } - -#define XPOS 0 // Indexes into the 'icons' array in function below -#define YPOS 1 -#define DELTAY 2 - -void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { - int8_t f, icons[NUMFLAKES][3]; - - // Initialize 'snowflake' positions - for(f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - Serial.print(F("x: ")); - Serial.print(icons[f][XPOS], DEC); - Serial.print(F(" y: ")); - Serial.print(icons[f][YPOS], DEC); - Serial.print(F(" dy: ")); - Serial.println(icons[f][DELTAY], DEC); - } - - for(;;) { // Loop forever... - display.clearDisplay(); // Clear the display buffer - - // Draw each snowflake: - for(f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE); - } - - display.display(); // Show the display buffer on the screen - delay(200); // Pause for 1/10 second - - // Then update coordinates of each flake... - for(f=0; f< NUMFLAKES; f++) { - icons[f][YPOS] += icons[f][DELTAY]; - // If snowflake is off the bottom of the screen... - if (icons[f][YPOS] >= display.height()) { - // Reinitialize to a random position, just off the top - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - } - } - } -} - diff --git a/marquee.c b/marquee.c new file mode 100644 index 0000000..37b2fc4 --- /dev/null +++ b/marquee.c @@ -0,0 +1,20 @@ +#include "marquee.h" +#include +marquee_t make_marquee(char* str) { + marquee_t marquee; + marquee.textLength = strlen(str); + marquee.text = malloc(sizeof(char) * (marquee.textLength + 1)); + strcpy(marquee.text, str); + marquee.scrolledBy = 0; + int pixelLength = marquee.textLength * 21; + marquee.scrollMax = 5 + pixelLength; + marquee.doesScroll = pixelLength > 128; + return marquee; +} +void scroll_marquee(marquee_t* marquee, int increment) { + //define the wrap point + int scrollMax = 5 + (marquee->textLength * 21); + //calculate the new scroll amount + int newScroll = marquee->scrolledBy + increment; + marquee->scrolledBy = newScroll <= marquee->scrollMax ? newScroll : 0; +} diff --git a/marquee.h b/marquee.h new file mode 100644 index 0000000..94f3288 --- /dev/null +++ b/marquee.h @@ -0,0 +1,18 @@ +#ifndef MARQUEE +#define MARQUEE +#ifdef __cplusplus +extern "C" { +#endif +typedef struct Marquee { + char* text; + int textLength; + int scrolledBy; + int scrollMax; + char doesScroll; +} marquee_t; +marquee_t make_marquee(char* str); +void scroll_marquee(marquee_t* marquee, int increment); +#ifdef __cplusplus +} +#endif +#endif diff --git a/upload.sh b/upload.sh old mode 100644 new mode 100755 index 4d7589c..0dee8c4 --- a/upload.sh +++ b/upload.sh @@ -6,3 +6,4 @@ then fi arduino-cli compile -b $BOARD arduino-cli upload -p $PORT -b $BOARD +arduino-cli monitor -p $PORT -- cgit v1.2.3-70-g09d2