7 Keyboard Input and Printed Output

For most simple programs it will be enough to read information in from the standard input device (e.g. a keyboard) and write information out to the standard output device (e.g. a terminal screen). We will focus on those capabilities in ways that make it easy to extend your understanding to reading and writing files on storage media.

Printed Output

The simplest programs have input values built right into the code by assigning variables, so we will start with output, focussing on three types of data, to be written out as human readable characters.

  • String constants are enclosed in quotes and used simply to label the rest of your output. String or character variables can be created in your programs, however we will focus on numbers,
  • integers, unsigned integers and
  • floating point numbers with decimals.

print(), or something with a similar name, is the usual function called, reflecting history of mechanically printing characters on paper, either one at a time, or line by line. Thinking of that step-wise mechanical process may help you visualize how to print more complicated messages in simple steps.

Python

print(i,j,x)

will print all three variables, leaving spaces in between and adding a line break at the end of printing, just as you might expect. Floating point values will be printed with many decimal places, usually more than you wanted to see. Formatting your output will make it more readable.

print("A format string for unsigned %5u, int %7d, and double %8.3f"%(i,j,x));
print("A format string for unsigned {0:5d},"
" int {1:7d}, and double {2:8.3f}".format(i,j,x));

are two different ways to accomplish the same thing in Python. The first one is deprecated (meaning it still works, but may not in the future) and descends from C. The second one is the preferred approach going forward. Recognize the first one when you see it, but try to use the second one if you want your code to keep working in the long term.

  • {0:5d} tells format()to use the first argument (i index value zero) and format it as an integer 5 or more characters long, padding the start with spaces if needed.
  • {1:7d} formats the second argument as an integer 7 or more characters long. Note that you can break a string across lines for readability by adding two quotation marks.
  • {2:8.3f} fills in the string with the third (2) argument formatted with 3 decimal places in a slot at least 8 characters  long.

Try it yourself by starting with the Printing and Formatting Data notebook in the Python Learning Sequence.

C

printf("A format string for unsigned %5u, int %7d, and double %8.3f\n",i,j,x);

will print the text string inside the quotation marks, filling in the three numeric variables at the locations with the % formatting elements

  • %5u tells printf() to expect something the sizeof() an unsigned variable and to format it as a range from 0 to a large positive value, using leading spaces so as to print at least 5 characters.
  • %7d is similar, except it interprets the raw data as an integer with a positive and negative range.
  • %8.3f is for a double variable, and will use at least 8 spaces, including 3 after the decimal point. If you send a float variable to printf() it will be automatically converted to a double.
  • \n adds a newline character to the end of the output. In legacy systems this often might be translated as two characters, a carriage return to move the print head back to the beginning of a line and a line feed to turn the roller and move the paper up a line. Watch out for them as potential hazards when interfacing with older equipment.

You need to make sure the data types of the variable list match the data types in the format string or unpredictable things may happen.

C will not print anything you don’t explicitly specify, making it easy to build a line piece by piece, but not automatically adding spaces and line breaks where a human might want them.

printf("A format string for unsigned ");
printf("%5u", i);
printf(", int ");
printf("%7d", j);
printf(", and double ");
printf("%8.3f", x);
printf("\n");

Building output one piece at a time like the code above can be useful when you want to write multiple array elements from the same row on the same line using a for() loop.

Arduino

Serial.print("A format string for unsigned ");
Serial.print(i);
Serial.print(", int ");
Serial.print(j);
Serial.print(", and double ");
Serial.print(x, 3);
Serial.print("\n");

achieves almost the same output as the C code in the previous section, sent to the USB port to appear on your serial monitor. The stock Arduino libraries require you to print things one chunk at a time to allow simpler, more compact compiled code on processors with limited memory space.

It is possible to add Serial.printf() functionality, but that will limit the use of your code to environments where others have already made the same modifications. (The environment for the Adafruit SAMD processors allows Serial.printf() if you #include"RTClib.h") For a start, defining some simple macro substitutions will make life easier:

#define P Serial.print
#define PCS Serial.print(", ");Serial.print
#define PCSL Serial.print(", ");Serial.println

placed at the top of your sketch will let you write the same code as:

P("A format string for unsigned ");
P(i);
PCS("int ");
P(j);
PCS("and double ");
P(x, 3);
P("\n");

Or even easier if all you wanted was commas between the values without the string labels:

P(i);    PCS(j);    PCSL(x, 3);

Usually putting multiple statements on the same line is bad form, making code harder to read. I think grouping those three together actually helps readability, making it easier to recognize it as equivalent to:

printf("%u, %d, %8.3f\n", i, j, x);

Note that Serial.print(x,3) will print x with 3 decimal places if x is a floating point number, but will print it in base 3 if x is int or unsigned. This is useful if you want to print integers in binary (2) or hexadecimal (16), but should usually be avoided.

Try it yourself by starting with the Define Print Macros sketch in the Arduino Learning Sequence.

Keyboard Input

Sometimes you need some input from the user of your program. Even simple keyboard input can be unpredictable because of the human behind the keyboard, so your user interface needs to deal with input errors without crashing. These pointers will give you a start, but the easiest way to get data into your programs will probably be typing it into your source code, or reading it into your Python code from a CSV file.

Python

Use Python’s input() function to get a string of text from the user, then convert it to numbers as needed with int() or float() functions. Use try: / except: to catch the inevitable errors your users will make. Experiment in a notebook.

text = input("Enter a number:")
print("You typed>>"+text+"<<")
try: 
    i = int(text)
except:
    print("Exception generated: " + text + " is not an integer -- setting i to zero")
    i = 0
print('As an integer it was converted to: {0:d}'.format(i))

Arduino C

Serial.read() will let you read character by character from the serial port. To make this work you will need to check using Serial.available() to see whether there are characters out there to be read. Details in S1.5_Get_User_Input of the learning sequence.

Serial.parseInt(), Serial.parseFloat(), and Serial.readStringUntil('n') will validate the data automatically. You will need to set the timeout long enough to let the user provide some input using Serial.setTimeout().

File Input

Python

Check out Learning Sequence 1.3.1 to see how to load CSV files into a pandas dataframe.

License

Icon for the Creative Commons Attribution-ShareAlike 4.0 International License

Rick's Measurement for Mechatronics Notes Copyright © 2019 by Rick Sellens is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License, except where otherwise noted.

Share This Book