book collections email follower instructable user

Dual 7-segment Displays Controlled by Potentiometer in CircuitPython - Demonstration of Persistence of Vision

Picture of Dual 7-segment Displays Controlled by Potentiometer in CircuitPython - Demonstration of Persistence of Vision

This project uses a potentiometer to control the display on a couple of 7-segment LED displays (F5161AH). As the potentiometer knob is turned the displayed number changes in the range 0 to 99. Only one LED is lit at any moment, very briefly, but the eye or a camera does not notice the flicker. This is persistence of vision.

Pressing the button slows down the action and you can see the individual LEDs turning on and off.

I've noticed that there are very few Instructables using CircuitPython so this project uses an Adafruit Itsybitsy M4 development board which runs CircuitPython beautifully. If you want to use a Raspberry Pi, or other microprocessor development board you only need to change the pins and their setup in the script.

Step 1: What We Need for the Project

Picture of What We Need for the Project


  • Adafruit Itsybitsy M4 - a small, powerful and inexpensive development board
  • microUSB cable - for programming from PC
  • breadboard (or stripboard and soldering iron)
  • breadboard jumper cables (or connecting wire and solder)
  • a pair of F5161AH 7-segment displays
  • a 10 K Ohm potentiometer
  • a button switch
  • a pair of 330 Ohm resistors


  • Mu Editor - to write the code and program the board

Setting up the Itsybitsy is explained here:

The latest version of CircuitPython:

CircuitPython libraries:

Mu Editor:

I normally build a project with stripboard after testing out a few ideas out on a breadboard. This means I can keep finished projects ready for demonstrations at 'show & tell' events or to show my students.

WilkoL3 months ago
You have coded it like this:

1 split the number into its tens and units components
2 pull the cathode low on one display to turn it on and then flash the segments one at a time if needed
3 pull the cathode high to turn off that display
4 repeat for other display
5 Do this over and over very quickly so that the observer cannot see the flicker.

But you can do better than that. The way it works now means that one segment is "active" only 1/14 th of the time. But that isn't necessary as you can activate the segments in a round robin way and pull down the common cathode of the display that needs to display it. This way you can have the segments active 1/7 th of the time. (I ignore the DP) Both displays are updated at the "same" time.

I have made it on a ATTINY2313, see the C code below.

* zeven_segment_alternatieve_sturing.c
* Created: 19-6-2019 13:42:16
* Author : wilko
* ATTINY2313
* 8 MHz RC oscillator
* TIMER0 generates 500 Hz overflow IRQs
* displays are updated in IRQ routine
* 2 common cathode 7segment displays
* rotate segment selection instead of common cathode
* selection, only one segment (of each display) is
* switched on at any time, but both displays are
* updated at the "same" time.

#include <avr/io.h>
#include "util/delay.h"
#include "avr/interrupt.h"

void initialisatie(void);

uint8_t digits[2];

int main(void)
uint8_t teller = 0;

while (1)
if (teller < 99) teller++;
else teller = 0;

digits[1] = (uint8_t) teller / 10;
digits[0] = (uint8_t) teller % 10;


void initialisatie()
DDRB |= (1 << PB0) | (1 << PB1); //PB0, PB1 (displays)
DDRD = 0x7F; //PD0 .. PD6 (segments)

TCCR0A = 0;
TCCR0B |= (1 << CS01) | (1 << CS00); //prescaler = 64
TIMSK |= (1 << TOIE0); //interrupt at overflow (~500 Hz)


static uint8_t tabel[10] = {0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B};
static uint8_t segment = 6;
static uint8_t temp0 = 0;
static uint8_t temp1 = 0;

if (segment < 6) segment++;
segment = 0;
temp0 = tabel[digits[0]]; //read 7_segment_char
temp1 = tabel[digits[1]];
PORTD = (1 << segment); //switch on selected segment

PORTB |= (1 << PB0); //display off
if (temp0 % 2) PORTB &= ~(1 << PB0); //display on when needed

PORTB |= (1 << PB1);
if (temp1 % 2) PORTB &= ~(1 << PB1);

temp0 >>= 1; //shift left 7_segment_char
temp1 >>= 1;
tonygo2 (author)  WilkoL3 months ago
Thank you for your comments.

I agree that I could have coded it more efficiently if I just
wanted to drive the displays flat out and appear as bright as possible.

I particularly wanted to demonstrate and encourage the use
of CircuitPython, much easier to understand than the C, using registers and bits rather than pins, if you are new to coding. (CircuitPython fits between Scratch 'blocky' code and more machine dependent languages and is becoming very popular in schools. Full Python is expected to overtake C++ and Java in industrial use in the near future.) I also wanted to be able to slow the code right down so that you can
see the individual segments turning on and off. The resulting display is bright
enough when running at full speed.
WilkoL tonygo23 months ago
I'll take another look at CircuitPython...
"Ordinary" Python I do use every now and then, when making things on a linux server, but CircuitPython is new for me.

I don't think C is hard to understand though, but then again, I come from hex-displays and keyboards on Z80 boards at school, followed by Pascal on teletype paper terminals, assembly for 6809 at work and assembly for 6502 as a hobby. C is a luxury.

What I always aim for is efficiency in power consumption and/or in execution time. (And I see it as a challenge to use as small a controller as possible.)
misterxp3 months ago
Very interesting. and well explained. I am learning and this seems a good project to experiment with. Thanks for sharing
misterxp misterxp3 months ago
? I think you meant to reply to somone else?
pemazzei misterxp3 months ago
Ok, thanks. I read part of jessyratfink's Instructable. I will complete it. I use Corel Paint Shop and a Lumix camera. Thank you for the hints! Best regards
pemazzei3 months ago
Very nice. Please, what equipment did you use to take the photos of your
Intractable? Very sharp photos! Thanks,
tonygo2 (author)  pemazzei3 months ago
Hi Paulo,
Thanks for your kind comments.
I used a Canon 700D SLR with a Canon 18 - 135mm EF-S f3.5-5.6 IS lens. I shoot in RAW and process the images with Lightroom and Photoshop. These were hand held.
pemazzei tonygo23 months ago
Thank you! The photos are very sharp and well illuminated. Do you have
any kind of special lights, light tent or similar? Best
tonygo2 (author)  pemazzei3 months ago
I have lights and a light tent but did not use them here. I have good light from my kitchen and lounge windows and use a white paper reflector to help fill in harsh shadows. I think it is the adjustments in Lightroom that make a difference, once you have a sharp image.
Have you read jessyratfink's piece on taking photographs?
jessyratfink3 months ago
Nicely explained!