Jump to content
43oh

Simple one-button combination lock


Recommended Posts

One of my first MSP430 projects here, this is a (very) simple one-button combination lock. At the moment it's just using the launchpad's single button and the two LEDs for lock status. You'd need to figure out what you were locking or unlocking and add code for that obviously.

It's all delay based, so it assumes you aren't doing anything overly crucial other than minding the button, or at least that the other tasks (if any) can be put on hold while the button is being used.

I'm sure there are "better" ways to do it, but this seems to work so far!

 

int counter;
byte wiggleRoom = 25;  //the amount + or - of the exact correct push length to pass a lock level, measured in 10ms steps.
byte lockLevel = 1;           //Stores what button press the lock is on
boolean open = false;
boolean buttonState;
int test1 = 100; //Number of 10ms steps the button should be held down for the first time
int test2 = 50;  //Same, for press two.
int test3 = 100; //And press 3. So for this setup, we press for 1s, let up, press for 0.5s, let up, press for 1s

void setup(){
 pinMode(P1_0, OUTPUT); 
 pinMode(P1_6, OUTPUT);
 pinMode(P1_3, INPUT_PULLUP);
}

void loop(){
 if (!open){  // normal state, red LED on, green LED off.
   digitalWrite(P1_0, HIGH);  //In this section you would shut the lock, whatever it was.
   digitalWrite(P1_6, LOW);
 }
 else{
   digitalWrite(P1_6, HIGH);  //Open the lock
   digitalWrite(P1_0, LOW);
   delay(3000);  //Wait a bit.
   lockLevel = 1;
   open = false;  //Set the lock to close next pass through the code.
                  //Might not be a bad idea to close the lock here too, really.
                  //That would prevent the button being held down keeping the lock open.
 }
 buttonState = digitalRead(P1_3);
 if (!buttonState){  //Button is pushed
   counter = 0;  //reset the counter, this is crucial.
   while (!buttonState){  //As long as the button is held down, this cycles.
     counter++;
     delay(10);  //10ms per cycle, record the number of cycles.
     buttonState = digitalRead(P1_3);  //We do need to get out eventually, when the button opens
   }

   switch (lockLevel){  //Now that we have a press duration, we need to find what level the lock is on
   case 1:  //If it's the first press, we start here.
     if (counter >= test1 - wiggleRoom && counter <=test1 + wiggleRoom){  
       lockLevel = 2;          //Adjust wiggleRoom to be the number of 10ms steps you want for wiggle room.      
       counter = 0;            //Right now we get +/- 250ms. 
       digitalWrite(P1_6, HIGH); //Flash the green LED if the push was successful. Mostly for debugging.
       delay(50);
       digitalWrite(P1_6, LOW);
     }
     else{
       lockLevel = 1;  //If the push is the wrong length, start over.
       counter = 0;
     }
     break;

   case 2:
     if (counter >= test2 - wiggleRoom && counter <=test2 + wiggleRoom){  //Second push, same deal.
       lockLevel = 3;
       counter = 0;
       digitalWrite(P1_6, HIGH);
       delay(50);
       digitalWrite(P1_6, LOW);
     }
     else{
       lockLevel = 1;  //If the push is the wrong length, start over from push 1.
       counter = 0;
     }
     break;

   case 3:

     if (counter >= test3 - wiggleRoom && counter <=test3 + wiggleRoom){
       open = true;  //Third correct push opens the lock.
       counter = 0;
     }
     else{
       lockLevel = 1;
       counter = 0;
     }
     break;
   }
 }
}

The next thing I'm inclined to work on is some learning, so that it remembers how long you hold the buttons down and adjusts the official "correct" number to match over time. The other thought is to time the delay between presses and use that as part of the combination, it would complicate the code fairly significantly but also increase security for a given time spent with the button.

I got the idea while contemplating vehicle security, my thought was to re-use a dash button as the input button and control the fuel pump relay (that wouldn't turn off after three seconds!). That would give you totally invisible anti-theft in theory.

I can't recommend it exactly, depending on how it's wired a dead MSP430 may render the vehicle suddenly stopped, not ideal!

 

Thoughts?

Link to post
Share on other sites

You could look into interrupt driven logic. This could be applied to the unlocking as well as the learning.

I haven't given this much bought but for the unlocking you could use combination of attachInterrupt() and mills(). The msp430 unfortunately does not have state change interrupt so you will have to flip RISING/FALLING interrupt inside the ISR by detaching and then attaching on the opposite edge. The counter for how long the button was pressed can be updated using mills() inside the ISR...

You could use the same logic for recording while in learning mode.

Link to post
Share on other sites

Thank you for the share, it helped my grasp the ability of using the one button for multiple purposes. For instance I was able to create a function where the press of a button adds to an index, while holding it longer than 1 seconds refreshes the index. Thanks again and good luck

Link to post
Share on other sites

It's grown somewhat, now it can be programmed (first, second and third push-time targets, plus the wiggle room) via that same one button.

It saves the combination to flash when it exits programming mode, and loads it from flash on boot.

 

The comments in the code aren't all accurate anymore, I haven't gone through to re-comment it yet.

Flash read/write is ripped out of the back end for the Energia flash library (which I could not convince to store anything but a string).

 

There are plenty of places for streamlining and general efficiency enhancement, but it works!

Next up is convincing it to turn power on to, and move, a servo for locking and unlocking a box.

 

#define FLASHCLOCK FSSEL1+((F_CPU/400000L) & 63); // SCLK
#define flash ((unsigned char*)0x1000)

boolean timeToFlash = false;
boolean waitACycle = false;
int counter;
byte lockLevel = 1;           //Stores what button press the lock is on
boolean open = false;
boolean buttonState;
byte password[4]; //Number of 10ms steps the button should be held down for the first time
//Same, for press two.
//And press 3. So for this setup, we press for 1s, let up, press for 0.5s, let up, press for 1s

void setup(){
 Serial.begin(9600);
 pinMode(P1_0, OUTPUT); 
 pinMode(P1_6, OUTPUT);
 pinMode(P1_3, INPUT_PULLUP);


 for (byte x = 0 ; x < 4 ; x++){
   password[x] = (*(flash+x));
   delay(10);
 }

 for (byte x = 0 ; x < 4 ; x++){
   Serial.println(password[x]);
   delay(10);
 }
}

void loop(){
 if (!open){  // normal state, red LED on, green LED off.
   digitalWrite(P1_0, HIGH);  //In this section you would shut the lock, whatever it was.
   digitalWrite(P1_6, LOW);
 }
 else{
   digitalWrite(P1_6, HIGH);  //Open the lock
   digitalWrite(P1_0, LOW);
   delay(3000);  //Wait a bit.
   lockLevel = 1;
   open = false;  //Set the lock to close next pass through the code.
   //Might not be a bad idea to close the lock here too, really.
   //That would prevent the button being held down keeping the lock open.
 }


 buttonState = digitalRead(P1_3);
 if (!buttonState){  //Button is pushed
   counter = 0;  //reset the counter, this is crucial.
   while (!buttonState){  //As long as the button is held down, this cycles.
     counter++;
     delay(10);  //10ms per cycle, record the number of cycles.
     buttonState = digitalRead(P1_3);  //We do need to get out eventually, when the button opens
   }
   waitACycle = false;
   if(counter > 500){
     Serial.println("Programming!");
     lockLevel = 8;
   }


   switch (lockLevel){  //Now that we have a press duration, we need to find what level the lock is on
   case 1:  //If it's the first press, we start here.
     if (counter >= password[0] - password[3] && counter <=password[0] + password[3]){  
       lockLevel = 2;          //Adjust password[4] to be the number of 10ms steps you want for wiggle room.      
       counter = 0;            //Right now we get +/- 250ms. 
       digitalWrite(P1_6, HIGH); //Flash the green LED if the push was successful. Mostly for debugging.
       delay(50);
       digitalWrite(P1_6, LOW);
     }
     else{
       lockLevel = 1;  //If the push is the wrong length, start over.
       counter = 0;
     }
     break;

   case 2:
     if (counter >= password[1] - password[3] && counter <=password[1] + password[3]){  //Second push, same deal.
       lockLevel = 3;
       counter = 0;
       digitalWrite(P1_6, HIGH);
       delay(50);
       digitalWrite(P1_6, LOW);
     }
     else{
       lockLevel = 1;  //If the push is the wrong length, start over from push 1.
       counter = 0;
     }
     break;

   case 3:

     if (counter >= password[2] - password[3] && counter <=password[2] + password[3]){
       open = true;  //Third correct push opens the lock.
       counter = 0;
     }
     else{
       lockLevel = 1;
       counter = 0;
     }
     break;


case 8:
lockLevel++;
Serial.println("Lock advanced to 9");
break;

case 9:
if (counter >100){
 lockLevel++;
 Serial.println("Lock advanced to 10");
}
break;


   case 10:

       password[0] = counter;
       lockLevel++;
       Serial.println(password[0]);


     break;

   case 11:
     password[1] = counter;
     lockLevel++;
     Serial.println(password[1]);
     break;

   case 12:
     password[2] = counter;
     lockLevel++;
     Serial.println(password[2]);
     break;

     case 13:
     password[3] = counter;
     lockLevel = 1;
     Serial.println(password[3]);
     timeToFlash = true;
     break;




   }
 }



 if(timeToFlash){
   disableWatchDog();        // Disable WDT
   FCTL2 = FWKEY+FLASHCLOCK; // SMCLK/2
   FCTL3 = FWKEY;            // Clear LOCK
   FCTL1 = FWKEY+ERASE;      //Enable segment erase
   *flash = 0;               // Dummy write, erase Segment
   FCTL3 = FWKEY+LOCK;       // Done, set LOCK
   enableWatchDog();         // Enable WDT


   disableWatchDog();        // Disable WDT
   FCTL2 = FWKEY+FLASHCLOCK; // SMCLK/2 
   FCTL3 = FWKEY;            // Clear LOCK
   FCTL1 = FWKEY+WRT;        // Enable write
   for (byte x = 0 ; x < 4 ; x++){
     *(flash+x) = (password[x]);
   }
   FCTL1 = FWKEY;            //Done. Clear WRT
   FCTL3 = FWKEY+LOCK;       // Set LOCK
   enableWatchDog();         // Enable WDT  
timeToFlash = false;
   Serial.println("Flashed!");


 }
}



Link to post
Share on other sites

Thanks!

I tried the library, it refused to write anything but strings. All my attempts at telling it to write anything else resulted in 210 being stored. Never did figure out why! It may well have been operator error. Probably was, really.

The flash reading and writing stuff is pulled out of the library (mspflash.cpp, to be specific) and changed slightly to suit my purposes.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...