Overview of the Serial Communication Protocol

Big Print

To create the block text on the display, the user calls bigPrint, which accepts two arguments: text, the string to display, and position, a tuple of the upper left corner that marks the starting point at which the block numbers are placed on the screen. (Python classes expect the instance of a class itself, called self, as the first argument of each class method. Therefore, it looks like each method takes one more argument than it actually does – even methods that take no arguments.)

Lines 95 and 96 break apart the position tuple and define x and y. The keen observer will note that the y coordinate is decoded from the first position in the tuple, which is the opposite of typical Cartesian coordinates. This is just the way curses handles coordinates. If your text seems to be going awry, it never hurts to check that you haven't swapped x and y at some point. Line 97 stores the starting y position in originalY which is reset after drawing each character.

Line 99 starts a set of loops to retrieve one character at a time from text, the string to display. The next line checks to see if the program knows how to draw this character (i.e., it is defined in the self.digits dictionary). If so, the drawing proceeds.

Starting on line 101, if you go back to the digit definitions in __init__, the first line is always blank (created by the newline after the triple quotes). That way, the columns of the digits align so they are easier to read (and define). This flag is needed later to discard the blank line.

Each line in self.digits is a full-size representation of the digit to be drawn. Therefore, line 102 (working right to left) uses split to divide self.digit at each newline. The index char comes from the loop on line 99 – the character the program is working with right now. The for then processes each character with the next block of code.

If firstLine is true, the flag is cleared (line 104) and the program continues. This discards the blank line at the top of the digit.

The outLine variable is the string that is drawn to the screen. Lines 107-109 create content by walking down each character in line (the big digit definition). If it is a pound sign (hash mark), the code adds chr(97) to outLine. ASCII character 97 is normally a lowercase a, but in "graphics" mode it is a solid block. If the character isn't a pound sign, the program passes through whatever is in the original string (probably a space).

Line 110 tells curses to put it all on the screen; that is, on the screen saved in self.screen, it adds a string (addstr). The first two arguments are the screen coordinates where the string is to appear (remember, the y coordinate is first). The third argument is the string to draw. I use a format statement defined with {0:5s} to make sure that five characters are always output. The final argument draws with graphics characters (curses.A_ALTCHARSET) instead of text. The end of the block has some housekeeping to get ready for the next line and ultimately the next digit by incrementing y, then checking to see whether five lines have been drawn. If so, it moves to the next digit and back to the top of the requested coordinates to draw the next digit before incrementing x by 7. If the program were drawing one character per "cell," it would only have to move over by one, but because each "cell" in this case is essentially a pixel it has to move over the full width of the character, plus a little to space things out.

Main Loop

The main loop (lines 116-134) calls all of the functions discussed so far. It starts by initializing looping – the flag that signals whether to exit – to True. The time.time function gets the current time, and nextClock is set to startTime + 1 before the loop starts on line 121.

In the loop, key initializes before trying to get a key in a try/except block. If a key is available, the try succeeds, and key contains the value; otherwise, the except block runs and does nothing (pass).

Lines 128 and 129 check to see whether key is a space. If so, looping is set to False. The next trip through the loop will terminate because looping is the condition checked (line 121) to see whether it should continue or not.

The value of nextClock (line 119) is when the clock needs to be refreshed. The loop is running much faster than once per second. So once the current time (time.time) is greater than nextClock, it is time to update the display. Line 132 gets the new time, and line 133 calls self.bigPrint and formats the current time as hour:minute:second. Finally, line 135 increments nextClock by one second so the loop knows when to refresh the display again.

By keeping track of when updates need to happen in the future, the main loop can keep doing other tasks (e.g., monitoring other communications channels, checking the status of a server, etc.) until it is time to redraw the display.

The final two lines run the program. Everything I've talked about so far won't do anything unless it is initialized and called. Line 136 creates an instance of the class in screen, and screen.loop (line 137) starts the main loop to set everything in motion.


In this article, I explored serial communications, starting with electrical specs and working all the way up to protocols and libraries. I also looked at different flavors of serial and how they can interact with one another. The next time you need to talk to a unique device or move data to or from a small-board computer like the Arduino, consider starting with these ideas and expanding them into your next project.

The Author

Scott Sumner is the Assistant Manager of the Charlie Noble Planetarium at the Fort Worth Museum of Science and History. He enjoys using Python to solve as many problems as possible.

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Perl: Arduino Project

    With a few lines of self-written firmware and a simple Perl script, Perlmeister Mike Schilli trains one of his Linux computers with a plugged in Arduino board to switch electrical equipment on and off using a relay. Enchanting.

  • Nerf Target Game

    A cool Nerf gun game for a neighborhood party provides a lesson in Python coding with multiple processors.

  • Escape Room Puzzle

    A digital puzzle presents a challenge for young people in an escape room.

  • WiFi Thermo-Hygrometer

    A WiFi sensor monitors indoor humidity and temperature and a Node-RED dashboard reports the results, helping you to maintain a pleasant environment.

  • ESP8266 for WiFi Sniffing

    The ESP8266 is in the core of many IoT devices. Thanks to ESP8266 sniffer mode, you can monitor the WiFi medium for diagnostics and optimization.

comments powered by Disqus

Direct Download

Read full article as PDF: