1st time Arduino user: product design involves multiple controllers?

As a 1st time Arduino user (25 years ago some QuickBasic experience) I am really amazed at the number of different-type controllers a project needs.
Maybe I am totally off-track with this design (no experience at all), but untill now, the basics work.

I try to make an old preamplifier design really smart and up-to-date.
As such, the 'core' has to be superfast: this receives encoder knobs, IR remote sensors, touch sensor, interrupt power button, and sends to MCP23017-connected relays.
When I try this controller also to update an arduino 3,5" screen, there are 2 shortcomings: not enough memory and not enough speed (I want the display to update while rotating the encoder or while receiving multiple IR-commands).

It seems only the MEGA is able to have enough memory and speed, so it is I2C connected to the master UNO, and handles nothing but the TFT screen (without touch). (there are also 2 oled screens on same I2C-bus, not updating frequently). As I have also 8-bit possibility to the display, I used that for speed, which could still be better I think. (I plan to try a ILI9341_FAST library I found).
For this MEGA controller I am looking for a substitute, as it is way too big for the project. I am thinking of a Due (also big), then I may use a (preferable) smaller ILI9341 3,3V 2,2" display (the red boards), and a seperate I2C bus for the OLED displays. Other than that, I am looking for a controller having the MEGA power, compatible with adafruits display libs, but with a fraction of its pinouts and dimensions.

Then in same area as that mega controller, there is a I2C connected nano 33 BLE for bluetooth functionality. It would have been perfect that this one did the TFT screen as well, but that seems very hard as there are no good-working libraries for this type of controller, I'm not skilled to create one.

So in this project there is one 'master' UNO, then 2 slave Arduinos, 2 slave MCP relay boards, 2 I2C oled displays. I have to keep UART free (I think) because I also want to implement RS232 functionality to home automation systems.

In future I will create a battery-remote control with another NANO BLE, a (touch)display and/or buttons. The real problem with these nano33 is libraries for displays.

Am I totally offtrack here? Code is ... hmm... working but could be better arranged. I don't dare to show to you experienced guys! Code is spread over 3 controllers (and in future a 4th remote).

Maybe I could be pointed in the good direction concerning design?
Many thanks

Nobody will be able to offer meaningful help without the code.
Start here: How to get the best out of this forum

1 Like

I am having a hard time understand why all the processors. I believe what you want to do can be done with one unit and properly written software without using the delay() instruction. I have seen this done with a 4-bit controller (NEC-1700 series). What speed is a " the 'core' has to be superfast"?

The MEGA is actually slightly slower than an Uno or Nano. (Same 16MHz clock speed, slightly slower instructions in order to handle the increased range of memory.)

the 'core' has to be superfast: this receives encoder knobs, IR remote sensors, touch sensor, interrupt power button, and sends to MCP23017-connected relays.

Those are not really "super fast" things, by Arduino standards. (though updating a bitmap display "instantly" in response to a rotary encoder may be beyond it, unless you're clever. The bottleneck is usually the interface TO the display, rather than the CPU itself.)

The relatively small amount of memory on ATmega328 boards is annoying when it comes to displays.

Basically if you are using more than one processor then you are doing it wrong. It is a common beginners mistake to think you need more than one, often this is caused by the lack of understanding of how to program.

what about using a ESP32 ? has the advantage of built in BLE for communication with a smaartphone?

Yeah. Overly complex due to the several microcontrollers that could be replaced by just one, but more importantly I get the strong impression of seriously shifting requirements as the project evolves, which makes your goal a moving target. Other than that, I think you've come quite far already and I have no doubt that with your perseverance you'll get where you want to be!

Yeah, it would also have some (considerable) excess processing power to accommodate those shifting requirements.

Funny thing btw: I just finished a little preamp project last week, but much simpler than this one. Just a logarithmic attenuator (volume control) fashioned from CMOS switches controlled by a 328PB and MCP23017 with some relays and CMOS switches for channel switching & mute. It also has a remote based on RF24 modules, with the actual remote controller being run by an ATtiny3227 (because that's the only one I could get fast in the required small QFN package...) Works a treat, but it helps that I knew what I wanted to make before I started...

Thank you for your insight.

Superfast is very relative indeed. It does not need to be very fast, it is the display not being able to catch up with encoder turns.

I discovered when using a seperate controller for the display, it is able to catch up while not disturbing the volume relays connected to the master arduino.

Which only goes to show that you are not coding it correctly.

Hi, thank you for your insight.

The MEGA is slower indeed, but it has enough memory space to display nice things on the tft, such as a startup screen from progmem, icons, and I have yet to create the user setup pages.

"
Those are not really "super fast" things, by Arduino standards. (though updating a bitmap display "instantly" in response to a rotary encoder may be beyond it, unless you're clever. The bottleneck is usually the interface TO the display, rather than the CPU itself.)
"
This is EXACTLY the problem, updating the display while not disturbing the rotary encoder and its volume relays seemed impossible (with adafruitGFX library). Interrupts for the encoder were also not the answer. But hey, as a beginner first-time C++ (have to learn that too), I'm not clever at all, allthough I have a working project.

Also your second anwser
"
The relatively small amount of memory on ATmega328 boards is annoying when it comes to displays.
"
seems very correct.

So it looked like a seperate controller for this was the answer.
The only bottleneck was the volume display, which is shown 'big' on the display, having many pixels per character to update.
If the nano33 BLE could do this display, with BT functionality, that would be the perfect solution in this project I think. But I couldn't find working libraries (yet).

Thank you a lot. The best answer answer so far, but no 'clever' solution (for now)

Hi grumpy mike.

As stated in the title AND text, I'm a first-time C++ user (never saw any programming language before except quickbasic 25 years ago).

I KNOW i'm not coding correctly, hence my visit to this forum.
But hey, I don't mind people telling me what I already know (as that's obvious having no experience at all).
I truly respect people that help people doing it better, finding solutions, but, with all respect and thank you for the effort, none of your messages were actually helping or meaningful for me. Very grumpy indeed!

Thank you anyway.

You are correct indeed. While working with the products, ideas came up and got implemented. But it seems it is really only the display making me a hard time.
Thank you for the compliment. I never thought I would have come this far!
(I never had nothing with programming languages, but I do have some 'insights').

I know for a preamp, you don't actually need a display, my first layout was using neopixel leds, which was much simpler on only an UNO. But working with the display, it could be a top-notch pre-amp!

So in the meantime, my prerequisits have moved to:

  • ILI9341 display (I have a touch version, but will not use touch). As for now, it is 8bit parallel conneced. I was already having a hard time with another make ILI9341 (the much cheaper chinese 3,3V ones in red).
  • rotary encoder for volume. This controls MCP23017 with volume 'ladder' attenuator, controlling relays. This is the main thing that has to go very smooth while turning the encoder, but same time the display has to update (it's 80-ish-pixel high volume number).
  • rotary encoder for input: thats plain simple, with MCP23017 which also controls internal pre-amp gain.
  • IR remote for any remote, that's simple too, only volume and input.
  • There are two more little oled displays with ascii only, not needing to update fast. Hence they are connected to the 'master' UNO.
  • There has to be a 'selfdiscovery' procedure for an extra audio-source, which settings will be controlled by this same preamp-controller. Have to do this, but it will be a 'discovered' mcp23017.
  • Then there's the power button which puts everything to sleep.
  • The bluetooth is offcourse the least important, but how cool would it be?! Ultimate goal is to make my own remote control with BT.

I only have to write the inputselect, and this selfdiscovery mcp23017. Then many graphics have to be written (the user setup pages). But before that, I have to 'clean up' the code.

Thank you for your insights!

I will look into that, if I could find some library usable for the ILI9341 display (and preferably the smaller non-touch chinese redboard 3,3V one).

Mega can track a pot and update the I2C faster than you can see it. I found that updating every .1S gave flicker free updates on the 2004 I2C LCD and still appeared to be instantly responsive to the knob.
All this talk but no real discussion of what you're trying to build.
If you have definite pieces working, you need to start moving off the breadboard. The more dupont's, the more likely one or more will not make good contact as things shift around. You can spend a lot of time chasing your tail as previously working sections randomly fail because a singleton pin has shifted.
You say that the Mega is too big but you're got room for THREE cpu's? Slow your roll and start thinking things thru.
Instead of rotary encoders, you can just wire a pot to one Ax and rescale that for everything. I have a project that uses the same pot for time/date/FM radio/Volume/Brightness, etc. Fast, responsive, .1% accuracy, simpler to interface than rotary encoder.
Not everything has to be dedicated. Use the same knob for multiple functions will reduce your pin count and simplify your code as you won't need to do 10 things simultaneously. The displays hold whatever you've sent so there's no need to keep refreshing a static display, just update the few chars that change. The I2C interface is fast.
The controller shouldn't be working that hard.
Here's an idea, instead of R-2R ladder to adjust volume with a crap ton of relays, just couple a pot to a servo shaft and dial it in? Clean electrically with 100% isolation possible. Faster and glitchless switching. Better resolution than an R-2R switch.
Think outside the box! Arduino is new ways of doing things. You're thinking in ladder logic.

There is what they call FRAM memory. It comes in I2C and SPI. 32K x 8 for a few bucks and is fast enough no delays are needed when using in. Red/Write cycles are in the range of 10-14th. Good maybe a bad feature is it is nonvolatile so it does not forget during power down reset etc. This would allow you to use the UNO but it is compatible with all Arduinos.

Hi,

By doing what?

What are ALL your inputs and outputs to the new control system?

Are you trying to JUST replace the audio switching?
Are you trying to replace the level controls?

Can you please post a block diagram of what you want to do?
Can you post a circuit diagram of what you have now?

Have you got code for JUST the display?
Have you developed your code in stages?

What other Arduino projects have you done before this?
Can you please tell us your electronics, programming, arduino, hardware experience?

Sorry for all the questions but we need to establish a base line of your knowledge/experience and scope of your project.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

But you still refuse to show your code so we can see what a mess you are making of your code and help you correct it. So how do we know why you don't know?

Take the rotary encoder for example. If you are polling it then that is wrong, you need to use interrupts. Your display, are you updating the whole of the screen when only a few pixels actually need changing.

You seem to think you need to see each individual consecutive number from the encoder, where as in practice you don't because anything faster that an update time of 30Hz you are not going to see.

Collectively here we are very good at advice, but unless you cooperate all we can do is guess, which as you have found is very unsatisfactory for both sides of the knowledge divide.

Personally I would have started with something simpler to learn coding - maybe just tackling one aspect of the project to improve your coding skills .
The use of multiple prototyping boards will be frustrating as bad connections and all those wires will cause an issue . Try to be a bit more logical - fix your boards to a piece of ply wood in a line , add a row of choc block connectors to bus together power supplies etc , or look at soldering up, try to be consistent with cable colours .
Possibly solder up
Circuits on strip board .
The Nano Every is worth considering too .

Thank you for answers and insights.

Some people mentioned the breadboard setup.
Offcourse that's not ideal, that's why it's a breadboard. I did not have one bad connection.

@madmark2150
I think I mentioned a TFT 320x240 display, parallel connected. I tried I2C LCD but don't like it.
I think I mentioned I'm building a preamplifier, narrowing down to the controlling section over here.
Allthough not completely click-free, the R2R design of volume regulating is what I want. There are other forums discussing the best possible volume controlling on analog audio. Many high-end (i mean really high-end) designs use R2R volume regulating. Yes that's with lots of relays.
The MEGA is too big in terms of pinouts, only using it for display. Space is not really restricted.
I am using just 2 encoders for volume, inputselect, balance, gainsettings, phonopreamp settings, setup menus, mute, etc. I think that's already enough narrowed down and fits the initial goal. No pots: these have a begin-and-end. and a pain when controlling volume from remote (preferably no motors/moving parts). Also in audio-terms there is no pot that beats the potential of a constant-load balanced (thus 4-way) R2R ladder design. The stepper switch comes close. As said, there are other forums for that. The R2R is completely made and tested, .1% resistors, pure silver leads,... , I heard it, I will keep it. I have no doubt you can learn me a lot about coding and arduinos, but you may not in terms of audiophile sound.

@gilshultz
Now that is an interesting path I already have seen. That may be a solution.

@TomGeorge
I am making a complete new preamp and phono preamp, based on existing (old) circuits.
The audio stuff is made, tested. That was the easy part (for me).
As a diy-er and enthousiast, I have no block diagrams. I do have circuits for the analog part.

The code for volume update (see below) is now running very smoothly. Next step is to embed the volume encoder in the same controller. If that works fine, I can move it all to one controller + the bluetooth controller, I have no problem having a seperate controller for bluetooth.

@TomGeorge

Citaat
What other Arduino projects have you done before this?
Can you please tell us your electronics, programming, arduino, hardware experience?

Please read previous posts. In short, no other arduino projects, respectively: basic, none, none and none. In real life, I'm a home automation engineer, working with existing products such as KNX. That's at most configuring, not programming.

@Grumpy_Mike
I certainly do not refuse to post my code, but it is not 'postable' yet ;-). See below for display code, now with smooth updating volume. It's all in seperate functions. So the display, no not updating all of the screen. As for the encoder, yes it is with polling and not with interrupts. I have not tried that. (For now I turn off interrupts only for volume updates, but I'm not sure if that's still necessary (it 'pends' the I2Creceive a bit without losing the information). Per % of displayed change, there are 2.55 times as much I2C 'receives'.

void tftPage1Update(bool Forced) {
//Serial.println("tftUpdate");
// PAGE SELECT
//++++++++++++page1 HOMEPAGE
if (DisplayLastPage != 1 && DisplayPage == 1 ||Forced == true) {
  tft.setFont(&FreeSans12pt7b);
  tft.fillScreen(ILI9341_BLACK); // background color
  tft.drawRoundRect(0,0,320,24,8,ILI9341_WHITE); //bovenste rechthoek
  tft.drawRoundRect(0,60,150,110,8,ILI9341_WHITE); //input rechthoek
  tft.drawRoundRect(170,60,150,110,8,ILI9341_WHITE); //volume rechthoek
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(1);
  tft.setCursor(10,20);
  tft.println("ALEPH P1.7     XONO 2019");
  tft.setFont(&FreeSansOblique9pt7b);
  tft.setCursor(10,54);
  tft.println("Input");
  tft.setCursor(190,54);
  tft.println("Volume");
    DisplayLastPage = 1;
  if (DisplayDebug == true)
  Serial.println(F("main page drawn"));

}
 
}
//------------------------------MAIN PAGE VOLUME UPDATE---------------------------
void doMainPageVolume(bool Forced) {
if ((Volume != LCDDisplayedVolume && Volume<100) ||Forced == true) {  //check op verandering
                                      //++++eerst paar rechtzettingen/berekeningen
//  if (Volume == 100) Volume = 99;     //display te klein om 100 weer te geven
  int volEenheid = Volume % 10;       //opsplitsen in eenheden
  int volTiental = Volume / 10;       //en tientallen
                                      //++++zet klaar voor screenupdate
  noInterrupts();                     //geen interrupts (door I2C) als volume geupdated wordt.
  tft.setFont(&FreeSansBold24pt7b);   // zet juiste font
  tft.setTextSize(2);                 // zet juiste grootte


  if (volTiental != lastVolTiental){  // tientallen veranderd?
    tft.fillRect(VolumeNumbersX+2,VolumeNumbersY-67,48,71,ILI9341_BLACK); //verwijder cijfer
    tft.setCursor(VolumeNumbersX,VolumeNumbersY);                         //zet positie/kleur
      if (muteEnabled == true) {tft.setTextColor(ILI9341_RED);}else{tft.setTextColor(ILI9341_WHITE);}
      tft.print(volTiental);                      //zet de waarde
      lastVolTiental = volTiental;                //onthoud de verandering
  }
                                      // eenheden hoeven niet vergeleken: veranderen altijdbij veranderd volume
  tft.setCursor(VolumeNumbersX+50,VolumeNumbersY); // zet juiste plaats
    if (muteEnabled == true) {
       tft.setTextColor(ILI9341_RED); // zet juiste tekstkleur
    } else {
       tft.setTextColor(ILI9341_WHITE); // zet juiste tekstkleur
    }
  tft.fillRect(VolumeNumbersX+52,VolumeNumbersY-67,50,71,ILI9341_BLACK);
  tft.print(volEenheid); // print waarde
  interrupts();

  doBargraph();                         //zet de bargarph erop
  BargraphShow = millis();              //en onthoud wanneer

  LCDDisplayedVolume = Volume;          // onthoud laatste waarde

  if (DisplayDebug == true)
  Serial.println(F("VolumeMainDisplay Updated")); //debug
}

if (millis() > BargraphShow + 2000){    //na verlopen van bargraphtijd
  doIconBar(ForcedUpdate);              //doe de iconbar
}
}

//-------------------------------main page--BARGRAPH VANUIT VOLUME UPDATE
void doBargraph() {
  

  if (Volume != LCDDisplayedVolume) {
if (IconBar != "Volume") {
  tft.fillRect(10,180,300,40,ILI9341_BLACK);
  tft.drawRoundRect(10,180, 300, 40, 8, ILI9341_WHITE); //bargraph
  IconBar = "Volume";
}
  tft.fillRoundRect(Volume*3+11,181,289-Volume*3,40-2,8,ILI9341_BLACK);
  tft.fillRoundRect(11,181,(Volume*3)-2,40-2,8,ILI9341_RED);

  if (DisplayDebug == true)
  Serial.println(F("BARGRAPH Updated")); //debug    

  }
}
//--------------------------------MAIN PAGE INPUT---------------------------
void doMainPageInput(bool Forced) {
if (InputSelect != InputSelectLast ||Forced == true) {
  tft.setFont(&FreeSansBold24pt7b);
  tft.setTextSize(2);
  tft.fillRect(5,65,140,90,ILI9341_BLACK); //verwijder het vorige
  tft.setCursor(5,150);
  tft.setTextColor(ILI9341_WHITE);
  tft.print(InputSelect);
  tft.setFont(&FreeSans12pt7b);
  tft.setTextSize(1);
  tft.print(InputSelectText);
  tft.fillRect(145-32,65,32,32,ILI9341_BLACK);
  switch (InputSelect) {
    case 1:
      drawBitmap(145-40,73,myBitmapvinylrecordplayer,32,32,ILI9341_WHITE);
    break;
    case 2:
      drawBitmap(145-40,73,myBitmapcdplayer,32,32,ILI9341_WHITE);
    break;
    case 3:
      drawBitmap(145-40,73,myBitmapcdwithmusicnote,32,32,ILI9341_WHITE);
    break;
    case 4:
      drawBitmap(145-40,73,myBitmapmobilephoneoff,32,32,ILI9341_WHITE);
    break;
    case 5:
    drawBitmap(145-40,73,myBitmapmicrophonerecorder,32,32,ILI9341_WHITE);
    break;
  }
  InputSelectLast = InputSelect;
  if (DisplayDebug == true)
    Serial.println(F("InputMainDisplay Updated"));
}
} 

void doIconBar(bool Forced) {
int oldCurrentGainsetting;
bool oldBalanced;
// De layout van icons zetten
if (IconBar != "Icons" ||Forced){
  tft.fillRect(10,180,300,40,ILI9341_BLACK);
  for (int i=0 ; i < 4 ; i++) {
  tft.drawRoundRect(10+i*75,180, 70, 40, 20, ILI9341_YELLOW);
  IconBar = "Icons";
  }
}
// ICON1 updaten
if (currentGainsetting != oldCurrentGainsetting) {
   tft.setTextSize(1);
    tft.setFont(&FreeSansBold9pt7b); // zet font
    tft.setTextColor(ILI9341_WHITE);
     tft.setCursor(12,208);
     tft.print(currentGainsetting);tft.print("dB");
     oldCurrentGainsetting = currentGainsetting;
}
//ICON 2 UPDATEN
if (balanced != oldBalanced) {
   tft.setTextSize(1);
    tft.setFont(&FreeSansBold9pt7b); // zet font
    tft.setTextColor(ILI9341_WHITE);
  if (balanced == true) {
    tft.setCursor(95,208);
    tft.print("XLR");
  } else {
        tft.setCursor(95,208);
    tft.print("RCA");
  }
  oldBalanced = balanced;
}

//ICON 4 UPDATEN

if (BTConnected != oldBTConnected) {
   tft.setTextSize(1);
    tft.setFont(&FreeSansBold9pt7b); // zet font
    tft.setTextColor(ILI9341_WHITE);
  if (BTConnected == 1) {
    tft.setCursor(250,208);
    tft.print("BT");
  } else {
    tft.setCursor(250,208);
   tft.fillRect(250,195,25,15,ILI9341_BLACK);
    Serial.println(F("BT blank printed"));
  }
  oldBTConnected = BTConnected;
  if (DisplayDebug){
    Serial.print(F("Bluetooth icon set to new/old "));Serial.print(BTConnected);Serial.println(oldBTConnected);
  }
}


}

Not everyting is completely ready: the bargraph works perfectly but there are some small pixels issues to resolve. The iconbar is to be done completely, but here is the basis.

Then this is in the loop, which is rather short:

if (DisplayPage == 1) {
  Volume = I2CReceive[1];
  muteEnabled = I2CReceive[2];
  InputSelect = I2CReceive[3];
  currentGainsetting = I2CReceive[4];
  balanced = I2CReceive[5];
  Alarm = I2CReceive[6];
  
    tftPage1Update(ForcedUpdate);        //Update het scherm met main page
    doMainPageVolume(ForcedUpdate); //    VAN HIERUIT DE VERSCHILLENDE ITEMS UPDATEN
    doMainPageInput(ForcedUpdate);
    if (IconBar != "Volume")
    doIconBar(ForcedUpdate);

}

// wordt altijd uitgevoerd (onderkant, displaypaginas hierboven)

//Helderheid scherm reduced na verlopen van laatste IICreceive
if (millis() > lastReceiveStamp + 30000 ){
analogWrite(BacklightPin, reducedDisplayBrightness);
currentDisplayBrightness = reducedDisplayBrightness;
}

//Check of bluetooth remote connected is
if (digitalRead(BTConnectedPin) == HIGH){
  BTConnected = true;
} else {
  BTConnected = false;
}

Working but not finished in the loop are sleepandwakeroutines (both triggered from I2C), other than that there's the Wire.onReceive function updating 7 variables.

For the encoder part (for now in other 'master' arduino) this is just in the (loop) section: (and maybe that's what i'm doing wrong according your 'by interrupts' tip:

//====================
  // Read the encoder and changevolume AND SEND TO DISPLAY
//====================  

  n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      changeVolume(-encoderIncrement);
            if (currentAttenuatorLevelDisplay != OldAttenuatorLevelDisplay) {
      sendToDisplayPage1(DisplayPage, currentAttenuatorLevel, muteEnabled, InputSelect, currentGainsetting, Balanced, Alarm);
    }
    } else {
      changeVolume(encoderIncrement);
      if (currentAttenuatorLevelDisplay != OldAttenuatorLevelDisplay) {
    sendToDisplayPage1(DisplayPage, currentAttenuatorLevel, muteEnabled, InputSelect, currentGainsetting, Balanced, Alarm);
    }
    }
  }
  encoder0PinALast = n;

Other than that the loop polls a 'slow' encoder, 1 encoder button, IR receive, a UNO-master-connected (very static) OLED display update if necessary, and - just for fun - a touchscreen press on the 'input' field. The encoder section above comes from an example preamp I found, but this was not incorporating a display.

@hammy
Thank you for your tips. I did not have wire or connection failure. That's stuff I'm good at. The whole setup is running as-is for two weeks now, without error. Offcourse it doesn't look the part. I have only a kitchentable, permanently divided into office, lab, and ... dining table.
You are right about tackling one aspect at a time. In the beginning I was way to overenthousiastic. Last few days I'm only bettering the display but will not change library anymore.

Thank everyone to the useful tips. Please hold off from the analog audio part. I know which volume control to use, the hardware is fixed. All of this is about the control part. The volume knob or remote has to go as smoothly as possible.

Thank you for answers and insights.

Some people mentioned the breadboard setup.
Offcourse that's not ideal, that's why it's a breadboard. I did not have one bad connection.

Yet ... Check out my cable shrouds if you have 3d printer access.

@madmark2150
I think I mentioned a TFT 320x240 display, parallel connected. I tried I2C LCD but don't like it.

Did you use the 16x2 or the 20x4?

I think I mentioned I'm building a preamplifier, narrowing down to the controlling section over here.
Allthough not completely click-free, the R2R design of volume regulating is what I want. There are other forums discussing the best possible volume controlling on analog audio. Many high-end (i mean really high-end) designs use R2R volume regulating. Yes that's with lots of relays.

Actually relays are passe, most of the stuff uses MOSFET's instead of relays. Silent and longer life.

The MEGA is too big in terms of pinouts, only using it for display. Space is not really restricted.

Not if you combine three into one.

Thanks.
I have no 3D printer (yet).
It was the 20x4 LCD I was using.

Still, I built a relay volume encoder, it sounds very accurate.

For now I'm combining two of them, I'm building hardware stuff and code together, and see how that goes.

One 'beginner' question though: Aren't I gonna end up with a very long page of written code? Even using function calls, splitting text code nicely, it still ends up with a very long page? I didn't get into libraries, just using them, or 'classes?', which I don't know about.

It keeps me busy, that's for sure!