I need help with this code

Hi everyone,

I tried a remake of a project I found on instructables. It is a tea-timer. I have assembled all the parts and uploaded the code to the Arduino Micro. There are no errors whatsoever, it uploaded just fine. However, there seems to be something wrong with the skript, because it turns on the servo moves a little and then nothing… the display turns on and lights up but all that shows is some recktangles.
Another question is, if there is any differnce in using a display with an I2C interface? I tried it both ways, of course with the different connections it requires but either way won’t work.

I hope you can help me.

#include <LiquidCrystal_I2C.h>
#include <Servo.h>

//state identifiers:
#define MENU 0
#define INPROCESS 1
#define DONE 2

const String welcomeMessage = (“Hi”);
const String doneMessage = (“Done”);

const int buttonPin = 4;
const int servoPin = 9;
const int buzzerPin = 8;
const int backlightPin = 3;
const int potPin = A0; // selection potentiometer
const int servoHighPosition = 150;
const int servoLowPosition = 70;
const int servoSpeedDelay = 20; // decrease this value to increase the servo speed

unsigned long steepingTime;
unsigned long startTime;
long timeLeft;

volatile int state;

LiquidCrystal_I2C lcd(0x27,16,2);
Servo servo;

//custom LCD characters:
byte leftArrow[8] = {0,0,4,12,28,12,4,0};
byte rightArrow[8] = {0,0,4,6,7,6,4,0};
byte clock[8] = {0,14,21,23,17,14,0,0};
byte sandTimer[8] = {31,17,10,4,10,31,31,0};
byte teaCup[8] = {10,5,0,31,25,9,15,0};

void setup() {

pinMode(buttonPin, INPUT_PULLUP);
pinMode(buzzerPin, OUTPUT);
pinMode(backlightPin, OUTPUT);

attachInterrupt(0, buttonISR, CHANGE);
servo.attach(servoPin);

digitalWrite(backlightPin, HIGH);

lcd.createChar(0, leftArrow);
lcd.createChar(1, rightArrow);
lcd.createChar(2, clock);
lcd.createChar(3, sandTimer);
lcd.createChar(4, teaCup);

state = MENU;

lcd.begin(16, 2);
lcd.print(welcomeMessage);
}

void loop() {

switch(state){

case MENU: moveServoTo(servoHighPosition);
lcd.clear();

lcd.setCursor(11,1);
lcd.print(“start”);

lcd.setCursor(8,1);
lcd.write(byte(0)); //display selection arrows
lcd.write(byte(1));

lcd.setCursor(1,0);
lcd.write(byte(2)); //display clock symbol

while(state == MENU){

steepingTime = 30000 * map(analogRead(potPin),0,1023,1,20);
lcd.setCursor(3,0);
lcd.print(millisToTime(steepingTime));
delay(200);
}
break;

case INPROCESS: moveServoTo(servoLowPosition);
startTime = millis();

lcd.clear();

lcd.setCursor(12,1);
lcd.print(“stop”);

lcd.setCursor(1,0);
lcd.write(byte(3)); //display sand timer symbol

while(state == INPROCESS){

timeLeft = steepingTime - (millis() - startTime);

if(timeLeft > 0){

lcd.setCursor(3,0);
lcd.print(millisToTime(timeLeft));
}
else state = DONE;

delay(500);
}
break;

case DONE: lcd.clear();
lcd.setCursor(1,0);
lcd.print(doneMessage + " ");

lcd.write(byte(4)); //display tea cup symbol

moveServoTo(servoHighPosition);

doneBeep();

lcd.setCursor(12,1);
lcd.print(“menu”);

while(state == DONE);
break;
}
}

void buttonISR(){

static unsigned long lastInterruptTime = 0; //used to debounce button input
unsigned long interruptTime = millis();

if(interruptTime - lastInterruptTime > 500){ //long debounce time to allow long presses

switch(state){

case MENU: state = INPROCESS;

break;

case INPROCESS: state = MENU;

break;

case DONE: state = MENU;

break;
}
}
lastInterruptTime = interruptTime;
}

void moveServoTo(int finalPosition){ //move the servo slowly to the desired position

int currentPosition = servo.read();

if(finalPosition > currentPosition){

for(int i = currentPosition; i <= finalPosition; i++){

servo.write(i);
delay(servoSpeedDelay);
}
}
else if(finalPosition < currentPosition){

for(int i = currentPosition; i >= finalPosition; i–){

servo.write(i);
delay(servoSpeedDelay);
}
}
}

String millisToTime(long milliseconds){

unsigned long minutes = (milliseconds/1000) / 60;
unsigned long seconds = (milliseconds/1000) % 60;

String minutesString = String(minutes);
String secondsString = String(seconds);

if(minutes < 10) minutesString = “0” + minutesString;

if(seconds < 10) secondsString = “0” + secondsString;

return minutesString + “:” + secondsString;
}

void doneBeep(){

tone(buzzerPin, 4000, 700);

Why does nobody ever Read this before posting a programming question and follow the instructions ?

To make it easy for people to help you please modify your post and use the code button </>

so your code 
looks like this

and is easy to copy to a text editor. See How to use the Forum

Also please use the AutoFormat tool to indent your code consistently for easier reading.

Your code is too long for me to study quickly without copying to my text editor. The text editor shows line numbers, identifies matching brackets and allows me to search for things like all instances of a particular variable or function.

ardunewbie123:
However, there seems to be something wrong with the skript, because it turns on the servo moves a little and then nothing… the display turns on and lights up but all that shows is some recktangles.

It is much easier to do fault finding if you separate out the different parts of the code. For example make a version of the program that only has servo stuff and has no display stuff. Make another version that only has the display code.

…R

Hi ardunewbie123,

which Arduino-board are you using? Is the code on instructable using the exact same Arduino-board?

Rectanges on the display can be wrong contrast-adjustment of the display.

The code uses a I2C-LCD-library. This means it can work only with I2C-LCDs. If you want to use a non-I2C-lcd you have to use an other library.

Summary: If you know almost nothing about programming & electronics and want to rebuild a project each and every detail have to be the same as in the project-instructions. Otherwise you need more knowledge to adapt it to your hardware. Micocontrollers are not superstandardized like USB-devices.

So please write a post which writes about the Arduino-board, and the LCD, Best would be to provide links where you have bought them or at least pictures of both sides of the board and the LCD

best reagrds Stefan

/*
Automatic Tea Timer

  The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 6
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 4
 * LCD D7 pin to digital pin 3
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VDD pin to 5V
 * LCD LEDA pin to digital pin 9
 * LCD LEDB pin to ground
 * 10K contrast potentiometer:
   * ends to 5V and ground
   * wiper to LCD VO pin
 
 * selection button to digital pin 2 and ground
 * 10K selection potentiometer:
   * ends to 5V and ground
   * wiper to analog pin A0
 * servo motor:
   * power wire to 5V
   * ground wire to ground
   * signal wire to digital pin 7
 * buzzer to digital pin 8 and ground
*/

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Servo.h>

//state identifiers:
#define MENU 0
#define INPROCESS 1
#define DONE 2

const String welcomeMessage = ("Hi");
const String doneMessage = ("Done");

const int buttonPin = 2;
const int servoPin = 7;
const int buzzerPin = 8;
const int backlightPin = 9;
const int potPin = A0; // selection potentiometer
const int servoHighPosition = 150;
const int servoLowPosition = 70;
const int servoSpeedDelay = 20; // decrease this value to increase the servo speed

unsigned long steepingTime;
unsigned long startTime;
long timeLeft;

volatile int state;

LiquidCrystal_I2C lcd(0x27,16,2);
Servo servo;

//custom LCD characters:
byte leftArrow[8] = {0,0,4,12,28,12,4,0};
byte rightArrow[8] = {0,0,4,6,7,6,4,0};
byte clock[8] = {0,14,21,23,17,14,0,0};
byte sandTimer[8] = {31,17,10,4,10,31,31,0};
byte teaCup[8] = {10,5,0,31,25,9,15,0};

void setup() {

  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buzzerPin, OUTPUT);
  
  attachInterrupt(0, buttonISR, CHANGE);
  servo.attach(servoPin);
  
  lcd.createChar(0, leftArrow);
  lcd.createChar(1, rightArrow);
  lcd.createChar(2, clock);
  lcd.createChar(3, sandTimer);
  lcd.createChar(4, teaCup);
  
  state = MENU;
  
  lcd.init(); // initialisiere LCD
  lcd.clear(); // lösche LCD Anzeige
  lcd.backlight(); // LCD Hintergrundbeleuchtung ein
  lcd.print(welcomeMessage);
}

void loop() {

  switch(state){
  
    case MENU:       moveServoTo(servoHighPosition);
                     lcd.clear();
                       
                     lcd.setCursor(11,1);
                     lcd.print("start");
                     
                     lcd.setCursor(8,1); 
                     lcd.write(byte(0));  //display selection arrows
                     lcd.write(byte(1));
                     
                     lcd.setCursor(1,0); 
                     lcd.write(byte(2));  //display clock symbol
                                                                        
                     while(state == MENU){
                                              
                       steepingTime = 30000 * map(analogRead(potPin),0,1023,1,20);
                       lcd.setCursor(3,0);
                       lcd.print(millisToTime(steepingTime));
                       delay(200);                                               
                     }
      break;
    
    case INPROCESS:  moveServoTo(servoLowPosition);
                     startTime = millis();
                     
                     lcd.clear();
                     
                     lcd.setCursor(12,1);
                     lcd.print("stop");
                     
                     lcd.setCursor(1,0); 
                     lcd.write(byte(3));  //display sand timer symbol              
          
                     while(state == INPROCESS){
                      
                       timeLeft = steepingTime - (millis() - startTime);
                       
                       if(timeLeft > 0){                    
                         
                         lcd.setCursor(3,0);
                         lcd.print(millisToTime(timeLeft));
                       }
                       else state = DONE;    
                       
                       delay(500);                    
                     }               
      break;
       
    case DONE:       lcd.clear();
                     lcd.setCursor(1,0);
                     lcd.print(doneMessage + " ");
                     
                     lcd.write(byte(4));  //display tea cup symbol
                                          
                     moveServoTo(servoHighPosition);
                                        
                     doneBeep();
                     
                     lcd.setCursor(12,1);
                     lcd.print("menu");
                     
                     while(state == DONE);                
      break; 
  }
}


void buttonISR(){
  
  static unsigned long lastInterruptTime = 0; //used to debounce button input
  unsigned long interruptTime = millis();
  
  if(interruptTime - lastInterruptTime > 500){ //long debounce time to allow long presses
       
    switch(state){
    
      case MENU:       state = INPROCESS;
                  
        break;
      
      case INPROCESS:  state = MENU;
                     
        break;
      
     case DONE:        state = MENU;
                  
        break;
    }
  }
  lastInterruptTime = interruptTime;
} 


void moveServoTo(int finalPosition){ //move the servo slowly to the desired position

  int currentPosition = servo.read();
  
  if(finalPosition > currentPosition){
  
    for(int i = currentPosition; i <= finalPosition; i++){
    
      servo.write(i);
      delay(servoSpeedDelay);
    }
  }
  else if(finalPosition < currentPosition){
  
    for(int i = currentPosition; i >= finalPosition; i--){
    
      servo.write(i);
      delay(servoSpeedDelay);
    }
  }
}  

String millisToTime(long milliseconds){

  unsigned long minutes = (milliseconds/1000) / 60;
  unsigned long seconds = (milliseconds/1000) % 60;
  
  String minutesString = String(minutes);
  String secondsString = String(seconds);
  
  if(minutes < 10) minutesString = "0" + minutesString;
  
  if(seconds < 10) secondsString = "0" + secondsString;
   
  return minutesString + ":" + secondsString; 
}

void doneBeep(){

  tone(buzzerPin, 4000, 700);
}

}

As you might notice I put some slight changes in the code. It still doesn’t work though. The information in the first passage is the original wiring. I tried that and then I just modified it for using the I2C version of the lcd. I would prefer using the I2C version because it is much less wiring.

I’m sorry for this mess. I was looking for the option to put code in but didn’t see it.

I got the part about the arduinoboard wrong. Here I used the Arduino-Pro-Mini the simple. In the IDE Software I selected the same board.

As I said I tried both LCDs and none worked. I noticed too, that in the code there is the I2C version but that’s exactly the way it was in the project. And he used a non I2C Display.

Here is the link to the original Project: https://www.instructables.com/id/Automatic-Tea-Timer/

Except for the pushbutton which wasn’t available anymore, I used all the parts he linked.

The LCD is HD44780 16x2 and I have one version with and one without the I2C backpack hooked up to it.

As I already mentioned the microcontrollerworld is not superstandardized like USB-devices.

If you want to hurry up things through short-text postings in fact you do slow down things through some extra-postings for asking back and - more or less - annoying the users that want to help.

What do you exactly mean by "it does not work"?

I want to give a demonstration what it means to be short on information:

did you check if the I2C-Adress is right? did you connect the I2C-LCD to the I2C-Io-pins? does the servo move when moved before powering up? did you analyse code-execution through serial? did you take care of common ground?

I guess in this short written way you will hardly understand what you should do

Please give a very detailed description of what is happening if you upload the software LCD stays off, servo does not move, Arduino onboard LED stays off?

attach pictures where it is easy to see which pin is connected to what

best regards Stefan

Hey Stefan,

thanks for your time and the input.

It works now. I only have to tweak the servo because it doesn't quite move the way it should.

The Problem that is left is the timer. The timer is very inaccurate and inconsistent. In rare cases a second is a second, but most times it is more like 2 or even 3 seconds.

I've read somewhere that the arduino is not very accurate in timing but I thought a simple timer, counting down seconds, shouldn't be a problem.

ardunewbie123: ...The Problem that is left is the timer. The timer is very inaccurate and inconsistent. In rare cases a second is a second, but most times it is more like 2 or even 3 seconds.

I've read somewhere that the arduino is not very accurate in timing but I thought a simple timer, counting down seconds, shouldn't be a problem.

Fine if it works now. Within an interval of 60 minutes the deviation between the time counted by the Arduino and an atomic clock should be less than 1 second.

edit: I donwloaded the code you posted above and flashed it to an Arduino Mega. The timer is counting down just fine So maybe some adjustements of the IDE are wrong

ardunewbie123: The Problem that is left is the timer. The timer is very inaccurate and inconsistent. In rare cases a second is a second, but most times it is more like 2 or even 3 seconds.

Then there is something very strange going on.

The timing error within an Arduino arises because its 16MHz oscillator does not work at precisely 16MHz. But the resulting error of time for 1000 millisecs will be a few microsecs, not 2000 millisecs.

...R

String millisToTime(long milliseconds){

  unsigned long minutes = (milliseconds/1000) / 60;
  unsigned long seconds = (milliseconds/1000) % 60;
 
  String minutesString = String(minutes);
  String secondsString = String(seconds);
 
  if(minutes < 10) minutesString = "0" + minutesString;
 
  if(seconds < 10) secondsString = "0" + secondsString;
   
  return minutesString + ":" + secondsString;

that’s the part in the program for the countersettings

The OP should be very wary of using the String class on a Micro as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

...R

I don't actually see the need to use Strings or strings

The bulk of the work of the function is done as soon as

  unsigned long minutes = (milliseconds/1000) / 60;
  unsigned long seconds = (milliseconds/1000) % 60;

executes

It works now.

How do you ever escape from this loop?

    while (state == MENU) {

        steepingTime = 30000 * map(analogRead(potPin), 0, 1023, 1, 20);
        lcd.setCursor(3, 0);
        lcd.print(millisToTime(steepingTime));
        delay(200);
      }

or this one:

     while (state == DONE);