/* Polisseur Copyright (C) 2019 Arofarn 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 . */ #include #include #include #include // PIN USAGE #define SEVSEG_DIGIT_1 16 #define SEVSEG_DIGIT_2 17 #define SEVSEG_DIGIT_3 3 #define SEVSEG_DIGIT_4 4 #define SEVSEG_COLON 2 #define SEVSEG_SEGMENT_A 8 #define SEVSEG_SEGMENT_B 14 #define SEVSEG_SEGMENT_C 6 #define SEVSEG_SEGMENT_D A1 #define SEVSEG_SEGMENT_E 23 #define SEVSEG_SEGMENT_F 7 #define SEVSEG_SEGMENT_G 5 #define SEVSEG_SEGMENT_H 22 #define ROT_BUTT 11 #define ROT_ENC_1 12 #define ROT_ENC_2 13 #define ROT_ENC_DIR -1 #define STEPPER_STEP 10 #define STEPPER_DIRECTION 0 #define STEPPER_ENABLE A5 //SETTINGS #define SEVSEG_REFRESH 250 // Refresh rate in ms #define SEVSEG_BRIGHTNESS 100 // 100%, full brightness #define STEPPER_MAX_SPEED 5000 #define STEPPER_MIN_SPEED 0 #define STEPPER_ACCELERATION 30.0 #define STEP_MOTOR_STEPS_PER_TURN 200 #define STEPPER_MICROSTEP 8 SevSeg sevseg; //Instantiate a seven segment controller object // Setup a RoraryEncoder for pins 12 and 13: RotaryEncoder encoder(ROT_ENC_1, ROT_ENC_2); AccelStepper stepper(1, STEPPER_STEP, STEPPER_DIRECTION); EveryTimer cntdwn; EveryTimer calc_dspl; //Global variables byte numDigits = 4; byte digitPins[] = {SEVSEG_DIGIT_1, SEVSEG_DIGIT_2, SEVSEG_DIGIT_3, SEVSEG_DIGIT_4}; byte segmentPins[] = {SEVSEG_SEGMENT_A, SEVSEG_SEGMENT_B, SEVSEG_SEGMENT_C, SEVSEG_SEGMENT_D, SEVSEG_SEGMENT_E, SEVSEG_SEGMENT_F, SEVSEG_SEGMENT_G, SEVSEG_SEGMENT_H}; bool resistorsOnSegments = false; // 'false' means resistors are on digit pins byte hardwareConfig = COMMON_ANODE; // See README.md for options bool updateWithDelays = false; // Default. Recommended bool leadingZeros = false; // Use 'true' if you'd like to keep the leading zeros long refresh_timer = 0; long countdown = 0; byte days = 0; byte hours = 0; byte minutes = 0; byte seconds = 0; int current_rpm = 0; int new_rpm = 0; static bool currBut = true; byte mode = 0; void countdown_callback() { if (current_rpm != 0) { // if speed = 0 => pause countdown countdown--; if (countdown < 0) { countdown = 0; } recalculate_DHMS(); //Serial.println(countdown); } else { Serial.println("Pause"); } } void calculate_display_callback() { // Update data to be displayed if (mode == 0) { // mode 0 = display speed digitalWrite(SEVSEG_COLON, false); sevseg.setNumber(current_rpm); } else if (mode == 1) { // mode 1 = display countdown //Blink colon each seconds if (countdown % 2) { digitalWrite(SEVSEG_COLON, true); } else { digitalWrite(SEVSEG_COLON, false); } //Display dd:HH if there is more than 1day left, HH:MM if less or MM:SS if there is less than 1h left if (days) { char dispBuf[] = "0d00"; dispBuf[0] = days + 48; dispBuf[2] = (hours / 10) + 48; dispBuf[3] = (hours % 10) + 48; sevseg.setChars(dispBuf); } else if (hours) { sevseg.setNumber(100*hours+minutes); } else { sevseg.setNumber(100*minutes+seconds); } } } void update_encoder() { static long currVal = 0; int multiplier = 10; encoder.tick(); long newVal = encoder.getPosition(); int dir = encoder.getDirection(); if (currVal != newVal) { currVal = newVal; if (mode == 0) { // Mode 0 : speed setting multiplier = 10; if (current_rpm >= 500) { multiplier = 100; // default : 1 encoder step = +/- 10 step/min // if speed > 500 : encoder step = +/- 100 step/min } new_rpm += multiplier * dir * ROT_ENC_DIR; if (new_rpm < STEPPER_MIN_SPEED) { new_rpm = STEPPER_MIN_SPEED; } if (new_rpm > STEPPER_MAX_SPEED) { new_rpm = STEPPER_MAX_SPEED; } } if (mode == 1) { //mode 1 : countdown setting multiplier = 60; // default : 1 encoder step = +/- 1min // if countdown > 1h : encoder step = +/- 10min (600s) // if countdown > 1d : encoder step = +/- 1h (3600s) if (countdown >= 86400) { multiplier = 3600; } else if (countdown >= 3600) { multiplier = 600; } countdown += multiplier * dir * ROT_ENC_DIR; //Min: 0 = no negative timer value if (countdown < 0) { countdown = 0; } // Max: 864000s = 10 days if (countdown >= 864000) { countdown = 863999; } recalculate_DHMS(); } Serial.print("RPM: "); Serial.print(new_rpm); Serial.print(" | Countdown: "); Serial.println(countdown); } //Check button for mode change bool newBut = digitalRead(ROT_BUTT); if (newBut != currBut) { currBut = newBut; if (currBut) { mode++; } if (mode == 2) { mode = 0; } else if (mode == 0) { encoder.setPosition(current_rpm); } else if (mode == 1) { encoder.setPosition(countdown); } Serial.print("Mode :"); Serial.println(mode); } } void update_stepper() { //Update speend setting and ENABLE pin if new speed value if (new_rpm != current_rpm) { current_rpm = new_rpm; stepper.setSpeed(current_rpm); // Enable/Disable motor if (current_rpm == 0) { stepper.disableOutputs(); Serial.println("Stepper : Off"); } else { stepper.enableOutputs(); Serial.println("Stepper : On"); } } //if Countdown = 0 => pause (no move but keep speed setting) if (countdown != 0 and current_rpm != 0) { //Serial.println("Run motor !"); stepper.runSpeed(); } } void recalculate_DHMS() { //Calculate days, hours, minutes and seconds to be display if (countdown >= 86400) { days = countdown / 86400; hours = (countdown % 86400) / 3600; } else { days = 0; minutes = (countdown / 60) % 60; if (countdown >= 3600) { hours = countdown / 3600; } else { hours = 0; seconds = countdown % 60; } } } void setup() { Serial.begin(115200); pinMode(ROT_BUTT, INPUT_PULLUP); pinMode(SEVSEG_COLON, OUTPUT); sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros); sevseg.setBrightness(SEVSEG_BRIGHTNESS); stepper.setEnablePin(STEPPER_ENABLE); stepper.disableOutputs(); stepper.setMaxSpeed(STEPPER_MAX_SPEED); stepper.setAcceleration(STEPPER_ACCELERATION); stepper.setSpeed(0); cntdwn.Every(1000, countdown_callback); calc_dspl.Every(SEVSEG_REFRESH, calculate_display_callback); } void loop() { update_encoder(); //Make the motor move update_stepper(); //Update countdown cntdwn.Update(); //refresh the 7-segment display calc_dspl.Update(); sevseg.refreshDisplay(); }