Arduino nano "swallowing" timings?

For a customer project I am retrofitting an old telephone and am using a nano inside the chassis to control the bell using a nano, a movement sensor and the phones speaker for input, and a relais as an output to power the bell.

I tested the system with an uno, it worked flawlessly. I also tested it using wokwi with a slightly modified code to compensate for differences with the inputs etc, the timings are the same though.

When I set up the final build using the nano with a 12v psu (movement sensor requires 12-36v so this was the sweet spot) the phone bell works flawlessly, only the cooldown at the end of the program seems to sometimes get swallowed up and the phone does not return to the idle state.

const int hoerer = 2; //Digital Pin 2 (hoerer = speaker)
const int melder = 3; //Digital Pin 3 (melder = movement sensor)
const int relais = 4; //Digital Pin 4

int hoererState = 0; //0 means contact is closed, 1 is open
int melderState = 1; //like hoererState
int bellState = 0;  //is the bell currently ringing?
int klingelCounter = 0; //how often was the bell ringing?
int abgehoben = 0;  //State-bit to only trigger relais once (not really necessary but i wanted it for security)
int cooldownTriggered = 0;  //Starts the Counter for Cooldown

int klingelZeitAn = 2500; //Time the bell is ringinging in ms
int klingelZeitAus = 4000; //Time the bell is not ringing in ms
unsigned long cooldownZeit = 45000; //Time for which the phone shall not ring after hanging up

unsigned long lastBellTime = 0; //When did the bell ring for tha last time?
unsigned long lastCooldownTime = 0; //When was the last time the cooldown was started?

enum status{
  IDLE, KLINGEL, ABGEH, COOLDOWN
};

int state = IDLE;

void idle(); //Idle-State
void klingel(); //Ringing-State
void abgeh(); //Phone was picked up state
void cooldown(); //Cooldown-state

void setup() {
  pinMode(relais, OUTPUT);
  digitalWrite(relais, HIGH); //first of all we don't want the phone to ring
  pinMode(melder, INPUT_PULLUP);
  pinMode(hoerer, INPUT_PULLUP);
  Serial.begin(9600); 
  Serial.println("System online");
}

void loop() {
  melderState = digitalRead(melder);
  hoererState = digitalRead(hoerer);
    
  
  if(state == IDLE){  
    idle();
  }

  if(state == KLINGEL){  
    klingel();
  }

  if(state == ABGEH){  
    abgeh();
  }

  if(state == COOLDOWN){   
    cooldown();
  }


  if(hoererState == 1){ //Quasi-Interrupt when the speaker is picked up allowing us to change to picked up state no matter where we are in the program
    if(abgehoben == 0){ //Causes these instructions to only be executed once
      Serial.println("Picked up");
      digitalWrite(relais, HIGH);
      abgehoben = 1;
      state = ABGEH;
    }
  }
  

delay(10);
}


void idle(){
  if(melderState == 0){ //when movement-sensor is triggered we go to bell state
    state = KLINGEL;
    bellState = 0;
    Serial.println("Going to ringing-state");
    }
}


void klingel(){  
  unsigned long bellTime = millis();
  if(bellState == 0 && ((bellTime - lastBellTime) > klingelZeitAus)){ 
    bellState = 1;
    digitalWrite(relais, LOW);
    Serial.println("Bell on");
    lastBellTime = bellTime;
  }
  if(bellState == 1 && ((bellTime - lastBellTime) > klingelZeitAn)){ 
    bellState = 0;
    digitalWrite(relais, HIGH);
    Serial.println("Bell off");
    klingelCounter++;
    if(klingelCounter > 4){ //Bell-counter, when nobody picks up the phone we also go to cooldown
      state = COOLDOWN;
      cooldownTriggered = 0; //Start signal Cooldown
      klingelCounter = 0;
      Serial.println("reset klingelCounter");
    }
    lastBellTime = bellTime;
  }
}


void abgeh(){ //
  if(hoererState == 0){ //Only when the speaker is hung up we go to cooldown
    state = COOLDOWN;
    Serial.println("Hanged up");
    abgehoben = 0; //so we can restart the whole process
    cooldownTriggered = 0; //Start signal for cooldown
  }
}


void cooldown(){
  unsigned long cooldownTime = millis();
  if(cooldownTriggered == 0){ 
    lastCooldownTime = cooldownTime;
    cooldownTriggered = 1;
    klingelCounter = 0;
    Serial.println("Starting Cooldown");
   }
  if((cooldownTime - lastCooldownTime) > cooldownZeit){ 
    state = IDLE;
    Serial.println("Cooldown finished, back to Start!\n");
    lastCooldownTime = cooldownTime;
  }
}

as i did further testing i noticed once, that the phone would ring constantly until it was picked up and afterwards did not go back to the idle state.
I am at a loss as i have never had this kind of behaviour during testing and it only came up once i was assembling the piece on site using the nano.

Thanks for any suggestions that can help resolve the issue.

EDIT:
Somebody passing by just triggered the phone and it would not stop ringing (not reacting to bell counter).. I have no explanation for this. Is it possible this arduino is simply DOA?

I'm reading this on my iPhone so can't really tell what is what — The state machine in your code could gain in readability. See Yet another Finite State Machine introduction for ideas

Do you have the Serial monitor connected to the phone ? it would be interesting to see if the Arduino reboots.

If the system gets stuck, you can implement a software watchdog timer to reset the system if it does not transition states within a reasonable time.

It was a voltage-problem!

I put the movement-sensor on a different psu and dropped the arduino supply voltage to 9v,
the problems are gone.
I guess the output was a little higher than 12v or (even though it is an original arduino nano) the nano could not handle the power properly.
anyways, it seems to be working now.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.