Compared with the incredible projects you could create with the GIGA dual core processor, this project is pretty mundane. It's just a tutorial about how to build a graphical user interface or GUI. But it may be a big help to someone who has never built one before, so I am presenting it here.
I was excited to try the Arduino Giga and its new Display shield. It is a very powerful combination – a display capable of implementing a full featured GUI and a dual core processor with built in WiFi and all kinds of other features.
At first, I was especially interested in learning about LVGL, as it is the Arduino recommended platform for creating a GUI on the display. LVGL (Light and Versatile Graphics Library) is a professional framework for building GUIs. It comes with a huge assortment of features, built in widgets like buttons and sliders, and looks capable of creating amazing user interfaces. I worked through many of the examples provided, and they all worked as advertised. But after two days of experimenting with their examples, I found I was still a long way from being able to design a GUI on my own. Simple things like changing font size seemed to be strangely difficult. I decided I might be better off building my GUI from the basic functions available in the GFX and Touch libraries.
So this project is about building a GUI from scratch. It turns out it’s not that difficult. I was able to do everything I wanted to do using the Arduino Giga Display GFX and Touch libraries. And I did it without going through the arduous task of mastering the band new (and not at all intuitive) language of LVGL.
To demonstrate a “build from scratch” GUI, I am implementing a TicTacToe game. I know this is a pathetic application of the GIGA, which is probably capable of playing 10, 000 TicTacToe games simultaneously. But it does require a GUI with various graphics and a touch screen. So it serves the purpose.
PlanningDesigning and implementing a GUI begins with planning. We need to know the coordinates of our graphics, especially the locations of buttons that are going to be touch sensitive. I used EXCEL to do the planning, using square cells each representing 20 x 20 pixels on our 800 x 480 pixel display.
For my TicTacToe game, I need a 9 box grid, and each box must be a button the player can push to put an X in that box. I also need two other buttons – one the player pushes when he wants to go first, and the other he can push to have the computer play first. I also need to display messages like “You Win” or “It’s a Tie”. I don’t show in my EXCEL file where these messages go, but they basically replace the “TIC TAC TOE” title.
I want the display horizontal – meaning 800 across and 480 pixels high. To get text horizontal, we need to rotate the display 90 degrees using GFX's setRotation(1) in setup. We also need the coordinate system to match what we have in the EXCEL drawing above. Once we have setRotation(1), the GFX graphics match these coordinates, but the Touch coordinates don’t match. So in the main loop where we are looking for button touches, we do the following:
touch_x = myPoint[0].y;
touch_y = 480 - myPoint[0].x;
MyPoint.x and.y are the touch coordinates supplied by the Touch library. The conversion above gives us x and y coordinates for touch that match the coordinates used in our plan. So we can now refer to display coordinates for both graphics and touch that match the coordinates listed in our EXCEL file.
Another topic that probably comes under planning is font management. The Arduino Giga Display GFX library comes with a built in font, which is derived from the default font built into Adafruit’s GFX library. You can use this default font and make it as large as you want using Display.setTextSize)(). However, it is a small font to start with, and pixelates rapidly as you scale it up.
For labeling buttons, this default font works fine. But for the title and X’s and O’s where I wanted large text, the default font didn’t work. Fortunately, though you have to refer to Adafruit documentation to find out about it, it is fairly easy to add other fonts, so I added a 24 pt Sans Bold font to my sketch and used it for the title and the X’s and O’s. We will talk more about it when we get into software.
HardwareThe hardware for this project is just the GIGA and its Display Shield. The display shield snaps into the back side of the Giga, and that is it. Documentation to get you started, with both hardware and software, is here:
https://docs.arduino.cc/tutorials/giga-display-shield/getting-started
One minor problem I encountered when I first connected the shield was that it attached loosely to the GIGA but didn’t snap onto it. I had to straighten some leads before it actually snapped in and was firmly attached to the GIGA.
SoftwareIn an attempt to make the GUI design a little clearer, I have divided up the TicTacToe sketch into 3 files or tabs in the Arduino IDE. (There are 4 files/tabs altogether, because our 24 pt font is another file in the sketch.) The first file creates objects, definitions, and global variables. It also contains the setup routine. The second one contains the main loop and the graphical user interface. The third one contains the TicTacToe game logic. We will discuss each of these three files in more detail.
Set Up
In our first file, just called TicTacToe, we have “includes” for the Arduino_GigaDisplay_GFX library, the Arduino_GigaDisplayTouch library, and our 24 pt Sans Bold font. Next we create an object or instance of display and touch. The GFX library uses an RGB565 color scheme where colors are defined in 16 bits. I included some #define statements so that common colors can be referred to by name. Next comes a few global variables, then the setup() routine.
The GUI Itself
The GUI Main Loop file is where everything associated with the GUI resides. So everything associated with the display and touch screen basically resides here.
The newGame() routine is where all the graphics are initially set up – the grid, the title, the buttons, and labels. The coordinates all come from our EXCEL planning sheet, although I did make some minor changes as I went along, like buttons being wider than originally planned to accommodate the required text. This routine also initializes the game variables that need to be reset at the beginning of a game. You can also see where we specified the larger font. And then we changed it back to the default font for the button labels by just using Display.setFont() with an empty font specification.
The loop() routine basically performs just one function. It watches for buttons to be pushed. When it sees a button press, it goes to other routines to determine which button was pressed and what other actions need to be performed. I chose to turn off the touch system when other functions are being performed. I am not sure this is necessary, but I did discover in my initial look at the touch system that it sometimes recorded multiple touches, as though a debouncing function needed to be added. Turning it off when a button press is detected seemed to resolve this issue.
The FindButton() routine determines which button was pushed and returns its number.
The DisplayXorO() routine, as the name implies, puts X’s and O’s in the grid, depending on which box in the grid was selected and whether the player or computer initiated the move. It does some other things as well. The status of the TicTacToe game is contained in a 3 x 3 array called myarray. In this array, 0 signifies an empty square, 1 a square with an X, and 2 a square with an O. This array is used by the “computer”, in this case the GIGA, to figure out its next move. So DisplayXorO() also updates this array, as well as keeping a count of moves and checking the progress of the game.
The statusCheck() routine looks for a game ending result. If found, it displays a message: “You Win”, “Computer Wins”, or “It’s a Tie”.
Game Logic
The third file, called GameLogic, is where the computer’s moves are determined. It tries most desirable moves first, like “Is there a place I can put an O that wins the game for me?” and gradually moves to less desirable goals, eventually settling for “Put an O in any empty box.” As you probably know, when this approach is fully implemented, it is possible to tie the computer, but impossible to beat it. But who wants to play a game you have no chance of winning? So in this version, I left out two steps, making the computer pretty good, but it is still possible for the player to win.
Incidentally, this game logic treats the nine TicTacToe boxes as 0-8, while the display software refers to the boxes as 1-9. So you will see in the putOinBox(pos) routine that pos goes out to DisplayXorO() as pos+1.
Some Additional Info on Fonts
You might be able to create your own GUI with the default font or at least with the default plus the one I have added for TicTacToe. But if you really want flexibility with fonts, there is a lot more info on fonts here:
https://learn.adafruit.com/adafruit-gfx-graphics-library?view=all#using-fonts
And here is Adafruit’s entire collection of fonts:
https://github.com/adafruit/Adafruit-GFX-Library/tree/master/Fonts
They all work just like the one I have used here.
ConclusionI have tried to show how to build a simple GUI from scratch, using just the tools provided by the GFX and Tough libraries. I’m sure that, if you build GUIs for a living, something like LVGL is a better way to go. But, if you are just a hobbyist like me, perhaps this “build from scratch” approach is the better solution.
Hopefully, there is enough basic information and examples here that will allow others to build a GUI for something other than TicTacToe. The GIGA with its display shield would make a great smart thermostat or sprinkler system programmer/timer, for example.
Comments