Using the RGBLcd shield buttons and i2c

For other supported Arduino products from Adafruit: Shields, accessories, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
eholz1
 
Posts: 16
Joined: Mon Jun 09, 2014 3:40 pm

Using the RGBLcd shield buttons and i2c

Post by eholz1 »

Hello Forum Members,
i have a project using an Arduino Nano (will also with with an Uno) that drives a brushless DC motor.
The basic functionality is to rotate the motor CW or CCW a certain number of turns and stop, then allow
the user to press the "left" button or the "right" button to more the motor the other direction. The RGB LCD and buttons
serve as a menu for various options. I use all 5 buttons, plus the reset which will reset the loaded program.

I read the buttons in the main "loop" to start the motor. I have a function called "read_buttons" which reads them (sort of).
I call this function in two places, in the loop mentioned above, and then in the run_motor function. The run_motor function
has a timing loop based on using a looptime variable of 100ms, and the millis() function. I have the second call to the read_buttons function in the timing loop while the motor is running.

My basic problem is that the reading of the buttons is not reliable - and seems to depend on how fast I can press a button, or how long I keep a button pressed. I have menu options that display on the LCD depending on what button I press, etc.

Do you have any suggestions on how to read these buttons reliably? I do know that when a button is held down, it send a signal multiple times.

I want to have a function that will set the distance the motor will move, save that value, come out of the call mode, and allow just left and right movement at the new distance.

Any programming suggestions?

thanks,
ewholz

User avatar
adafruit_support_bill
 
Posts: 88154
Joined: Sat Feb 07, 2009 10:11 am

Re: Using the RGBLcd shield buttons and i2c

Post by adafruit_support_bill »

If you post the code you are using, we can take a look.

eholz1
 
Posts: 16
Joined: Mon Jun 09, 2014 3:40 pm

Re: Using the RGBLcd shield buttons and i2c

Post by eholz1 »

Hello and Thanks,

I am going to try one more thing, I had an idea while typing my post.
I will try that first, and if it gives me problems I will post the code. Warning, my
code is not the best in the world - and may not be elegant!

thanks for the reply, I will reply to this post as to my results (or lack of)

thanks for the help,

ewholz

eholz1
 
Posts: 16
Joined: Mon Jun 09, 2014 3:40 pm

Re: Using the RGBLcd shield buttons and i2c

Post by eholz1 »

Hello Members,

I found a way to get things working at a basic, but not reliable level.
I created another button reading routine - cal_buttons = lcd.ReadButtons() - which has the code for running in
the calibration mode only. I have another button readinging routine - buttons = lcd.ReadButtons() - which works for the
"normal" mode.

I still have an intermittent issue: if I hold a button down too long (or too short) the program will jump through the menu
to a "wrong" option.

I will upload the code with this post. This is really an ino file, but I am using Atmel studio 7, and it converts the ino file to a cpp.

Thanks for the help on this.

eholz1

Code: Select all

/*Begining of Auto generated code by Atmel studio */
#include <Arduino.h>
/*End of auto generated code by Atmel studio */

/*************************************************************************
New File - Brushless.ino take from BackandForthPid.ino
Rename to ReadButtons.ino, rename to Test6.ino for new motor and step mode
http://robotics.stackexchange.com/questions/167/what-are-good-strategies-for-tuning-pid-loops
Rename MilitaryMotor.ino 12 Jan 2015
Rename To Test6.ino for step mode, etc
Rename to PololuFinalTest.ino
Rename to MotorFinal_V1
Rename to Brushless - for Anaheim Automation test - 16 Feb 2015
Rename to BLDC_INDEX - to add the index pulse for accurate positioning
          I hope!
Rename to BLDC_INDEX3 - to add the calibration mode - 10 Dec 2015
******************************************************************************
16 Feb 2015 - ewh - New code for MDC010-024031 24V, 2A Brushless controller

Output RPM = ((Pulses Recieved in 1 sec * 60) / PPR) / Gear Ratio
LInk:
Cattledog reply
I think that there is some confusion in the vendor's descriptions between
encoder descriptions of PPR (pulses per revolution) and CPR
(counts per revolution). Given the 90 degree offset between the A and B
pulses, there are four states(counts) available per pulse set. There are
routines available for reading 1,2 or 4 of these changes. You are wise to test
your encoders and determine what is actually referred to by the description.

Pololo seems like a highly reliable supplier, and their encoder with
64 CPR (16 PPR), fits the standard nomenclature. You are reading only half the
available counts with the ISR in my old post. The +/- 30 to 50 counts seems high
but since that is only a few degrees of rotation, and I don't know how well you can
determine exactly 1 complete rotation.

The second encoder, by observation, could  be described as a 128 CPR (32 PPR) model.
I don't know what the spec sheet really shows but it sounds like the 32 refers
to pulses and not counts.

I think that most encoders are usually specified by pulses per revolution (PPR)
because the counts per revolution will be a factor of how the encoder is read.

Did you revise your program to put interrupts on both pins, use Nilton61's way of
reading the pin states when the interrupts are triggered, and move your count up
to 4 per pulse? It sounds like you may not need the increased resolution.
64CPR = 16PPR!!  and 32PPR sorta equals 128CPR
//DDRD = B00010100;
//PORTD = B00010000; // for the port values
http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
http://www.societyofrobots.com/robotforum/index.php?topic=13068.0 for rpm
gives shaft rpm:
(encoder_count_per_second * 60) / (encoder_count_per_revolution * output_gear_ratio)
27 Feb 2015 - ewh - Note: using brushless motor with functioning encoder
                    Next step is to try motor with PID and encoder, etc.
                    Change Kp to 0.7, Ki to 1.5, Kd to 0.11
28 Feb 2015 - ewh - Changed pin 7 to STATUS detect from driver
01 Mar 2015 - ewh - Revised Kp, Ki, and Kd down - will test.
                    PID values OK, deleted un-needed code
14 Mar 2015 - ewh - Change direction values - LOW = CW, HIGH = CCW
24 Apr 2015 - ewh - lost newer file, change rev to 1/2 turn,using Atmel Studio
					to upload files - works ok
24 Apr 2015 - ewh - Add a "step" distance selection - 1/2,1/4,1/16,1/32,1/64,1/128
					13500, 6750, 1688, 844, 422, 211
07 Jun 2015 - ewh - Added code to define YELLOW background for LCD (new) -
09 Jun 2015 - ewh - Revised code and board to look for LOW signal from Limit
                    switches - Pin 3 was set to 0, now set to 1
09 Jul 2015 - ewh - recode to test buttons for step mode and messages
                    Deleted debounce for LCD buttons - added delay in loop
                    to slow reading of the buttons - works
12 Jul 2015 - ewh - Revised step mode setpoint down from 15 to 10
					Took pid compute out of step mode - set a fixed
					Output (40) for the PID in step mode
03 Aug 2015 - ewh - Moved motorenable line in stop_motor, increased delay to 65
                    to test to see if we can move the platform farther from the
		            limit switch.
11 Aug 2015 - ewh - create a test only version - commented out various lines
12 Aug 2015 - ewh - added delay to loop, and set buttons delay to 60
17 Sep 2015 - ewh - changed motor to one with a 100:1 gear ratio - was 71:1
		            Modified speed/rpm area in code for the 100:1 gear ratio
05 Oct 2015 - ewh - Eliminate reading pin 3 from grounding limit switch
					Switching dig pin 3 from the index count interrupt, from
					high to low to high - should change limitSwitch state...
08 Oct 2015 - ewh - Changed count values for step mode
11 Oct 2015 - ewh - Increased the MAX_TRAVEL value to 240000 (1/4 turn)
29 Oct 2015 - ewh - Rename file to BLDC_INDEX2.ino to enable usb serial output
                    to monitor PID values
16 Nov 2015 - ewh - Have code moving the motor, but not getting index count
					for the MAX_TRAVEL value
26 Nov 2015 - ewh - Rewrote the read_buttons function to use switch statement
29 Nov 2015 - ewh - This version - 17, works with cal_mode set to 0.
30 Nov 2015 - ewh - In cal mode pressing left button after setting the start
                    causes the motor to move way fast
09 Dec 2015 - ewh - New program, based on BLDC-INDEX2, and add CAL_MODE code
*****************************************************************************/

#include <PID_v1.h>
#include <Wire.h>
#include <PWM.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
//#include <Bounce2.h>
//Beginning of Auto generated function prototypes by Atmel Studio
void setup();
void counter_clockwise();
void clockwise();
void OpenMenu();
void clearLCD(int charx, int row, boolean bClear);
void setLCD(String line1, String line2, int start, int row);
int readPot();
void change_direction();
void stop_motor_index();
void stop_motor();
void getMotorData();
long set_delay();
void motor_step();
void motorEnable(byte ENA);
void run_motor(uint8_t DIR);
void set_rotation(uint8_t intr);
void getDelay();
void cal_buttons();
void read_buttons();
void loop();
void SerialReceive();
void SerialSend();
//End of Auto generated function prototypes by Atmel Studio


// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
#define YELLOW 0x3

/*
Pin numbers and inputs and outputs for controller
1 Motor Winding 1		10 Status Indication Output
2 Motor Winding 2 		11 Digital Input 1
3 Motor Winding 3		12 Digital Input 2
4 Supply Voltage 8-24VDC	13 Enable Input
5 Ground	          	14 Direction Input
6 +5VDC Output Voltage  	15 Ground
7 Hall Sensor 1			16 Set Current Limit Input
8 Hall Sensor 2			17 Set Value Speed Input - this is
9 Hall Sensor 3			   PIN 9 on arduino for PWM
*/

// Arduino Pin to BLDC controller pin
#define motorDir     2 	 // Pin 14 on BLDC Direction Input
#define mtrEnable    5 	 // Pin 13 on BLDC Enable Input
#define statPin	     7 	 // read status from driver
#define PWM1         9   // PWM motor pin
#define encodPinA1   11  // encoder A pin
#define encodPinB1   13  // encoder B pin - set interrupt here
//#define Index 	     8   // digital pin 8 on Nano
//*#define Vpin         A3  // battery monitoring analog pin
//*#define Apin         A0  // motor current monitoring analog pin

//*#define CURRENT_LIMIT   3000            // high current warning
//*#define LOW_BAT         8000 //10000    // low bat warning
#define LOOPTIME 100      // PID loop time - may not be needed
#define CW   0  // change to clockwise
#define CCW  1  // change to counter clockwise

unsigned long lastMilli = 0;      // loop timing
unsigned long lastMilliPrint = 0; // loop timing
int Index = 0;

int speed_req = 0;              // speed (Set Point)
int speed_act = 0;              // speed (actual value)
int PWM_val = 0;                // (25% = 64; 50% = 127; 75% = 191;100% = 255)
int voltage = 0;                // in mV
int current = 0;                // in mA

volatile long encoderCount = 0;
volatile long lastEncoderValue = 0;
volatile long count = 0;              	// rev counter
volatile byte lastEncoded;
volatile long last_count;

double Input, Output, Setpoint;
//double kp=0.45,ki=1.0,kd=0.0;      	// Anaheim motor values
double kp=0.50,ki=1.2,kd=0.0;

unsigned long serialTime;

PID myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);

/* code for counting the index pulse */
long index_count = 0;
volatile long MAX_TRAVEL = 500; // index setting MAX = 235000

int limitButtonPin3State = 1; // was 0;
int LastButtonPin3State = 1;  //was 0;
int val;
int mspeed;
int state;
int factor;

boolean rotate1;
boolean useMenu = true;
boolean bLeft = false;
boolean LimitButtonState;
boolean stepMode;
boolean STATUS = false;
boolean MIN = false;
boolean MAX = false;

byte cal_mode;

//long rev = 27000; // 4192 is about 1/7 of a turn
long rev = 8000;   // 1/128 of a turn = 211, use 8K for 1/2 turn
long countInit;
long t_delay;
long _value;

uint8_t buttons;
uint8_t calib_buttons;
uint8_t direction;
uint8_t motorRUN;
uint8_t incr;
uint8_t sel_count = 0;

const uint8_t limitButtonPin3 = 3;
const uint8_t analogPin = A2;      // detects the mapped pot value, set speed of motor
const unsigned long BAUD_RATE = 115200;

// Bounce debouncer = Bounce();

String mtrSpeed;
char char_array[8];

int32_t frequency = 5000;  //PWM frequency

/***************************
Pins 9 and 10: controlled by timer 1 in phase-correct
PWM mode (cycle length = 510)

Setting 	Divisor 	Frequency
0x01 	 	1 	 	31372.55
0x02 	 	8 	 	3921.16
0x03  		64 	 	490.20   <--DEFAULT
0x04  		256 	122.55
0x05 	 	1024 	30.64

TCCR1B = TCCR1B & 0b11111000 | <setting>;
****************************/

void setup()
{
   //analogReference(EXTERNAL);  // Current external ref is 3.3V, appiled to the aREF pin
   Serial.begin(BAUD_RATE);
   count = 0;
   countInit = 0;
   InitTimersSafe();
   SetPinFrequencySafe(PWM1,frequency);
   Serial.println("Booted and Ready");

   cli();  // disable interrupts
    // CANNOT USE ARDUINO PIN 8,9,10,12,A0,A1 for non-controller/Arduino signals
    // bit-pin map 0=8,1=9,2=10,3=11,4=12,5=13 "B" register (digital pin 8 to 13)
    // cannot use bits 6 and 7 on reg B
    DDRD  |= (1 << 3);  //  Enable pin 3 as OUTPUT for index option (no limit switch)
    PORTD |= (1 << 3);  //  Set Arduino pin 3  HIGH to enable
    DDRD  |= (1 << 2);  //  Set direction for Arduino pin 2 as Output
    PORTD |= (1 << 2);  //  Set digial pin 2 HIGH CCW turns motor, LOW = CW
    DDRD  |= (1 << 5);  //  Set to enable the controller, OUTPUT
    PORTD |= (0 << 5);  //  Set low for "not ready"

    // set index pulse input
    DDRB |= (0 << 0);   //  Set Digital pin 8 as input for index pulse

    // for PWM control set both 4 and 7 to 0 (LOW)
    //**DDRD  |= (1 << 4);  //  Set digIn 1 for Arduino pin 4 as Output
    //**PORTD |= (0 << 4);  //  Set digital pin 1 level
    DDRD  |= (0 << 7);  //  Set pin 7 INPUT reads status from driver
    PORTD |= (0 << 7);  //  Set digital pin 7 LOW
    //***DDRD  = B00000000; // for the port direction - all zero = INPUT
    //***PORTD = B00000000; // for the port values
    DDRB  = B00000010;
    PORTB = B00100000;
    //DDRB  |= (1 << 1);  //  eqiv to pinMode PWM1
    //DDRB  |= (0 << 3);  //  Enable pin 11 as INPUT for encodPinA1 set low (was 2)
    //PORTB |= (1 << 3);  //  Set Arduino pin 11 HIGH for pull up (encodPinA1) (was 2)
    //DDRB  |= (0 << 5);  //  Enable pin 13 as INPUT for limit switch - set low (was 3)
    //PORTB |= (1 << 5);  //  Set Arduino pin 13 HIGH for pull up and encodPinB1 (was 3)
    PCICR  |= (1 << PCIE0);   // enable group interrupts on PORTB PCINT[7:0]
    PCMSK0 |= (1 << PCINT5); // enable interrupt pin 13-bit 5
    PCMSK0 |= (1 << PCINT3); // enable interrupt pin 11-bit 3, added 21 Jan
    //*************** FREQ Change for test
    //TCCR1B = (TCCR1B & 0XF8) | 2;
	//3906 HZ=2, 3=488HZ Frequency change from default to higher
     index_count = 0;
     //PCMSK0 |= (1 << PCINT0); // enable interrupt pin 8-bit 3, for index
   sei();  // enable interrupts

   Input = speed_act;
   Setpoint = readPot(); //15; //speed_req;
   //turn the PID on
   myPID.SetMode(AUTOMATIC);
   direction = CCW;

   lcd.begin(16, 2);
   lcd.print(F("CALIBRATE MODE"));
   lcd.setCursor(0,1);
   lcd.print(F("UP Starts Cal"));

   LimitButtonState = false;
   LastButtonPin3State = 0;
   rotate1 = true;
   motorRUN = 1;
   useMenu = false;
   stepMode = false;
   STATUS = (PIND & (1 << PD5));  // reads the pin 5 register value
   incr = 1; // set the rev counter
   lcd.setBacklight(YELLOW);
   mtrSpeed = "Speed: " + String(Setpoint);
   factor = 1;
   last_count = 0;
   lastEncoderValue = 0;
   sel_count = 1;
   cal_mode = 1;
 }

/***************ISR for pin 13 compare to pin 11 ORIG single pin ******************************/
//***ISR (PCINT0_vect)    // handle pin change interrupt for D8-D13;  triggered by arduino pin 13
//***{
//***  if(bitRead(PINB,5)== bitRead(PINB,3)) {  //(PINB, x) is the syntax
//***      encoderCount++;                      // to read the input state from
             // PORTB, bit x
//***  } else {
//***  }
//***}
/*****************************************************************************/

ISR (PCINT0_vect)//handle pin change interrupt for PortB (d8 to D13), triggered by pins 11 and 13
{
  byte MSB = bitRead(PINB,3);
  byte LSB = bitRead(PINB,5);

  byte encoded = (MSB << 1) | LSB; //converting the 2 pin values to single value
  //more compact is byte encoded = bitRead(PINB3)<<1 | bitRead(PINB5);

  //sum = adding encoded to the previous encoded value, Nilton61 uses decimal representation of sum as an array index

  byte sum  = (lastEncoded << 2) | encoded;

 if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderCount ++;
 if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderCount --;

 lastEncoded = encoded; //store this value for next time
 //Serial.println(encoderCount);

 // for index pin
// if(bitRead(PINB,0) == 1) {
//   last_count++;
  // Serial.println(index_count);
// }
}

void counter_clockwise()
{
  digitalWrite(motorDir, HIGH); // CCW
}

void clockwise()
{
   digitalWrite(motorDir, LOW);   // CW
}

/*void CalMenu()
{
  
    lcd.begin(16, 2);
    lcd.print(F("CALIBRATE MODE"));
    lcd.setCursor(0,1);
    lcd.print(F("UP-CAL/DWN-RUN"));
   
}*/

void OpenMenu()
{
   //setLCD("Motor/PID INIT", "Press L or R", 0, 2);
   // 2 is two lines, 0 is top 1 is top or bottom line
   //rotate1 = true;
   //last_count = 0;
   //lastEncoderValue = 0;
   lcd.print(F("Press L or R"));
   lcd.setCursor(0,1);
   lcd.print(F("to Run Motor"));
 }

void clearLCD(int charx, int row, boolean bClear)
{
   if (bClear) { lcd.clear(); }
   lcd.setCursor(charx,row);
}

void setLCD(String line1, String line2, int start, int row)
{   // 2 is two lines, 0 is top 1 is top or bottom line
     switch (row) {
       case 0:
          lcd.setCursor(start,0);
          lcd.print(line1);
         break;

       case 1:
          lcd.setCursor(start,1);
          lcd.print(line1);
           break;

       case 2:
           lcd.setCursor(start,0);
           lcd.print(line1);
           lcd.setCursor(start,1);
           lcd.print(line2);
           break;
           default:
           Serial.println("break");
       }
       line1 = "";
       line2 = "";
} // end setLCD

// read pot values and map to "speed or rpm"
int readPot()
{
  val = analogRead(analogPin);
  mspeed = map(val, 0, 1023, 0, 105);
  return mspeed;
}

void change_direction()
{
  if (Setpoint > 20)  {  //was setpoint not Setpoint
      Setpoint = 15;
   } else {
      Setpoint = 15;  // new motor
   }

  if (direction == CCW) {
      clockwise();  // try delete, see if sign on pid changes dir?
      Input = speed_act;
  }else{
      counter_clockwise();
      Input = -speed_act;
  }

  if (!stepMode)
   myPID.Compute();

   pwmWrite(PWM1,Output);
}

void stop_motor_index()
{
	PORTD = (0 << 3);  // sets limit sw "low"
	if (cal_mode == 0) index_count = 0;   // may not want to reset this count
    //MAX_TRAVEL = index_count;
	encoderCount = 0;  // restarts encoder count
	last_count = 0;
	delay(50);
	PORTD = (1 << 3);  // sets limit sw "high"
	if (cal_mode == 1) {
		 MAX_TRAVEL = index_count;
		 Setpoint = readPot();
		 myPID.SetMode(MANUAL);
	}
	
	if (cal_mode == 0) {
	  //limitButtonPin3State = bitRead(PIND,3);
	  LastButtonPin3State = 0;
	  LimitButtonState = true;	
	  Setpoint = readPot();
	  myPID.SetMode(AUTOMATIC);
	  myPID.Compute();
	}
}

void stop_motor()
{
  if (cal_mode == 1) {
	// MAX_TRAVEL = index_count;
	// Serial.print("maxtravel: ");
	// Serial.print(index_count);
	// cal_mode = 0;
  }else{
	  index_count = 0;
      delay(265);
      speed_req = 0;
  //**PORTD &= ~(1 << 5);
  //PORTD &= ~(1 << 4); // set ENABLE LOW, D2, to stop motor
  /* set D2 LOW */
      LimitButtonState = false; // messes with buttons? try commenting out
      rotate1 = false;	   // messes with buttons?
      motorRUN = 0;
      count = 0;
      motorEnable(0);
  }
}

void getMotorData()     // calculate speed, volts and Amps
{
   static long countAnt = 0;  // last count //  pulses X 131 gear ratio = 8384
   /* Value below changed to use Setpoint & Input in terms of encoder counts*/

   index_count = abs(encoderCount);
   
   if (cal_mode == 1) {
	   cal_buttons();
   } else {
       read_buttons();
   }
   
   if (stepMode)
   {
	 //if (factor*6 == last_count) stop_motor_index();
   }

   if (index_count >= MAX_TRAVEL)
   {
	   //Serial.println("Stopping Motor");  // Debug
	  // MAX_TRAVEL = index_count;
	   stop_motor_index();
	   //lcd.clear();
	   //if (sel_count == 2) cal_mode = 0;
	   // if (MIN && MAX) {
	   // setLCD("CALIBRATION","COMPLETE",0,2);
	   //  } else {
	   if (cal_mode == 1) {
		   lcd.clear();
		   MAX_TRAVEL = index_count;
	       setLCD("MAX TRAVEL SET","at "+String(MAX_TRAVEL)+" count "+sel_count,0,2);
	   }
	   // }
   }

   //** gear ratio change: was: 192*71, IS: 192*100
   speed_act = ((encoderCount - countAnt)*(60*(1000/LOOPTIME)))/(192*100);
   // Output RPM = ((Pulses Recieved in 1 sec * 60) / PPR) / Gear Ratio
   if (direction == CCW) {
     Input = -speed_act;
   }else{
     Input = speed_act;
   }
   countAnt = encoderCount;
 }

void getDelay()
{
  t_delay = set_delay();
  mtrSpeed = "Delay: " + String(t_delay/1000) + " SEC";
}

long set_delay()
{
  val = analogRead(analogPin);
  _value = map(val, 0, 1023, 500, 30000);
  return _value;
}

void motor_step()
{
   if (last_count >= factor*6 ) stop_motor_index();
   if (abs(encoderCount) >= rev) {  // THIS DELAY ACTUALLY WORKS!
	   lastEncoderValue = abs(encoderCount);
	   Serial.println(last_count);
       motorEnable(0);
       last_count++;
       delay(t_delay);
       encoderCount = 0;
       //Setpoint = 20;
       motorEnable(1);
       myPID.SetMode(AUTOMATIC);
   }
}

void motorEnable(byte ENA)
{
   digitalWrite(mtrEnable,ENA);
}

void run_motor(uint8_t DIR)
{
  // enable motor
  motorEnable(1);
  STATUS = digitalRead(statPin);  // read the pin 7 driver status

  //(PIND & (1 << PD5));
  // Serial.println("left pushed in run_motor");

  do {

      limitButtonPin3State = digitalRead(limitButtonPin3);

      if(!stepMode) {
          Setpoint = readPot();
          mtrSpeed = "Speed: " + String(mspeed);
      }

      if (limitButtonPin3State != LastButtonPin3State) {
           count++;
           LimitButtonState = true;
           LastButtonPin3State = limitButtonPin3State;
      }

      if (DIR == CW) {
          direction = CW;
          clockwise();

         if((millis()-lastMilli) >= LOOPTIME) {  // enter timed loop
	       lastMilli = millis();
		   getMotorData();            // calculate speed, volts and Amps
	     }
	       motorRUN = 1;
      }

      if (DIR == CCW) {
        direction = CCW;
        counter_clockwise();

	     if((millis()-lastMilli) >= LOOPTIME) {    // enter timed loop
	       lastMilli = millis();
	       getMotorData();        // calculate speed, volts and Amps
	     }
      }
/***  Or create a function to run, try this: motor_step();***/
      if(stepMode) {
          motor_step();
	      myPID.SetMode(MANUAL);
	      Output = 40;
      } else {
	      myPID.Compute();
      }

    // send PWM to motor, arduino  pin 9
       if (STATUS)
         pwmWrite(PWM1,Output);

      if(millis()>serialTime) {  // for Processing 2 graph program
	     SerialReceive();
	     SerialSend();
	     serialTime+=500;
      }

      if (LastButtonPin3State == 0) {  // was 1
          setLCD("MOTOR STOPPED   ", "Press L or R", 0, 2);
	  } else {
	   //***Serial.println("Motor Running!");
      }
    } while (!LimitButtonState);
} // end run motor

void set_rotation(uint8_t intr)
{
	//Serial.println(intr);
	switch (intr) {     //13500, 6750, 1688, 422, 211
						// One turn of gear approx 38333 encoderCounts
	  case 1:
	    rev = 19150;     // 1/2 turn
	    setLCD("Step Rotation", "1/2 Turn        ", 0, 2);
		factor = 2;
		 break;
	  case 2:
		rev = 9570;  // 1/4 turn
		setLCD("Step Rotation", "1/4 Turn        ", 0, 2);
		factor = 4;
		break;
	  case 3:
	    rev = 4780;	     // 1/8 turn
		setLCD("Step Rotation", "1/8 Turn       ", 0, 2);
		factor = 8;
		break;
	  case 4:
		rev = 2390;  // 1/16 turn
		setLCD("Step Rotation", "1/16 Turn       ", 0, 2);
		factor = 16;
		break;
	  case 5:
		rev = 1190;  // 1/32 turn
		setLCD("Step Rotation", "1/32 Turn       ", 0, 2);
		factor = 32;
		break;
	  case 6:
		rev = 580;   // 1/64 turn
		setLCD("Step Rotation", "1/64 Turn       ", 0, 2);
		factor = 64;
		break;
	  case 7:
		rev = 275;		// 1/128 turn
		setLCD("Step Rotation", "1/128 Turn      ", 0, 2);
		factor = 128;
		break;
	  default:
	  	rev = 4000;
	}
}

void cal_buttons()
{

    limitButtonPin3State = digitalRead(limitButtonPin3);
	LastButtonPin3State = limitButtonPin3State;

	calib_buttons = lcd.readButtons();
	if (calib_buttons) lcd.clear();

      switch (calib_buttons) {

			  case (BUTTON_DOWN):
			    lcd.clear();
			    cal_mode = 0;
			    //index_count = 0;  
		        OpenMenu();			 		
			    //rotate1 = true;
			  break;

			  case (BUTTON_UP):			  
			    setLCD("IN CAL MODE", "PRESS L or R", 0, 2);
			    MAX_TRAVEL = 235000;			 
			    rotate1 = true;
			  break;

			  case (BUTTON_LEFT):
			  //Serial.println("Pressed Left Button");
			      //if (sel_count = 1) MIN = true;
				  setLCD("MOVING LEFT", "SELECT to SET", 0, 2);
				  Setpoint = readPot();
				  run_motor(CCW);
				  direction = CCW;
				  motorRUN = 1;
			  break;

			  case (BUTTON_RIGHT):
			      //if (sel_count = 1) MIN = true;
				  setLCD("MOVING RIGHT", "SELECT to SET", 0, 2);
				  Setpoint = readPot();				 
				  run_motor(CW);
				  direction = CW;
				  motorRUN = 1;
			  break;

			  case (BUTTON_SELECT):
			  
				  sel_count++;

				  if (sel_count == 2) {
					  MAX = true;
					  stop_motor_index();
					  lcd.clear();
					  if (direction == CCW) {
						  setLCD("MIN SET, PRESS", "RIGHT for MAX", 0, 2);
					  } else {
						   setLCD("MIN SET, PRESS", "LEFT for MAX", 0, 2);
					  }

					  Serial.print("Index Set at: ");
					  Serial.println(index_count);
				  }

				  if (sel_count == 3) {  // this is not used
					  stop_motor_index();
					  lcd.clear();
					  MIN = true;
					  Serial.print("count max: ");
					  Serial.println(MAX_TRAVEL);
				  }

				  if (direction == CCW) {
					  //***lcd.clear();
					  //***setLCD("CAL MODE: RIGHT", "MIN Val Set", 0, 2);
				  } else {
					  //***lcd.clear();
					  //***setLCD("MIN SET, LEFT", "LEFT Set to MAX", 0, 2);
				  }

				  if (MIN && MAX) {
					  lcd.clear();
					  MAX_TRAVEL = index_count;
					  limitButtonPin3State = bitRead(PIND,3);
				      LastButtonPin3State = 0;  //need these for normal operation was 0
					  LimitButtonState = true;
					  setLCD("CAL COMPLETE",String(MAX_TRAVEL),0,2);
					  //cal_mode = 0;
					  //sel_count = 0;
					  //index_count = 0;
				  }
			  break;  /*** Break for Select button ***/

			  default:
			  break;
	  }
}

void read_buttons()
{
	limitButtonPin3State = digitalRead(limitButtonPin3);
	LastButtonPin3State = limitButtonPin3State;

	buttons = lcd.readButtons();

	if (buttons) lcd.clear();

	  // use switch statement
	  switch (buttons) {

		  case (BUTTON_DOWN):
		    lcd.clear();
		    //OpenMenu();
			 setLCD("CAL COMPLETE",String(MAX_TRAVEL),0,2);
		    cal_mode = 0;
			index_count = 0;
		    if (cal_mode == 0) {
	          MAX_TRAVEL = 235000;//index_count;
			  sel_count = 0;
			//OpenMenu();
		    }
		  if (incr > 1) incr--;

		  if(stepMode) {
			  set_rotation(incr);
		  }
		  rotate1 = true;
		  break;

		  case (BUTTON_UP):
		    incr++;
		    if (incr > 7) incr = 1;

		    if(stepMode) {
			  set_rotation(incr);
		    }
		    rotate1 = true;
		  break;

		  case (BUTTON_LEFT):

			  if (rotate1) {
				if (!stepMode) {
				  setLCD("MOTOR RUNNING", "Moving LEFT", 0, 2);
				}else{
				  getDelay();
				  setLCD("Pressed L Button", mtrSpeed, 0, 2);
				}
				  run_motor(CCW);
				  motorRUN = 1;
				  } else {
				  setLCD("Pressed L Button", mtrSpeed, 0, 2);
				  rotate1 = true;
				  run_motor(CCW);
		  }
		  break;

		  case (BUTTON_RIGHT):

			  if (rotate1) {
				  if (!stepMode) {
					  setLCD("MOTOR RUNNING", "Moving RIGHT", 0, 2);
				  }else{
					  getDelay();
					  setLCD("Pressed R Button", mtrSpeed, 0, 2);
				  }
				  run_motor(CW);
				  motorRUN = 1;
			 } else {
				  myPID.SetMode(AUTOMATIC);
				  setLCD("Pressed R Button", mtrSpeed, 0, 2);
				  rotate1 = true;
				  run_motor(CW);
		     }
		  break;

		  case (BUTTON_SELECT):
			  Setpoint = 10;
		      stepMode = true;
		      rotate1 = true;
		      getDelay();
		      incr = 1;
		      setLCD("STEP MODE-PRESS", "UP / DWN Set REV", 0, 2);			
		  break;  /*** Break for Select button ***/

		  default:
		  break;
	  }
}

void loop()
{

  limitButtonPin3State = digitalRead(limitButtonPin3);

   while (limitButtonPin3State == 1) //(!LimitButtonState) - state was 0
   {
	   limitButtonPin3State = digitalRead(limitButtonPin3);
	   // Serial.print("pin 3 statel: ");
	   // Serial.println(LastButtonPin3State);

	   if(limitButtonPin3State != LastButtonPin3State) {
		   delay(150);
		   if (cal_mode == 0) stop_motor();
		   //***buttons = lcd.readButtons();
		   //***read_buttons();
	   }
	   //delay(60);  // hopefully to delay buttn reads
	   if (cal_mode == 1) {
		   cal_buttons();
	   } else {
		   read_buttons();
	   }
	   //LastButtonPin3State = limitButtonPin3State;
   }

}  // end loop

/***int digital_smooth(int value, int *data_array)  {    // remove signal noise
  static int ndx=0;
  static int count=0;
  static int total=0;
  total -= data_array[ndx];
  data_array[ndx] = value;
  total += data_array[ndx];
  ndx = (ndx+1) % NUMREADINGS;
  if(count < NUMREADINGS) count++;
  return total/count;
}  ***/

/********************************************
 * Serial Communication functions / helpers
 ********************************************/

union {                // This Data structure lets
  byte asBytes[24];    // us take the byte array
  float asFloat[6];    // sent from processing and
}                      // easily convert it to a
foo;                   // float array

// getting float values from processing into the arduino
// was no small task.  the way this program does it is
// as follows:
//  * a float takes up 4 bytes.  in processing, convert
//    the array of floats we want to send, into an array
//    of bytes.
//  * send the bytes to the arduino
//  * use a data structure known as a union to convert
//    the array of bytes back into an array of floats

//  the bytes coming from the arduino follow the following
//  format:
//  0: 0=Manual, 1=Auto, else = ? error ?
//  1: 0=Direct, 1=Reverse, else = ? error ?
//  2-5: float setpoint
//  6-9: float input
//  10-13: float output
//  14-17: float P_Param
//  18-21: float I_Param
//  22-245: float D_Param
void SerialReceive()
{
  // read the bytes sent from Processing
  int index=0;
  byte Auto_Man = -1;
  byte Direct_Reverse = -1;
  while(Serial.available()&&index<26)
  {
    if(index==0) Auto_Man = Serial.read();
    else if(index==1) Direct_Reverse = Serial.read();
    else foo.asBytes[index-2] = Serial.read();
    index++;
  }

  // if the information we got was in the correct format,
  // read it into the system
  if(index==26  && (Auto_Man==0 || Auto_Man==1)&& (Direct_Reverse==0 || Direct_Reverse==1))
  {
    Setpoint=double(foo.asFloat[0]);
    //Input=double(foo.asFloat[1]);       // * the user has the ability to send the
                                          //   value of "Input"  in most cases (as
                                          //   in this one) this is not needed.
    if(Auto_Man==0)                       // * only change the output if we are in
    {                                     //   manual mode.  otherwise we'll get an
      Output=double(foo.asFloat[2]);      //   output blip, then the controller will
    }                                     //   overwrite.

    double p, i, d;                       // * read in and set the controller tunings
    p = double(foo.asFloat[3]);           //
    i = double(foo.asFloat[4]);           //
    d = double(foo.asFloat[5]);           //
    myPID.SetTunings(p, i, d);            //

    if(Auto_Man==0) myPID.SetMode(MANUAL);// * set the controller mode
    else myPID.SetMode(AUTOMATIC);             //

    if(Direct_Reverse==0) myPID.SetControllerDirection(DIRECT);// * set the controller Direction
    else myPID.SetControllerDirection(REVERSE);          //
  }
  Serial.flush();                         // * clear any random data from the serial buffer
}

// unlike our tiny microprocessor, the processing ap
// has no problem converting strings into floats, so
// we can just send strings.  much easier than getting
// floats from processing to here no?
void SerialSend()
{
  Serial.print("PID ");
    Serial.print(Setpoint);
    Serial.print(" ");
    Serial.print(Input);
    Serial.print(" ");
    Serial.print(Output);
    Serial.print(" ");
    Serial.print(myPID.GetKp());
    Serial.print(" ");
    Serial.print(myPID.GetKi());
    Serial.print(" ");
    Serial.print(myPID.GetKd());
    Serial.print(" ");
    if(myPID.GetMode()==AUTOMATIC) Serial.print("Automatic");
    else Serial.print("Manual");
    Serial.print(" ");
    if(myPID.GetDirection()==DIRECT) Serial.println("Direct");
  else Serial.println("Reverse");
}

/*
Alternative encoder reading:
//needed declarations
const char encTable[16] ={0, 1, -1, -0, -1, 0, -0, 1, 1, -0, 0, -1, -0, -1, 1, 0};//gives -1, 0 or 1 depending on encoder movement
byte encState;//remembering the encoder output and acting as index for encTable[]
long actPos;//actual position from encoder

//code in a TIGHT loop (or you will miss pulses)
encState = ((encState<<2)|(digitalRead(encPinB)<<1|digitalRead(encPinA))&15;//use encoder bits and last state to form index
actPos += encTable[encState];//update actual position on encoder movement
*/

eholz1
Attachments
BLDC_INDEX.cpp
(30.91 KiB) Downloaded 152 times
Last edited by adafruit_support_bill on Sun Dec 13, 2015 12:05 pm, edited 1 time in total.
Reason: Added code in-line

User avatar
adafruit_support_bill
 
Posts: 88154
Joined: Sat Feb 07, 2009 10:11 am

Re: Using the RGBLcd shield buttons and i2c

Post by adafruit_support_bill »

lcd.readbuttons() is going to give you the current state of the buttons. If you press too long, the next time through the loop it will detect the button press again. The way around this is: after a button press, keep calling lcd.readbuttons() until the button has been released.

eholz1
 
Posts: 16
Joined: Mon Jun 09, 2014 3:40 pm

Re: Using the RGBLcd shield buttons and i2c

Post by eholz1 »

Hello Support,

Thanks for the reply. I will take a look and see what I can do.

Thanks Again,

eholz1

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Arduino products from Adafruit”