Stuck -_-

I cannot figure out what I am doing wrong here... I am trying to control a hard drive motor by setting a speed from a keypad and then having a PID take an input speed and run the motor at that speed. I want the (I2C)LCD to show the input speed and the speed that is read by a little photodiode/LM393 chip thing.

I am days deep into this code and just cant get it. I am a total newb so it might be some simple thing that I dont understand properly.

Care to look it over and tell me whats wrong? Everything compiles fine, I am just dumb.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <PID_v1.h>
#include <Servo.h>
#define MAX_SIGNAL 2000
#define MIN_SIGNAL 700
#define MOTOR_PIN 9

LiquidCrystal_I2C lcd(0x27,2,16);

const byte rows = 4;
const byte cols = 4;

char keys[rows][cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[rows] = {4,5,6,7};
byte colPins[cols] = {8,10,11,12};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, rows, cols );



Servo motor;

double Setpoint, Input, Output;
int toofast, inputspeed, rpmcount, rpm, timeold;



PID myPID (&Input, &Output, &Setpoint,2,5,1, DIRECT);
volatile int status=LOW;

void setup() {
  char key = keypad.waitForKey();
  char exitkey = keypad.getKey();
 //turn on lcd
lcd.init();
lcd.init();
lcd.begin(16,2);
lcd.backlight();
lcd.setCursor(1,1);
//calibrate esc controller
motor.attach(10);
motor.writeMicroseconds(2400);
lcd.print("Turn on motor, wait 2 sec and press key");
key;
lcd.clear();
motor.writeMicroseconds(544);
//initialize variables
//getInputSpeed();
//determineRpm();
Input= determineRpm();
//toofast=0;
//inputspeed=0;

Setpoint = getInputSpeed();
//turn on the PID
myPID.SetMode(AUTOMATIC);

attachInterrupt(digitalPinToInterrupt(3), rpm_fun, FALLING);
//pinMode(3, OUTPUT);   
rpmcount = 0;   
rpm = 0;   
timeold = 0;   
status = LOW;

}

   

void loop() {
  //pid control
  int inputspeed;
  int rpm;
 
  Input= determineRpm();
    char key = keypad.waitForKey();
  char exitkey = keypad.getKey();
while(exitkey != 'B')
{
Input = rpm;
myPID.Compute();
analogWrite(9,Output);
lcd.print(inputspeed);
}
}
//get setpoint for pid loop (the desired speed for the spincoater)
//exit key is a
//enter input speed is b
int getInputSpeed(){
int count;
int accumulator=0;
    char exitkey = keypad.getKey();

  char key = keypad.getKey();
 
    if (key != NO_KEY)
     {
     
    lcd.print(key);
    count++; if (key =='A'){accumulator=inputspeed;}
    accumulator=accumulator*10;
    accumulator+key;
   
        if (count==6)
    {
      lcd.clear();
      count=0;
    }
   
  }return inputspeed;

}

   

//rpm function
 void rpm_fun() {
 
  rpmcount++;
  if (status == LOW) 
  {     status = HIGH;   } 
  else {     status = LOW;   }   
  digitalWrite(3, status);
  }
 
int determineRpm() {  
  
  delay(1000);   
   detachInterrupt(3);  
   rpm = 60000/(millis() - timeold)*rpmcount;
timeold = millis();   
rpmcount = 0;   
//Write it out to lcd   
lcd.setCursor(0,1);
lcd.print(rpm);
//Restart the interrupt processing  
attachInterrupt(3, rpm_fun, FALLING);  
return rpm;
}

What does it do or not do that you expect it to?

A "total newb" (the poster's description, not mine) and interrupts rarely mix well.

For example. rpmcount should be volatile.

There's some garbage, which should not hurt,

but if you reduce the full project into a test environment just for the problem you see, it might already help you find the problem yourself.

lcd.init();
lcd.init();   // ? ? ?
...

lcd.print("Turn on motor, wait 2 sec and press key"); // Probably not visible ;)
key;           // legal but garbage
lcd.clear();
   ...

accumulator + key;Another anomaly.
return inputspeed;Why return this value when it has not changed in the getInputSpeed() function ? Why do you have two different variables named inputspeed, one of them global and one of them local to the loop() function ?

Make life simple. Leave the LCD stuff to one side until you have the other stuff working. Just output data to the Serial Monitor.

What sort of motor is it? Is it a simple DC motor or is it a stepper motor?

In either case why are you using the Servo library?

And please use the AutoFormat tool to make your code readable.

...R

Whats the autoformat tool?

It is a HDD motor.

It tells me to declare variables and I was just trying to get it so it would compile, so I just declared stuff all over the place because I dont really know what I am doing.

It does not run the motor when I put any input. It does not return any value for input speed, it just goes to all zeros or repeats only the first digit I enter. If I hit zero it starts the entire program over from outputting "turn on motor..."

Is there a better way to count rpm than with an interrupt?

I guess I need to figure out how to do this accumulator thing to get a value from my keypad...

OK I made some changes and autoformated so its easier to read. It compiles. Still dosnt work :confused:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <PID_v1.h>
#include <Servo.h>
#define MAX_SIGNAL 2000
#define MIN_SIGNAL 700
#define MOTOR_PIN 9

LiquidCrystal_I2C lcd(0x27, 2, 16);

const byte rows = 4;
const byte cols = 4;

char keys[rows][cols] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[rows] = {4, 5, 6, 7};
byte colPins[cols] = {8, 10, 11, 12};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, rows, cols );



Servo motor;

double Setpoint, Input, Output;
int toofast, inputspeed, rpmcount, rpm, timeold;



PID myPID (&Input, &Output, &Setpoint, 2, 5, 1, DIRECT);
volatile int status = LOW;

void setup() {
  char key = keypad.waitForKey();
  char exitkey = keypad.getKey();
  //turn on lcd
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.setCursor(1, 1);
  //calibrate esc controller
  motor.attach(10);
  motor.writeMicroseconds(2400);
  lcd.setCursor(0, 1);
  lcd.print("Turn on motor, wait 2 sec and press key");
  delay(2000);
  keypad.waitForKey();
  lcd.clear();
  motor.writeMicroseconds(544);
  //initialize variables
  //getInputSpeed();
  //determineRpm();
  Input = (determineRpm());
  //toofast=0;
  //inputspeed=0;

  Setpoint = getInputSpeed();
  //turn on the PID
  myPID.SetMode(AUTOMATIC);

  attachInterrupt(digitalPinToInterrupt(3), rpm_fun, FALLING);
  //pinMode(3, OUTPUT);
  rpmcount = 0;
  rpm = 0;
  timeold = 0;
  status = LOW;

}



void loop() {
  //pid control
  char exitkey = keypad.getKey();
  while (exitkey != 'B')
  {
    Input = determineRpm();
    myPID.Compute();
    analogWrite(9, Output);
    lcd.setCursor(0, 2);
    lcd.clear();
    lcd.print(rpm);
  }
}
//get setpoint for pid loop (the desired speed for the spincoater)
//exit key is a
//enter input speed is b
int getInputSpeed() {
  int count = 0;
  int accumulator = 0;
  int number = 0;
  char exitkey = keypad.getKey();
  char key = keypad.getKey();
  lcd.print("Input Speed");
  delay(2000);
  lcd.clear();
  while (key != NO_KEY)
  {
    number = key;
    count++;
    accumulator = accumulator * 10;
    accumulator += number;
    lcd.print(accumulator);
    if (count == 6)
    {
      lcd.clear();
      count = 0;
    }
    if (key == 'A') {
      inputspeed = accumulator;
      break;
    }
  }
}
//rpm function
void rpm_fun() {

  rpmcount++;
  if (status == LOW)
  {
    status = HIGH;
  }
  else {
    status = LOW;
  }
  digitalWrite(3, status);
}

int determineRpm() {

  delay(1000);
  detachInterrupt(3);
  rpm = 60000 / (millis() - timeold) * rpmcount;
  timeold = millis();
  rpmcount = 0;
  //Write it out to lcd
  lcd.setCursor(0, 1);
  lcd.print(rpm);
  //Restart the interrupt processing
  attachInterrupt(3, rpm_fun, FALLING);
  return rpm;
}

Ungrounded:
It is a HDD motor.

That is no more informative than saying it is an inkjet printer motor.

...R

its a brushless motor that has 3 input wires and a ground. It uses an ESC... I am pretty sure it works like a servo.

Ungrounded:
its a brushless motor that has 3 input wires and a ground. It uses an ESC... I am pretty sure it works like a servo.

Now we can make some progress.
If there is an ESC, all we need concern ourselves with is the interface between the ESC and the Arduino.

Have you tried some simple code using the servo library to see if it does respond properly?

Going back to the code in your Original Post ...
There seems to be some confusion with MOTOR_PIN defined as 9 and the Servo attached to 10. And if your device responds to servo signals why do you have analogWrite() ?

And, rather than have analogWrite(9,Output); it would be much easier to follow your code with analogWrite(MOTOR_PIN, Output);

...R

I didnt catch that it was attached to 10!!!! This makes so much sense. After playing around with the code it started doing all sorts of funky things. 10 should be a pin for my keypad. Everything makes sense now.

Ungrounded:
I didnt catch that it was attached to 10!!!!

That's the best reason I can think of always to use meaningful variable (and constant) names.

Glad to hear it is working.

...R