Main »

Computers-software-arduino-stepper Winderino



stepper_winder.ino


/*
 *  License: GPLv3
 *  by tom
 *  
 *  built on linux using arduino ide v1.8.5
 *  for the ESP8266 NodeMCU LUA CP2102 ESP-12E w/ cpu 80mhz
 *  
 *  
 *  $Id: stepper_winder.ino,v 1.17.1.4 2018/06/08 18:34:42 me Exp me $
 */

#include <AccelStepper.h>  // driver for the stepper 28BYJ-48 5v steppers
#define HALFSTEP 8
#include <ESP8266WiFi.h>
#include <TimeLib.h>
#include <time.h>    // only used for time(nullptr), which seems to set the rtc from ntp on the esp8266 !??!
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
SSD1306  display(0x3c, D2, D1);   // i2c oled nodeMCU pin mapping  D2->sda, D1->scl ; can't put this in 'setup' ?

#define ACTION_LED_PIN LED_BUILTIN
#define CONNECTION_LED_PIN 2

// -- set as needed:
const char* ssid     = "YourAPgoesHere";
const char* password = "YourPasswordGoesHere";
const int timezone = -8;        // pst ... change to yours.
const unsigned int tpd = 1600;  // rotations per day in either direction.
const unsigned int rot = 3;     // how many rotations we want.

// -- our constants below
long int prevDisplay = 0;  // used in loop to see if time has changed
const unsigned long int timeSyncNist = 60*10*1000;  // 600,000ms is mins between getting nist time
const unsigned long int myConnSpeed = 500000;  // this is the serial connection speed.
unsigned int dst = 0;  // we start at zero and auto set via dstSet() below.
boolean update_tm = 1;
boolean done_rot = 0;
boolean toggleAction = false;
long int oldPosition = 10;
unsigned long int rcntCW = 0;  // counts the CW rotations of the servo.
unsigned long int rcntCCW = 0;  // counts the CCW rotations of the servo.
unsigned long int hrs24Millis = 24*60*60*1000;  // we start with 24hrs in ms
const unsigned int sleepBtwnTurns = ( (24*60*60) / (tpd/(rot*2)) )*1000;  // (minsDay/(tpd/rotGroup))*1000ms; 324,000ms ~5mins @ 1600tpd this is how long we sleep in ms, between turning groups.
unsigned long previousMillis = 0;
unsigned long previousNistMillis = 0;  // sync with nist time.
unsigned long int k = 0;  // used to see if we should get re sync'd with nist time server    timeSyncNist 60 - min
unsigned int m = 0;   // used to count wifi connect tries.
String myVersion ="$Revision: 1.17.1.4 $";   // this will change with each rcs ci
String myVersionNumber = myVersion.substring(11,20);
time_t tNow;

// Switch pin definitions NOTE: don't use gpio 9,10
#define enter_button D3 // gpio 0   can't be low at power up.
#define up_button 2    // gpio 2
#define down_button 10  // gpio 10

// Motor pin definitions
#define motorPin1  D5     // IN1 on the ULN2003 driver 1
#define motorPin2  D6     // IN2 on the ULN2003 driver 1
#define motorPin3  D7     // IN3 on the ULN2003 driver 1
#define motorPin4  D8     // IN4 on the ULN2003 driver 1

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
  stepper1.setMaxSpeed(900.0);
  stepper1.setAcceleration(100.0);  // orig acc was '100' gives about 3.5sec startup and 3.5sec startdown
  stepper1.setSpeed(900);          //  28BYJ-48 max 800pps or about 5sec/rev max ... 
  stepper1.moveTo(rot*4096);   // 4096 seems to be one revolution. 4076 some say this is one revolution, seemed a little short.
  pinMode(enter_button, INPUT);
  pinMode(enter_button, INPUT_PULLUP); // connect internal pull-up
//  pinMode(up_button, INPUT);
//  pinMode(up_button, INPUT_PULLUP);
//  digitalWrite(up_button, HIGH); // connect internal pull-up      
//  pinMode(down_button, INPUT);
//  digitalWrite(down_button, HIGH); // connect internal pull-up

  display.init();
  display.flipScreenVertically();
  display.setContrast(255);
  pinMode(ACTION_LED_PIN, OUTPUT);
  pinMode(CONNECTION_LED_PIN, OUTPUT);
  SetConnectionLEDOff();    // make sure we start in off as we haven't logged into wifi yet.
  SetActionLEDOn();         // show we are in setup or active.
  Serial.begin(myConnSpeed);
  delay(100);
  wifiUP("v"+String(myVersionNumber)+": First try ... ");

  if(nistTime()){   // set our time of day up.
    dstSet();       // set dst if we have a good rtc/nist time.
    nistTime();     // re set it after we have dst set.
  }


}//--(end setup )---


void SetActionLEDOn(){ digitalWrite(ACTION_LED_PIN, false);}
void SetActionLEDOff(){ digitalWrite(ACTION_LED_PIN, true); }
void SetConnectionLEDOn(){ digitalWrite(CONNECTION_LED_PIN, false); }
void SetConnectionLEDOff(){ digitalWrite(CONNECTION_LED_PIN, true); }

boolean button_debounce(int button) {
  Serial.print("got a button push on "+String(button));
  while( ! digitalRead(button) ) {
    delay(10);
  }
  delay(5);
    while( ! digitalRead(button) ) {
    delay(10);
  }
  Serial.print(". Just debounced button: ");
  Serial.println(String(button));

}  // end of function button_debounce


void loop() {

  if( ! digitalRead(enter_button) ){button_debounce(enter_button);}
//  if( ! digitalRead(up_button) ){button_debounce(up_button);}
//  if( ! digitalRead(down_button) ){button_debounce(down_button);}

  //-- section to move the steppers if needed, this runs as fast at the loop will run, but the calls to stepper1 do not.
  if ( (stepper1.distanceToGo() == 0) && ! done_rot){
    stepper1.moveTo(0);  // lets go ccw, ie the oppisite direction.
    done_rot = 1;  }                                  // flag that we've done the cw and still need to do the ccw
  if ( (stepper1.distanceToGo()) == 0 && done_rot ) {
    stepper1.disableOutputs();  }    // if we've made our rotation turn stepper off. 
  else{
    stepper1.run();
    if ( ! (stepper1.currentPosition() % (4096)) && (stepper1.currentPosition()!= oldPosition) ){ 
      oldPosition = stepper1.currentPosition();
      if ( done_rot ){++rcntCCW;}
      else{++rcntCW;}
    }
  }  // end of section on moving the steppers.

  //-- display update section, only if the seconds have changed.
  tNow = time(nullptr);   // store the current time in 'tNow'. epoch seconds
  if ( tNow != prevDisplay){ //update the display only if the time has changed{
    prevDisplay = tNow;      // seconds since epoch.
    display.clear();
    oled();
    display.display();  // Display it on the screen
    if ( toggleAction ){ SetActionLEDOff(); toggleAction = false; }  // toggles the red led so we now we have heartbeat
    else { SetActionLEDOn(); toggleAction = true; }
  }  // end of section to update display.

  //-- start of rotation group every 'sleepBtwnTruns' ms ie every 162,000 ms for 3200 tpd (turns per day).
  if( (unsigned long)(millis() - previousMillis) >= sleepBtwnTurns ){   // 324,000ms for 1600 tpd sleep between rotation groups
    previousMillis = millis();
    SetActionLEDOn();          
    if (stepper1.distanceToGo() == 0) {     //Change direction when the stepper reaches the target position
      stepper1.enableOutputs();             // turn the stepper back on.
      stepper1.moveTo(rot*4096);  // lets go cw
      done_rot = 0;                         // flag that we've done our rot group.
    }
    Serial.print("sleeping for ");
    Serial.print(sleepBtwnTurns/1000/60);
    Serial.println(" mins before next turn group.");
  } // end of start rotation check.

  //-- resync with nist every 'timeSyncNist' ms ... 10 mins seems good.
  if( (unsigned long)(millis() - previousNistMillis) >= (timeSyncNist)){  // 600,0000ms every 10 mins
    if (WiFi.status() != WL_CONNECTED) {    //if we drop wifi, can't do below.   
      tNow = time(nullptr);
      String timeNow = String(hourFormat12(tNow))+":"+twoDigits(minute(tNow))+":"+twoDigits(second(tNow));
      Serial.print(timeNow);  // displays 'Thur Dec 14 13:52:05 2017'
      wifiUP("v"+String(myVersionNumber)+":  dropped, we try again ... "); }  // v1.17.1.4
    else{
      Serial.print("wifi is up.");
      SetConnectionLEDOn();
      Serial.print(" checking nist time: ");
      tNow = time(nullptr);
      String timeNow = String(hourFormat12(tNow))+":"+twoDigits(minute(tNow))+":"+twoDigits(second(tNow));
      Serial.println(timeNow);  // displays 'Thur Dec 14 13:52:05 2017'
      dstSet();  // -- change dst varible march and november and startup
      nistTime();  // -- sync with nist/ntp  
    }
    previousNistMillis = millis(); // sync with nist, sync or no sync we wait 10mins to do it again.
  } // end of nist ntp check.

  // -- reset rotation counters ever 24hrs from startup
  if( (unsigned long)(millis() - hrs24Millis) >= 24*60*60*1000 ){   // has it been 24hrs in ms since we started ?
    hrs24Millis = millis();
    rcntCCW = 0;
    rcntCW = 0;
  }  // end of rotation count reset check



}  //--- end of main loop.

//================= functions


boolean nistTime(){
  if (WiFi.status() == WL_CONNECTED) { 
    tNow = time(nullptr);
    String timeNow = (String(hourFormat12(tNow))+":"+String(twoDigits(minute(tNow)))+":"+String(twoDigits(second(tNow)))+", "+monthShortStr(month(tNow))+"-"+String(day(tNow))+"-"+String(year(tNow)) );
    Serial.println("our current time is: "+timeNow);
    Serial.print("Getting nist time.");
    configTime((timezone * 60*60),(dst * 60*60), "pool.ntp.org", "time.nist.gov");  // set the chips rtc from nist
    delay(2000);
    int i = 0;
    while ((time(nullptr) < 1522565410) && i < 15) {  // 1522565410 sec = April 1, 2018 6:50:10 AM
      Serial.print(".");
      delay(1000);
      i++;
    }
    if(i >= 15){Serial.println("");Serial.println("getting nist time failed. No responce from query.");return(false);}
    tNow = time(nullptr);
    timeNow = (String(hourFormat12(tNow))+":"+String(twoDigits(minute(tNow)))+":"+String(twoDigits(second(tNow)))+", "+monthShortStr(month(tNow))+"-"+String(day(tNow))+"-"+String(year(tNow)) );
    Serial.print(" Our rtc was just sync'd and the time is: ");
    Serial.println(timeNow);
    return(true); }
  else { Serial.println(" No wifi to check nist time with.");return(false); }
}  // end of function: nistTime


String twoDigits(int digits){    // utility function for digital clock display: prints leading 0
  if(digits < 10) {
    String zeroPaded = '0'+String(digits);
    return zeroPaded;
  }
  else {
    return String(digits);
  }
}  // end function twoDigits

void oled(){
  tNow = time(nullptr);   // store the current time in 'tNow'. epoch seconds
  String timeNow = String(hourFormat12(tNow))+":"+twoDigits(minute(tNow))+":"+twoDigits(second(tNow));
  display.setFont(ArialMT_Plain_16);         // size 16 works ok if no decending char like "g" or all caps.
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0, 0, timeNow);
  if(WiFi.status() == WL_CONNECTED) {SetConnectionLEDOn();}
  else{SetConnectionLEDOff();}
  long rssi = WiFi.RSSI();
  String signalStrength = String(rssi)+"dbm";
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.drawString(128, 0, signalStrength);
  IPAddress ip = WiFi.localIP();   
  String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);  // ip address
  display.setFont(ArialMT_Plain_10);
  display.drawString(128, 16, ipStr);         // ip address
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0,16, String("tpd  ") + String(tpd));
  display.drawString( 0,26, String("start in  ") + String((sleepBtwnTurns - (unsigned long)(millis() - previousMillis))/1000) );
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.drawString( 128,26, String(rot*2) + String("  turns/grp") );
  display.drawString( 128,36, "v"+String(myVersionNumber) );  // v1.17.1.4 to 4th line
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 54, String("ccw"));
  display.drawString(30, 54, String(rcntCCW));
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.drawString(105, 54, String(rcntCW));
  display.drawString(128, 54, String("cw"));
}   // end function oled

void dstSet() {  // check and set the dst flag when needed
   tNow = time(nullptr);   // store the current time in 'tNow'. epoch seconds
   int y = year(tNow) - 2000;                // Get year from RTC and subtract 2000
   int x = (y + y/4 + 2) % 7;          // remainder will identify which day of month
                                                // is Sunday by subtracting x from the one
                                                // or two week window.  First two weeks for March
                                                // and first week for November
                                                // need to set dst = 0 above

   if(month(tNow) == 3 && day(tNow) == (14 - x) && hour(tNow) == 2 && dst==0){    // *********** Test DST: BEGINS on 2nd Sunday of March @ 2:00 AM *********                                  
        setTime( tNow + (60*60*1000) );  // advance clock one hour in ms
        dst = 1;                      
   }
   if(month(tNow) == 3 && day(tNow) > (14 - x) || month(tNow) > 3){     // Daylight Savings Time is TRUE on powerup
        dst = 1;
   }

   if(month(tNow) == 11 && day(tNow) == (7 - x) && hour(tNow) == 2 && dst==1){      // ************* Test DST: ENDS on 1st Sunday of Nov @ 2:00 AM ************       
        setTime( tNow - (60*60*1000) );  // setback clock one hour in ms
        dst = 0;                        
   }
   if(month(tNow) == 11 && day(tNow) > (7 - x) || month(tNow) > 11 || month(tNow) < 3){    // daylight savings time is FALSE on powerup
        dst = 0;
   }


}  // end function to check for and set the dst flag.

void wifiUP(String wifiStatus){    // can't do it out of setup ie pass setup a string.
  SetConnectionLEDOff();    // make sure we start in off as we haven't logged into wifi yet.
  SetActionLEDOn();         // show we are in setup or active.
  WiFi.disconnect(); // 1st time or on a retry, we disconnect so we can begin again.
  delay(1000);
  display.clear();
  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0, 3, "ssid: "+String(ssid)+"\n"+wifiStatus+" connecting:");
  display.display();  // Display it on the screen
  Serial.println();
  Serial.print(wifiStatus);
  Serial.print("\nconnecting to ");
  Serial.println(ssid);
  String wifiStatusCat = "";   // marching ssid connect status results.
  WiFi.begin(ssid, password); 
  m = 0;  // local counter for connect tries. 
  while ( (WiFi.status() != WL_CONNECTED) && (m<15) ) {  // try 16 times then give up.
    wifiStatusCat += String(WiFi.status());
    display.drawStringMaxWidth(0, 29, 128, wifiStatusCat);  // wraps text
    display.display();  // Display it on the screen
    Serial.print(WiFi.status());
    m++;
    delay(1000);
  }
  if(WiFi.status() == WL_CONNECTED) {
    IPAddress ip = WiFi.localIP();   
    String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);  // ip address
    display.drawString(0, 54, "connected! "+ipStr);
    display.display();  // Display it on the screen
    SetConnectionLEDOn();
    Serial.println("WiFi connected");  
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    delay(1000);}
  else{
    SetConnectionLEDOff();
    Serial.println("");
    Serial.println("NOT connected");
  }
  SetActionLEDOff();         // show we are done.

}   // end function: wifiUP



// change log
// $Log: stepper_winder.ino,v $
// Revision 1.17.1.4  2018/06/08 18:34:42  me
// added current version to be displayed on oled.
//
// Revision 1.17.1.3  2018/06/08 17:39:40  me
// same as v 1.21 trunk.
//
// Revision 1.17.1.2  2018/06/08 16:11:51  me
// works. No switches. Cleaned up serial status output.
//
// Revision 1.17.1.1  2018/06/08 15:38:37  me
// works.
// this branch to look into adding switches.
//




top level subjects:

Page last modified on June 12, 2018, at 07:17 PM

^