fork download
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. int i, j;
  6. long dec; /* ให้รับค่าอินพุทแบบ Long Integer - เลขจำนวนเต็มแบบยาว */
  7. int bit[32]; /* จองพื้นที่ในการเก็บข้อมูลเลขฐาน 2 ลงใน Array */
  8.  
  9. clrscr(); /* เคลียร์หน้าจอ */
  10. printf("Decimal Number : "); /* แจ้งผู้ใช้เพื่อเตรียมป้อนค่าเลขฐาน 10 */
  11. scanf("%ld", &dec); /* ต้องใช้ ld เพราะ Input มันเป็นแบบ Long Integer */
  12. i = 0; /* กำหนดค่าเริ่มต้นของ Array */
  13. /* ทำตามที่ได้ออกแบบโปรแกรมเอาไว้ ... ยังไงยังงั้นเลย 55555+ */
  14. do {
  15. bit[i++] = dec % 2; /* การหารเอาเศษ เพื่อให้เป็นคำตอบ */
  16.  
  17. /* การหารทั่วไป แต่ตัวแปร dec ของภาษา C มันเป็น Integer หรือ เลขจำนวนเต็ม */
  18. /* ดังนั้นมันจึงตัดเศษ (หรือทศนิยม) ทิ้งไปโดยอัตโนมัติ */
  19. dec = dec / 2;
  20.  
  21. } while (dec > 0); /* เงื่อนไขที่ทำจนกระทั่ง dec = 0 ก็ออกจากวังวนเงื่อนไข */
  22.  
  23. /* การแสดงผลของการแปลงเลขฐาน 10 เป็นเลขฐาน 2*/
  24. /* j = i - 1 และให้ j ลดค่าลงทีละ 1 ... ก็คืออ่านข้อมูลถอยหลังกลับเท่านั้นเองครับ */
  25. /* เพราะตัวแปรแบบ Array ในภาษา C มันเก็บข้อมูลจากซ้ายไปขวา */
  26. /* ทำให้ LSB มันไปอยู่ทางซ้าย ส่วน MSB มันไปอยู่ทางขวา */
  27. for(j = i - 1; j >= 0; j--)
  28. printf("%d", bit[j]);
  29.  
  30. printf("\n");
  31. return 0;
  32.  
  33. }
Success #stdin #stdout 0.03s 26120KB
stdin
/*  ENCODER OPERATED COMBINATION LOCK V 3.2

     Copyright 2019 by Doug Pirkey

    This work is licensed under the Creative Commons Attribution 4.0 International License.
    To view a copy of this license, visit http://c...content-available-to-author-only...s.org/licenses/by/4.0/.


     A simulation of a mechanical dial combination lock to run on an Arduino UNO

     Program Demonstrates:
       EEPROM save/restore
       Pin change interrupts
       Sleep mode
       Self-made timer library
       memset(), memcmp(), memcpy()
       Rotary encoder w external interrupts
       #defines for compile time options
       Switch/case state machine

     Number of possible combinations is given by n^r:
     n = number of different numbers (40)
     r = number of tumblers used (5)

     So the current configuration yields 102,400,000 possible combinations,
     correctly called permutations.

     Number lock permutations calculator
     https://w...content-available-to-author-only...n.com/statistics/number-lock-permutations.php
*/
//-----------------------------------------------
//    EEPROM.h is part of the Arduino library.

// https://w...content-available-to-author-only...o.cc/en/Reference/EEPROM/

// https://c...content-available-to-author-only...s.org/licenses/by-sa/3.0/

#include <EEPROM.h>  // For storage/retrieval of lock code

//-----------------------------------------------
//   Change these two numbers to the pins connected to your encoder.
//   Best Performance: both pins have interrupt capability
//   Good Performance: only the first pin has interrupt capability
//   Low Performance:  neither pin has interrupt capability
//   Refer to the link for the rotary encoder license

// PaulStoffregen's GitHub page for the encoder library - https://g...content-available-to-author-only...b.com/PaulStoffregen/Encoder
// license description - https://g...content-available-to-author-only...b.com/PaulStoffregen/Encoder/blob/master/Encoder.h
#include <Encoder.h>
Encoder ComboDial(2, 3);

//---------------------------------------------

#include "Multi_Timer.h" // self-made timer library

//----------------------------------------------

/* Sleep library is copyright Microchip.

  https://w...content-available-to-author-only...u.org/avr-libc/user-manual/sleep_8h_source.html.

   Copyright (c) 2002, 2004 Theodore A. Roth
   Copyright (c) 2004, 2007, 2008 Eric B. Weddington
   Copyright (c) 2005, 2006, 2007 Joerg Wunsch
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

     Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

     Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

     Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
*/
#include <avr/sleep.h>
//
// ****  Defines to control runtime features  ****
//
#define POWER_SAVE  // enables processor power down feature
//
#define VERIFY_NEW_COMBO  // enables new combo verification code in state machine
//
#define DISPLAY_LOCK_CODE  // print stored code and entered code on serial monitor
//
// ================  Constants  ==============

const uint8_t INTPIN1 = 2;        // Rotary encoder interrupt on this Arduino Uno pin.
const uint8_t INTPIN2 = 3;        // Rotary encoder interrupt on this Arduino Uno pin.
const uint8_t ENCODER_PB = 5;     // Encoder pushbutton input
const uint8_t lockSolenoid = 7;      // +5--/\/\/- 330Ω -->|--DIO7
const uint8_t SET_TO_DEFAULT = 8;    // Pin held low at power-up resets to default combo - 221
const uint8_t modeLED = 9;           // +5--/\/\/- 330Ω -->|--DIO9
const uint8_t detentFlashLED = 12;   // +5--/\/\/- 330Ω -->|--DI12

const uint8_t MAX_TUMBLERS = 5;      // number of possible code entries
const uint8_t MAX_TUMBLER_CODE = 40; // max number of dial turns per code entry.
const unsigned int EEPROM_BASE = 20; // starting EEPROM address for code storage

const bool CW = true;                // Encoder direction
const bool CCW = !CW;                // booleans

const bool PB_PULSE = true;     // readEncoderPB argument
const bool PB_STATE =  false;   // readEncoderPB argument

// =================  Variables  ====================

uint8_t tumblerData[MAX_TUMBLERS];  // holds numbers entered for opening or combo setting
uint8_t lockCode[] {2, 2, 1, 0, 0}; // holds working combination to open lock.
//                                     221 is default for reset/troubleshooting
uint8_t newCode[MAX_TUMBLERS]; // temp storage of changed code
int8_t workingTumbler = -1;   // which code number is being entered
bool isEncoderDirectionCW;    // clockwise/counterclockwise indicator
bool isEncoderPBPressed;
bool telltale = false;    // debugging aid
bool isChangeComboFlag;
bool codeError; // Too many numbers entered

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

bool encoderTurned;  //  Signals encoder activity

// =============  Define state machine names  ============
enum : byte {
  FIRST_SCAN,
  INIT_ENTER,
  ENTER_COMBO,
  INIT_OPEN,
  OPEN_LOCK,
  INIT_NEW,
  NEW_COMBO,
  INIT_VERIFY,
  VERIFY_COMBO,
} lockState;

// Timers - from Multi_timer.h
OnDelay_tmr detentFlash_timer(20); // Blinks for visual indication of encoder movement
//                                    could be a buzzer instead, if desired.
//                                    or deleted entirely.
OnDelay_tmr solenoidON_timer(3000); // Actuate mechanical lock release
Flasher_tmr modeFlasher_timer(1000, 200); // 1 sec. period, 200ms on time
OnDelay_tmr NewCombo_timer(1000);   // Enter set mode when this times out
WatchDog_tmr activity_timer(15000); // Reset to idle or enter sleep mode if nothing happening on the encoder


// === S E T U P ===
//----------------------------------------------------------
void setup() {
  Serial.begin(115200);
  Serial.println(__FILE__);
  pinMode(SET_TO_DEFAULT, INPUT_PULLUP);
  if (digitalRead(SET_TO_DEFAULT) == 0) { // Optional load of default code at startup.
    EEPROM.put(EEPROM_BASE, lockCode);
    Serial.println("Default code set!");
  }
  EEPROM.get(EEPROM_BASE, lockCode); // retrieve current lock code to RAM

  pinMode(ENCODER_PB, INPUT_PULLUP);
  PCICR |= (1 << PCIE2); // enable interrupts on port D - for wakeup

  // assign LEDs - use onboard pin 13 for dial status indicator
  pinMode(detentFlashLED, OUTPUT);
  // external LED  - use as lock solenoid indicator
  pinMode(lockSolenoid, OUTPUT);
  digitalWrite(lockSolenoid, HIGH);
  // external LED  - use as mode indicator
  pinMode(modeLED, OUTPUT);
  digitalWrite(modeLED, HIGH);

  lockState = FIRST_SCAN;
  activity_timer.setEnable(true);
} // end of setup

//
//--------------------------------------------------------
void loop() {
  // If no activity cancel any combo setting modes and
  // return lock to INIT_ENTER state.
  // If power save option enabled, go to sleep.

  // Is it time to reset or go to sleep?
  if (activity_timer.getDone()) {
    isChangeComboFlag = false;
    lockState = INIT_ENTER; // cancel any leftover active modes
#ifdef POWER_SAVE
    goToSleep();
#endif
  }
  // Refresh the timers

  detentFlash_timer.update();
  solenoidON_timer.update(); // onDelay_tmr
  modeFlasher_timer.update();
  NewCombo_timer.update();
  activity_timer.update();  // no activity for X seconds initiates
  //                           state machine reset or sleep mode
  //
  dialMoved(); // Register dial rotation and direction
  encoderFlasher(); // Flash the onboard LED to verify movement

  //-----------------------------------------------------------
  switch (lockState) {
    /* This state machine guides us through the several phases of
      lock operation.
    */
    case FIRST_SCAN:

    /* Fallthrough is deliberate */

    case INIT_ENTER:
      clearTumblers();
      lockState = ENTER_COMBO;
      isChangeComboFlag = false;
      codeError = false;

    /* Fallthrough is deliberate */

    case ENTER_COMBO:
      getEntries(); // Record code inputs
      if (codeError) {
        Serial.print("code error\n");
        lockState = INIT_ENTER;
        break;
      }
      if (readEncoderPB(PB_PULSE)) { // User request to open lock
        lockState = INIT_OPEN;
      }
      break;

    case INIT_OPEN:
#ifdef DISPLAY_LOCK_CODE
      displayTumblers(); // display lock code & submitted code
#endif
      if (memcmp(lockCode, tumblerData, MAX_TUMBLERS) == 0) {
        // Correct combination entered, enable lock solenoid
        solenoidON_timer.setEnable(true);
        lockState = OPEN_LOCK;
      }
      else {
        lockState = INIT_ENTER; // wrong code, start over
      }
      break;

    case OPEN_LOCK:// Actuate the opening mechanism and begin
      //              testing for set new combo request
      NewCombo_timer.setEnable(!readEncoderPB(PB_STATE)); // Start waiting for set mode

      // If encoder PB pressed for one second while solenoid is on, set
      // isChangeComboFlag to enable prompt for new code
      if (NewCombo_timer.getDone() and solenoidON_timer.getRunning()) {
        isChangeComboFlag = true; // When button pressed for one second
      }
      if (solenoidON_timer.getDone()) { // Solenoid on time ends
        solenoidON_timer.setEnable(false);
        NewCombo_timer.setEnable(false);
        if (isChangeComboFlag) {
          lockState = INIT_NEW;
        }
        else lockState = INIT_ENTER;
        break;
      }
      else break;

    // User request to change lock code
    case INIT_NEW:
      clearTumblers();
      modeFlasher_timer.setOnTime(500);  // Set flash ratio
      lockState = NEW_COMBO;

    /* Fallthrough is deliberate */

    case NEW_COMBO:
      getEntries(); // Record new code inputs
      if (codeError) { // Too many codes entered, abort
        Serial.print("code error\n");
        lockState = INIT_ENTER;
        break;
      }
      if (readEncoderPB(PB_PULSE)) {
#ifdef VERIFY_NEW_COMBO
        lockState = INIT_VERIFY; // If verification option #defined
        break;
#endif
        // Set new combo, no verify
        setNewCombination(); // Xfr new code to storage
        lockState = INIT_ENTER; // Return to idle state
        break;
      }
      break;

    case INIT_VERIFY: // Prepare for new code verification
      // Copy first code to staging array
      memcpy(newCode, tumblerData, MAX_TUMBLERS); // Make a copy of the new code
      clearTumblers();
      modeFlasher_timer.setOnTime(950);  // Change flash ratio
      lockState = VERIFY_COMBO;

    /* Fallthrough is deliberate */

    case VERIFY_COMBO:
      getEntries(); // Collect verification code
      if (codeError) { //
        Serial.print("code error\n");
        lockState = INIT_ENTER;
        break;
      }
      if (readEncoderPB(PB_PULSE)) { // User requests new code verification
        if (memcmp(newCode, tumblerData, MAX_TUMBLERS) == 0) { // compare reentered code with previous
          //
          // Codes match - store to eeprom and also to lockCode.
          setNewCombination();
          lockState = INIT_ENTER; // Return to idle state
          break;
        }
        // Codes don't match, restart new code verification process
        else lockState = INIT_NEW;
      }
      break;
    default:
      lockState = INIT_ENTER;
      break;
  }  // End of lockState switch

  //------  O U T P U T S  ---------

  modeFlasher_timer.setEnable(isChangeComboFlag);
  if (modeFlasher_timer.getEnable()) {
    digitalWrite(modeLED, !modeFlasher_timer.getFlash());
  }
  else digitalWrite(modeLED, LOW); // Leave mode LED on to indicate wakefulness

  digitalWrite(lockSolenoid, !solenoidON_timer.getRunning()); // energize lock solenoid

  //  digitalWrite(detentFlashLED, detentFlash_timer.getRunning()); // LED on
  digitalWrite(detentFlashLED, !detentFlash_timer.getRunning()); // LED on
}
//  --------------  E N D  O F  L O O P  ==============
stdout
#include <stdio.h>

int main(void)
{
int i, j;
long dec;  /* ให้รับค่าอินพุทแบบ Long Integer - เลขจำนวนเต็มแบบยาว */
int bit[32];  /* จองพื้นที่ในการเก็บข้อมูลเลขฐาน 2 ลงใน Array */

    clrscr();  /* เคลียร์หน้าจอ */
    printf("Decimal Number : ");  /* แจ้งผู้ใช้เพื่อเตรียมป้อนค่าเลขฐาน 10 */
    scanf("%ld", &dec);  /* ต้องใช้ ld เพราะ Input มันเป็นแบบ Long Integer */
    i = 0;  /* กำหนดค่าเริ่มต้นของ Array */
    /* ทำตามที่ได้ออกแบบโปรแกรมเอาไว้ ... ยังไงยังงั้นเลย 55555+ */
    do {
        bit[i++] = dec % 2;  /* การหารเอาเศษ เพื่อให้เป็นคำตอบ */

        /* การหารทั่วไป แต่ตัวแปร dec ของภาษา C มันเป็น Integer หรือ เลขจำนวนเต็ม */
        /* ดังนั้นมันจึงตัดเศษ (หรือทศนิยม) ทิ้งไปโดยอัตโนมัติ */
        dec = dec / 2;

    } while (dec > 0);  /* เงื่อนไขที่ทำจนกระทั่ง dec = 0 ก็ออกจากวังวนเงื่อนไข */

    /* การแสดงผลของการแปลงเลขฐาน 10 เป็นเลขฐาน 2*/
    /* j = i - 1 และให้ j ลดค่าลงทีละ 1 ... ก็คืออ่านข้อมูลถอยหลังกลับเท่านั้นเองครับ */
    /* เพราะตัวแปรแบบ Array ในภาษา C มันเก็บข้อมูลจากซ้ายไปขวา */
    /* ทำให้ LSB มันไปอยู่ทางซ้าย ส่วน MSB มันไปอยู่ทางขวา */
    for(j = i - 1; j >= 0; j--)
        printf("%d", bit[j]);

printf("\n");
return 0;

}