Hi there. So I'm using an Arduino Nano Every for a smart watch, and at the moment it's just a basic digital watch that prints the time and date to an SSD1320 flexible OLED (eventually I will switch over to an ESP32 TinyPICO). For now, I'd like to try and figure out if it's possible to program a basic GUI that prints to the display, which I can navigate using physical push buttons, to do things like set alarms, timers, etc. I couldn't seem to find much on this topic except for using the Processing IDE and the Control P5 library, but from what I could tell that GUI only exists in an IDE window? If anyone can shed some light on this or point me in the direction of some resources that I can use, that would be greatly appreciated. Thanks guys!
Don't get too tripped up on it being a GUI. It's just an image or some font you need to display and then program the nearby buttons to do their thing.
What is possible:
320x132 White 3.83 inch SPI OLED Display Double SSD1320 16-level Grayscale - YouTube
But, your talk of a menu is essentially "character-based". Graphic menu can be done, but will consume more SRAM than text.
There is an Arduino menu library:
ArduinoMenu library - Arduino Reference
Ray
the answer is yes, you can do all those things. to many different degrees. How complex does this thing need to be? how dynamic does it need to be?
I've done a few from scratch, its not a lot of fun...mostly just tedious work laying everything out. I'll attach a class I wrote for my last one, ifs very purpose built, so you wont be able to just use it. but it will give you an idea.
There are a bunch of libraries writing on the subject, I've not actually used any of them, so I cant recommend one specifically, just that you investigate them(i plan to the next time i need a menu)
processing is java code that runs on the computer, not part of arduino idea, but a different one called processing. Not what you'd use for the task at hand.
Have a look at Nexion displays or these nice round ones on eBay have a lot of support ( google) and also allow a background picture to be uploaded
Put this in eBay -
“ round LCD Display Module 240×240 Resolution
GC9A01 Driver 4 Wire SPI Interface Board”
This display stuff is not hard! The first order of business is to understand your graphic display coordinates: example is the common ILI9341 and the associated Adafruit library:
/*************************** ILI9341 320x240 DISPLAY LAYOUT ****************************
0,0
----------------------------------------------------------------------------> 319
| nnnT DOW
| lcd.fillRect( 0, 0, 319, 59, 0); // blank top
|
|
|<- 059
|
| lcd.fillRect( 0, 60, 319, 114, 0); // blank middle
| HH:MM:SS A
|
|
|
|<- 174
| lcd.fillRect( 0, 175, 319, 64, 0); // blank lower
|
| MON DD YYYY
|
|<- 239
*/
Use a text editor or graph paper, mark the corner coordinates. Then in "overwrite mode", position major text features for captions or elements.
The rough sketch can be left in your Arduino code as a comment for reference!
As can be seen above, very little programming is needed to produce a nice display and informative!
void setup() {
lcd.begin();
lcd.setRotation(3); // landscape with SPI conn J2 to left side.
lcd.fillScreen(ILI9341_BLACK);
lcd.setCursor(0, 0);
lcd.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
// lcd.setTextSize(1); // Tiny 53 char / line
// lcd.setTextSize(2); // Small 26 char / line
lcd.setTextSize(3); // Medium 17 char / line 10Pixels Wide x 25 Pixels / line
//lcd.setTextSize(4); // Large 13 char / line
lcd.setCursor(0, 0);
lcd.print("Testing circuit:\n\r\n\r");
It is important to note how various size fonts will change character mapping per line.
Often, the whole screen is only drawn once in setup{} although one may wish to create a function for such an event if program logic requires the screen to be cleared & repainted.
lcd.drawFastHLine(0, 23, 319, ILI9341_RED); // Hello Screen
lcd.setTextColor(ILI9341_CYAN, ILI9341_BLACK);
lcd.setCursor(0, 25);
lcd.print("by: Ray Burnette");
lcd.setCursor(0, 50);
lcd.println("Barometric Pres.");
lcd.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
lcd.setTextSize(1);
lcd.setTextWrap(false);
lcd.fillScreen(ILI9341_BLACK);
lcd.setCursor(30, 100);
lcd.print( "History updates every 36 minutes"); // 48 hours for entire display
}
Now, things on-screen like the graph and numeric data can be output in loop{}
void loop() {
barometer.setControl(BMP085_MODE_TEMPERATURE); // request temperature
lastMicros = micros();
while (micros() - lastMicros < barometer.getMeasureDelayMicroseconds()); // wait for conversion (4.5ms delay)
if (Fahrenheit) { // read calibrated temperature value in degrees Fahrenheit
temperature = barometer.getTemperatureF();
} else {
temperature = barometer.getTemperatureC();
}
temperature = temperature - 4.0; // individual unit correction by observation (Anagela's unit)
lastMicros = micros();
barometer.setControl(BMP085_MODE_PRESSURE_3); // request pressure (3x oversampling mode, high detail, 23.5ms delay)
while (micros() - lastMicros < barometer.getMeasureDelayMicroseconds());
pressure = barometer.getPressure(); // read calibrated pressure value in Pascals (Pa)
pressure += localCorrect; // rough adjustment ... as we are plotting, non-adjusted pressure is just as appropriate
inHg = double((pressure) * mmhg_conversion * 10.0);
M = pressure / 100L; // scale to hPa
// graph values are typically between a low of 985 and a high of 1040
// clipping high/low forces the dynamic range to be limited to a maximum change of 45 hPa
if (M > 1040L) M = 1040L; // clip (flatten) ceiling
if (M < 985L) M = 985L; // clip (flatten) floor
if ((TimeMarker + GraphResponsemS) < millis() )
{ // machine clock has advanced beyond trigger, so store current pressure
TimeMarker = millis(); // reset trigger for future (next) event
StoreHistory(); // update pHistory matrix
lcd.fillRect(xRect, yRect, wRect, hRect, 0) ; // erase history graph area with transparancy
displayHistory(); // Intent is to only display on command
}
displayCurrent(); // Header and current sensor data
drawLegends(); // Grid and right-hand graph legends
}
void StoreHistory ( void ) { // Creates a boxed border using lines 0 & 1
int n; // avoid compiler complaints in for(;;) loop
// array [0] is reserved for newest value // Therefore [80] = [79], [79] = [78],..., [1]==[0] after shift
for (n = 80; n > 0; n--) // shift history array to the right, oldest value [80] is lost
{
pHistory[n] = pHistory[(n - 1)]; // shift data right, oldest value lost, [1] becomes [0] the current value
}
pHistory[0] = M; // save current "adjusted" pressure hPa [0]
}
void displayCurrent( void ) {
int temp1, temp2; // working vars for type conversion
lcd.setTextSize(3); // Print hPa and inHg legends and readings in large font
lcd.setCursor(0, 1); lcd.print("hPa inHg temp");
lcd.setCursor(0, 35); lcd.print( M );
if ( M < 1000 ) {
lcd.print(" ");
} else {
lcd.print(" ");
}
temp1 = inHg / 10; // Integer component
temp2 = ((inHg / 10) - (float) temp1 ) * 100; // 2 decimal places
lcd.print(temp1); lcd.print(".");
lcd.print(temp2);
lcd.setCursor(235, 35);
lcd.print( temperature, 0 );
if (Fahrenheit) {
lcd.print(" F");
} else {
lcd.print(" C");
}
}
void displayHistory( void ) {
long M;
long minimum = 1040L;
long maximum = 985L;
uint8_t h, z;
uint16_t x, y;
z = 0; // z will span 0 to 319, full screen landscape width in pixels
for ( x = 1; x < 240; x++ ) // 80 elements @1 element per 18 minutes = 10 elements per 3 hours
{
if ( x % 3 == 0 ) { // this provides for skipping every 3th position for bar spacing
z++;
} else if (pHistory[z] != 0) { // array is initially init to zero value, no need to plot this
if (pHistory[z] < minimum) minimum = pHistory[z]; // capture the lowest 24 hour pressure reading
if (pHistory[z] > maximum) maximum = pHistory[z]; // capture the highest 24 hour pressure reading
h = (pHistory[z] - 985) * 2; // h is for height and x2 is for scaling factor
y = 200 - h; // Adafruit's GFX y coordinates plots upside down, flip reference
lcd.drawFastVLine(x, y, h, ILI9341_WHITE); // 2 bars are drawn per array element and 1 blank space for separation
}
}
y = 200 - ((minimum - 985) * 2);
for (x = y ; x < 200; x++) { // Alternate display mode
lcd.drawFastHLine(1, x, 245, ILI9341_BLACK);
}
// drawFastHLine(uin86_t x0, uin86_t y0, uint8_t length, uint16_t color);
lcd.drawFastHLine(1, y, 245, ILI9341_WHITE); // draw baseline 24 hour lowest reading
y = 200 - ((maximum - 985) * 2);
lcd.drawFastHLine(239, y, 6, ILI9341_YELLOW); // draw marker tic 24 hour highest reading
}
void drawLegends( void )
{
// Legends and axis for display
lcd.setTextSize(1);
// Atlanta: High = 30.79 on 1/6/1924 Low = 29.08 on 1/11/1918
// 2X scaling: 1040 - 1026 = 14 x 2 = 28 pixels
lcd.setCursor(240, 84); lcd.print("_ 1040= 30.71"); // setup Y legends
lcd.setCursor(240, 112); lcd.print("_ 1026= 30.30");
lcd.setCursor(240, 140); lcd.print("_ 1012= 29.88");
lcd.setCursor(240, 168); lcd.print("_ 998= 29.47");
lcd.setCursor(240, 194); lcd.print("_ 985= 29.09");
// tiny fonts for timeline legend @53 char/line (6px/char)
lcd.setCursor(0, 205); lcd.print("N ^ ^ ^ ^ Historical ");
lcd.setCursor(0, 213); lcd.print("O 1 2 3 4 Timeline ");
lcd.setCursor(0, 221); lcd.print("W 2 4 6 8 In Hours ");
lcd.drawFastVLine(0, 88, 112, ILI9341_RED); // setup Y axis
lcd.drawFastHLine(0, 200, 238, ILI9341_RED); // setup X axis
lcd.drawFastHLine(0, 201, 238, ILI9341_RED); // setup X axis double-width X axis for emphasis
}
BP180_GLCD_48.zip (33.3 KB)
does your do any other than print to the display? Thats what the op asked for, and that DOES take a bit of programming. Not really difficult or anything, but lots of code.
These seem very convenient, if your willing to spend the money on their screens...which are pricey. But they built a whole computer GUI to help you build your uC GUI. Do you remember "frontpage", it basically wrote the html for a webpage for you. Nexion is similar in concept.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.