LCD 1602 Upgrade

In order to use the hd44780 library to run your LCD display you need to include the right files, declare an instance of a LCD object and initialize the display. The examples for the appropriate class will show how to do those things. Then, as pointed out by @red_car in post #6, you will have to develope functions that the code uses that are not supported by the library.

Ok... let's start slow. Firstly you need to install this library. In the IDE, under Tools > Manage Libraries, search for and install this:

Once you have done that you will have access to the examples that come with it...
I suggest starting with this one...

See if you can get that working first. If you can then you can move onto making changes to your code to use this new library.

If, after installing the hd44780 library and uploading the "Hello World" example you do not get a satisfactory display, you can upload and run the diagnostic program. The output, in serial monitor, from that program can be a great aid in helping to get your display to work. Copy and paste the serial monitor output to a post so that we can see it. Also the author of the library is often around and can be of great help.

Path to the diagnostic code:

Got that working great. Thanks.

Ok... now you just need to include the same library into your code.

Remove these lines...

#include "NHDLCD9.h"

NHDLCD9 lcd(4,2,16); // desired pin, rows, cols   //BB for LCD

and replace with...

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

Then in setup() add...

	int status = lcd.begin(LCD_COLS, LCD_ROWS);
	if(status) // non zero status means it was unsuccesful
	{
		// hd44780 has a fatalError() routine that blinks an led if possible
		// begin() failed so blink error code using the onboard LED if possible
		hd44780::fatalError(status); // does not return
	}

Now you need to find equivalent functions for these...

lcd.setup()
lcd.contrast()
lcd.cursorOff()
lcd.bright()
lcd.empty()
lcd.at()

lcd.setup... has been replaced with lcd.begin in the code posted above.

You can probably run without the next 3... so just comment those out for now.

lcd.empty() I think can be replaced with lcd.clear().

So that only leaves lcd.at()

I think you can replace by using a combination of:

lcd.setCursor()
lcd.print()

Ok I think I got it right but get an error

\TB3_Black_109_Release1 (1) (1)\TB3_Black_109_Release1\WiiNunchuck3.cpp:13:10: fatal error: ../Wire/Wire.h: No such file or directory
#include "../Wire/Wire.h"
^~~~~~~~~~~~~~~~
compilation terminated.

exit status 1

Compilation error: ../Wire/Wire.h: No such file or directory

Remove that line... the first one below.

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

Looks like that library is already included in your sketch (line 77).

Thats not working If I remove ../Wire/Wire.h . I am not seeing what you are referring to.

#include <hd44780.h>

/*

(c) 2015 Brian Burling eMotimo INC


    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.



*/

/*


    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
111 Target - Aux Distance with ability for continuous loop - shorten lean.
Add Stopmotion to Inshot menu
Add Brightness to in shot menu

109 Release Notes

-Fixed Aux reverse to work in all cases
-Added ability to reverse AUX_REV to EEPROM direction.
-Added interval change functionality to in shot menu - don't recommend this is used ever unless your shot is already ruined.  Changing anything mid shot will show.
-Added functionality to use left right to set frame to go to.  Can go forward or back.
-Relaxed tight requirements for joystick absolute centering - check
-Fixed motor feedrate issue when Static Time was maxed out.  If you are maxing out your static time by default, you are not using this setting correctly and hurting your shot!  
-Made Static time a max of Interval minus 0.3 seconds to allow at least a .15 second move - check
-Added abs on feedrate min calc to accommodate spurious overrun negatives on SMS shoots resulting in single long frame delays
-Added check on minimum for video to ensure we don't catch 3PT video moves on min calc.
-Added test against power policy for loop 52 (ext triggering)  
-Added ramping and new motor move to starts and ends (decoupled inputs)
-Added coordinated return to start and three axis moves.
-Updated the motorMoving to accurately assign this
-Broke up move profiles.  Added slow down routine to the move to start/move to end.
-Throttled the calc of the move to respect max jog speeds by axis.  If we hit this we indicates "Speed Limit" on video run screen.  If you hit this, lengthen move and/or decrease ramp
-Added to the Setup Menu the Motor Speed parameter - from 2000 to 20000 max to allow folks to tune.the speeds for AUX.  Pan and Tilt are hardcoded.
-Start delay cleaned up and fixed - now down to the second - also a bailout of CZ to get to 5 seconds so you aren't stuck with accidental long delays
-Add Going to End LCD prompt if heading there.
-Target, Go To End. This now works
-Focus on return to start method.  Pause parameters improved to prevent toggling - added CZ released to check for long holds and released.
-Added new Tab for TB3_InShootMenu - just pauses now and only from progstep 50 (regular SMS)
-Added return to start - just called the same routine from the repeat move at the end of the shot - finds start fine (0's) not sure
*/ 

/* 

 =========================================
Main Program
 =========================================
 
*/

#include <Wire.h>
#include <SoftwareSerial.h> 
#include <EEPROM.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "WiiNunchuck3.h"
#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;



char lcdbuffer1[20]; //this used to be 16, but increased to 20 do to overflow when we moved to Arduino 1.6 (stalled and failed)

const char setup_0[] PROGMEM = "Setup Complete";   
const char setup_1[] PROGMEM = "    TB3_109";  
const char setup_2[] PROGMEM = "Connect Joystick";
const char setup_3[] PROGMEM = "C-Next Z-Go Back";
const char setup_4[] PROGMEM = "C-Use Stored";
const char setup_5[] PROGMEM = "Z-Reset";
const char setup_6[] PROGMEM = "Params Reset";
const char setup_7[] PROGMEM = "Low Power"; 
const char setup_8[] PROGMEM = "Move to Start Pt";
const char setup_9[] PROGMEM = "Start Pt. Set";
const char setup_10[] PROGMEM = "Move to Point"; 
const char setup_11[] PROGMEM = "Moving to stored";
const char setup_12[] PROGMEM = "end point";
const char setup_13[] PROGMEM = "Confirm or Move";
const char setup_14[] PROGMEM = "C-Next";
const char setup_15[] PROGMEM = "Move to End Pt.";
const char setup_16[] PROGMEM = "End Point Set";
const char setup_17[] PROGMEM = "Set Sht Interval";
const char setup_18[] PROGMEM = "Intval:   .  sec";
const char setup_19[] PROGMEM = " Ext.Trig";
const char setup_20[] PROGMEM = " Video   ";
const char setup_21[] PROGMEM = "Interval Set";
const char setup_22[] PROGMEM = "Set Static Time";
const char setup_23[] PROGMEM = "Stat_T:   .  sec";
const char setup_24[] PROGMEM = " Video   ";
const char setup_25[] PROGMEM = "Static Time Set";
const char setup_26[] PROGMEM = "Set PreFire Time";
const char setup_27[] PROGMEM = " Pre_T:   .  sec";
const char setup_28[] PROGMEM = "Prefire Time Set";
const char setup_29[] PROGMEM = "    Set Ramp";
const char setup_30[] PROGMEM = "Ramp:     Frames";
const char setup_31[] PROGMEM = "Ramp Set";
const char setup_32[] PROGMEM = "Set Move";
const char setup_33[] PROGMEM = "Duration";
const char setup_34[] PROGMEM = "H:MM:SS";
const char setup_35[] PROGMEM = "Duration Set";
const char setup_36[] PROGMEM = "Set Static Lead";
const char setup_37[] PROGMEM = "In/Out Frames";
const char setup_38[] PROGMEM = "In      Out";
const char setup_39[] PROGMEM = "Lead Frames Set";
const char setup_40[] PROGMEM = " Going to Start";
const char setup_41[] PROGMEM = "Review and";
const char setup_42[] PROGMEM = "Confirm Setting";
const char setup_43[] PROGMEM = "Pan Steps:";
const char setup_44[] PROGMEM = "Tilt Steps:";
const char setup_45[] PROGMEM = "Cam Shots:";
const char setup_46[] PROGMEM = "Time:";
const char setup_47[] PROGMEM = "Ready?";
const char setup_48[] PROGMEM = "Press C Button";
const char setup_49[] PROGMEM = "Program Running";
const char setup_50[] PROGMEM = "Waiting for Ext.";
const char setup_51[] PROGMEM = "LeadIn";
const char setup_52[] PROGMEM = "RampUp";
const char setup_53[] PROGMEM = "Linear";
const char setup_54[] PROGMEM = "RampDn";
const char setup_55[] PROGMEM = "LeadOT";
const char setup_56[] PROGMEM = "Finish";
const char setup_57[] PROGMEM = "Center Joystick";
const char setup_58[] PROGMEM = "Program Complete";
const char setup_59[] PROGMEM = " Repeat Press C";
const char setup_60[] PROGMEM = "Battery too low";
const char setup_61[] PROGMEM = "  to continue";
const char setup_62[] PROGMEM = "Pause ";
const char setup_63[] PROGMEM = "Point X Set";
const char setup_64[] PROGMEM = "Using Set Params";
const char setup_65[] PROGMEM = "UpDown  C-Select";
const char setup_66[] PROGMEM = "New   Point Move";
const char setup_67[] PROGMEM = "Enabled";
const char setup_68[] PROGMEM = "Disabled";
const char setup_69[] PROGMEM = "PowerSave";
const char setup_70[] PROGMEM = "Always";
const char setup_71[] PROGMEM = "Program";
const char setup_72[] PROGMEM = "Shoot (accuracy)";
const char setup_73[] PROGMEM = "Shoot (pwr save)";
const char setup_74[] PROGMEM = "Aux Motor:";
const char setup_75[] PROGMEM = "Set Angle o'View";
const char setup_76[] PROGMEM = "C-Set, Z-Reset";
const char setup_77[] PROGMEM = "Pan AOV: ";
const char setup_78[] PROGMEM = "Tilt AOV: ";
const char setup_79[] PROGMEM = "   % Overlap";
const char setup_80[] PROGMEM = "Overlap Set";
const char setup_81[] PROGMEM = "Rev   Point Move";
const char setup_82[] PROGMEM = "DF Slave Mode";
const char setup_83[] PROGMEM = "Setup Menu"; //not sure why this fails
const char setup_84[] PROGMEM = "Panorama";
const char setup_85[] PROGMEM = "AuxDistance";
const char setup_86[] PROGMEM = "Resume";
const char setup_87[] PROGMEM = "Restart";
const char setup_88[] PROGMEM = "Go to Frame";
const char setup_89[] PROGMEM = "Go to End";
const char setup_90[] PROGMEM = "90";



//PROGMEM const char *setup_str[] = {setup_0,setup_1,setup_2,setup_3,setup_4,setup_5,setup_6,setup_7,setup_8,setup_9,setup_10,
PGM_P const setup_str[] PROGMEM ={setup_0,setup_1,setup_2,setup_3,setup_4,setup_5,setup_6,setup_7,setup_8,setup_9,setup_10,	
setup_11,setup_12,setup_13,setup_14,setup_15,setup_16,setup_17,setup_18,setup_19,setup_20,
setup_21,setup_22,setup_23,setup_24,setup_25,setup_26,setup_27,setup_28,setup_29,setup_30,
setup_31,setup_32,setup_33,setup_34,setup_35,setup_36,setup_37,setup_38,setup_39,setup_40,
setup_41,setup_42,setup_43,setup_44,setup_45,setup_46,setup_47,setup_48,setup_49,setup_50,
setup_51,setup_52,setup_53,setup_54,setup_55,setup_56,setup_57,setup_58,setup_59,setup_60,
setup_61,setup_62,setup_63,setup_64,setup_65,setup_66,setup_67,setup_68,setup_69,setup_70,
setup_71,setup_72,setup_73,setup_74,setup_75,setup_76,setup_77,setup_78,setup_79,setup_80,
setup_81,setup_82,setup_83,setup_84,setup_85,setup_86,setup_87,setup_88,setup_89,setup_90};


//Global Parameters 
#define DEBUG 0//
#define DEBUG_MOTOR 0//
#define DEBUG_NC 0 //
#define DEBUG_PANO 0
#define DEBUG_GOTO 0
#define POWERDOWN_LV false //set this to cause the TB3 to power down below 10 volts
#define MAX_MOVE_POINTS 3
#define VIDEO_FEEDRATE_NUMERATOR 375L // Set this for 42000L, or 375L for faster calc moves
#define PAN_MAX_JOG_STEPS_PER_SEC 10000.0
#define TILT_MAX_JOG_STEPS_PER_SEC 10000.0
//#define AUX_MAX_JOG_STEPS_PER_SEC 15000.0 //this is defined in the setup menu now.


//Main Menu Ordering

#define MENU_OPTIONS  8


#define REG2POINTMOVE 0
#define REV2POINTMOVE 1
#define REG3POINTMOVE 2
#define REV3POINTMOVE 3
#define PANOGIGA      4
#define PORTRAITPANO  5
#define DFSLAVE       6
#define SETUPMENU     7
#define AUXDISTANCE   99



//Portrait Pano
#define PanoArrayTypeOptions 5

#define PANO_9ShotCenter	1
#define PANO_25ShotCenter	3
#define PANO_7X3			2
#define PANO_9X5Type1		6
#define PANO_9X5Type2		7
#define PANO_5x5TopThird	4
#define PANO_7X5TopThird	5

//In Program Menu Ordering
#define INPROG_OPTIONS  5    //up this when code for gotoframe

#define INPROG_RESUME       0
#define INPROG_RTS          1 //return to start
#define INPROG_GOTO_END     2 //Go to end
#define INPROG_GOTO_FRAME   3 //go to frame
#define INPROG_INTERVAL     4 //Set Interval
#define INPROG_STOPMOTION   99 //Manual Forward and Back

//Interval Options
#define VIDEO_INTVAL  2
#define EXTTRIG_INTVAL 3
#define MIN_INTERVAL_STATIC_GAP 3  //min gap between interval and static time
//#define STOPMOT //not used

//TB3 section - Black or Orange Port Mapping for Step pins on Stepper Page
#define MOTORS 3
#define MOTOR0_STEP  5 
#define MOTOR1_STEP  6 
#define MOTOR2_STEP  7
#define MOTOR0_DIR   8 
#define MOTOR1_DIR   9 
#define MOTOR2_DIR   10
#define MOTOR_EN  A3
#define MOTOR_EN2  11
#define MS1 A1 
#define MS2 A2 
#define MS3 A2
#define IO_2  2 // drives middle of 2.5 mm connector on I/O port
#define IO_3  3 // drives tip of 2.5 mm connector on I/O port
#define CAMERA_PIN  12 // drives tip of 2.5 mm connector
#define FOCUS_PIN   13 // drives  middle of 2.5mm connector
#define STEPS_PER_DEG  444.444 //160000 MS per 360 degees = 444.4444444

/*
STEPS_PER_INCH_AUX for various motors with 17 tooth final gear on 5mm pitch belt
Phidgets 99:1	95153
Phidgets 27:1	25676
Phidgets 5:1	4955
20:1 Ratio	19125
10:1 Ratio	9562
*/

#define STEPS_PER_INCH_AUX 19125 //
#define MAX_AUX_MOVE_DISTANCE 311 //(31.1 inches)
//end TB3 section

unsigned long build_version=10951; //this value is compared against what is stored in EEPROM and resets EEPROM and setup values if it doesn't match
unsigned int  intval=2; //seconds x10  - used for the interval prompt and display
unsigned long interval = 2000; //calculated and is in ms
unsigned int  camera_fired     = 0; //number of shots fired
unsigned int  camera_moving_shots = 200; //frames for new duration/frames prompt
unsigned int  camera_total_shots= 0; //used at the end target for camera fired to compare against
unsigned int  overaldur=20; //seconds now for video only
unsigned int  prefire_time = 1; //currently hardcoded here to .1 second - this powers up motor early for the shot
unsigned int  rampval=50;
unsigned int  static_tm=1; //new variable
unsigned int  lead_in=1;
unsigned int  lead_out=1;
unsigned int  start_delay_sec=0;
int aux_dist;

//External Interrupt Variables
volatile int state = 0; //new variable for interrupt
volatile boolean changehappened=false;  //new variable for interrupt
long shuttertimer_open=0;
long shuttertimer_close=0;
boolean ext_shutter_open = false;
int ext_shutter_count = 0;
int ext_hdr_shots = 1; //this is how many shots are needed before moving - leave at one for normal shooting - future functionality with external 

//Start of variables for Pano Mode
unsigned int P2PType=1;  // 0 = no accel, 1= accel
unsigned int PanoPostMoveDelay=200;

//3 Point motor routine values
float motor_steps_pt[MAX_MOVE_POINTS][MOTORS];  // 3 total points.   Start point is always 0.0
float percent; //% through a leg 
unsigned int keyframe[2][6]= {{0,0,0,0,0,0},{0,0,0,0,0,0}}; //this is basically the keyframes {start, end of rampup, start or rampdown, end}   - doesn't vary by motor at this point
float linear_steps_per_shot [MOTORS] = {0.0,0.0,0.0}; //{This is for the calculated or estimated steps per shot in a segment for each motor
float ramp_params_steps [MOTORS] = {0.0,0.0,0.0}; //This is to calc the steps at the end of rampup for each motor.  Each array value is for a motor

//Program Status Flags
boolean Program_Engaged=false;
boolean Shot_Sequence_Engaged=false;
boolean Prefire_Engaged=false;
boolean Shutter_Signal_Engaged=false;
boolean Static_Time_Engaged=false;
boolean IO_Engaged=false;
boolean Move_Engaged=false;
boolean Interrupt_Fire_Engaged=false;

//Timer2flags
unsigned long MsTimer2_msecs;
//void (*MsTimer2_func)();
volatile unsigned long MsTimer2_count;
volatile char MsTimer2_overflowing;
volatile unsigned int MsTimer2_tcnt2;

//New Powersave flags
/*Power Save explanation
We can power up and power down the Pan Tilt motors together.  We can power up and power down the Aux motor port as well.  We see three levels of power saving:
1)  None - Motors are always on - for VFX work where power isn't a factor and precision is most important.  Motors will get warm here on hot days.
2)  Low - only at the end of program 
3)  Standard - Power up the motors for the shooting time (all the time we hold the trigger down), and move, power down between shots.
4)  High - Only power on for motor moves, turn off the motors when we reach the shooting position.  
    We are powered down for the shot and only power on for moves. This saves a ton of battery for long astro shots.   
    We do lose microstep resolution for this, but it usually is not visible.   We could be off by as much as 8/16 mircosetps for a shot or 0.018 degrees - Really small stuff!  Try this mode out!
*/


//CVariables that are set during the Setup Menu store these in EEPROM
unsigned int  POWERSAVE_PT;  //1=None - always on  2 - low   3=standard    4=High
unsigned int  POWERSAVE_AUX;  //1=None - always on  2 - low   3=standard    4=High
byte AUX_ON;  //1=Aux Enabled, 2=Aux disabled
byte PAUSE_ENABLED;  //1=Pause Enabled, 0=Pause disabled
boolean REVERSE_PROG_ORDER; //Program ordering 0=normal, start point first. 1=reversed, set end point first to avoid long return to start
boolean MOVE_REVERSED_FOR_RUN=0;
unsigned int  LCD_BRIGHTNESS_DURING_RUN;  //0 is off 8 is max
unsigned int  AUX_MAX_JOG_STEPS_PER_SEC; //value x 1000  20 is the top or 20000 steps per second.
byte AUX_REV;  //1=Aux Enabled, 2=Aux disabled


//control variable, no need to store in EEPROM - default and setup during shot
unsigned int progstep = 0; //used to define case for main loop
boolean progstep_forward_dir=true; //boolean to define direction of menu travel to allow for easy skipping of menus
unsigned int progtype=0; //updownmenu selection
int inprogtype=0; //updownmenu selection during shoot
boolean reset_prog=1; //used to handle program reset or used stored
unsigned int first_time=1; //variable to help with LCD dispay variable that need to show one time
boolean first_time2=true;
int batt_low_cnt=0;
unsigned int max_shutter;
unsigned int max_prefire;
unsigned int program_progress_2PT=1;  //Lead in, ramp, linear, etc for motor routine case statement
unsigned int program_progress_3PT=1;  //phase 1, phase 2
unsigned long interval_tm        = 0;  //mc time to help with interval comparison
unsigned long interval_tm_last =0; //mc time to help with interval comparison
int cursorpos=1; //use 1 for left, 2 for right  - used for lead in, lead out
unsigned int lcd_dim_tm     = 10;
unsigned long input_last_tm = 0;
unsigned long diplay_last_tm = 0;
unsigned int  lcd_backlight_cur=100;
unsigned int  prompt_time=500; // in ms for delays of instructions
//unsigned int  prompt_time=350; // for faster debugging
int  prompt_delay = 0; //to help with joystick reads and delays for inputs - this value is set during joystick read and executed later in the loop
int prompt_val;
unsigned int  video_sample_ms=100; //
unsigned int video_segments=150; //arbitrary
int reviewprog = 1;
//variables for display of remaining time
int timeh; 
int timem;
int time_s;

unsigned long start_delay_tm = 0;  //ms timestamp to help with delay comparison
unsigned int goto_shot=0;

int sequence_repeat_type=1; //1 Defaults - Run Once, 0 Continuous Loop,  -1 Continuous Forward
int sequence_repeat_count=0; //counter to hold variable for how many time we have repeated



//remote and interface variables

float joy_x_axis; int joy_x_axis_Offset; int joy_x_axis_Bucket; int joy_x_axis_Threshold; int joy_x_axis_map; int speedx;
float joy_y_axis; int joy_y_axis_Offset; int joy_y_axis_Bucket; int joy_y_axis_Threshold; int joy_y_axis_map; int speedy;
float accel_x_axis; int accel_x_axis_Offset; int accel_x_axis_Bucket; int accel_x_axis_Threshold;

int PanStepCount;
int TiltStepCount;

int z_button = 0;
int c_button = 0;
int prev_joy_x_reading=0;
int prev_joy_y_reading=0;
unsigned int joy_y_lock_count=0;
unsigned int joy_x_lock_count=0;
int prev_accel_x_reading=0;
int CZ_Button_Read_Count=0;
boolean CZ_Released=true;
int C_Button_Read_Count=0;
boolean C_Released=true;
int Z_Button_Read_Count=0;
boolean Z_Released=true;
int NCReadStatus=0; //control variable for NC error handling
unsigned int NCReadMillis=42; //frequency at which we read the nunchuck for moves  1000/24 = 42  1000/30 = 33
long NClastread=1000; //control variable for NC reads cycles




//Stepper Setup
unsigned long  feedrate_micros = 0;

struct FloatPoint {
	float x;
	float y;
 	float z;
};
FloatPoint fp;

FloatPoint current_steps;
FloatPoint target_steps;
FloatPoint delta_steps;

//our direction vars
byte x_direction = 1;
byte y_direction = 1;
byte z_direction = 1;

//End setup of Steppers

//Start of DF Vars
#define DFMOCO_VERSION 1
#define DFMOCO_VERSION_STRING "1.2.6"


// supported boards
#define ARDUINO      1
#define ARDUINOMEGA  2

//eMotimo TB3 - Set this PINOUT_VERSION 3 for TB3 Orange (Uno)
//eMotimo TB3 - Set this PINOUT_VERSION 4 for TB3 Black (MEGA)
#define PINOUT_VERSION 4

/*
  This is PINOUT_VERSION 1
  
  channel 5
        PIN  22   step
        PIN  23   direction
  channel 6
        PIN  24   step
        PIN  25   direction
  channel 7
        PIN  26   step
        PIN  27   direction
  channel 8
        PIN  28   step
        PIN  29   direction
*/

// detect board type
#define BOARD ARDUINOMEGA

#define SERIAL_DEVICE Serial
  
#define PIN_ON(port, pin)  { port |= pin; }
#define PIN_OFF(port, pin) { port &= ~pin; }

#define MOTOR_COUNT 4

#define TIME_CHUNK 50
#define SEND_POSITION_COUNT 20000

// update velocities 20 x second
#define VELOCITY_UPDATE_RATE (50000 / TIME_CHUNK)
#define VELOCITY_INC(maxrate) (max(1.0f, maxrate / 70.0f))


  //Start TB3 Black Port Mapping

  #define MOTOR0_STEP_PORT PORTE
  #define MOTOR0_STEP_PIN  B00001000 //Pin 5 PE3
  
  #define MOTOR1_STEP_PORT PORTH
  #define MOTOR1_STEP_PIN  B00001000//Pin  6 PH3
  
  #define MOTOR2_STEP_PORT PORTH
  #define MOTOR2_STEP_PIN  B00010000 //Pin 7 PH4

  #define MOTOR3_STEP_PORT PORTC //  Map this to pin 30 PC7 on the Mega board for debug
  #define MOTOR3_STEP_PIN  B10000000 //
  //End TB3 Black Port Mapping


/**
 * Serial output specialization
 */
#if defined(UBRRH)
#define TX_UCSRA UCSRA
#define TX_UDRE  UDRE
#define TX_UDR   UDR
#else
#define TX_UCSRA UCSR0A
#define TX_UDRE  UDRE0
#define TX_UDR   UDR0
#endif
 
char txBuf[32];
char *txBufPtr;

#define TX_MSG_BUF_SIZE 16

#define MSG_STATE_START 0
#define MSG_STATE_CMD   1
#define MSG_STATE_DATA  2
#define MSG_STATE_ERR   3

#define MSG_STATE_DONE  100

/*
 * Command codes from user
 */
#define USER_CMD_ARGS 40

#define CMD_NONE       0
#define CMD_HI         10
#define CMD_MS         30
#define CMD_NP         31
#define CMD_MM         40 // move motor
#define CMD_PR         41 // pulse rate
#define CMD_SM         42 // stop motor
#define CMD_MP         43 // motor position
#define CMD_ZM         44 // zero motor
#define CMD_SA         50 // stop all (hard)
#define CMD_BF         60 // blur frame
#define CMD_GO         61 // go!

#define CMD_JM         70 // jog motor
#define CMD_IM         71 // inch motor

#define MSG_HI 01
#define MSG_MM 02
#define MSG_MP 03
#define MSG_MS 04
#define MSG_PR 05
#define MSG_SM 06
#define MSG_SA 07
#define MSG_BF 10
#define MSG_GO 11
#define MSG_JM 12
#define MSG_IM 13


struct UserCmd
{
  byte command;
  byte argCount;
  int32_t args[USER_CMD_ARGS];
} ;

/*
 * Message state machine variables.
 */
byte lastUserData;
int  msgState;
int  msgNumberSign;
UserCmd userCmd;


struct txMsg
{
  byte msg;
  byte motor;
};

struct TxMsgBuffer
{
  txMsg buffer[TX_MSG_BUF_SIZE];
  byte head;
  byte tail;
};

TxMsgBuffer txMsgBuffer;


/*
 Motor data.
 */

uint16_t           motorAccumulator0;
uint16_t           motorAccumulator1;
uint16_t           motorAccumulator2;
uint16_t           motorAccumulator3;

uint16_t*          motorAccumulator[MOTOR_COUNT] =
{
  &motorAccumulator0, &motorAccumulator1, &motorAccumulator2, &motorAccumulator3, 

};

uint16_t           motorMoveSteps0;
uint16_t           motorMoveSteps1;
uint16_t           motorMoveSteps2;
uint16_t           motorMoveSteps3;

uint16_t*          motorMoveSteps[MOTOR_COUNT] =
{
  &motorMoveSteps0, &motorMoveSteps1, &motorMoveSteps2, &motorMoveSteps3,
};


uint16_t           motorMoveSpeed0;
uint16_t           motorMoveSpeed1;
uint16_t           motorMoveSpeed2;
uint16_t           motorMoveSpeed3;

uint16_t         * motorMoveSpeed[MOTOR_COUNT] =
{
  &motorMoveSpeed0, &motorMoveSpeed1, &motorMoveSpeed2, &motorMoveSpeed3,

};

volatile boolean nextMoveLoaded;


unsigned int   velocityUpdateCounter;
byte           sendPositionCounter;
boolean        hardStopRequested;

byte sendPosition = 0;
byte motorMoving = 0;
byte toggleStep = 0;


#define P2P_MOVE_COUNT 7

struct Motor
{
  byte   stepPin;
  byte   dirPin;

  // pre-computed move
  float   moveTime[P2P_MOVE_COUNT];
  int32_t movePosition[P2P_MOVE_COUNT];
  float   moveVelocity[P2P_MOVE_COUNT];
  float   moveAcceleration[P2P_MOVE_COUNT];

  float   gomoMoveTime[P2P_MOVE_COUNT];
  int32_t gomoMovePosition[P2P_MOVE_COUNT];
  float   gomoMoveVelocity[P2P_MOVE_COUNT];
  float   gomoMoveAcceleration[P2P_MOVE_COUNT];

  int       currentMove;
  float     currentMoveTime;
  
  volatile  boolean   dir;

  int32_t   position;
  int32_t   destination;
  
  float     maxVelocity;     //Orig - delete later
  float     maxAcceleration; //Orig - delete later
  
  float     moveMaxVelocity;     //Pass this into calculator for synchronized moves
  float     moveMaxAcceleration; //Pass this into calculator for synchronized moves
  
  float     jogMaxVelocity; //replaced the original maxVelocity
  float     jogMaxAcceleration; //replaced the original maxAcceleration
 
  uint16_t  nextMotorMoveSteps;
  float     nextMotorMoveSpeed;
  

};

boolean maxVelLimit=false;

boolean goMoReady;
int     goMoDelayTime;

Motor motors[MOTOR_COUNT];

//End of DFVars


/* 
 =========================================
 Setup functions
 =========================================
*/



void setup() {
 
  // setup motor pins
 pinMode(MOTOR0_STEP, OUTPUT);
 pinMode(MOTOR0_DIR, OUTPUT);
 pinMode(MOTOR1_STEP, OUTPUT);
 pinMode(MOTOR1_DIR, OUTPUT);
 pinMode(MOTOR2_STEP, OUTPUT);
 pinMode(MOTOR2_DIR, OUTPUT);
 
pinMode(MS1,OUTPUT);
pinMode(MS2,OUTPUT);
pinMode(MS3,OUTPUT);
 
digitalWrite(MS1, HIGH);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, HIGH);

 pinMode(MOTOR_EN, OUTPUT);
 pinMode(MOTOR_EN2, OUTPUT);
 digitalWrite(MOTOR_EN, HIGH); //LOW Enables output, High Disables
 digitalWrite(MOTOR_EN2, HIGH); //LOW Enables output, High Disables
 
// setup camera pins
 pinMode(CAMERA_PIN, OUTPUT); 
 pinMode(FOCUS_PIN, OUTPUT); 
 
digitalWrite(CAMERA_PIN, LOW);
digitalWrite(FOCUS_PIN, LOW);

//Setup of I/0 Pings Start with output of I/Oport
pinMode(IO_2, OUTPUT);
pinMode(IO_3, OUTPUT);

digitalWrite(IO_2, LOW);
digitalWrite(IO_3, LOW);

pinMode(A0, INPUT); //this is for the voltage reading

//Setup LCD
 lcd.setup();  
 delay(100);
 draw(0,1,2); // Setup Complete
 draw(1,2,1); // Version Number
 //strcpy_P(lcdbuffer1, (PGM_P)pgm_read_word(&(setup_str[0]))); // Necessary casts and dereferencing, just copy.
 //lcd.at(2,1,lcdbuffer1);
 //lcd.contrast(50);
 //lcd.cursorOff();
 lcd.bright(4);
 
 delay(prompt_time*2);
 lcd.empty();
 delay(100);

 draw(2,1,1); // Connect Joystick

//Setup Serial Connection

//if (DEBUG) Serial.begin(115200);
//else Serial.begin(57600);
Serial.begin(57600);
Serial.println("Opening Serial Port");

// Handle EEPROM Interaction and upgrades

//Check to see if our hardcoded build version set in progam is different than what was last put in EEPROM - detect upgrade.
if(build_version != check_version()) { //4 byte string that now holds the build version.
  if(DEBUG) Serial.println(check_version());
  if(DEBUG) Serial.println("Upgrading Memory");   
  write_defaults_to_eeprom_memory();  //these are for setting for last shot
  set_defaults_in_setup(); //this is for our setup values that should only be defaulted once.
  //review_RAM_Contents();
}
else { //load last setting into memory - no upgrade
   if(DEBUG) Serial.println("Restoring EEPROM Values");
   restore_from_eeprom_memory();
   //review_RAM_Contents();
 }
//End Setup of EEPROM

//begin  Setup for Nunchuck
Nunchuck.init(0);
delay(50);
for (int reads=1; reads<17; reads++) {
   Nunchuck.getData();
   //Nunchuck.printData();
   lcd.at(2,reads,"+");
   if (abs(Nunchuck.joyx()-127)>60||abs(Nunchuck.joyy()-127)>60 ){
     lcd.empty();
     draw(57,1,1);//lcd.at(1,1,"Center Joystick"); 
     reads=1;
   }
   delay(10);
   
}

calibrate_joystick(Nunchuck.joyx(),Nunchuck.joyy());

 //end  Setup for Nunchuk
 lcd.empty(); 
 

//Setup Motors  
init_steppers();

//init_external_triggering();
pinMode(IO_3, INPUT);
digitalWrite(IO_3, HIGH);
attachInterrupt(1, cam_change, CHANGE); 



} //end of setup

void loop() {  //Main Loop
  while(1) {  //use debugging WHEN HIT here for monitoring - {sequence_repeat_type},{progstep},{progtype},{camera_fired}
    switch (progstep) 
    {

 //start of 2 point SMS/Video routine
      case 0:   // 
        Choose_Program();
		
      break;
      
      case 1:   // Move to Start Point
        Move_to_Startpoint(); //don't jump in this loop by accident
      break;
            
      case 2:   // Move to End Point
        Move_to_Endpoint(); //don't jump in this loop by accident
      break;
      
      case 3: //  Set Camera Interval
        Set_Cam_Interval();
      break;
     
      case 4: // 
        Set_Duration();
      break;
      
      case 5: //  	    Static Time
	  
	  if (intval==VIDEO_INTVAL) {   //don't show this for video
	      if (progstep_forward_dir) progstep_forward(); //skip the menu, go forward
	      else progstep_backward();  //skip the menu, go backward
      }
      else  Set_Static_Time(); //not needed for video
	  
      break;
         
      case 6: //  
	  	
		Set_Ramp();
		
      break;
       
      case 7: //  Lead in and lead out
       
	   if (intval==VIDEO_INTVAL) {   //don't show this for video
			if (progstep_forward_dir) {
				Calculate_Shot(); //
				progstep_forward();
			} //skip the menu, go forward
	        else progstep_backward();  //skip the menu, go backward
       }
       
	   else  Set_LeadIn_LeadOut(); //  not needed for video
		
		
      break;       
        
       case 8: //  Set Shot Type
       	   if (intval!=VIDEO_INTVAL) {   //skip for non video
	       	   if (progstep_forward_dir) {
					progstep_forward();  //skip the menu, go forward
	       	   } 
	       	   else progstep_backward();  //skip the menu, go backward
       	   }
       	   
       	   else Set_Shot_Repeat(); 
       break;
  
      case 9: //  review and confirm
        Review_Confirm(); //also has the delay start options here
      break;
      
//end of the two point move
      
 //start of the three point move      
       case 100:
        Choose_Program();
      break;
      
      case 101:   // Move Point 0
          Move_to_Point_X(0);
      break;
            
      case 102:   // Move Point 1
          Move_to_Point_X(1);
      break;      
      
      case 103:   // Move Point 2
          Move_to_Point_X(2);
      break; 
      
      case 104: //  Set Camera Interval
        Set_Cam_Interval();
      break;
     
      case 105: // 
        Set_Duration();
      break;
      
      case 106: //  
        Set_Static_Time();
      break;
         
      case 107: //  
        Set_Ramp();
      break;
       
      case 108: //  
        Set_LeadIn_LeadOut();
      break;       
        
      case 109: //  review and confirm
        Review_Confirm();
      break;
 //end of the three point move     
 
 //start of pano Mode
     
          //  define field of view
       //We want to know how wide and tall our field of view is in steps so we can get our overlap right.  Anytime you zoom or change lenses, this need to be redefined
       //This should be a 10 seconds process to define by specifying corners
       //Step 1 - Put a point in the upper right corner - set zeros, pan up and right to hit same point with lower left corner of viewfinder
       //Display values  - write to ram - use these values 
      
      case 200:  //
        Choose_Program();      
      break;
	  
	  case 201:  //
	    Move_to_Point_X(0); //move to sharp point 
	  break;
     
      case 202:  //
         Set_angle_of_view();
      break;
            
      case 203:   //
        Define_Overlap_Percentage();
      break;      
      
      case 204:   // 
        Move_to_Point_X(0);
      break; 
      
      case 205: //  
        Move_to_Point_X(1);
      break;
     
      case 206: // 
          Set_Static_Time();   
      break;
      
      case 207: //  
        Pano_Review_Confirm();  
      break;
 //end of Pano Mode
    
    
    
 //start of Portrait Pano Method
     
       //  define field of view
       //We want to know how wide and tall our field of view is in steps so we can get our overlap right.  Anytime you zoom or change lenses, this need to be redefined
       //This should be a 10 seconds process to define by specifying corners
       //Step 1 - Put a point in the upper right corner - set zeros, pan up and right to hit same point with lower left corner of viewfinder
       //Display values  - write to ram - use these values 
      
      case 210:  //
        Choose_Program();      
      break;
      
      case 211:  //
        Move_to_Point_X(0); //move to sharp point      
      break;
     
      case 212:  //
         Set_angle_of_view();
      break;
            
      case 213:   //
        Define_Overlap_Percentage();
      break;      
      
      case 214:   // 
        Move_to_Point_X(0);  //set subject point
      break; 
      
      case 215: //  
        Set_PanoArrayType();   //this sets variable that define how we move camera - load the appropriate array.
      break;
     
      case 216: // 
          Set_Static_Time();   
      break;
      
      case 217: //  
        Pano_Review_Confirm();  
      break;
 //end of Pano Mode
    
 
 
 
 //start of entered distance on aux mode
      case 300:   // 
        Choose_Program();
      break;
      
      case 301:   // Move to Start Point
        Move_to_Startpoint();
      break;
            
      case 302:   // Move to End Point
        Enter_Aux_Endpoint();
      break;
      
      case 303: //  Set Camera Interval
        Set_Cam_Interval();
      break;
     
      case 304: // 
        Set_Duration();
      break;
      
      case 305: //  
        Set_Static_Time();
      break;
         
      case 306: //  
        Set_Ramp();
      break;
       
      case 307: //  
        Set_LeadIn_LeadOut();
      break;       
        
      case 308: //  review and confirm
        Review_Confirm();
      break;
      
//end entered distance mode
      
 //start of setup      
 
      case 901:   // AUX_ON
        Setup_AUX_ON();
      break;
            
      case 902:   // PAUSE_ENABLED
        Setup_PAUSE_ENABLED();
      break;      
      
      case 903:   // POWERSAVE_PT
        Setup_POWERSAVE_PT();
      break; 
      
      case 904: //  POWERSAVE_AUX
        Setup_POWERSAVE_AUX();
      break;
      
      case 905: //  LCD Bright
        Setup_LCD_BRIGHTNESS_DURING_RUN();
      break;
      
      case 906: //  Aux Motor Max Speed
        Setup_Max_AUX_Motor_Speed();
      break;
      
      case 907: //  LCD Bright
        Setup_AUX_Motor_DIR();
      break;
      
     
      case 908: //  Exit
        delay(100);
      break;
     
    
//end of setup       

 //start of in program menu options      
 
      case 1001:   // AUX_ON
        InProg_Select_Option();
      break;
            
     
     
    
//end of in program menu  

        
      
case 50:  // loop for SMS
    
    // //Step 1 if internal interval.Kick off the shot sequence. This happens once per camera shot.   
      if( (intval>3) && (Program_Engaged) && !(Shot_Sequence_Engaged) && ((millis() - interval_tm) > interval) ) { 
        interval_tm_last=interval_tm; //just used for shot timing comparison
        interval_tm=millis(); //start the clock on our shot sequence
        
        if (DEBUG) {Serial.print("trueinterval: ");Serial.print(interval_tm-interval_tm_last);Serial.print(";");}
        Interrupt_Fire_Engaged=false; //clear this flag to avoid rentering this routine
        Shot_Sequence_Engaged=true;//
        Prefire_Engaged=true;//
        IO_Engaged=true;//
        digitalWrite(FOCUS_PIN, HIGH); //for longer shot interval, wake up the camera
 
        if (POWERSAVE_PT<4)   enable_PT();  //don't power on for shot for high power saving
        if (AUX_ON && POWERSAVE_AUX<4)   enable_AUX();  //don't power on for shot for high power saving

      }
      
      //Step 1 if external triggering. This happens once per camera shot.
      if( (Program_Engaged) && !(Shot_Sequence_Engaged) && (intval==EXTTRIG_INTVAL) && Interrupt_Fire_Engaged ) { 
        interval_tm_last=interval_tm; //just used for shot timing comparison
        
        interval_tm=millis(); //start the clock on our shot sequence
        if (DEBUG) {Serial.print("trueinterval: ");Serial.print(interval_tm-interval_tm_last);Serial.print(";");}
        Interrupt_Fire_Engaged=false; //clear this flag to avoid rentering this routine

        Shot_Sequence_Engaged=true;//
        Prefire_Engaged=true;//
        IO_Engaged=true;//
        digitalWrite(FOCUS_PIN, HIGH); //for longer shot interval, wake up the camera
        
        if (POWERSAVE_PT<4)   enable_PT();  //don't power on for shot for high power saving
        if (AUX_ON && POWERSAVE_AUX<4)   enable_AUX();  //don't power on for shot for high power saving
      }
         
             
      //End our prefire - check that we are in program active,shot cycle engaged, and prefire engaged and check against our prefire time
      //If so set prefire flag off, static flag on, fire camera for static time value, update the display 		

      if ((Shot_Sequence_Engaged) && (Prefire_Engaged)  && ((millis()-interval_tm) > prefire_time*100)) { 
 
        Prefire_Engaged=false;
        if (DEBUG) {Serial.print("PreDoneAt ");Serial.print(millis()-interval_tm);Serial.print(";");}
        
        Static_Time_Engaged=true;
       //Fire Camera
          if (intval!=3) fire_camera((long)static_tm*100); //start shutter sequence
          camera_fired++;
      }

      //End out static time - check that we are in an program active and static time,  Shutter not engaged, check shot cycle time agains prefire+statictime
      //If so remove flags from Static Time Engaged and IO engaged, Turn off I/O port, set flags for motors moving, move motors
      //move motors - figure out delays.   Long delays mean really slow - choose the minimum of the calculated or a good feedrate that is slow
	     
      //if (Program_Engaged && Shot_Sequence_Engaged && Static_Time_Engaged && !Shutter_Signal_Engaged && ((millis() - interval_tm) > (prefire_time*100+static_tm*100)) ) {
      if (Shot_Sequence_Engaged && Static_Time_Engaged && !Shutter_Signal_Engaged && ((millis() - interval_tm) > (prefire_time*100+static_tm*100)) ) 
      { //removed requirement for Program Engaged for external interrupt
   
       
        Static_Time_Engaged=false; //Static Time Engaged is OFF
        IO_Engaged=false; //IO Engaged is off
          //digitalWrite(IO_2, LOW); //Use this as the iterrupt
          //digitalWrite(IO_3, LOW);  //Turn off Pin 3
          //Serial.print("IO3_off"); //Serial.println(millis()-interval_tm);
        
       
        //Move the motors - each motor move is calculated by where we are in the sequence - we still call this for lead in and lead out - motors just don't move
 
          Move_Engaged=true; //move motors  
          if (DEBUG_MOTOR) {Serial.print("MoveStart "); Serial.print(millis()-interval_tm);Serial.print(";");}
          move_motors();
          if (DEBUG_MOTOR) {Serial.print("Moveend "); Serial.print(millis()-interval_tm);Serial.print(";");}
          
        //Turn off the motors if we have selected powersave 3 and 4 are the only ones we want here
          if (POWERSAVE_PT>2)   disable_PT(); 
          if (POWERSAVE_AUX>2)   disable_AUX();  //
   
          
        //Update display
          if (intval!=3) display_status();  //update after shot complete to avoid issues with pausing
    

       Shot_Sequence_Engaged=false;  //Shot sequence engaged flag is is off - we are ready for our next 
       Interrupt_Fire_Engaged=false;
       //CZ_Button_Read_Count=0;
       //InterruptAction_Reset(); //enable the external interrupts to start a new shot
       if (DEBUG) {Serial.println("EOL");} 
      }
      
      if ( camera_moving_shots > 0  && camera_fired >= camera_total_shots) {  //end of program
        lcd.empty();
        draw(58,1,1);//lcd.at(1,1,"Program Complete"); 
        Program_Engaged=false;
        if (POWERSAVE_PT>1)   disable_PT();  //  low, standard, high, we power down at the end of program
        if (POWERSAVE_AUX>1)  disable_AUX();  // low, standard, high, we power down at the end of program
        delay(prompt_time*2);
        progstep=90;
        first_time=1;
      }
      
  //This portion always runs in empty space of loop.      
      
    NunChuckQuerywithEC();
    NunChuckjoybuttons();
    Check_Prog(); //look for button presses
    //if (CZ_Button_Read_Count>10 && intval==EXTTRIG_INTVAL ) Interrupt_Fire_Engaged=true; // manual trigger
    //if (PAUSE_ENABLED && CZ_Button_Read_Count>10 && intval>3 && !Shot_Sequence_Engaged ) Pause_Prog(); //pause an SMS program
    if (PAUSE_ENABLED && CZ_Button_Read_Count>25 && intval>3 && !Shot_Sequence_Engaged && CZ_Released ) SMS_In_Shoot_Paused_Menu(); //jump into shooting menu
    

break; //break 50      
      
 
 
 
case 51:  

//main video loop interrupt based.  This runs for 2 point moves only.
   
if (progtype==REG2POINTMOVE || progtype==REV2POINTMOVE) {
   synched3AxisMove_timed(motor_steps_pt[2][0],motor_steps_pt[2][1],motor_steps_pt[2][2], float(overaldur), float(rampval/100.0));
   if (maxVelLimit){ //indicates the move is limited to enforce velocity limit on motors)
     lcd.at(2,1,"Speed Limit");
   }
    //Start us moving 
  // interval_tm_last=interval_tm;
   interval_tm=millis();  
    
    startISR1 ();
      do 
      {
        if (!nextMoveLoaded)
        {
          updateMotorVelocities();
        }
      } while (motorMoving);

    stopISR1 ();

    Serial.print("Video Runtime"); Serial.println(millis()-interval_tm);  

    
    
    

      if (!motorMoving&&(sequence_repeat_type==0)) { //new end condition for RUN CONTINOUS
			boolean break_continuous=false;
			lcd.empty(); 
			draw(58,1,1);//lcd.at(1,1,"Program Complete"); 
			Program_Engaged=false;
			for (int i=0; i<30; i++){
			    NunChuckQuerywithEC();
			    NunChuckjoybuttons();
			    Check_Prog(); //look for button presses
			    if (PAUSE_ENABLED && CZ_Button_Read_Count>25 ) {
					break_continuous=true;
					lcd.empty();				
					lcd.at(1,1,"Stopping Run");
					lcd.at(2,1,"Release Buttons");
					do {
					NunChuckQuerywithEC();
					NunChuckjoybuttons();	
										
					} while (c_button || z_button);
					progstep=9;
					}
				
			}
			
			//add section to delay here if the delay is set.
			while (start_delay_tm>millis()/1000L) {
				//enter delay routine
				calc_time_remain_start_delay ();
				if ((millis()-diplay_last_tm) > 1000) display_time(2,1);
				NunChuckQuerywithEC();
				NunChuckjoybuttons();
				Check_Prog(); //look for long button press
				//if (CZ_Button_Read_Count>20 && !Program_Engaged) {
				//	start_delay_tm=((millis()/1000L)+5); //start right away by lowering this to 5 seconds.
				//	CZ_Button_Read_Count=0; //reset this to zero to start
				//}

			}
			
			//end start delay
			
			
			if(!break_continuous) Auto_Repeat_Video(); //only run this if there isn't a break command
			first_time=1;
      }
	  else if (!motorMoving&&(sequence_repeat_type==1)) { //new end condition for RUN ONCE
		        lcd.empty();
		        draw(58,1,1);//lcd.at(1,1,"Program Complete");
		        Program_Engaged=false;
		        if (POWERSAVE_PT>1)   disable_PT();  //  low, standard, high, we power down at the end of program
		        if (POWERSAVE_AUX>1)  disable_AUX();  // low, standard, high, we power down at the end of program
		        progstep=90;
		        first_time=1;
		        delay(100);
		        //NunChuckQuerywithEC();
	  }
	  
	  
      
} // end interrupt routine driven for 2 points

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

  //Start video loop for 3 Point moves - this loop does not use the new motor move profile as it needs to calculate each and every segment
if (progtype==REG3POINTMOVE || progtype==REV3POINTMOVE) {  //this is regular 3 point move program that can be modified later
      if (DEBUG) {
            interval_tm_last=interval_tm;
            interval_tm=millis(); 
          }
      //Start us moving  
      
      if (DEBUG) {Serial.print("trueinterval ");Serial.print(interval_tm-interval_tm_last);Serial.print(";");}
       
      if (DEBUG_MOTOR) {Serial.print("MoveStart "); Serial.print(millis());Serial.print(";");}
      
      camera_fired ++; //still need this for framing
      move_motors();
      
      if (DEBUG_MOTOR) {Serial.print("Moveend "); Serial.println(millis());}
          

      if ( camera_total_shots > 0  && camera_fired >= camera_total_shots) { 
        lcd.empty();
        //draw(58,1,1);//lcd.at(1,1,"Program Complete"); 
        Program_Engaged=false;
        if (POWERSAVE_PT>1)   disable_PT();  //  low, standard, high, we power down at the end of program
        if (POWERSAVE_AUX>1)  disable_AUX();  // low, standard, high, we power down at the end of program
        delay(prompt_time*2);
        progstep=90;  
        first_time=1;
        //delay(100);
        //NunChuckQuerywithEC();
      }

} // End video loop for 3 Point moves


break; //break 51 - VIDEO



case 52:  // loop for external interrupt - external triggering
    
    //New interrupt Flag Checks
      
      if (changehappened)
      {
          changehappened=false;
          if(!state) //start the clock as the cam shutter witch closed and sense pin, was brought low
          {
            ext_shutter_open=true;
            shuttertimer_open=micros(); 
            if(DEBUG) Serial.print("shuttertimer_a=");Serial.print(shuttertimer_open);
            
          }
          else if (state) //shutter closed - sense pin goes back high - stop the clock and report
          {
              ext_shutter_open=false;  
              shuttertimer_close=micros(); //turn on the led / shutter
               ext_shutter_count++;
             if(DEBUG) Serial.print(" ext_shutter_count=");Serial.print(ext_shutter_count);
             if(DEBUG) Serial.print(" shuttertimer_b=");Serial.print(shuttertimer_close);Serial.print("diff=");Serial.println(shuttertimer_close-shuttertimer_open);
          }
          
      }
      //end interrupt check and flagging
     
             
      //  Start of states for external shooting loop	

      if( (Program_Engaged) && !(Shot_Sequence_Engaged) && !(Shutter_Signal_Engaged) && (ext_shutter_open) ) { //start a shot sequence flag
      
          Shot_Sequence_Engaged=true; //
      
      }  
        
        
      if( (Program_Engaged) && (Shot_Sequence_Engaged) && !(Shutter_Signal_Engaged) && (ext_shutter_open) ) { //fire the camera can happen more than once in a shot sequence with HDR
         
          if (DEBUG) {Serial.print("Startshot_at:");Serial.print(millis());Serial.println(";");}
      
       //Fire Camera
          //don't fire the camera with the timer, just turn on our focus and shutter pins - we will turn them off when we sense the shot is done.
          digitalWrite(FOCUS_PIN, HIGH);
          digitalWrite(CAMERA_PIN, HIGH);
          Shutter_Signal_Engaged=true;
          //camera_fired++;
      }

   	     
       if (Shot_Sequence_Engaged && (Shutter_Signal_Engaged) && !(ext_shutter_open) ) { //shutter just closed, stop the camera port and move
       
          digitalWrite(FOCUS_PIN, LOW);
          digitalWrite(CAMERA_PIN, LOW);
          Shutter_Signal_Engaged=false;
       
        
            if (ext_shutter_count >=ext_hdr_shots) { //this is future functionality  - leave at 1 for now
            
                    camera_fired++;
                    ext_shutter_count=0;  
            //Move the motors - each motor move is calculated by where we are in the sequence - we still call this for lead in and lead out - motors just don't move
           
                    Move_Engaged=true; //move motors  
                    if (DEBUG_MOTOR) {Serial.print("MoveStart "); Serial.print(millis()-interval_tm);Serial.print(";");}
                    move_motors();
                    if (DEBUG_MOTOR) {Serial.print("Moveend "); Serial.print(millis()-interval_tm);Serial.print(";");}
                    
            //Turn off the motors if we have selected powersave 3 and 4 are the only ones we want here
              if (POWERSAVE_PT>2)   disable_PT(); 
              if (POWERSAVE_AUX>2)   disable_AUX();  //  
             
                  
                  //Update display
                    display_status();  //update after shot complete to avoid issues with pausing
           
                   Shot_Sequence_Engaged=false;  //Shot sequence engaged flag is is off - we are ready for our next 
                   CZ_Button_Read_Count=0;
                   //InterruptAction_Reset(); //enable the external interrupts to start a new shot
                   if (DEBUG) {Serial.println("EOL");}
            }
             
      }
      
      if ( camera_moving_shots > 0  && camera_fired >= camera_total_shots) {  //end of program
        lcd.empty();
        draw(58,1,1);//lcd.at(1,1,"Program Complete"); 
        Program_Engaged=false;
        if (POWERSAVE_PT>1)   disable_PT();  //  low, standard, high, we power down at the end of program
        if (POWERSAVE_AUX>1)  disable_AUX();  // low, standard, high, we power down at the end of program
        delay(prompt_time*2);
        progstep=90;
        first_time=1;
      }
    NunChuckQuerywithEC();
    NunChuckjoybuttons();
    Check_Prog(); //look for button presses
    if (CZ_Button_Read_Count>10 && intval==EXTTRIG_INTVAL ) Interrupt_Fire_Engaged=true; // manual trigger
    //if (PAUSE_ENABLED && CZ_Button_Read_Count>20 && intval>3 && !Shot_Sequence_Engaged ) Pause_Prog(); //pause an SMS program

break; //break 52 - end external triggering loop



case 90: // end of program - offer repeat and reverse options - check the nuncuck
          if (first_time==1){
            lcd.empty();
            lcd.at(1,4,"Repeat - C");
            lcd.at(2,4,"Reverse - Z");
            NunChuckQuerywithEC();
            first_time=0;
            delay(100);
          }
		  
	  //This portion always runs in empty space of loop.
  
	  NunChuckQuerywithEC();
	  NunChuckjoybuttons();
	  Check_Prog(); //look for button presses
 	 //add error handling here to prevent accidental starts
	  //if (CZ_Button_Read_Count>25  && CZ_Released ) button_actions_end_of_program();  //Repeat or Reverses
	  button_actions_end_of_program();
	  //delay(1); //don't just hammer on this - query at regular interval

break;  // break 90

case 250:  // loop for Pano
    
    //Kick off the shot sequence!!!  This happens once per camera shot.   
      if( (intval>2) && (Program_Engaged) && !(Shot_Sequence_Engaged) && ((millis() - interval_tm) > interval) ) { 
        interval_tm_last=interval_tm; //just used for shot timing comparison
        
        interval_tm=millis(); //start the clock on our shot sequence
        if (DEBUG) {Serial.print("trueinterval: ");Serial.print(interval_tm-interval_tm_last);Serial.print(";");}
        Interrupt_Fire_Engaged=false; //clear this flag to avoid re-entering this routine

        Shot_Sequence_Engaged=true;//
        Prefire_Engaged=true;//
        IO_Engaged=true;//
        digitalWrite(FOCUS_PIN, HIGH); //for longer shot interval, wake up the camera
     
        //if (POWERSAVE_PT<4)   enable_PT();  //don't power on for shot for high power saving
        //if (AUX_ON && POWERSAVE_AUX<4)   enable_AUX();  //don't power on for shot for high power saving
        enable_PT();

      }
      
  
             
      //End our prefire - check that we are in program active,shot cycle engaged, and prefire engaged and check against our prefire time
      //If so set prefire flag off, static flag on, fire camera for static time value, update the display 		

      if ((Shot_Sequence_Engaged) && (Prefire_Engaged)  && ((millis()-interval_tm) > prefire_time*100)) { 
 
        Prefire_Engaged=false;
        if (DEBUG) {Serial.print("PreDoneAt ");Serial.print(millis()-interval_tm);Serial.print(";");}
        
        Static_Time_Engaged=true;
       //Fire Camera
          fire_camera((long)static_tm*100); //start shutter sequence
          camera_fired++;
      }

      //End out static time - check that we are in an program active and static time,  Shutter not engaged, check shot cycle time against prefire+statictime
      //If so remove flags from Static Time Engaged and IO engaged, Turn off I/O port, set flags for motors moving, move motors
      //move motors - figure out delays.   Long delays mean really slow - choose the minimum of the calculated or a good feedrate that is slow
	     
      //if (Program_Engaged && Shot_Sequence_Engaged && Static_Time_Engaged && !Shutter_Signal_Engaged && ((millis() - interval_tm) > (prefire_time*100+static_tm*100)) ) {
      if (Shot_Sequence_Engaged && Static_Time_Engaged && !Shutter_Signal_Engaged && ((millis() - interval_tm) > (prefire_time*100+static_tm*100)) ) { //removed requirement for Program Engaged for external interrupt
   
       
        Static_Time_Engaged=false; //Static Time Engaged is OFF
        IO_Engaged=false; //IO Engaged is off
          //digitalWrite(IO_2, LOW); //Use this as the iterrupt
          //digitalWrite(IO_3, LOW);  //Turn off Pin 3
          //Serial.print("IO3_off"); //Serial.println(millis()-interval_tm);
        
       
        //Move the motors - each motor move is calculated by where we are in the sequence - we still call this for lead in and lead out - motors just don't move
 
          Move_Engaged=true; //move motors  
          if (DEBUG_MOTOR) {Serial.print("MoveStart "); Serial.print(millis()-interval_tm);Serial.print(";");}
          if (DEBUG_PANO) Serial.print("progtype "); Serial.println(progtype);
          if (progtype==PANOGIGA)//regular pano
            {       
              if (P2PType==0)
              {
               move_motors_pano_basic();
              }
              else if (P2PType==1)
              {
                move_motors_pano_accel();
              }
            }
            
           else if (progtype==PORTRAITPANO) //PORTRAITPANO method array load
            {       
                if (DEBUG_PANO) Serial.print("entered PORTRAITPANO loop");   
                move_motors_accel_array();
                delay (PanoPostMoveDelay);
            }
            
            
            
            
            
          //
          if (DEBUG_MOTOR) {Serial.print("Moveend "); Serial.print(millis()-interval_tm);Serial.print(";");}
          
        //Turn off the motors if we have selected powersave 3 and 4 are the only ones we want here
          //if (POWERSAVE_PT>2)   disable_PT(); 
          //if (POWERSAVE_AUX>2)   disable_AUX();  //
   
          //
          
          
          if (P2PType==0)
            {
                       Serial.println("finished basic move");
                       if (intval!=3) display_status();  //update after shot complete to avoid issues with pausing
                       Move_Engaged=false;
                       Shot_Sequence_Engaged=false;  //Shot sequence engaged flag is is off - we are ready for our next 
                       Interrupt_Fire_Engaged=false;
                       CZ_Button_Read_Count=0;
                       //InterruptAction_Reset(); //enable the external interrupts to start a new shot
                       if (DEBUG) {
                         Serial.println("EOL");
                       }
            }

      } //end test 

      //just have this repeat like we are in loop
          if (P2PType==1) //acceleration profiles
            {
              
              if (!nextMoveLoaded)  
                  {
                      updateMotorVelocities();  //finished up the interrupt routine 
                      //Print_Motor_Params(2);
                  }
              
               //test for completed move
               if (Shot_Sequence_Engaged && Move_Engaged && motorMoving==0)  //motors completed the move
                  { 
                       Serial.println("finished accel move");
                       if (intval!=3) display_status();  //update after shot complete to avoid issues with pausing
                       Move_Engaged=false;
                       Shot_Sequence_Engaged=false;  //Shot sequence engaged flag is is off - we are ready for our next 
                       Interrupt_Fire_Engaged=false;
                       CZ_Button_Read_Count=0;
                       //InterruptAction_Reset(); //enable the external interrupts to start a new shot
                       if (DEBUG) {
                         Serial.println("EOL");
                         }
                   
                   } 
            }
      
    
      
      if ( camera_moving_shots > 0  && camera_fired >= camera_total_shots) {  //end of program
        lcd.empty();
        draw(58,1,1);//lcd.at(1,1,"Program Complete"); 
        Program_Engaged=false;
        if (POWERSAVE_PT>1)   disable_PT();  //  low, standard, high, we power down at the end of program
        if (POWERSAVE_AUX>1)  disable_AUX();  // low, standard, high, we power down at the end of program
        delay(2000);
        progstep=290;
        first_time=1;
      }
    //updateMotorVelocities();  //uncomment this for DF Loop
    NunChuckQuerywithEC();
    NunChuckjoybuttons();
    //Check_Prog(); //look for button presses
    // if (CZ_Button_Read_Count>10 && intval==EXTTRIG_INTVAL ) Interrupt_Fire_Engaged=true; // manual trigger
    // if (PAUSE_ENABLED && CZ_Button_Read_Count>20 && intval>3 && !Shot_Sequence_Engaged ) Pause_Prog(); //pause an SMS program

    break; //break 250


case 290: //  finished up pano
          if (first_time==1){
            lcd.empty();
            stopISR1();  
            draw(58,1,1);//lcd.at(1,1,"Program Complete");
            draw(59,2,1);//lcd.at(2,1," Repeat Press C");
            NunChuckQuerywithEC();
            first_time=0;
            delay(100);
          }
          NunChuckQuerywithEC();
          NunChuckjoybuttons();
          button_actions290();  //read buttons, look for c button press to start run
break;  // break 90
   

    } //switch
  } // while
} //loop


You have it included twice...

Ok got that one . Still getting this error

\TB3_Black_109_Release1\WiiNunchuck3.cpp:13:10: fatal error: ../Wire/Wire.h: No such file or directory
#include "../Wire/Wire.h"

Compilation error: ../Wire/Wire.h: No such file or directory

WiiNunchuck3.cpp line 13

Do you have this library? Where did you get in from - I was not able to find?

Errors like that are typically from really old code that will no longer build with more recent Arduino IDEs and tools.

The older IDEs did not support automatically locating dependent libraries within library code.
i.e. if a library depended on another library the IDE would not locate the directory where the library lives and add it to the include path. This meant that doing something like
#include <Wire.h>
would not work for library code.
To work around this issue, library code would do something like
#include "../Wire/Wire.h"
This worked since in the old days user libraries were installed next to the bundled libraries like Wire so the relative path for the include would find it.
Those days are LONG over and since bundled libraries are no longer near user libraries an include like that will fail.

I'm guessing that this is the issue.
If so, the code with the issue of using the relative path for the include should be modified to include Wire.h from the include path, i.e.
#include <Wire.h>

That said, if the code is old enough to be using that older type relative path include, it may also have other issues.

--- bill

The changing of the LCD for this project is not a simple task of swapping to a new LCD and swapping libraries.
It will involve making code changes.

It could be quite a challenge if coding skills are limited.

The project code must be ported to use a different LCD API to use the different LCD.
IMO, while this is not monumental task, it is not a trivial task, especially when I see that there may be other things related to stale/old code as well.

It sounds like there may still be some LCD backpacks out there that are s/w compatible with the code you have so that may be an option.

If not,
Have you looked to see if there is updated code for this project and perhaps someone else has already ported this to a LIquidCrystal type API for this project.

If not, and you are going to try to make the updates & changes yourself,
I would first get the existing code compiling and linking before making any changes for a new LCD. Given it looks like some of the code is quite old,
this may involve some changes like getting newer libraries like the nunchuck library or doing some modifications to get the code to get it to build with the more recent IDE and gcc toolset.
(surely there is a newer version of the nunchuck library that works with the newer IDE)

There are two ways to port the code over to a LiquidCrystal API type device.

  • Modify the main sketch for the new LCD API
  • Modify/re-write the NHDLCD9 code to map to the alternate LCD API

Either way can work.
Me personally, I'd modify the main sketch as creates a simpler solution with fewer dependencies.

--- bill

Are you certain you can not get the LCD? The number you mention is shown at Digikey. https://www.digikey.com/en/products/detail/newhaven-display-intl/NHD-0216K3Z-FL-GBW-V3/1701251
Also some parallel port devices are available at Jameco electronics.

1 Like

What is say in post #8. I don't understand why he brick a good working product, that only need a new LCD, to reprogram completely. But it is his choice.

I have multiple NewHavenDisplay running on RS232. Needs only Serial.print and Serial.write.

Ok thanks. I was told that the LCD was no longer available from the manufacturer of the timelapse controller when I tried to purchase one from them.
I am in New Zealand and it is $84 NZ dollars to get one sent here.

Then in setup() add...

	int status = lcd.begin(LCD_COLS, LCD_ROWS);
	if(status) // non zero status means it was unsuccesful
	{
		// hd44780 has a fatalError() routine that blinks an led if possible
		// begin() failed so blink error code using the onboard LED if possible
		hd44780::fatalError(status); // does not return
	}

Now you need to find equivalent functions for these...

lcd.setup()
lcd.contrast()
lcd.cursorOff()
lcd.bright()
lcd.empty()
lcd.at()

lcd.setup... has been replaced with lcd.begin in the code posted above.

You can probably run without the next 3... so just comment those out for now.

lcd.empty() I think can be replaced with lcd.clear().

So that only leaves lcd.at()

I think you can replace by using a combination of:

lcd.setCursor()
lcd.print()

Is this in Setup LCD line 773

Is this the same LCD https://www.digikey.co.nz/en/products/detail/newhaven-display-intl/NHD-0216K3Z-FL-GBW-V3/1701251 as this NHD-0216K3Z-FL-GBW.

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