Подключение LCD 20X4

vvadim
Offline
Зарегистрирован: 23.05.2012

 

 На дисплей lcd 16x2 выводится меню из шести строк для управления мотором. Всё работает. Нужно подключить lcd 20x4. Инициировал. Написал заставку  - выводится на все четыре строчки . Меню выводится только на две строки. В чём проблема ? 

maksim
Offline
Зарегистрирован: 12.02.2012

1. Скорее всего меню писалось для дисплея 16х2, а не 20х4.
2. Проблема в том, что здесь нет экстрасенсов и никто не видит что у вас за код. 
Вставка программного кода в тему/комментарий

vvadim
Offline
Зарегистрирован: 23.05.2012

Вот часть кода, где есть дисплей


#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include "MsTimer2.h"
#include "TimerOne.h"
#include "merlin_mount.h";


#define FIRMWARE_VERSION  900

  // motor PWM
#define MOTOR0_P 5
#define MOTOR1_P 6
#define MOTOR0_DIR 15
#define MOTOR1_DIR 16

 // camera pins
#define CAMERA_PIN 13
#define FOCUS_PIN 12

#define MAX_MOTORS 2

//#define MP_PERIOD 30
#define MP_PERIOD 30


/* User Interface Values */

  // lcd pins
#define LCD_RS  17
#define LCD_EN  18
#define LCD_D4  4
#define LCD_D5  11
#define LCD_D6  9
#define LCD_D7  8

 // which input is our button
#define BUT_PIN 14

  // lcd backlight pin
#define LCD_BKL 7

  // max # of LCD characters (including newline)
#define MAX_LCD_STR 17



 // how many buttons dow we have?
#define NUM_BUTTONS 5

 // button return values

#define BUT0  1
#define BUT1  2
#define BUT2  3
#define BUT3  4
#define BUT4  5

  // which buttons?
#define BUT_UP BUT4
#define BUT_DN BUT3
#define BUT_CT BUT0
#define BUT_LT BUT2
#define BUT_RT BUT1

  // analog button read values
#define BUT0_VAL  70
#define BUT1_VAL  250
#define BUT2_VAL  450
#define BUT3_VAL  655
//#define BUT3_VAL 540
#define BUT4_VAL  830

  // button variance range
#define BUT_THRESH  60


 // how many ms does a button have
 // to be held before triggering another
 // action? (for scrolling, etc.)
 
#define HOLD_BUT_MS 200

 // how much to increment for each cycle the button is held?
 
#define HOLD_BUT_VALINC 10

 // ALT input debouncing time
 
#define ALT_TRIG_THRESH 250


  // menu strings
prog_char menu_1[] PROGMEM = "Manual Move";
prog_char menu_2[] PROGMEM = "Motor Rot-Pan";
prog_char menu_3[] PROGMEM = "Motor Lin";
prog_char menu_4[] PROGMEM = "Camera";
prog_char menu_5[] PROGMEM = "Settings";
prog_char menu_6[] PROGMEM = "Scope";

prog_char manual_menu_1[] PROGMEM = "Motor Rot-Pan";
prog_char manual_menu_2[] PROGMEM = "Motor Lin";
prog_char manual_menu_3[] PROGMEM = "Scope";

prog_char axis_menu_1[] PROGMEM = "Ramp Shots";
prog_char axis_menu_2[] PROGMEM = "RPM";
prog_char axis_menu_3[] PROGMEM = "Fixed SMS";
prog_char axis_menu_4[] PROGMEM = "Angle";
prog_char axis_menu_5[] PROGMEM = "Calibrate";
prog_char axis_menu_6[] PROGMEM = "Slow Mode IPM";
prog_char axis_menu_7[] PROGMEM = "Dist. per Rev";
prog_char axis_menu_8[] PROGMEM = "Min Pulse";
prog_char axis_menu_9[] PROGMEM = "Axis Type";
prog_char axis_menu_10[] PROGMEM = "Lead In";
prog_char axis_menu_11[] PROGMEM = "Lead Out";
prog_char axis_menu_12[] PROGMEM = "Cal. Constant";


prog_char camera_menu_1[] PROGMEM = "Interval sec";
prog_char camera_menu_2[] PROGMEM = "Max Shots";
prog_char camera_menu_3[] PROGMEM = "Exp. Time ms";
prog_char camera_menu_4[] PROGMEM = "Exp. Delay ms";
prog_char camera_menu_5[] PROGMEM = "Focus Tap ms";
prog_char camera_menu_6[] PROGMEM = "Shutter+Focus";
prog_char camera_menu_7[] PROGMEM = "Repeat";
prog_char camera_menu_8[] PROGMEM = "Repeat Delay";

prog_char set_menu_1[] PROGMEM = "Motor Disp";
prog_char set_menu_2[] PROGMEM = "Motor Sl.Mod";
prog_char set_menu_3[] PROGMEM = "Backlight";
prog_char set_menu_4[] PROGMEM = "AutoDim (sec)";
prog_char set_menu_5[] PROGMEM = "Blank LCD";
prog_char set_menu_6[] PROGMEM = "I/O 1";
prog_char set_menu_7[] PROGMEM = "I/O 2";
prog_char set_menu_8[] PROGMEM = "Metric Disp.";
prog_char set_menu_9[] PROGMEM = "Reset Mem";
prog_char set_menu_10[] PROGMEM = "Scope";
prog_char set_menu_11[] PROGMEM = "Cal. Spd Low";
prog_char set_menu_12[] PROGMEM = "Cal. Spd Hi";
prog_char set_menu_13[] PROGMEM = "AltOut Pre ms";
prog_char set_menu_14[] PROGMEM = "AltOut Post ms";

prog_char scope_menu_1[] PROGMEM = "Pan Man. Spd.";
prog_char scope_menu_2[] PROGMEM = "Tilt Man. Spd.";

 // menu organization

PROGMEM const char *menu_str[]  = { menu_1, menu_2, menu_3, menu_4, menu_5, menu_6 };

PROGMEM const char *man_str[]   = { manual_menu_1, manual_menu_2, manual_menu_3 };

PROGMEM const char *axis0_str[] = { axis_menu_1, axis_menu_10, axis_menu_11, axis_menu_2, axis_menu_3, axis_menu_4, axis_menu_5, axis_menu_12, axis_menu_6, axis_menu_7, axis_menu_8, axis_menu_9 };
PROGMEM const char *axis1_str[] = { axis_menu_1, axis_menu_10, axis_menu_11, axis_menu_2, axis_menu_3, axis_menu_4, axis_menu_5, axis_menu_12, axis_menu_6, axis_menu_7, axis_menu_8, axis_menu_9 };
PROGMEM const char *cam_str[]   = { camera_menu_1, camera_menu_2, camera_menu_3, camera_menu_4, camera_menu_5, camera_menu_6, camera_menu_7, camera_menu_8 };
PROGMEM const char *set_str[]   = { set_menu_1, set_menu_2, set_menu_3, set_menu_4, set_menu_5, set_menu_6, set_menu_7, set_menu_8, set_menu_9, set_menu_10, set_menu_11, set_menu_12, set_menu_13, set_menu_14 };
PROGMEM const char *scope_str[] = { scope_menu_1, scope_menu_2 };

 // max number of inputs for each menu (in order listed above, starting w/ 0)

 byte max_menu[7]  = {5,2,10,10,7,13,1};

 // support a history of menus visited up to 5 levels deep
byte hist_menu[5] = {0,0,0,0,0};

char lcd_buf[MAX_LCD_STR];

  // what is our currently selected menu?
  // what is our current position?
byte cur_menu      = 0;
byte cur_pos       = 0;
byte cur_pos_sel   = 0;

  // which input value position are we in?
byte cur_inp_pos   = 0;

  // input buffers
unsigned long cur_inp_long  = 0;
float cur_inp_float         = 0.0;
boolean cur_inp_bool        = false;

  // which input are we on, if on
  // the main screen.
  
byte main_scr_input         = 0;

  // last read button (analog) value
int last_but_rd = 1013;

  // flags for each button
  // use indivial bits to indicate
  // whether a given button was pressed.
  
byte button_pressed = 0;

  // input value multiplier
  
unsigned int inp_val_mult = 1;

  // how long has a button been held for?
unsigned long hold_but_tm = 0;
  // when was ui last updated on home scr?
unsigned long ui_update_tm = 0;

  // lcd dim control
byte cur_bkl     = 255;
boolean blank_lcd   = false;

 // for dimming lcd
unsigned int lcd_dim_tm     = 5;
unsigned long input_last_tm = 0;

 // show cm instead of inch?
boolean ui_is_metric = false;
  // floats are input in tenths?
boolean ui_float_tenths = false;

 /* user interface control flags
 
   B0 = update display
   B1 = currently in setup menu
   B2 = in value entry
   B3 = have drawn initial value in value entry
   B4 = have used decimal in current value
   B5 = in manual mode
   B6 = lcd bkl on
   B7 = in calibrate mode
   
 */
   
byte ui_ctrl_flags = B00000000;

 /* calibration screen flags
 
    B0 = Currently calibrating
    B1 = Done Calibrating
    
 */
 
byte ui_cal_scrn_flags = 0;

 // whether to show ipm (true) or pct (false)
 
boolean ui_motor_display = true;

 /* input type flags
 
   B0 = input value is a float
   B1 = input is a bool (on/off) value
   B2 = input is a bool (up/dn) value
   B3 = input is a bool (lt/rt) value
   B4 = input is a bool (ipm/pct) value
   B5 = input is a bool (pulse/sms) value
   B6 = input is a bool (rotary/linear) value
   B7 = input is list (0,45,90) value
   
 */
 
byte ui_type_flags = 0;

 /* input type flags vector #2
 
   B0 = input value is list (Disable/Start/Stop)
   B1 = input value is forced metric
   
 */
 
byte ui_type_flags2 = 0;



  /* run status flags
  
    B0 = running
    B1 = camera currently engaged
    B2 = camera cycle complete
    B3 = motors currently running
    B4 = external trigger engaged
    
  */
  
volatile byte run_status = 0;

  /* external intervalometer
    
    B0 = I/O 1 is external intervalometer
    B1 = I/O 2 is external intervalometer
    B2 = interval OK to fire
  
  */
  
byte external_interval = 0;

 /* external trigger via alt i/o pins
 
  B0 = I/O 1 external enabled (before)
  B1 = I/O 2 external enabled (before)
  B2 = I/O 1 external enabled (after)
  B3 = I/O 2 external enabled (after)

 */
  
byte external_trigger  = 0;

 // trigger delays
unsigned long ext_trig_pre_delay = 0;
unsigned long ext_trig_pst_delay = 0;

 // motor slow mode is pulse (true) or sms (false)
boolean motor_sl_mod = true;

 // camera exposure time
unsigned long exp_tm      = 100;
 // tap focus before exposing
unsigned int focus_tap_tm = 0;
 // delay after exposing (mS)
unsigned int post_delay_tm      = 100;
 // brign focus pin high w/ shutter
boolean focus_shutter   = true;
 // intervalometer time (seconds)
float cam_interval = 1.0;
 // max shots
unsigned int cam_max  = 0;
  // camera repeat shots
byte cam_repeat = 0;
  // delay between camera repeat cycles
unsigned int cam_rpt_dly = 250;

byte pre_focus_clear      = 0;
unsigned long cam_last_tm = 0;

  // currently selected motor
byte cur_motor = 0;
  // set speed for the current motor
unsigned int m_speeds[2] = {0,0};
  // currently set speed (for altering motor speed)
unsigned int mcur_spds[2] = {0,0};
  // prev direction for motor
byte m_wasdir[2] = {0,0};
  // distance (i) per revolution
float m_diarev[2] = {3.53, 3.53};
  // motor RPMs
float m_rpm[2]    = { 8.75, 8.75 };
  // calculated max ipm
float max_ipm[2] = {m_diarev[0] * m_rpm[0], m_diarev[1] * m_rpm[1]};
  // user-configurable min ipm
float min_ipm[2] = {20.0, 20.0};
  // minimumspeed (min ipm->255 scale value)
byte min_spd[2] = { (min_ipm[0] / max_ipm[0]) * 255, (min_ipm[1] / max_ipm[1]) * 255 };
 // minimum pulse cycles per motor
byte m_min_pulse[2] = { 125, 125 };
 // calibration points
byte motor_spd_cal[2] = {1,40};

  // linear or rotation type?
byte m_type[2] = {0,0};
  // fixed sms?
byte m_smsfx[2] = {1,1};
  // maximum sms distance
unsigned int m_maxsms[2] = { max_ipm[0] * 100, max_ipm[1] * 100};


 // for timer1 pulsing mode control
boolean timer_used = false;
volatile  bool timer_engaged      = false;
volatile bool motor_engaged      = false;
volatile byte motor_ran = 0;

 // motor calibration

float m_cal_constant[2] = {0.69, 0.69};

float m_cal_array[2][3][3][2] = { 
              { 
                {
                  {0.61914329,0.61914329},{1.0,1.0},{2.01133251,2.11453032}
                },
                {
                  {0.61914329,0.61914329},{1.0,1.0},{2.01133251,2.11453032}
                },
                {
                  {0.61914329,0.61914329},{1.0,1.0},{2.01133251,2.11453032}
                } 
              }, 
              { 
                {
                  {0.61914329,0.61914329},{1.0,1.0},{2.01133251,2.11453032}
                },
                {
                  {0.61914329,0.61914329},{1.0,1.0},{2.01133251,2.11453032}
                },
                {
                  {0.61914329,0.61914329},{1.0,1.0},{2.01133251,2.11453032}
                } 
              } 
            };
            
byte m_cur_cal = 0;
byte m_angle[2] = {0,0};

boolean m_cal_done = false;

 // ramping data
byte m_ramp_set[2]     = {0,0};
float m_ramp_shift[2]  = {0.0,0.0};
byte m_ramp_mod[2]     = {0,0};

 // lead-ins for axis movement
unsigned int m_lead_in[2] = {0,0};
unsigned int m_lead_out[2] = {0,0};

 // for controlling pulsing and sms movement
unsigned long on_pct[2]                = {0,0};
unsigned long off_pct[2]               = {0,0};
unsigned int m_sms_tm[2]              = {0,0};

 // shots fired
unsigned long shots = 0;

 // function types for alt inputs...
 
 /* 
   0 = disabled
   1 = start
   2 = stop
 */
 
byte input_type[2]            = {0,0};
unsigned long input_trig_last = 0;


boolean merlin_enabled = false;

byte  merlin_dir[2]        = {0,0};
byte  merlin_wasdir[2]     = {0,0};
float merlin_speeds[2]     = {0.0,0.0};
float merlin_man_spd[2]    = {1440.0,1440.0};

 /*
   
   0 = axis 0 currently running free (continuous)
   1 = axis 1 currently running free
   2 = in merlin manual control
   3 = displaying merlin config screen
   
*/

byte merlin_flags = 0;


 // initialize LCD object
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);




void setup() { 

 pinMode(CAMERA_PIN, OUTPUT);
 pinMode(FOCUS_PIN, OUTPUT);
 pinMode(MOTOR0_P, OUTPUT);
 pinMode(MOTOR1_P, OUTPUT);
 pinMode(MOTOR1_DIR, OUTPUT);
 pinMode(MOTOR0_DIR, OUTPUT);

 Serial.begin(9600); 

 init_user_interface();
 delay(1000);

    // check firmware version stored in eeprom
    // will cause eeprom_saved() to return false
    // if version stored in eeprom does not match
    // firmware version.  This automatically clears
    // saved memory after a new firmware load -
    // saving lots of support questions =)
    
 eeprom_versioning();
 
   // did we previously save settings to eeprom?
 if( eeprom_saved() ) {
     // restore saved memory
   restore_eeprom_memory();
 }
 else {
     // when memory has been cleared, or nothing has been
     // saved, make sure eeprom contains default values
   write_all_eeprom_memory();
 }

 show_home();
 
 /*
 for( byte i = 0; i <= 2; i++) {
   Serial.print(i, DEC);
   Serial.print(":");
   for ( byte x = 0; x < 2; x++ ) {
     Serial.print(m_cal_array[0][0][i][x], 8);
     Serial.print(":");
   }
   Serial.println("");
 } 
 */
 
}



void loop() {

  if( run_status & B10000000 ) {
    // program is running
    main_loop_handler();
  } // end if running
  else {
      // not running, not in manual, but merlin motors are running?
    if( ! ( ui_ctrl_flags & B00000100 ) && merlin_flags & B11000000 ) {
      merlin_stop(0);
      merlin_stop(1);
    }
  }
  
    // always check the UI for input or
    // updates
    
  check_user_interface();    
 
}




void main_loop_handler() {
  
  
  static boolean camera_fired   = false;
  static boolean motors_clear   = false;
  static boolean ok_stop        = false;
  static boolean in_sms_cycle   = false;
  static boolean do_fire        = false;
  static boolean ext_trip       = false;
  static byte    cam_repeated   = 0;
  
  if( cam_max > 0 && shots >= cam_max && ( ok_stop || (m_speeds[0] <= 0.0 && m_speeds[1] <= 0.0) || motor_sl_mod ) ) {
    
     // stop program if max shots exceeded, and complete cycle completed
     // if in interleave, ignore ocmplete cycle if in pulse
   ok_stop = false;
   stop_executing();
      // interrupt further processing      
  }
  else if( pre_focus_clear == 2 ) {  
        // allow 100ms for focus line to settle before allowing any further
      MsTimer2::set(100, clear_cam_focus);
      MsTimer2::start();
      pre_focus_clear = 3;
  }
  else  if( motor_sl_mod &&
            (( m_speeds[0] > 0 && m_speeds[0] < min_spd[0] ) ||
             ( m_speeds[1] > 0 && m_speeds[1] < min_spd[1] ) ) ) {
        
      // if pulse mode is on and at least
      // one motor needs to be pulsed...
    
    motor_run_pulsing();
        
  }
  
    // run merlin in continuous mode if needed
    
  if( motor_sl_mod && merlin_enabled ) {
    merlin_run_cont();
    ok_stop = true; // allow max shots stop when
                    // in continuous mode
  }
  
   
    // we need to deterime if we can shoot the camera
    // by seeing if it is currently being fired, or 
    // is blocked in some way.  After making sure we're
    // not blocked, we check to see if its time to fire the
    // camera

  if( motor_engaged ) {      
    // motor currently moving
    // do not fire camera until motors are
    // done - we get caught up in here until the
    // motors have stopped moving
    
    if( motor_ran == 1 ) {
      // check to see if motor #2 needs to be run...
      if( in_sms_cycle == false && m_sms_tm[0] > 0 && m_sms_tm[1] > 0 ) {
        in_sms_cycle = true;
          // motor #2 remains to be run
        MsTimer2::set(m_sms_tm[1], stop_motor_sms);
        run_motor_sms(1);
        MsTimer2::start();
      } 
       else if(in_sms_cycle == false) {         
           // no motors remain
         motor_engaged = false;
         ok_stop       = true;
       }
    }
    else if ( motor_ran > 0 ) {
        // all of our motors have run one
        // cycle, let the camera fire
       motor_engaged = false;
       ok_stop       = true;
       in_sms_cycle  = false;
    }
      
  } // end if motor_engaged
  else if( run_status & B01001000 || pre_focus_clear == 3 ) {
      // currently firing the camera, focus, or triggering an external
      // control line
      
      // do nothing
    ;
  }
  else if( run_status & B00100000 ) {
      // camera cycle completed
        // clear exposure cycle complete flag
    run_status &= B11011111;
    if( camera_fired == true ) {
      // the shot just fired
      camera_fired = false;
      shots++;
      
      
        // for ramping motor speeds
        // we change speed in ramps after shots...

      motor_execute_ramp_changes();
        // check to see if a post-exposure delay is needed
      
      if( post_delay_tm > 0 ) {
          // we block anything from happening while in the
          // post-exposure cycle by pretending to be an
          // exposure
        run_status |= B01000000;
        
        MsTimer2::set(post_delay_tm, camera_clear);
        MsTimer2::start();
        
        motors_clear = false;
        ok_stop = false;
      }
      else {
          // no post-exp delay, is the external trigger to fire?
        if( external_trigger & B00110000 && ext_trig_pst_delay > 0 )
          alt_ext_trigger_engage(false);
       

        //no post-exposure delay, motors can run
        motors_clear = true;
      }
        
    } 
    else {
        // this was a post-exposure delay cycle completing, not
        // an actual shot
        
        // is the external trigger to fire?
      if( external_trigger & B00110000 && ext_trig_pst_delay > 0 )
        alt_ext_trigger_engage(false);
      

        // we can set the motors clear to move now
      motors_clear = true;        
    }
    
        // is the merlin head set to move?    
    if( motors_clear == true && merlin_enabled  && ! motor_sl_mod ) {
        // send merlin head to move sms distances (if desired)             
  
      if( merlin_speeds[0] > 0 ) {        
        merlin_send_angle(0, merlin_speeds[0]);
        ok_stop = false;
      }
      if( merlin_speeds[1] > 0 ) {
        merlin_send_angle(1, merlin_speeds[1]);
        ok_stop = false;
      }
      
    }

  }
  else if( motors_clear == true && ! motor_sl_mod && 
            ( merlin_enabled && ( merlin_flags & B11000000 ) ) ) {
    
        // merlin motors are currently running!
        // other actions cannot continue...
        
    if( ! merlin.readAxisStatus(1) && ! merlin.readAxisStatus(2) ) {
        // but not actually running... now remove the flags
        // indicating so.
      merlin_flags &= B00111111;
      ok_stop = true;
    }  
    
  } 
  else if( motors_clear == true && ! motor_sl_mod &&
              ( m_sms_tm[0] > 0 || m_sms_tm[1] > 0 ) ) {
      
       // if we're set to go to s-m-s and at least one motor is set to move
      // start DC motor(s) moving
  
      motor_ran = 0;
  
        // set motors to move, and then
        // set timer to turn them off  
        
      if( m_sms_tm[0] > 0 ) {
            // start first motor
        run_motor_sms(0); 
        MsTimer2::set(m_sms_tm[0], stop_motor_sms);
      }
      else if( m_sms_tm[1] > 0 ) {
          // start second motor (see state
          // handling above, where motor_engaged is set)
        run_motor_sms(1); 
        MsTimer2::set(m_sms_tm[1], stop_motor_sms);
      }
  
        // engage timer
      MsTimer2::start();
      
      motor_engaged = true;
      motors_clear = false;
      ok_stop      = false;
    
  }   
  else if( external_interval & B11000000 ) {
    // external intervalometer is engaged
    
    if( external_interval & B00100000 ) {
      // external intervalometer has triggered
 
          // clear out ok to fire flag
      external_interval &= B11011111;      
      do_fire = true;
    }
  }
  else if( cam_last_tm < millis() - (cam_interval * 1000) ) {
      // internal intervalometer triggers
    do_fire = true;
  }
  
  if( do_fire == true ) {
      // we've had a fire camera event
    
           // is the external trigger to fire? (either as 'before' or 'through')
    if( external_trigger & B11000000 && ext_trig_pre_delay > 0 && ext_trip == false && (cam_repeat == 0 || cam_repeated == 0) ) {
        alt_ext_trigger_engage(true);
        ext_trip = true;
    }
    else {

        // make sure we handle pre-focus tap timing
        
      if( ( pre_focus_clear == 4 || focus_tap_tm == 0 || (cam_repeat > 0 && cam_repeated > 0) ) && !(run_status & B00001000) ) {
  
          // we always set the start mark at the time of the
          // first exposure in a repeat cycle (or the time of exp
          // if no repeat cycle is in play
          
        if( cam_repeat == 0 || cam_repeated == 0 )
          cam_last_tm  = millis();
  
          // deal with camera repeat actions
        if( cam_repeat == 0 || (cam_repeat > 0  && cam_repeated >= cam_repeat) ) {
          camera_fired = true;
          do_fire = false;
          ext_trip = false;
          cam_repeated = 0;
        }
        else if( cam_repeat > 0 ) {
            // only delay ater the first shot
          if( cam_repeated > 0 )
            delay(cam_rpt_dly); // blocking delay between camera firings (we should fix this later!)
            
          cam_repeated++;
        }
        
        // camera is all clear to fire, and enough
        // time is elapsed
        fire_camera(exp_tm);
        pre_focus_clear = 0;
        
      }
      else if( focus_tap_tm > 0 && pre_focus_clear == 0 && !(run_status & B00001000) ) {
          // pre-focus tap is set, bring focus line high
        digitalWrite(FOCUS_PIN, HIGH);
        MsTimer2::set(focus_tap_tm, stop_cam_focus);
        MsTimer2::start();
        pre_focus_clear = 1;
      }
    } // end else (not external trigger...
  } // end if(do_fire...
}


void start_executing() {
  // starts program execution
  
   run_status |= B10010000;
  
    // turn on motors
  motor_control(0,true);
  motor_control(1,true);
  
    // if ramping is enabled for a motor, start at a zero
    // speed
  if( m_ramp_set[0] >= 1 )
      motor_set_speed(0, 0); 
  if( m_ramp_set[1] >= 1 )
      motor_set_speed(1, 0); 

    // reset shot counter
  shots = 0;
}

void stop_executing() {
  run_status &= B01100111;
  motor_stop_all();
}

  

 

vvadim
Offline
Зарегистрирован: 23.05.2012

 Ещё




void init_user_interface() {

  pinMode(LCD_BKL, OUTPUT);
  
    // turn on lcd backlight
  analogWrite(LCD_BKL, 255);

    // init lcd to 16x2 display
  lcd.begin(16, 2);
  lcd.setCursor(0,0);

    // clear and turn on autoscroll
 lcd.clear();
 //lcd.autoscroll();
 
   // banner
 lcd.setCursor(0,0);             //vstavil ja  
 lcd.print("      2012");
 
 lcd.setCursor(0,1);              // 5,1
 lcd.print("      VVR");

 delay(1500);

 lcd.clear(); 

 lcd.setCursor(0,0); 
 lcd.print("  Dolly - Pan");
 lcd.setCursor(0,1);                // 4,1
 lcd.print("Timelapse Engine");
 
   // setup button input

 pinMode(BUT_PIN, INPUT);   
   // enable internal pull-up
 digitalWrite(BUT_PIN, HIGH);
 
 
   // set the update screen flag (draw main
   // screen)
 ui_ctrl_flags |= B10000000;
 
 delay(3000);
 
}


void check_user_interface() {
  

    // turn off/on lcd backlight if needed
  if( ui_ctrl_flags & B00000010 && input_last_tm < millis() - (lcd_dim_tm * 1000) ) {
    
    ui_ctrl_flags &= B11111101;
    
    if( blank_lcd ) 
      lcd.noDisplay();
      
    digitalWrite(LCD_BKL, LOW);
  }
  else if( ! (ui_ctrl_flags & B00000010) && input_last_tm > millis() - (lcd_dim_tm * 1000) ) {
    ui_ctrl_flags |= B00000010;
    
    lcd.display();
    
    analogWrite(LCD_BKL, cur_bkl);
  }
  
    // if we're set to update the display
    // (on-demand or once a second when not
    // in a menu)
  if( ui_ctrl_flags & B10000000 ||
      ( (ui_update_tm < millis() - 1000) && ! (ui_ctrl_flags & B01000000) ) ) {
  
      // determine whether to show home or manual screen      
    if( ! ( ui_ctrl_flags & B00000100 ) ) {
      show_home();
    }
    
//#ifdef MERLIN_ENABLED
    else if( merlin_flags & B00100000 ) {
      show_merlin();
    }
//#endif

    else {
      show_manual();
    }
     
    ui_ctrl_flags &= B01111111;
    ui_update_tm = millis();
  }
  
  byte held = ui_button_check();
  
      // make sure to turn off motor if in manual
      // control and no button is held
  if( ui_ctrl_flags & B00000100 && held == false && run_status & B00010000 )
    motor_control(cur_motor, false);
 

}


byte ui_button_check() {

 static byte hold_but_cnt = 0;
  
 get_button_pressed();

 boolean held = false;
 
 for( byte i = BUT0; i <= BUT4; i++) {
   byte bt_press = is_button_press( i );
   
   if( bt_press == 0 )
     continue;
   
   if(  bt_press == 1 && millis() - input_last_tm > HOLD_BUT_MS ) {
       // button is pressed        

     hold_but_cnt  = 0;
     inp_val_mult  = 1;
     input_last_tm = millis();
     handle_input(i, false);

   }
   else if( bt_press == 2 ) {
     held = true;
     // button being held
     if( hold_but_tm <= millis() - HOLD_BUT_MS) {
       hold_but_tm   = millis();
       input_last_tm = millis();
               
       handle_input(i, true);
       
       hold_but_cnt++;
       
       if( hold_but_cnt >= 8 ) {
         inp_val_mult = inp_val_mult >= 1000 ? 1000 : inp_val_mult * HOLD_BUT_VALINC;
         hold_but_cnt = 0;
       }

     }

   } // end else if button press state == 2

 } // end for loop
 
 return(held);
 
}


void get_button_pressed() {
  // see which buttons are pressed
  // buttons are on one analog pin, the value
  // determines which button, if any is pressed

    // read analog input
  int val_read = analogRead(BUT_PIN - 14);

    // don't let it flip in a single read
  if( abs(last_but_rd - val_read) > BUT_THRESH ) {
    last_but_rd = val_read; 
    button_pressed = 0;
    return;
  }
  
  if( val_read > (BUT0_VAL - BUT_THRESH) && val_read < (BUT0_VAL + BUT_THRESH) ) {
    button_pressed = BUT0;
  }
  else if( val_read > (BUT1_VAL - BUT_THRESH) && val_read < (BUT1_VAL + BUT_THRESH) ) {
    button_pressed = BUT1;
  }
  else if( val_read > (BUT2_VAL - BUT_THRESH) && val_read < (BUT2_VAL + BUT_THRESH) ) {
    button_pressed = BUT2;
  }
  else if( val_read > (BUT3_VAL - BUT_THRESH) && val_read < (BUT3_VAL + BUT_THRESH) ) {
    button_pressed = BUT3;
  }
  else if( val_read > (BUT4_VAL - BUT_THRESH) && val_read < (BUT4_VAL + BUT_THRESH) ) {
    button_pressed = BUT4;
  }
  else {
    button_pressed = 0;
  }
  
  
}


byte is_button_press(byte button) {
  
    // determine if the given button was
    // pressed, held, or is neither

  static byte button_was = 0;
  
    // if the button is set as 'active'
  if( button_pressed == button ) {
      // if we have already registered a press without
      // registering a non-press
    if( button_was ) {
        // increase 'skip hold count'
      return(2);
    }
      // button was not previous pressed...
    button_was = button;
    hold_but_tm = millis();
    return(1);
  }
 
    // if button set as inactive
    
    // if button was previously set as active,
    // register previous state as inactive
  if( button_was == button ) {
    button_was = 0;
        // set button as not currently pressed
    button_pressed = 0;
  }
    
  return(0);
}
  
  
byte get_menu( byte mnu, byte pos ) {

  // where is our target menu when 
  // mnu.pos is pressed?


  switch(mnu) {
    case 0:
      switch(pos) {
        case 0:
          return(1);
        case 1:
          return(2);
        case 2:
          return(3);
        case 3:
          return(4);
        case 4:
          return(5);
        case 5:
          return(6);
      }
      break;
    
    case 1:
        // manual control is special return code
      return(254);
      
    default:
      break;        
  }
      
 

  // default is 'no target', an input value
 return(255);
 
}

/*
   handle user input
*/

void handle_input( byte button, boolean held ) {
  
  // do what needs to be done when whatever
  // button is hit
  
  if( button == BUT_CT ) {
      // call center button function
    ui_button_center(held);    
  }
  
  else if( button == BUT_DN ) {
    ui_button_down(held);
  }
  
  else if( button == BUT_UP ) {
    ui_button_up(held);
  }
  
  else if( button == BUT_RT ) {
    ui_button_rt(held);
  }  
  else if( button == BUT_LT ) {
    ui_button_lt(held);
  }


  return;
    

}


  // button handlers
  
  
void ui_button_center( boolean held ) {
      // center button

        // on calibration screen

     if( ui_ctrl_flags & B00000001 ) {
       
       if( ui_cal_scrn_flags & B01000000 ) {
         // completed calibrating
         ui_cal_scrn_flags &= B00111111;
         show_calibrate();
         return;
       }  
       else if( ui_cal_scrn_flags & B10000000 ) {
         // in calibrating input
         
         if( held == true )
           return;
           
         m_cal_done = true;
         return;
       }
       
       execute_calibrate();
       return;
     }


     if( main_scr_input > 0 ) {
         // make sure to abort main screen input
       lcd.noBlink();
       main_scr_input = 0;
     }
     
     
       // if in manual control
     if( ui_ctrl_flags & B00000100  ) {
         // clear out manual ctrl flag
       ui_ctrl_flags &= B11111011;
       
       merlin_flags &= B11011111;

         // resume back to setup menu
       ui_ctrl_flags |= B01000000;
       cur_menu = 1; // show manual menu again
       draw_menu(0, false);
       return;
     }


    if( ! (ui_ctrl_flags & B01000000) ) {
        // not in any setup menu
      ui_ctrl_flags |= B01000000;
      cur_menu = 0;
      draw_menu(0,false);
    }
    else {
       
      
        // in a setup menu, find
        // the next menu to go to
        
          // calibration, don't do anything else
      if( (cur_menu == 2 || cur_menu == 3) && cur_pos == 6 ) {
        get_value(cur_menu, cur_pos, false);
        return;
      }


      byte new_menu = get_menu(cur_menu, cur_pos);

        // if drawing motor manual screen...
        
      if( new_menu == 254 ) {
        get_value(cur_menu, cur_pos, false);
        return;
      }
      
      
      if( new_menu == 255 && ! (ui_ctrl_flags & B00100000) )  {
            // this is not a menu, but an input of some
            // sort
                  
          draw_menu(3,true);
          return;
      }
      else if( ui_ctrl_flags & B00100000 ) {
          // exiting out of value entry (save...)
          // go to previous menu

          // clear the cursor position
        cur_inp_pos = 0;
          
          // read value back from input
        get_value(cur_menu, cur_pos, true);
        
          // reset the float tenths (vs 100ths) parameter
        ui_float_tenths = false;
        
          // clear in value setting flag
          // and the flag indicating that
          // we've already displayed this value
        ui_ctrl_flags &= B11001111;
        draw_menu(0,false);
      }
      else {

          // entering another menu
          
          // record the last menu we were at
        push_menu(cur_menu);

          // clear in value setting flag
        ui_ctrl_flags &= B11011111;

          // set menu to new menu
        cur_menu = new_menu;
        draw_menu(0,false);
      }


    }
}


void ui_button_down( boolean held ) {

        // on calibration screen

     if( ui_ctrl_flags & B00000001 ) {
         
       if( ui_cal_scrn_flags & B10000000 ) {
         // in calibrating settings
         move_val(false);
         update_cal_screen();
         return;
       }
         
       m_cur_cal = m_cur_cal > 0 ? m_cur_cal - 1 : 0;
       show_calibrate();
       
       return;
     }
  

      // if in manual motor mode...
    if( ui_ctrl_flags & B00000100 ) {

      if( merlin_flags & B00100000 ) {

        if( held == true ) 
           return;
        
        if( merlin_flags & B01000000 ) {
            merlin_stop(1);
              // speed was modified by running, return to
              // original value
            merlin_set_speed(1, merlin_speeds[1]);
          }
          else {
            merlin.setSpeed(2, merlin_man_spd[1]);
            merlin_set_dir(1,1);            
            merlin_run(1);
          }

        show_merlin();
      }
      else {
        motor_speed_adjust(cur_motor, -1 * inp_val_mult, true);
        show_manual();
      }


      return;
    }
    
      // if not currently in setup menus, or
      // modifying a main screen value
    if( ! (ui_ctrl_flags & B01000000) & main_scr_input == 0 )
      return;

   if( main_scr_input > 0 ) {
     move_val(false);
       // save present value
     get_mainscr_set(main_scr_input, true);
       // set screen to update
     ui_ctrl_flags |= B10000000;
   }
   else if( ui_ctrl_flags & B00100000 ) {
        // entering a value
      move_val(false);
      draw_menu(3,true);
    }
    else {
        // moving to next menu item
      draw_menu(2,false);
    }
    
}

void ui_button_up( boolean held ) {

        // on calibration screen
     if( ui_ctrl_flags & B00000001 ) {
         
       if( ui_cal_scrn_flags & B10000000 ) {
         // in calibrating settings
         move_val(true);
         update_cal_screen();
         return;
       }

       m_cur_cal = m_cur_cal > 1 ? 2 : m_cur_cal + 1;
       show_calibrate();
       
       return;
     }
  
      // if in manual motor mode...
    if( ui_ctrl_flags & B00000100 ) {

      if( merlin_flags & B00100000 ) {

          if( held == true ) 
           return;

        
          if( merlin_flags & B01000000 ) {
            merlin_stop(1);
              // speed was modified by running, return to
              // original value
            merlin_set_speed(1, merlin_speeds[1]);
          }
          else {
            merlin.setSpeed(2, merlin_man_spd[1]);
            merlin_set_dir(1,0);            
            merlin_run(1);
          }

        show_merlin();
      }
      else {
        motor_speed_adjust(cur_motor,1 + inp_val_mult, true);
        show_manual();
      }
      return;
    }
    
    if( ! (ui_ctrl_flags & B01000000) & main_scr_input == 0 ) {
      
        // alternate between merlin and home screens
        
      if( merlin_enabled ) {
          // switch between merlin and normal home screens
        if( merlin_flags & B00010000 ) {
          merlin_flags &= B11101111;
        }
        else {          
          merlin_flags |= B00010000;
        }

      return;
      
      }
    }
      
   if( main_scr_input > 0 ) {
    
     move_val(true);
       // save present value
     get_mainscr_set(main_scr_input, true);
     
       // set screen to update
     ui_ctrl_flags |= B10000000;
   }
   else if( ui_ctrl_flags & B00100000 ) {
        // entering a value
      move_val(true);
      draw_menu(3,true);
    }
    else {
      draw_menu(1,false);
    }

}

void ui_button_rt( boolean held ) {
  
     // clear out calibration screen value, if
     // set
    if( ui_ctrl_flags & B00000001 )
      ui_ctrl_flags &= B11111110;

      // if in manual control
    if( ui_ctrl_flags & B00000100 ) {

      if( merlin_flags & B00100000 ) {

         if( held == true ) 
           return;
           
         if( merlin_flags & B10000000 ) {
           merlin_stop(0);
              // speed was modified by running, return to
              // original value
            merlin_set_speed(0, merlin_speeds[0]);
          }
         else {
            merlin.setSpeed(1, merlin_man_spd[0]);
            merlin_set_dir(0,0);            
            merlin_run(0);
         }
          
        //show_merlin();
      }
      else {
           // in manual
        if( held == true ) {
           // change motor direction
          motor_dir(cur_motor, 0);
          if( ! (run_status & B00010000) )
            motor_control(cur_motor, true);
          }
  
        show_manual();
      }
      
      return;
    }  


    if( ! (ui_ctrl_flags & B01000000) ) {
      // we're on main screen, rt switches value we can
      // adjust
      main_screen_select(true);
      return;
    }
    
    if( ui_ctrl_flags & B00100000 ) {
        // we're in a value entry mode.  Exit
        // entry without saving the value

        // clear in value setting flag
        // and the flag indicating that
        // we've already displayed this value
      ui_ctrl_flags &= B11001111;        
              // reset the float tenths (vs 100ths) parameter
      ui_float_tenths = false;

      draw_menu(0,false);
      return;
    }
    
      // draw previous menu
      
    if( cur_menu == 0 ) { 
        // we're at the highest menu, back to main screen 
      cur_pos = 0;  
        // clear setup flag
        // indicate display needs updating
      ui_ctrl_flags &= B10111111;
      ui_ctrl_flags |= B10000000;
        // clear out list of menus
      flush_menu();
    }
    else {
        // a parent menu can be drawn
      cur_menu = pop_menu();
      draw_menu(0,false);
    }
  

}


void ui_button_lt(boolean held) {
        // if in manual control
    if( ui_ctrl_flags & B00000100 ) {

      
      if( merlin_flags & B00100000 ) {

          if( held == true ) 
           return;

          if( merlin_flags & B10000000 ) {
            merlin_stop(0);
              // speed was modified by running, return to
              // original value
            merlin_set_speed(0, merlin_speeds[0]);
          }
          else {
            merlin.setSpeed(1, merlin_man_spd[0]);
            merlin_set_dir(0,1);            
            merlin_run(0);
          }

      }
      else {
        if( held == true ) {        
           // change motor direction
          motor_dir(cur_motor, 1);
            // get motor moving (if not already)
          if( ! (run_status & B00010000) )
            motor_control(cur_motor, true);
        }

      show_manual();
      }

      return;
    }  

    if( ! (ui_ctrl_flags & B01000000) ) {
      // we're on main screen, lt switches value we can
      // adjust
      main_screen_select(false);
      return;
    }

    // left button
    if( ! (ui_ctrl_flags & B01000000) || ui_ctrl_flags & B00100000 )
      return;
}



/* 
  Draw screens
*/


void draw_menu(byte dir, boolean value_only) {

  
    // turn off blinking, if on...
  lcd.noBlink();
  
  boolean draw_all = false;

  // determine the direction we are going, up/down (1/2),
  // draw all (but don't move position) (3), and draw
  // new menu from top (0)
  
  if( dir == 2 ) {
      // down
    cur_pos++;
    if( cur_pos > cur_pos_sel ) {
      lcd.clear();
      draw_all = true;
    }
  }    
  else if( dir == 1 ) {
      // up
    cur_pos = cur_pos == 0 ? 0 : cur_pos - 1;
    
    if( cur_pos < cur_pos_sel ) {
      lcd.clear();
      draw_all = true;
    }
  }
  else if( dir == 3 ) {
      // draw all (no move)
    draw_all = true;
  }
  else {
      // draw new menu (from top)
    cur_pos = 0;
    draw_all = true;
  }
  
    // don't overrun the memory locations for this menu
    
  cur_pos = cur_pos > max_menu[cur_menu] ? max_menu[cur_menu] : cur_pos;
  
   switch( cur_menu ) {
    
    case 0:
    
      draw_values(menu_str, draw_all, value_only);
      break;
      
    case 1:
    
      draw_values(man_str, draw_all, value_only);
      break;
      
    case 2:
    
      draw_values(axis0_str, draw_all, value_only);
      break;
      
    case 3:
    
      draw_values(axis1_str, draw_all, value_only);
      break;

    case 4:

      draw_values(cam_str, draw_all, value_only);
      break;
  
    case 5:
    
      draw_values(set_str, draw_all, value_only);
      break;

    case 6:
    
      draw_values(scope_str, draw_all, value_only);
      break;
      
    default: 
      return;  
  }
  

}

   
void draw_values(const char *these[], boolean draw_all, boolean value_only) {
  
  if( draw_all == true ) {

    // must draw the whole display
    lcd.clear();
      // clear out lcd buffer
      
    memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);
    
      // draw first option
    lcd.noCursor();
    lcd.setCursor(0,0);
    cur_pos_sel = cur_pos;
    
    strcpy_P(lcd_buf, (char*) pgm_read_word(&(these[cur_pos])));
    lcd.print("> ");
    lcd.print(lcd_buf);
    lcd.setCursor(0,1);
    
      // if we're not displaying only a value, and there's
      // another menu entry to display -- display it on the 
      // second line..
      
    if( ! value_only ) {
      if( cur_pos + 1 <= max_menu[cur_menu] ) {
        cur_pos_sel = cur_pos + 1;
        memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);
        strcpy_P(lcd_buf, (char*)pgm_read_word(&(these[cur_pos + 1])));
        lcd.print("  ");
        lcd.print(lcd_buf);
      }
        // clear out in value entry setting, if set
      ui_ctrl_flags &= B11011111;
      
    }
    else {
      
        // display the value of the current entry
      ui_ctrl_flags |= B00100000;
      
 
      if(! ( ui_ctrl_flags & B00010000 ) ) {
         // have just drawn this value

           // place value from variable into
           // temporary buffer
        get_value(cur_menu, cur_pos, false);
         
        ui_ctrl_flags |= B00010000;
      }
      
   

        // display the correct current
        // temporary input value
        
      if( ui_type_flags2 & B10000000 ) {
            // for alt i/o inputs
            
        if( cur_inp_long == 0 ) {
          lcd.print("Disabled");
        }
        else if( cur_inp_long == 1 ) {
          lcd.print("Start");
        }
        else if( cur_inp_long == 2 ) {
          lcd.print("Stop");
        }
        else if( cur_inp_long == 3 ) {
          lcd.print("Toggle");
        }
        else if( cur_inp_long == 4 ) {
          lcd.print("Ext. Interval.");
        }
        else if( cur_inp_long == 5 ) {
          lcd.print("Out Before");
        }
        else if( cur_inp_long == 6 ){
          lcd.print("Out After");
        }
        else {
          lcd.print("Out Both");
        }
        return;
      }
      else if( ui_type_flags2 & B01000000 ) {
          // cal speed inputs in gobal set menu
        display_spd_ipm(cur_inp_long, 0);
        return;
      }
      
      switch(ui_type_flags) {
        case B10000000:
          lcd.print(cur_inp_float, (byte) 2);
          break;
        case B01000000:
          if (cur_inp_bool == true) {
           lcd.print("On");
          } 
          else {
             lcd.print("Off");
          }
          break;
        case B00100000:
          if (cur_inp_bool == true) {
           lcd.print("Up");
          } 
          else {
             lcd.print("Dn");
          }
          break;
        case B00010000:
          if (cur_inp_bool == true) {
           lcd.print("Rt");
          } 
          else {
             lcd.print("Lt");
          }
          break;
        case B00001000:
          if (cur_inp_bool == true) {
           lcd.print("IPM");
          } 
          else {
             lcd.print("PCT");
          }
          break;
        case B00000100:
          if (cur_inp_bool == true) {
           lcd.print("Pulse");
          } 
          else {
             lcd.print("Interleave");
          }
          break;
        case B00000010:
          if (cur_inp_bool == true) {
           lcd.print("Rotary");
          } 
          else {
             lcd.print("Linear");
          }
          break;
        case B00000001:
          if( cur_inp_long == 0 ) {
            lcd.print(0,DEC);
          }
          else if( cur_inp_long == 1 ) {
            lcd.print(45,DEC);
          }
          else {
            lcd.print(90,DEC);
          }
          break;
        default:
          lcd.print((unsigned long)cur_inp_long);
          return;
      }
      
      
      
    }
    
  } // end if( draw_all == true
        
  else {
    
      // do not need to re-draw the whole screen
      
      // move cursor down if we're not in
      // a value input screen
    if( ! (ui_ctrl_flags & B00100000) ) {
      lcd.setCursor(0,0);
      lcd.print(' ');
      lcd.setCursor(0,1);
      lcd.print('>');
    }

  }
}



/* 

 Menu history functions
 
*/
 
void push_menu(byte this_menu) { 
    // push the given entry to the end of the list
  for( byte i = 0; i < sizeof(hist_menu) / sizeof(hist_menu[0]); i++) {
    if( hist_menu[i] == 0 ) {
      hist_menu[i] = this_menu;
    }
  }
}

byte pop_menu() {
  byte bk_menu = 0;
  for( byte i = sizeof(hist_menu) / sizeof(hist_menu[0]); i > 0 ; i--) {
    if( hist_menu[i-1] != 0 ) {
      bk_menu = hist_menu[i-1];
      hist_menu[i-1] = 0;
    }
  }
  return(bk_menu);
}

void flush_menu() {
  memset(hist_menu, 0, sizeof(hist_menu) / sizeof(hist_menu[0]));
}

 

vvadim
Offline
Зарегистрирован: 23.05.2012

 Ещё



void prep_home_screen() {
  lcd.clear();
  lcd.setCursor(0,0);

  if( run_status & B10000000 ) {
      // in 'external intervalometer' mode, show 'ext' inseatd of 'on'
    if( external_interval & B11000000 ) {
      lcd.print("Ext");
    }
    else {
      lcd.print("On");
    }
  }
  else {
    lcd.print("Off");
  }

  lcd.setCursor(4, 0);
}

void show_merlin_home() {

  lcd.print("  Scope");  

  lcd.setCursor(0,1);
  
  if( merlin_dir[0] == 1 ) {
    lcd.print('L');
  }
  else {
    lcd.print('R');
  }


 display_spd_merlin(merlin_speeds[0], 0);

 
  lcd.setCursor(8,1);
  
  
  if( merlin_dir[1] == 1 ) {
    lcd.print('D');
  }
  else {
    lcd.print('U');
  }

 display_spd_merlin(merlin_speeds[1], 1);

    // we call this here mainly to reset the
    // cursor position when in an input
  if( main_scr_input ) 
    get_merlin_set(main_scr_input, false);

}


void show_home() {
  
  prep_home_screen();  
  
  if( merlin_flags & B00010000 ) {
    // show merlin screen instead
    show_merlin_home();
    return;
  }
  
    // deal with interval times that are less than total time
    // required between shots
  float i_total = calc_total_cam_tm();
  
  if( cam_interval < i_total ) {
    lcd.print(i_total, 1);
  }
  else {
    lcd.print((float) cam_interval, 1);
  }
  
  lcd.print("s ");
 
  
  if( shots > 999 ) {
    lcd.setCursor(10,0);
  }
  else if( shots > 99 ) {
    lcd.setCursor(11, 0);
  }
  else if( shots > 9 ) {
    lcd.setCursor(12, 0);
  }
  else {
    lcd.setCursor(13,0);
  }

  lcd.print('[');
  lcd.print(shots, DEC);
  lcd.print(']');
 
  lcd.setCursor(0,1);
  
  if( m_wasdir[0] == 1 ) {
    lcd.print('L');
  }
  else {
    lcd.print('R');
  }

 
 if( m_type[0] == 1 ) {
   display_spd_deg(m_speeds[0], 0);
 }
 else if( ui_motor_display ) {
  // display pct 
   display_spd_ipm(m_speeds[0], 0);
 }
 else {
  display_spd_pct(m_speeds[0]);
 }

 
  lcd.setCursor(8,1);
  
  
  if( m_wasdir[1] == 1 ) {
    lcd.print('L');
  }
  else {
    lcd.print('R');
  }

 if( m_type[1] == 1 ) {
   display_spd_deg(m_speeds[0], 1);
 }
 else if( ui_motor_display ) {
  // display pct 
   display_spd_ipm(m_speeds[1], 1);
 }
 else {
  display_spd_pct(m_speeds[1]);
 }

    // we call this here mainly to reset the
    // cursor position when in an input
  if( main_scr_input ) 
    get_mainscr_set(main_scr_input, false);
}


void main_screen_select(boolean dir) {
  
  if( main_scr_input == 0 && dir == true ) {
    lcd.blink();
  }
  
  if( dir ) {
    main_scr_input++;
  }
  else {
    main_scr_input--;
  }

    
    // merlin screen has five inputs, normal home
    // has six
    
  byte max_inputs = (merlin_flags & B00010000) ? 5 : 6;

    // exit main scr setup
  
  if( (dir == true && main_scr_input > max_inputs) ||
      (dir == false && main_scr_input == 0 ) ) {
    lcd.noBlink();
    main_scr_input = 0;
    return;
  }
  
 get_mainscr_set(main_scr_input, false);
}

      
void show_manual() {

 ui_ctrl_flags |= B00000100;

 lcd.clear();
 lcd.noBlink();

 lcd.setCursor(0, 0);

 if( cur_motor == 0 ) {
  lcd.print("Motor Rot-Pan");
 }
 else {
  lcd.print("Motor Lin");
 }
 
 lcd.setCursor(0, 1);
 lcd.print("Speed: ");

 if( ui_motor_display ) {
  // display ipm 
   display_spd_ipm(m_speeds[cur_motor], cur_motor);
 }
 else {
  display_spd_pct(m_speeds[cur_motor]);
 }
 
  
}

 
void show_calibrate() {

    // show the motor calibrate screen
    
 ui_ctrl_flags |= B00000001;

 lcd.clear();
 lcd.noBlink();

 lcd.setCursor(0,0);
 
 lcd.print("Cal M");
 lcd.print(cur_motor + 1, DEC);
 lcd.print(" [");
 
 byte angle = m_cur_cal * 45;
 
 lcd.print(angle, DEC);
 lcd.print(" Deg]");
 
}



void execute_calibrate() {

    // in calibration  
  ui_cal_scrn_flags |= B10000000;
    // floating point input
  ui_type_flags |= B10000000;

  ui_float_tenths = false;
 
  
  byte was_cur_pos = 0;
  byte completed = 0;   
  
    // sms calibration
  for( byte i = 0; i <= 1; i++ ) {
    float traveled = 0.01 * (max_ipm[cur_motor]);
    unsigned int runspd = 0.01 * m_maxsms[cur_motor];
    cur_inp_float = traveled;

    completed++;
    
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Running ");  
    lcd.print('[');
    lcd.print(completed, DEC);
    lcd.print(" of 6]");
    
      // sms moving in i dir
      // at 6% of total distance
    motor_run_calibrate(1, runspd, i);

    update_cal_screen();
        
    m_cal_done = false;

    while( m_cal_done == false ) {
        byte held = ui_button_check();
    }
    
    m_cal_array[cur_motor][m_cur_cal][0][i] = traveled / cur_inp_float;

  }

    // save this for now, to avoid calc problems
  byte was_smsfx[2] = { m_smsfx[0], m_smsfx[1] };
  m_smsfx[0] = 0; m_smsfx[1] = 0;
  
    // pulse calibration  
  for( byte c = 1; c <= 2; c++ ) {
    byte ths_spd = c == 1 ? motor_spd_cal[0] : motor_spd_cal[1];
    
    for( byte i = 0; i <= 1; i++ ) {
      float des_ipm = motor_calc_ipm(cur_motor, ths_spd, true);
      cur_inp_float = des_ipm;

      completed++;
      
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Running ");  
      lcd.print('[');
      lcd.print(completed, DEC);
      lcd.print(" of 6]");

        // pulse moving in i dir
      motor_run_calibrate(2, ths_spd, i);
    
      update_cal_screen();
      
      m_cal_done = false;
      
      while(  m_cal_done == false ) {
          byte held = ui_button_check();
      }
      
      m_cal_array[cur_motor][m_cur_cal][c][i] = ( cur_inp_float / des_ipm );
    }
  }

    // restore values
  m_smsfx[0] = was_smsfx[0]; m_smsfx[1] = was_smsfx[1];
  
  ui_cal_scrn_flags &= B01111111;
  ui_cal_scrn_flags |= B01000000;
  
   // save values to memory
   // handle m_cal_array in a sane manner
   // float m_cal_array[2][3][3][2] 
   // 2 * 3 * 3 * 2 * 4 = 144
   
  byte* p = (byte*)(void*)&m_cal_array;
  eeprom_write(71, *p, 144);
  
}

  
void update_cal_screen() {
  
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Dist Moved:");
    lcd.setCursor(0,1);
    
    lcd.print(cur_inp_float, 2);
}

 

flying
Offline
Зарегистрирован: 12.11.2011

vvadim пишет:

  На дисплей lcd 16x2 выводится меню из шести строк для управления мотором. Всё работает. Нужно подключить lcd 20x4. Инициировал. Написал заставку  - выводится на все четыре строчки . Меню выводится только на две строки. В чём проблема ? 

Проблема в том скорее всего что он состоит из двух 20х2 и есть два пина enable смотрите даташит.

Инициализацию проводите примерно так 

LiquidCrystal lcd1(8, 6, 5, 4, 3, 2);
LiquidCrystal lcd2(8, 11, 5, 4, 3, 2);

lcd1.begin(20, 2);
lcd2.begin(20, 2);

Будет две строки верхние и две нижние, такой способ применил для 40х4

vvadim
Offline
Зарегистрирован: 23.05.2012

 Дисплей Winstar WN2004d с одним E. Работают все строчки. Проблема в программе наверное. Но как сделать, что бы на дисплей выводилось 4 стоки меню у меня знаний не хватает. 

flying
Offline
Зарегистрирован: 12.11.2011

 У вас в коде инициализация только двух строк  lcd.begin(16, 2);

Замените на lcd.begin(16, 4);

maksim
Offline
Зарегистрирован: 12.02.2012

 Да, да или lcd.begin(20, 4); попробуйте.

vvadim
Offline
Зарегистрирован: 23.05.2012

 Я всё пробовал с lcd.begin(20,4). замена на 16,4 ничего не даёт. Нашёл часть кода связанного с отображением меню. Ночью пробовал разные комбинации дописывать -курсор всё равно только на двух строчках, а в меню появляются глючные записи на 4 строке

    // draw first option
    lcd.noCursor();
    lcd.setCursor(0,0);
    cur_pos_sel = cur_pos;
    
    strcpy_P(lcd_buf, (char*) pgm_read_word(&(these[cur_pos])));
    lcd.print("> ");
    lcd.print(lcd_buf);
    lcd.setCursor(0,1);
    
      // if we're not displaying only a value, and there's
      // another menu entry to display -- display it on the 
      // second line..
      
    if( ! value_only ) {
      
      if( cur_pos + 1 <= max_menu[cur_menu] ) {
        cur_pos_sel = cur_pos + 1;
        memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);
        strcpy_P(lcd_buf, (char*)pgm_read_word(&(these[cur_pos + 1])));
        lcd.print("  ");
        lcd.print(lcd_buf);
      }
        // clear out in value entry setting, if set
     ui_ctrl_flags &= B11011111;
      

 

vvadim
Offline
Зарегистрирован: 23.05.2012

 После проб  и ошибок заставил меню появиться на всех четырёх строчках. осталось заставить курсор бегать по 3 и 4 строке

void draw_values(const char *these[], boolean draw_all, boolean value_only) {  
  if( draw_all == true ) {
    // must draw the whole display
    lcd.clear();
      // clear out lcd buffer      
    memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);    
      // draw first option
    lcd.noCursor();
    lcd.setCursor(0,0);
    cur_pos_sel = cur_pos;    
    strcpy_P(lcd_buf, (char*) pgm_read_word(&(these[cur_pos])));
    lcd.print("> ");
    lcd.print(lcd_buf);
    lcd.setCursor(0,1);    
      // if we're not displaying only a value, and there's
      // another menu entry to display -- display it on the 
      // second line..      
    if( ! value_only ) {      
      if( cur_pos + 1 <= max_menu[cur_menu] ) {
        cur_pos_sel = cur_pos + 1;
        memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);
        strcpy_P(lcd_buf, (char*)pgm_read_word(&(these[cur_pos + 1])));
        lcd.print("  ");
        lcd.print(lcd_buf);
        lcd.setCursor(0,2);
      }    
      if( cur_pos + 2 <= max_menu[cur_menu] ) {
        cur_pos_sel = cur_pos + 2;
        memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);
        strcpy_P(lcd_buf, (char*)pgm_read_word(&(these[cur_pos + 2])));
        lcd.print("  ");
        lcd.print(lcd_buf);
        lcd.setCursor(0,3);
      }      
      if( cur_pos + 3 <= max_menu[cur_menu] ) {
        cur_pos_sel = cur_pos + 3;
        memset(lcd_buf, ' ', sizeof(char) * MAX_LCD_STR);
        strcpy_P(lcd_buf, (char*)pgm_read_word(&(these[cur_pos + 3])));
        lcd.print("  ");
        lcd.print(lcd_buf);
      }      
   ui_ctrl_flags &= B11011111; 

 

dzmitry
Offline
Зарегистрирован: 12.08.2012

Полное решение не скажу, но думается мне, что вам должно помочь следующее: 

в методе "draw_values" при условии draw_all == false надо написать как то так:

  else {
      // do not need to re-draw the whole screen
      // move cursor down if we're not in
      // a value input screen

			if( ! (ui_ctrl_flags & B00100000) ) {
				lcd.setCursor(0, cur_pos - 1);
				lcd.print(' ');
				lcd.setCursor(0, cur_pos);
				lcd.print('>');
		}
	}

 Это должно помочь с движением курсора ниже второй строчки.

А вообще, было бы неплохо вам чутка порефакторить код :)

vvadim
Offline
Зарегистрирован: 23.05.2012

 Сейчас попробую ваш вариант. Серьёзно изменить код знаний не хватает. Сейчас всё работает - боюсь влезу глубоко и потом управление накроется.

dzmitry
Offline
Зарегистрирован: 12.08.2012

vvadim пишет:

 Сейчас попробую ваш вариант. Серьёзно изменить код знаний не хватает. Сейчас всё работает - боюсь влезу глубоко и потом управление накроется.

Можно начать с простого, например разбить большие методы на более маленькие, дав им при этом  осмысленные имена. Так же можно сгруппировать и разнести методы по разным исходным файлам, например: методы для работы с меню в Menu.cpp(.h), методы для работы с кнопками в Keyboard.cpp(.h) и т.д. Это сильно поможет в поддержке кода.

vvadim
Offline
Зарегистрирован: 23.05.2012

Курсор пошёл на 3 и 4 строчки, но не удаляется с предыдущих. Попробовал поиграться в строчках

if( dir == 2 ) {
      // down
    cur_pos++;
    if( cur_pos  >  cur_pos_sel )
 {
      lcd.clear
      draw_all = true;
    }

 

Вот что получается.  При замене  cur_pos на  (cur_pos + 2)  курсор работает только на двух строках, а потом поднимается меню.

При (cur_pos + 3 ) курсор вообще на месте, а поднимается меню.

 

 

 

 

dzmitry
Offline
Зарегистрирован: 12.08.2012

 В какой ситуации не удаляется? При движении вверх или вниз?

vvadim
Offline
Зарегистрирован: 23.05.2012

Меню из шести строк. Сначала на дисплее 4 строки. Курсор при нажатии кнопки опускается вниз и остаётся на каждой строке. При переходе на 5 строку меню на дисплее выведено две строки (5 и 6). Курсор на первой и последней (4) строке дисплея. При нажатии кнопки курсор бегает по дисплею произвольно и не в начале строк. Всё это при движени вниз. Движение курсора вверх изначально было нормально.

dzmitry
Offline
Зарегистрирован: 12.08.2012

 Эм... странно, вот тот кусочек кода, что я скинул как раз и должен удалять старый курсор при движении вниз. Перепроверьте, что пробел выводится именно в положении (0, cur_pos - 1).

lcd.setCursor(0, cur_pos - 1); lcd.print(' ');

 

vvadim
Offline
Зарегистрирован: 23.05.2012

Нашёл у себя ошибку. Теперь курсор бегает вниз нормально, но при переходе на 5 и 6 строки меню глюки как писал выше. 

vvadim
Offline
Зарегистрирован: 23.05.2012

Для дисплея 16х2 написано

 // max # of LCD characters (including newline)
#define MAX_LCD_STR 17

А как для дисплея 20х4 ? 

step962
Offline
Зарегистрирован: 23.05.2011

 логично предположить, что 21: 20 под отображаемые символы и 1 под символ перевода строки '\n' (или скорее - под символ конца строки - '\0')

vvadim
Offline
Зарегистрирован: 23.05.2012

Спасибо 

alexeko
Offline
Зарегистрирован: 03.01.2014

Вечер добрый.

Подскажите. Есть LCD 20*4 совершенно левая, но рабочая, проверял на параллельном порту ПК.

Можно подключать панельки сторонние, а не те что на сайте производителя?

ВОт еще нашел LiquidCrystalRus.h 

#include <LineDriver.h>
#include <LiquidCrystalExt.h>
#include <LiquidCrystalRus.h>

LiquidCrystalRus lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  lcd.begin(16, 2);
  lcd.print("Здравствуй, мир!");
}

void loop()
{
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);
}

НУ если кому интересно.

Качать тут https://github.com/RoboCraft/LiquidCrystalRus/zipball/master

Клапауций
Offline
Зарегистрирован: 10.02.2013

alexeko пишет:

Можно подключать панельки сторонние, а не те что на сайте производителя?

какие панели имеются ввиду?

alexeko
Offline
Зарегистрирован: 03.01.2014

Сторонних производителей. К примеру 20*4 размером 150мм х 60мм

Незнаю как описать, у меня 20*4 с 3-мя чипами с зади.

Занимался модингом лицевых панелей ПК, ранее. Вот осталось.

Клапауций
Offline
Зарегистрирован: 10.02.2013

alexeko пишет:

Сторонних производителей. К примеру 20*4 размером 150мм х 60мм

Незнаю как описать, у меня 20*4 с 3-мя чипами с зади.

Занимался модингом лицевых панелей ПК, ранее. Вот осталось.

если у вас голый индикатор, то никакой панели для подключения не нужно - проводами подключайте.

alexeko
Offline
Зарегистрирован: 03.01.2014

Спасибо.

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

Доброго времени суток господа!

Имел не осторожность раздербанить устройство и извлечь из него дисплей 20х4 BT42008 LED.

Решил его подключить к UNO  по стандартной схеме для начинающих и... ничего не получилось. Не кажет!!!

Подключил обратно в старое устройство все работает.

Что может быть не так? Подскажите посоветуйте!!!

 

alexeko
Offline
Зарегистрирован: 03.01.2014

Ну, давай, по порядку:

1. Подали питание - (в двух местах) - есть "контрольная" строка? загораются "квадратики"?

2. Параллельную шину как используешь - 4 или 8 бит? (при подключении должна пропасть контрастность на "контрольной строке")

--------------------------------------

Подключал разные панельки и все без проблем. ПОНЯЛ только одно! какие библиотеки юзаем.

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

Подключался по вот этому примеру.

http://wiki.amperka.ru/схемы-подключения:подключение-текстового-экрана

нашел даташит на экран все один в один как в примере.

по первому пункту контрольной строки не было

по второму 4 бит

alexeko
Offline
Зарегистрирован: 03.01.2014

А в листинге, в инициализации, 20х4 ставишь?

Воевал с "бубном" при подключении графических дисплеев, но вроде побеждал всегда.

А тут то, два провода

 

КРУТИ КОНТРАСТНОСТЬ. посмотрел таташид - стандартный контроллер

alexeko
Offline
Зарегистрирован: 03.01.2014

http://robocraft.ru/blog/arduino/503.html или

http://audio.probudget.ru/arduino/arduino-i-lcd-ekran

Вот так подключи. Контакты 1,2 и 15,16 - питание!!!!!!!!!!!!!!!

И учти, во многих статьях есть специальные опечатки! Что бы сами думали.

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

да меняю с 16x2 на 20х4

пробывал ни хухе(

(блин надо руки пересаживать:))

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

Бесполезно не могу запустить(

что еще можно подумать?

alexeko
Offline
Зарегистрирован: 03.01.2014

Для начала , подключи 1,2 и 15,16

Должна загореться строка "кубиками"

alexeko
Offline
Зарегистрирован: 03.01.2014

Покажи ФОТО с обеих сторон

toly
Offline
Зарегистрирован: 17.05.2014

Точно такая же ситуация, не могу победить дисплей  BONO MC2402. Подключен по даташиту (пробовал и 4 и 8 бит). Ни с одной библиотекой не работает, при этом кубики в верхней строке есть и контрастность регулируется. То ли команды инициализации другие, то ли что-то не то с распиновкой выводов :(

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

фото дисплея?

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

потыкал мультиметром и определил, что первый выход 0V, второй +5V, а с третьим загвоздка при замере между 1 и 3 напряжение около -6,5V между 2 и 3 - 12V вот как то так)))

И как это сделать мемогу догнать помогите!!! HELP ME!!!

alexeko
Offline
Зарегистрирован: 03.01.2014
# Контакты Для чего используется Примечание
1 VSS (VSS) GND. Земля. Питание микроконтроллера дисплея. 0V
2 VDD (VCC) Питающее напряжение для микроконтроллера дисплея. +5V
3 V0 (VEE) Контраст символов на дисплее. Подключать лучше через потенциометр. от 0v до +5V
4 RS (RS) Выбор регистра.  
5 RW (R/W) Переключение режима чтения/записи. Утянем на землю, нам нужно только передавать информацию на дисплей. 0-запись +5V-чтение
6 E Тактирование  
7 D0 (DB0) Передача данных. (Не будем использовать) Данные
8 D1 (DB1) Передача данных. (Не будем использовать) Данные
9 D2 (DB2) Передача данных. (Не будем использовать) Данные
10 D3 (DB3) Передача данных. (Не будем использовать) Данные
11 D4 (DB4) Передача данных. (Задействуется) Данные
12 D5 (DB5) Передача данных. (Задействуется) Данные
13 D6 (DB6) Передача данных. (Задействуется) Данные
14 D7 (DB7) Передача данных. (Задействуется) Данные
15 A (LED+) +5V Напряжение, подсветка дисплея, через потенциометр можно регулировать яркость дисплея. +5V
16 K (LED-) GND Земля, подсветка дисплея 0V

 

alexeko
Offline
Зарегистрирован: 03.01.2014

ВОТ тут скачать можно 

alexeko
Offline
Зарегистрирован: 03.01.2014

Ну, начну с самого начала.

Как и писал. подкидываем питание и смотрим, должна показать высокий контраст одна из строк (обычно первая). В принципе убить чипы, путем не правильного подключения нельзя, но статикой убиваются мгновенно, сам пару спалил, пока понял, что капут дисплеям.

После питания, подключаем данные. Заливаем тест сетча.

НО. я уде давно использую шину  I2C .  Проводов меньше и дискретчики лишними не бывают.

Вот тут покупаю, если быстро надо и дешево, или по ссылке выше, но долго.

alexeko
Offline
Зарегистрирован: 03.01.2014

результат.

А вот и полный пример, с промежуточными результатами. 

denis_tmbk
Offline
Зарегистрирован: 28.05.2014

Мозг кипит, а каши нету!

По третьему пункту не могу понять хоть убей(

Может кто разъяснит?

alexeko
Offline
Зарегистрирован: 03.01.2014

А какой результат по такому подключению?

И давай на почту, а тут результат работы выставишь!

А то модераторы забанят, за флуд на сайте.

korzhavin@gmail.com

alexeko
Offline
Зарегистрирован: 03.01.2014

denis_tmbk пишет:

Имел не осторожность раздербанить устройство и извлечь из него дисплей 20х4 BT42008 LED.

Что за девайс разобрал??

Murz0id
Murz0id аватар
Offline
Зарегистрирован: 08.02.2018

Здравствуйте друзья! Заказал на али дисплей 20х4 Noname. Попытки подключить не увенчались успехом. Подскажите пожалуйста, при подаче питания должно что либо высветиться на дисплее? Он у меня молчит...

arduinec
Offline
Зарегистрирован: 01.09.2015

Murz0id пишет:

Здравствуйте друзья! Заказал на али дисплей 20х4 Noname. Попытки подключить не увенчались успехом. Подскажите пожалуйста, при подаче питания должно что либо высветиться на дисплее? Он у меня молчит...

Там подстроечным резистором 10k (он бывает сразу на дисплее) нужно контраст выставлять.

Murz0id
Murz0id аватар
Offline
Зарегистрирован: 08.02.2018

Спасибо дружище огромнейшее! Схема очень помогла. А в заблуждение меня ввел старый LCD, который при подаче на 1 и 2 ногу питания загорался, и так я испытал 2 абсолютно разных дисплея, подозреваю что они на HD44780, а подключаемые мной были с S6A0069 от Самсунга. Теперь буду знать. Еще раз благодарю за помощь!