Outils pour utilisateurs

Outils du site


issue172:micro-ci_micro-la

Ceci est une ancienne révision du document !


“LADIES AND GENTLEMEN, BOYS AND GIRLS. CHILDREN OF ALL AGES” (That last part is for Ronnie [“guilty as charged” - Ronnie]). Welcome to part 6 of Micro This Micro That!

This month (August 2021), we’ll take a look at using the SSD1302 128×64 I2C OLED Display with our Microcontrollers. For all intents and purposes, it’s pretty much the same between the ESP8266, ESP32 and RPi Pico with a few exceptions. Those exceptions are where we connect the wiring for the I2C device and the way we access the I2C device. For many reasons, I selected the ESP8266 for this month’s project.

Lately, both the ESP32 and RPi Pico MicroPython firmware have started to support Software I2C which works on all output pins as opposed to the limited Hardware I2C which supports only the two I2C bus structures. The ESP8266 still uses the hardware-only I2C methodology.

To use the hardware-only option on any of the microcontrollers, you need to import the I2C and Pin classes from the machine library, then define the scl (clock) and sda (data) pins using the GPIO number. The frequency parameter is optional.

from machine import Pin, I2C

# construct an I2C bus

i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

If, on the other hand, you want to use the software I2C support, you can do it like this…

from machine import Pin, SoftI2C

# construct an I2C bus

i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)

Very similar, but, of course, if you are using the software solution, you really have to be sure you define the pins. In the earlier versions of the RPi MicroPython firmware, you could simply use

i2c = I2C(0)

And use the defined pins for bus 0 (or 1). This, however, created a number of problems, since there were so many options for the I2C bus pins. So, to be safe and avoid confusion, always define your pins.

The Wiring

In this month’s project, the wiring is really simple. There’s only 4 wires. 3 volts, ground, data and clock. On my breadboard, I used the following pins.

Of course, the red and black pins are Voltage and ground, the yellow is clock, and the white is data. You can use whatever color wires you wish. The ESP8266 has very limited memory, so if you are using that microcontroller, you might want to back off your files and reflash with the latest and greatest firmware version from http://micropython.org .

Scanning the I2C Port

Once we have the wiring done and the firmware flashed, we want to make sure that everything is working correctly before we try to do a bunch of coding. We’ll use the REPL window in Thonny to do a quick scan of the I2C bus.

from machine import Pin, I2C
i2c = I2C(scl=Pin(5), sda=Pin(4))
devices = i2c.scan()
for dev in devices:
      print(hex(dev))

0x3c

We can see that there is only one I2C device in our project and it is at address 0x3c, which is correct for our display.

Before we get into the coding of this month’s project, we need to download a driver library. You can find it at https://github.com/peterhinch/micropython-font-to-py. This will enhance our ability to print to the display. We’ll use this library in a little bit. Go ahead and download the zip and unpack it somewhere where you can get to it quickly.

The Basic Code

We will start with a simple program to talk to the display. To use the display, you’ll have to get a copy of the base driver library for the ssd1306. If you are using the Raspberry Pi Pico, you can find it at https://github.com/makerportal/rpi-pico-ssd1306. Unzip it and copy the code onto the Pico. If you are using the ESP32, you can get the driver at https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py. Again, copy that to the device. If you are using the ESP8266, the driver is already built into the latest firmware.

This test program will simply verify that we can write to the OLED and that it shows us what was sent to it.

from machine import Pin, I2C import ssd1306

# using default address 0x3C i2c = I2C(sda=Pin(4), scl=Pin(5)) display = ssd1306.SSD1306_I2C(128, 64, i2c)

display.text('Hi, Human!', 0, 0, 1) display.show()

Save the file as displaybasic1.py and run it. If everything is working correctly, you will see something like this.

Let’s take a closer look at a couple of the lines of code. When we create the display object, we send the driver the width and height in pixels of the display and the bus that it is on. If you are using a smaller or larger display, your values will be a bit different.

display = ssd1306.SSD1306_I2C(128, 64, i2c)

The next line is the way we send the text to the display. The parameters are text string, column (x), row (y), and color. In our case, we are going to display it in only white (the 1).

display.text('Hi, Human!', 0, 0, 1)

Finally, to actually display the text, we use the show method.

display.show()

That’s it. We’ll look at the graphics capability and other options of the “regular” driver in a later article. If you get the expected results, then we’ll look at the library we downloaded earlier.

Better Displays

If you are one of the lucky people who have great eyesight, then you can read the display from 3 feet or more without problems. However, for an old man like me, while the display is bright, trying to read anything greater than about 16 inches away is a strain. Wouldn’t it be nice to be able to use a bigger and denser font? That’s what we are here to talk about. (I know, it took me 4 pages to get to the real reason we are here. Sorry about that.)

The distribution zip of micropython-font-to-py contains a really large number of files, but we need only a few for right now. In the writer folder, you’ll need to copy the following files to your microcontroller; font6.py, font10.py, courier20.py, freesans20.py, ssd1306_setup.py and writer.py

We’ll be modifying the writer_demo.py file, so you can either copy that as well, or just get the code from the repository for this month. The first four files are the font files, the ssd1306_setup.py file allows you to set your I2C pin configuration, and the writer.py file is the actual driver that does all the magic. We’ll start by modifying the ssd1306_setup.py file to set our configuration.

As usual, the imports come first. There is no change to these three lines:

import machine

from machine import Pin

from ssd1306 import SSD1306_SPI, SSD1306_I2C

If you are using a ssd1306 that has 128×64 resolution, then you don’t need to change anything here. However, if you are using a 128×32 ssd1306, change the height value to 32. I show it commented out here.

WIDTH = const(128)

HEIGHT = const(64)

# HEIGHT = const(32)

The other thing that needs to be changed is in the setup function, down near the end of the function. The first part allows you to use an SPI based display. I’ve just got it here for reference. Since this driver was originally written for the Pyboard, we will have to change a few things here. In order to make things easier for our three possible microcontrollers, I’ve commented everything out in the I2C portion of the function except the portion following the last else. Make sure that you fix the indentation so that the lower portion of the code falls under the starting if statement (if use_spi:). Once again, make sure the I2C pin numbers match your setup (code shown above).

At this point, we need to edit or create the writer_demo.py file. I’m going to leave out most of the comments here, but they will be in the file in my distribution.

I’ll show you the main parts of the demo file and then I’ll explain how you can change it.

import machine

from ssd1306_setup import WIDTH, HEIGHT, setup

from writer import Writer

import time

Again, we start with the support file imports. We also need to import the font file(s) that we want to include. Since I purposely chose to use the ESP8266, memory is at a premium, so I’m going to deal with only one font file at a time in this demo. For now, we’ll begin with just the font10.py file. I’ve commented out the other two in our code (I’ve chosen to ignore the courier20.py font, but you can certainly include it if you wish).

# Font # import freesans20 # import font6 import font10

Now that the imports are done, we’ll create a test function. The original author chose to make the function generic in nature, so he included the parameter use_spi. I chose to include this as well, and it is set to False by default. We call the setup function from the ssd1306_setup.py library with both parameters (use_spi and soft (software I2C)) set to False. It’s important to remember to comment out the fonts that you won’t be using and uncomment the font that you will be using.

def test(use_spi=False):

  ssd = setup(False, False)
  wri = Writer(ssd, font10)
  # wri = Writer(ssd, font6)
  # wri = Writer(ssd,freesans20)

The base (always used) code is almost done. You can always use this code in your own project.

You will also want to include the next line (first line below) as well. This ensures that the display starts at row 0, column 0, at startup. The next steps are to get the current time and date (time.localtime()) and format it to show the date on the first line and the time on the second line. Finally, we use ssd.show() to actually display the information. The information that we get from the localtime call is returned as (2021, 8, 4, 8, 52, 49, 2, 216). Year, Month, Day, Hour, Minute, Second, Milliseconds. Remember the data is zero based, so the date information is dt[1], dt[2], dt[0] for the crazy americans. If you live in one of the saner countries, feel free to format it as you wish! (code shown above)

This is where I deviate (moreso) from the demo code that the author provides. I want to show how to display the time every second and what you have to do to overwrite the previous information. I chose to do this for a period of 2 minutes. If you feel that is too long or short, go ahead and change the 120 in the for loop to a different value.

We set the text position to row 18 column 0 (shown below) to overwrite the previous time display, verify that the seconds have a leading zero, send the string out, tell the driver to display the new information and then sleep for 1 second. The value of row 18 will change depending on the font you are using. I had to try various values to come up with that. I found that if you are using font6, then you should use 14, for font10 use 18, and for freesans20, 20 works well. You can tweek these values to suit your needs.

Finally, we call our test function to start the fun.

test(False)

Save the file as writer_demo2.py (just to make sure the original one is still there), and run the program. There is a chance that, if you are using the ESP8266, then you might get a memory error when you try to run it. The author’s documentation suggests that you should be able to use the file writer_minimal.py to replace writer.py. However, when I tried to use it, I got errors. So, if you are having memory issues, try to remove any unused files from your device and/or try a smaller font file.

Here is what each font looks like on my display. Font6.py Font10.py

Freesans20.py

And the basic driver again for comparison.

You can see that either of the three generated by the Writer driver are much better at a distance than the basic driver. Even when using font6.py, the text is easy enough to read at about 2 feet and, at least for me, font10.py is the best when you consider the readability at a distance and the memory size.

As I suggested earlier, there is a lot more to both the “original'' ssd1306 driver and the enhanced writer program. In addition, we used only a small part of the font-to-py repository. There is, as the name suggests, a helper program that will allow you to create your own font files (from ttf font files) that can be used in your own programs. We’ll look into all of these in later articles.

You can find all of the code and image files on my github repository at https://github.com/gregwa1953/FCM172_MicroThisMicroThat .

As always, until next time: stay safe, healthy, positive and creative!

issue172/micro-ci_micro-la.1630309546.txt.gz · Dernière modification : 2021/08/30 09:45 de auntiee