Notifications
Clear all

ESP32 Seven Segment AlphaNum LED Counter - Doc Brown Remote Control (BTTF)

14 Posts
3 Users
3 Likes
744 Views
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

Hi All,

At this stage I am trying to create athe LED counter using a ESP32 Wroom and a HT16K33 Quad 14 Segment Alphanumeric Display Module from Jaycar here in Australia (like radio shack).

 

I am using the Adafruit_LEDBackpack.h  library as the Seven Seg is an i2C interface.  I am persevering with this unit as it is orange in color and compact, albeit 4 digits is not accurate to the movie.  The display is alphanumeric, unlike other HT16K33 backpacks that are numeric only.  It has 5241A0 on the sides.

The alpha code works fine, please see here, however when I try to do the code for the counter, (0 to 88) I have two issues:

1. It counts on the far right digit (of the 4) and counts only to 8, not 88.   How to justify left and with decimal?

2. The code doesn't light up the horizontal LED as shown here.  (same for all digits as I tested count to 1000), Alpha example shows LED segment as healthy.

I would like to have the 88 on the far left with a decimal as shown in the movie here

Here is the code I am using to produce the code and video in item 2 above:

#include "Adafruit_LEDBackpack.h"


Adafruit_7segment matrix = Adafruit_7segment();


void setup() {
#ifndef __AVR_ATtiny85__
  Serial.begin(9600);
  Serial.println("7 Segment Backpack Test");
#endif
  matrix.begin(0x70);
}


void loop() {
 
  // print with print/println
  for (uint16_t counter = 0; counter < 88; counter++) {
    Serial.println(counter);
    matrix.println(counter);
    matrix.writeDisplay();
    delay(50);
  }
}

 

I would really appreciate some assistance as these libraries and the hardware are knew to me. I have done some elegant projects with arduino and LCD screens, but this is now an area of growth.

I hope to include you all in the project through to the final working remote control.

Thank you.

Tibby


   
Quote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 7065
 

@tibby I am unable to test anything at the moment, but I think this is a case where you have to invoke a library call to position the 'cursor' where you want to write the digit. For 0 to 88 that means in the loop detecting when the units position changes and when the tens position changes and positioning the virtual cursor in the right spot before writing the next value.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 7065
 

@tibby I had a quick look at the library and didn't see any methods that would do what I said. I have to go out, but I will look deeper when I get back if someone else doesn't answer beforehand.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.


   
Tibby reacted
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2535
 

@tibby

The number is displayed to the right hand side because it's a number. If you want to move it to the left, you may have to convert it to a 4 character string with enough blanks padding on the right to force the digit into the position you need.

As for the decimal point, I'm confused because the URL you specify is redirected to another URL which has a display that shows the number on the RIGHT HAND side of the display (not the left).

Also, your sketch does not conform to the sample sketch shown on the URL for the Quad 14 display.

Could you please expand your question to include more detail.

Anything seems possible when you don't know what you're talking about.


   
Tibby reacted
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

@will thank you for the correction, my poor choice or words.

it should as u say be on RHS as shown by the original, but my counter does not progress to the left as it reaches 10. It does in the monitor, but not on the screen.

The code I used is a sample from the example library, when left at 1000 it counts up okay, but not when changed to 88.  I’ll revisit the quad sample code again. Thank you 


   
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

@will Is it possible to edit my original post to clean up the URL etc?


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2535
 

@tibby 

Sorry, I was distracted by Real Life here for the afternoon.

Posts are only editable for an hour or so and that has long since elapsed. If you return (soon enough) to your post, there will be buttons at the bottom right side which will allow you to Edit or even Delete the post.

Anything seems possible when you don't know what you're talking about.


   
Tibby reacted
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

Hi All,

I have made some great progress with my code, and have it on the bench now (please see here for video), I have played the audio from the scene for you while recording the display for context and effect.

Other than my project objective, please now discard my comments above, I am no longer using an I2C or Adafruit_LEDBackpack.h library. I am now using 3 x single seven segment displays that have been multiplexed together, (both physically and by code).  Happy to elaborate on this later if of any interest, suffice to say its actually more authentic to the movie prop.

As you can see in the vid, the code counts, but my next step, and one I thought would be easy,  is to get the display to stay on the value 880 at the end of the count for say 5000 millisecs.  

"According to my calculations" I should be able to just insert a delay(5000); at the end of the loop code, but "this stupid thing does not work!".

I have kept the delay(5000) out of the 'for' routine as the delay(1) value makes it present on the display so quickly that the human eye thinks its static, (so it has to be there, its indicative to seven segment).  A bit like a refresh rate or frame rate value.

Current code below; It counts from zero to 880, then it returns to zero and waits five seconds then counts again, but it needs to wait for five secs while displaying 880 at the end of the 'for' routine.

FYI "seven_segment()" is a function defined earlier in the code  to present numbers on the display. If I were to only have seven_segment(880) in the loop it would display 88.0 all the time. 

void loop() {
//Starts display with "00.0"
 seven_segment(0);         
    
//Count to "880"
for (int i = 0; i <= 880; i++) {       
      seven_segment(i);
      delay(1);
    }
  //Attempt to have display stay on 88 for 5 secs
 delay(5000);              
 }
 
I have also tried adding " seven_segment(880);"  before the delay(5000), but I think it flashes really fast then returns to zero.
 
Thank you ad appreciate any advice
Tim

 

This post was modified 9 months ago 3 times by Tibby

   
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

This worked as a workaround

v

void loop() {
  // analogRead(sensor_Value);
  // Serial.println(sensor_Value);
  seven_segment(0);
  touchValue = touchRead(touchPin);
  Serial.println(touchRead(T9));  // get value using T1
  if (touchValue < 40) {
    for (int i = 0; i <= 880; i++) {
      seven_segment(i);
      delay(1);
    }
#define REPLICATE(x, n) \
  for (int _i = 0; _i < n; _i++) { x; }
    // Usage
    REPLICATE(seven_segment(880), 500)
  }
}
 I replicated the line 500 times and it appeared as a delay.
 
I have also added a touch function that the esp32 offers on some of its pins. So it now:
starts with the display of 00.0
waits for the touch pin to be touched to trigger the count
counts to 88.0
reads out 88.0 for 5 secs.
 
Next step is to replace the touch with an AO potentiometer, because thats what the joystick on the RC unit is.
I did try this using a Jaycar 1000 ohm potentiometer, with an ISR that was triggered by 'RISING' but I could not get it going.
 
I also tried using the potentiometer to control the count using seven_segment(potentiometerValue) but it was too twichy and unstable. All I need the potentiometer for is to trigger the count, that will be good enough.
So, if (potentiometerValue > 20 ) then the count starts.
 
Any tips on getting this going is appreciated.
Thanks
Tim
This post was modified 9 months ago by Tibby

   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2535
 

@tibby 

Not sure why the delay alone didn't work. I'm assuming that the seven_segment function sets and holds the value only while it's operating. If that's true you could add a new subroutine as follows ...

void pauseAt880(int msToWait)
{
  unsigned long beginTime = millis;       // Get current time
  while ( millis()-beginTime<msToWait ) { // While time not expired
    seven_segment(880);                   // Display the value
    delay(1);                             // Wait a bit
  }
}

You then call this routine after the for loop is complete and it will keep the display reading 880 for at least msToWait milliseconds.

    for (int i = 0; i <= 880; i++) {
      seven_segment(i);
      delay(1);
    }
    //
    pauseAt880(5000);

The advantage is that you don't swamp your available memory with 500 repeated (and unnecessary) code segments. You may need that program space later 🙂

Another, and maybe simpler, approach might be to add a second parameter to the seven_segment subroutine and pass a delay time in ms as that second parameter.

Since you haven't included the code for your seven_segment routine, I'm having to extrapolate from what I THINK should be in there; so I think you'd need to change your seven_segment routine to something like ...

void seven_segment( int i, int wait)
{
  ... // The current guts of seven_segment
  //
  delay(wait);
}

You're currently delaying for 1 ms after the seven_segment call anyway, so passing a 1 for I from 0-879 and 5000 for I=880 would be pretty easy. Something like ...

seven_segment( i, wait=(i<880) ? 1 : 5000) );

As for starting the count with a pot, can you please add some more detail to what you want ? Don't be confused by the

(condition) ? valueIfTrue : valuesOtherwise;

It's just a fast, one line version of the IF;THEN;ELSE command. So what it does is decide "if I is less than 880" send the subroutine the value 1 otherwise send the subroutine the value 5000.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

Thanks Will you have put alot of time and effort into this, thank you its appreciated.

I will run those commands this week to see how they go and to learn from the experience, yes I was worried about burying the memory on that last REPLICATE statement 🙂

"You then call this routine after the for loop is complete and it will keep the display reading 880 for at least msToWait milliseconds."  - Does this mean it sits completely outside and underneath the loop routine ?

RE: "starting the count with a pot,"  The plan is to trigger the count by pushing forward on the remote joystick as Doc Brown does.  I think the RC js is simply a potentiometer, so I was simulating with a 1k rotary from my electronics store (Jaycar), but I plan to use an RC as close to the Futaba as possible.

All I need is for the count to begin if the potentiometer value is > x.

Basically the digits are zero, but when you push forward, the potentiometer value increases past x and then the count begins, so it appears that the js is controlling the count, but it simply started it.  The challenge is that it will loop the count if the js is still sitting forward, so I was thinking of doing this via an ISR with the condition RISING so that it would count only if the js was pushed forward.

Back To The Future Doc Brown s Remote Control 1
This post was modified 9 months ago 3 times by Tibby

   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2535
 

Posted by: @tibby

"You then call this routine after the for loop is complete and it will keep the display reading 880 for at least msToWait milliseconds."  - Does this mean it sits completely outside and underneath the loop routine ?

I don't know what you mean by 'outside' or 'underneath' the loop() routine. The first method is a series of commands that is placed outside of the loop() {...} code, if that's what you mean. You can't define a routine inside of another routine.

Not sure what you mean by 'underneath' either but I can't find a viable interpretation for that, so I'll just let it go for now. What happens is that after the for loop is complete, control shifts to the code in the pauseAt880 sub which then keeps calling the seven_segment routine to display the digits 880. What's different is that this code is NOT repeated and so it doesn't chew up memory.

Note that you haven't included code for seven_segment and you've stated that a straight delay doesn't work after the for loop. This forces me to make blind assumptions about how your code works (or fails) and I have to build those assumptions into my response. I may have guessed wrong 🙂

Posted by: @tibby

RE: "starting the count with a pot,"  The plan is to trigger the count by pushing forward on the remote joystick as Doc Brown does.  I think the RC js is simply a potentiometer, so I was simulating with a 1k rotary from my electronics store (Jaycar), but I plan to use an RC as close to the Futaba as possible.

All I need is for the count to begin if the potentiometer value is > x.

Sorry, I haven't watched TV in over 20 years and I have not been out to see a movie for over 10 years so I have no idea who Doc Brown is or his normal mode of locomotion.

I do note however, that your code reads a touchValue and then tests it against the value 40. To use a pot (at LEAST 5k, preferably 10K) use an analog pin A0-A5 something like 

  const byte  potPin = A0;

and change in the loop body to

  int   potValue = analogRead(potPin);
  if (potPin>40) {
    ... // same code as you're using now
  }

 

Posted by: @tibby

Basically the digits are zero, but when you push forward, the potentiometer value increases past x and then the count begins, so it appears that the js is controlling the count, but it simply started it.  The challenge is that it will loop the count if the js is still sitting forward, so I was thinking of doing this via an ISR with the condition RISING so that it would count only if the js was pushed forward.

Do you mean that if the joystick is held forward it should only run from 0-880 once and then hold at 880 until the joystick returns to a value below 40 again ?

If that's what you want, then declare a logical value which will determine if the joystick is properly set. Something like ...

  //
  //    Place at top with other declarations
  //
  bool  jsReset = false;

  // 
  //    Place at start of loop()
  //
  jsReset = analogRead(potPin)<40;   // Joystick is active

  //
  //    Change number running to 
  //
  if (potPin>40 && jsReset) {        // Only do this if js is forward AND has been reset
    jsReset = false;                 // Joystick in use, must now be reset before reuse
    ... // same code as you're using now
  }

 This creates a logical value jsReset (joystick is active) and starts it off as false (i.e. joystick needs to go below 40 before number running is available).

Just inside the loop() code, jsReset is set true if the pot is below 40 (ie, has returned low and is nw available to run numbers again). If the joystick is >40 then jsReset is set false it means that the joystick has NOT been reset and we won't run the numbers this time through,

You'll change the part that runs the numbers so that the test now requires that the joystick be pushed past 40 AND that the joystick has been reset (i.e. jsReset is true) since the numbers were run last time.

Immediately upon starting the number running, you set jsReset to false because we're running the numbers and the joystick must now be reset.

 

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

Thanks Will!

The prop I am creating is a remote control from Back to the Future, photo above.

Sorry for the confusion (underneath etc) your interpretaation is correct.  Your help has been great and given me alot to play with and learn. 

Your first part of code worked for the 5 sec delay.

Ill try the others now 🙂

void pauseAt880(int msToWait)
{
  unsigned long beginTime = millis();       // Get current time
  while ( millis()-beginTime<msToWait ) { // While time not expired
    seven_segment(880);                   // Display the value
    delay(1);                             // Wait a bit
  }
}


void loop() {
  // analogRead(sensor_Value);
  // Serial.println(sensor_Value);
  seven_segment(0);
  touchValue = touchRead(touchPin);
  Serial.println(touchRead(T9));  // get value using T1
  if (touchValue < 40) {
    for (int i = 0; i <= 880; i++) {
      seven_segment(i);
      delay(1);
    }
  //
    pauseAt880(5000);
  }
}

   
ReplyQuote
(@tibby)
Member
Joined: 12 months ago
Posts: 10
Topic starter  

Posted by: @will

Do you mean that if the joystick is held forward it should only run from 0-880 once and then hold at 880 until the joystick returns to a value below 40 again ?

Almost, if the joystick is held forward it should only run from 0-880 once, and the display can reset to zero while still forward, I just didnt want it looping because the stick was being held forward, or triggering the count when the joystick springs back to zero.

Having said that, I love your suggestion and will try it 🙂

Thanks again for your help.


   
ReplyQuote