Introduction
Inspired by the Pi Pico with 7-segment display blog, written by ntewinkel, I decided to give it a go as I had a 4-digit 7-segment display in box that had never been used before.
Little did I realise what's involved to get a 4-digit display to work using just a microcontroller. I have to say it's all rather clever to trick the eye like that.
Once I figure out what's involved and I had figured out whether my unknown branded display was common anode or cathode I gave it a quick test using the SevSeg library for Arduino and after a bit of trial and error it worked thanks to a bit of help from Fritzing in working out which connection was which.
Of course I couldn't help myself when it comes to over-complicating matters.
So it didn't take long before I reasoned that the Pico's multicore feature would provide some very useful benefits here. I just had to think of an application. Then, while thinking about what sort of multicore application I could come up with, I spotted a HC-SR04 ultrasonic ranger in another box and thought, aha, these two devices could work well together in this context as both were timing critical.
Getting it to work
After a quick search online and I found a very interesting library for the HC-SR04 ultrasonic ranger designed just for the Arduino Nano RP2040 Connect, which made use of Programmable I/O (PIO).
The library is called NanoConnectHcSr04 and can be found on GitHub: https://github.com/MrYsLab/NanoConnectHcSr04
I was eager to see if I could get this to work via Pico's Core1 processor.
At first I was not very confident as when I first tested multicore (you can read all about it in my blog) it would lock up if any delays were inserted. Well, I was rather pleased to see that this has been resolved. It actually worked.
It was now a case of merging the two examples for my test application.
To get this to work, I reasoned that as the Pico has plenty of memory and that RAM is shared between both cores, the simplest thing to do is make all variables global. This ensured static allocation of memory during runtime. I also wanted both cores to run independently so I used the non-blocking method where the main core would poll to check if data was available to read from Core 1. The result was then sent via UART to the serial monitor via the main core.
And here's the code:
/* Copyright (c) 2020-2021 Alan Yorinks All rights reserved (NanoConnectHcSr04 library). This example constantly reads and prints the distance measured by an HC-SR04 Ultrasonic distance sensor. This program is free software; you can redistribute it and/or modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 as published by the Free Software Foundation; either or (at your option) any later version. This library is distributed in the hope that it will be useful,f but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have receivSketch uses 82844 bytes (0%) of program storage space. Maximum is 16777216 bytes.ed a copy of the GNU AFFERO GENERAL PUBLIC LICENSE along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA SevSeg Library Copyright 2020 Dean Reading This example demonstrates a very simple use of the SevSeg library with a 4 digit display. It displays a counter that counts up, showing deci-seconds. */ #include "pico/multicore.h" #include "hardware/irq.h" #include <NanoConnectHcSr04.h> #include "SevSeg.h" // D16 == trigger, D17 == echo // Using pio0 and sm 0 NanoConnectHcSr04 sonar(16,17, pio0, 0); //Instantiate HR-SR04 controller object SevSeg sevseg; //Instantiate a seven segment controller object // distance value returned static float c1_value = 0.0; static float c0_value = 0.0; static unsigned long timer = 0L; static int deciSeconds = 0; static byte numDigits = 4; static byte digitPins[] = {15, 14, 13, 12}; static byte segmentPins[] = {11, 10, 19, 20, 21, 18, 22, 26}; static bool resistorsOnSegments = false; // 'false' means resistors are on digit pins static byte hardwareConfig = COMMON_ANODE; // See README.md for options static bool updateWithDelays = false; // Default 'false' is Recommended static bool leadingZeros = false; // Use 'true' if you'd like to keep the leading zeros static bool disableDecPoint = false; // Use 'true' if your decimal point doesn't exist or isn't connected void core1_entry() { while (1) { // Function pointer is passed to us via the FIFO // We have one incoming int32_t as a parameter, and will provide an // int32_t return value by simply pushing it back on the FIFO // which also indicates the result is ready. // put your main code here, to run repeatedly: c1_value = sonar.readSonar(); // Sanity check on values received if (c1_value > 0.0 && c1_value < 200.0) { // Send results back to core 0 if (multicore_fifo_wready()) multicore_fifo_push_blocking(c1_value); } } } void setup() { Serial.begin(115200); while (!Serial) {;;} Serial.println("\r\nPico PIO Multicore 7Segment Display SonicRanger\r\n"); sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint); sevseg.setBrightness(90); timer = millis(); multicore_launch_core1(core1_entry); } void loop() { if (multicore_fifo_rvalid()) { c0_value = multicore_fifo_pop_blocking(); Serial.println(c0_value); } if (millis() - timer >= 100) { timer += 100; deciSeconds++; // 100 milliSeconds is equal to 1 deciSecond if (deciSeconds == 10000) { // Reset to 0 after counting for 1000 seconds. deciSeconds=0; } sevseg.setNumber(deciSeconds, 1); } sevseg.refreshDisplay(); // Must run repeatedly }
The Demo
And finally, here's the demo:
Addendum: RangeFinder using 7-Segment Display
Of course it's very easy to then amend the code so that the range finder distance is displayed on the 7-segment display.
One gotcha worth mentioning is that when I commented out the while (!Serial)
I discovered that I needed to add in a delay in setup otherwise core1 locked up.
void setup() { //Serial.begin(115200); delay(1000); //while (!Serial) {;;} //Serial.println("\r\nPico PIO Multicore 7Segment Display SonicRanger\r\n"); sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint); sevseg.setBrightness(90); //timer = millis(); multicore_launch_core1(core1_entry); }
Then to display the distance all I did was the following:
void loop() { if (multicore_fifo_rvalid()) { c0_value = multicore_fifo_pop_blocking(); //Serial.println(c0_value); sevseg.setNumber(int(c0_value*10), 1); } sevseg.refreshDisplay(); // Must run repeatedly }
It's as simple as that. And here's a short video: