Creating multiple square waves with different frequencies simultaneously

Hey there,
Im currently trying to control a BMW E36 instrument cluster using an Arduino Uno r2,
which requires one square wave signal per gauge.
I can already drive the gauges using the Tone library but this has the problem that it can't generate waves below 31hz.
Then I found toneAC which works perfectly for one gauge but it's not able to drive two or more.

So is there any hardware/software way of generating two or more waves with different frequencies on different pins?

How much lower than 31 Hz do you need? What's the maximum frequency you need?

For really low frequencies you can use micros() and millis(). For example to get a 12 Hz square wave just toggle the output every 1/24th of a second (41667 microseconds). Look at the BlinkWithoutDelay example for how to do it.

Thanks for your answer.

I need a range of around 2Hz-400Hz.
Should be doable with micros(), I’ll try it and come back if there’s any issue.

//Edit: Okay, so here’s my code that seems to work basically, the problem is that it’s pretty unprecise
and the gauge needle jumps around sometimes.

const int spdPin =  5, rpmPin = 6;
int spdState = LOW, rpmState = LOW;
unsigned long spdDelay = 0, rpmDelay = 0;
unsigned long spdLastMic = 0, rpmLastMic = 0;

void setup() {

void loop()
  //Just for getting a value to show on the gauge
  int spd = analogRead(A0)/3.5;
  int mapped = map(spd,0,260,1,332);
  if(spd > 260)
    mapped = 332;
  //Here begins the important stuff
  float fmap = mapped;
  spdDelay = (1/(fmap*2))*1000000;
  unsigned long curMic = micros();
  if(spdLastMic + spdDelay <= curMic) {
    spdLastMic = curMic;   
    spdState = !spdState;
    digitalWrite(spdPin, spdState);

So I guess using an external timer or signal generator IC should work much better, shouldn’t it?
Do you have any recommendations for ICs or circuits that do such a thing?
Or might it even be better to get a second Arduino/Teensy/etc to drive the second gauge on its own?
This would allow me to use toneAC again which does work perfectly.

Perhaps the reason the needle jumps around a bit is because when you change the timer, you are either stretching the current square wave or cutting the current square wave short and beginning another.