This is one of a collection of pages which, together, attempt to show you "everything" about the Arduino's programming language.
There is a series of pages for you explaining the access control system in more detail, building it up along the lines of how it was originally developed.
There also is a page for you with more information about the Arduino programming course in general, and the way these pages are organized, if you want that.
Please visit my page about power browsing notes sometime.
This page, and the software it references, ©TK Boyd, 1/2010.
========
This page gives you a not-very-fully-explained Arduino "sketch", or program, for a device made up of an Arduino, two LEDs, two switches and an electro-mechanical strike plate (which can be simulated with an LED if you wish). The device presents a "challenge" in the form of the pattern of ons and offs on the two LEDs. If a user enters the right response, by pressing one or both of the buttons, the electro-mechanical strike plate is activated for a pre-set interval, and the user can open a door which was previously locked. Full sourcecode, with extensive in-line documentation.
The device presented here is a teaching example. If you came to this page looking for a "finished" product for installation in the real world, then please contact me? Producing something with a more complex set of challenges and right responses would not be difficult, I just haven't had time. Of course, many of you will be able to do that for yourself, I hope, based on what follows. Just add a few more LEDs and the code to implement whatever rule you want to use so that legitmate users know what the correct response is for any challenge. I'd be interested to hear from people who visit this page. Did you want an actual device for real-world use? Did you use what's presented here for that? Did you extend it? Etc! :-)
/*FEAa1AccContFinal: access control system- All singing, all dancing ver 1 Jan 2010 Final Stage edition of AccCont started 30 Dec 2009 Written during final stages of a nasty cold, and while strained back muscles (snow shoveling) were healing. << (I often include such "pointless" odds and ends here, because it is, to me, fun to be reminded of things later.) The VERSION is the version of this STAGE in the development of the program "FEAa1AccCont". This potentially confusing matter of "version" versus "stage" doesn't usually occur in my work, as early "stages" are overwritten as the programming progresses. It was only because FEAa1AccCont was being used as the basis of a tutorial for.... http://sheepdogguides.com/ ... that the need to introduce "stages" as well as "versions" arose. ============================================================== This program.... Requires 3 LEDs, two switches. One of the LEDs is standing in for an electromechanical strike plate Two of the LEDs present a "challenge" to the user If the user responds by holding down the correct combination of switches for a short while, the "lock" "opens" for a time, i.e. the LED standing for the lock switches on. (That LED could be replaced with an electro-mechanical strike plate very easily... and with no changes to the software.) The lock doesn't open WHEN the user presses the right combination on the switches... that would make trial and error too easy. Rather, the software looks at the switches at a pre-determined moment, and if they are properly set at that moment, the door opens... or at least the "lock" LED turns on for a set period. The correct answer will be as follows.... If LEDs show: Then press (x) or don't press (-).... Left LED Right LED Left button Right button off off - - (See futher notes below later) off on * * on off * - on on - * You don't have to memorize the table above. To know what buttons to press, use the following rule.... a) Complement the LED pattern. (That means that if an LED is on, then in the complement it is off. b) Treat what you have as a binary number. c) Add one to that binary number. d) Throw away any extra digit created by a "carry". Here are all four cases done for you by those steps.... 11 Starting with both LEDs on... 00 The complement 01 The result of adding 1 01 Starting with left off, right on... 10 The complement 11 The result of adding 1 10 Starting with left off, right on... 01 The complement 10 The result of adding 1 00 Starting with both LEDs off... 11 The complement Adding 1 would give you 100. Throw away the carried digit... leaves you with... 00... so press NEITHER key to answer the "off/off" challenge. (the program does not offer this challenge for two reasons... a) The device would look "off" if presenting zero as the challenge b) Users would have to remember to press AND QUICKLY RELEASE a button to answer the "zero" challenge. Without the "press and release", the countdown to "check buttons now" would never start. So, in the version presented here, there are only three challenges... making solution by trial and error almost possible. But it would be easy to add more LEDs, more buttons, which would making many more challenges to find answers for. (The exclusion the "zero" challenge was added between the 4th stage of the program's development and the final stage. The change was trivial, because the program was well structured. Can you find where the change was made?) */ const byte LEDlock=13;//Pin where lock would be connected. const byte LED1=12;//LED1 connected here (MS bit)... left hand LED const byte LED0=11;//LED0 connected here (LS bit) const byte bYel1=5;//pin yellow switch is on... left hand switch const byte bGrn0=4;//pin green switch is on // N.B.: "Yel1" is "wye-ee-ell-one" for YELlow switch, bit ONE byte bNumToShow; byte bNumShownPreviously=0; /*This variable above is part of the mechanism to ensure that the same challenge never arises twice in a row. The variable must be initialized, or there will be unpredictable results the first time @if (bNumToShow==bNumShownPreviously)" is encountered. As we we will never (see other) present the challenge defined by bNumToShow=0, we can safely initialize bNumShownPreviously to zero. (Even if it were initialized to something else, the code would "work", with the tiny "flaw" that the first challenge presented would never be whatever bNumShownPreviously was initialized to.*/ byte bFailuresInARow=0; void setup() { //Serial.begin(9600);//for debug work only pinMode(LEDlock,OUTPUT); pinMode(LED0,OUTPUT); pinMode(LED1,OUTPUT); pinMode(bGrn0,INPUT); pinMode(bYel1,INPUT); LockDoor(); bFailuresInARow=0; } void loop() { bNumToShow=bPickAChallenge(1,3,bNumShownPreviously); /*The previous line originally simply @bNumToShow=random(1,4)"... which set bNumToShow to 1,2 or 3. Don't include zero in the things that can be presented as the challenge, i.e. always use 1 or more for the first parameter. (See notes in header for the reasons for avoiding zero.)*/ bNumShownPreviously=bNumToShow;/*Update contents of bNumShownPreviously, ready for the next time we need to know what was most resently shown*/ showInBinary(bNumToShow);//Show it on LEDs. while ((!boSwitchPressed(bYel1))&&(!boSwitchPressed(bGrn0))) {;};//Wait for a switch to be pressed delay(600);//User must finish getting right buttons pressed during this delay /*Beware: If you think the program "isn't working", be careful that you are keeping the buttons of the correct response down long enough. You must keep them down until the access control device either says "Right" or "Wrong". If you enter the CORRECT code, but release the buttons too soon, your answer will still be treated as WRONG. */ if (boCorrectButtonsPressedNow(bNumToShow)) {SaySuccessAndOpenDoorDuringMessage();} else {SayFailed();}; randomSeed(BottomOfMillis());//Only NEEDED once, but it does no //harm to do it every time we pass through this loop. }//end of function "loop" boolean boSwitchPressed(byte bWhichSwitch) //In this version, the function does NOT wait for the switch //to be released. { boolean boAns=false;//What is in this will eventually be passed //back to the calling code. Assume switch NOT pressed, //for the moment. if (digitalRead(bWhichSwitch)==LOW) { delay(20);//Wait for bounces to pass boAns=true; }//end of "if..." return boAns; }//end of boSwitchPressed void SayFailed() { word wHowManyFlashCycles=6; //Th following multiple @if@s are a bit crude.. //but they Do The Job! if (bFailuresInARow>0) {wHowManyFlashCycles=12;}; if (bFailuresInARow>1) {wHowManyFlashCycles=40;}; if (bFailuresInARow>3) {wHowManyFlashCycles=60;}; if (bFailuresInARow>5) {wHowManyFlashCycles=100;}; //(Could be extended) FlashLEDs(wHowManyFlashCycles,60); if (bFailuresInARow<255) bFailuresInARow++; //Don't do the "add 1" to bFailuresInARow if it is 255, //because you will get overflow. A byte-type variable //can't hold 256. }//end of SayFailed void SaySuccessAndOpenDoorDuringMessage() //That name looks silly... but it will appear only //once, and the extra information will help you //be clear about what is done inside the function. { UnlockDoor(); FlashLEDs(6,200); LockDoor(); bFailuresInARow=0; }//end of SaySuccess... void setLEDs(byte bL1, byte bL0) //Easily extended for more LEDs { if (bL0==0) digitalWrite(LED0,LOW); else digitalWrite(LED0,HIGH); if (bL1==0) digitalWrite(LED1,LOW); else digitalWrite(LED1,HIGH); }//end of "setLEDs" void FlashLEDs(byte bReps,byte bRate) //Call this a number of times to cause the LEDs to //flash on-off-on-off. The number in bRate controls //how fast the LEDs flash. The number in bReps //determines how many flash cycles happen. { for (int i=0;i<bReps;i++) { setLEDs(1,1); delay(bRate); setLEDs(0,0); delay(bRate); }//end of "for..." }//end of FlashLEDs void LockDoor() //Simple at the moment... but it is //still worth "packaging" this in its //own function, in case the program //has to be adapted for an unusual //locking device. { digitalWrite(LEDlock,LOW); } void UnlockDoor() //See LokDoor rems. { digitalWrite(LEDlock,HIGH); } void showInBinary(byte bNum) /*Set LED1 on or off depending on left hand digit in binary representation of number in bNum... And set LED0 on or off depending on right hand digit in binary representation of number in bNum. For debug: send what's in bNum to the serial monitor, so we can check that what the LEDs are showing is right... (The int() stuff around bNum converts it from byte type data, which println can't handle, to an equivalent int type datum, which println IS okay with.) */ { //Serial.println(int(bNum)); //Set LED1 on or off... if ((bNum & B10)==B10) {digitalWrite(LED1,HIGH);} else {digitalWrite(LED1,LOW);}; //Set LED0 on or off... if ((bNum & 1)==1) {digitalWrite(LED0,HIGH);} else {digitalWrite(LED0,LOW);}; }//end of showInBinary boolean boCorrectButtonsPressedNow(byte bToDecode) /*Don't overlook the "bo" at the start of the name. This function is asking "ARE the correct buttons pressed now?" It isn't, for instance, establishing a state in which the right buttons ARE pressed. The byte in bToDecode is what is showing on the LEDs. The user must apply whatever rule the access control system is applying, and press the switches accordingly.*/ { boolean boReturn=false;//Assume for the time being that //user has NOT pressed the right switches. //Fetch and record the current state of the switches... //Yellow switch is left hand switch. boolean boStateOfYel1; boStateOfYel1=boSwitchPressed(bYel1); //"true" means switch is closed boolean boStateOfGrn0;//Create variable boStateOfGrn0=boSwitchPressed(bGrn0);//Fill it //Put the state of the LEDs into easily accessed booleans... boolean boStateOfLED1; if ((bToDecode&B10)==B10) {boStateOfLED1=true;} else {boStateOfLED1=false;} //"true" means LED on boolean boStateOfLED0; if ((bToDecode&1)==1) {boStateOfLED0=true;} else {boStateOfLED0=false;} /*Followiong for debug... Serial.print(int(bToDecode)); Serial.print(" "); serialdb("Yel",boStateOfYel1); serialdb("Grn",boStateOfGrn0); serialdb("LED1",boStateOfLED1); serialdb("LED0",boStateOfLED0); Serial.println(""); ... end of debug lines*/ /*Now look at various "correct" answers, and if any are present change boReturn to true. We could write some "clever" code to calculate the correct answers.... but I'm not clever enough to read that reliably, so I'm just going to do the job "the hard way". In each of the following blocks, the rem a the top will explain the LED challenge and the correct response with the following code: "off on * *" ... will mean if LEDs are "off" and "off", in that order, then the correct responmse is: both buttons pressed.*/ //off on * * if ( ((!boStateOfLED1)&&(boStateOfLED0)) && ((boStateOfYel1)&&(boStateOfGrn0)) ) {boReturn=true;}; //on off * - if ( ((boStateOfLED1)&&(!boStateOfLED0)) && ((boStateOfYel1)&&(!boStateOfGrn0)) ) {boReturn=true;}; //on on - * if ( ((boStateOfLED1)&&(boStateOfLED0)) && ((!boStateOfYel1)&&(boStateOfGrn0)) ) {boReturn=true;}; //off off: This challenge will not be issued. return boReturn; }//end of boCorrectButtonsPressedNow void serialdb(char sPrompt[8],boolean boVal) { Serial.print(sPrompt); if (boVal) {Serial.print(":true ");} else {Serial.print(":false ");}; } long BottomOfMillis() /*You don't have to understand everything here... But the more you master, the better off you will be. The MAIN thing to understand is that this function returns a number that depends on how long it has been since the processor was last reset. As that is measured in milliseconds, it is very, very unlikely that you will get the same number twice if you call this function after some delay which has been affected by human reponse times. This function returns the "bottom part" of whatever millis is returning at the time the function is called. What I mean by that, roughly speaking, is.... Millis is an "unsigned long" type datum. Among other tbings this means that it is made up of many digits. Slightly distorting things, just so I can discuss this in decimal terms, lets say that "millis" can be a number up to 999,999. And lets say that I want a number of no more than three digits. The "long()" funtion MAY be chopping unsigned long numbers down as follows.... 123,456 becomes 123 123,987 becomes 123... etc. I want something more like... 123,456 becomes 456 123,987 becomes 987.... ... and that, roughly speaking, is what this function does with the number it fetches from millis. It uses a bitwise AND to accomplish its task. The "0xFFFFFF" is just a quick way of writing a very big... but not too big!... number which in binary would be all ones. The decimal "equivalent", in essense, would be a number consisting of a lot of 9's*/ { long lngReturn; lngReturn=(millis()&0xFFFFFF); return lngReturn; }//end of BottomOfMillis byte bPickAChallenge(byte bLowInc, byte bHiInc, byte bPrev) /*Picks a number in the range bLowInc to bHighInc, INCLUSIVE... i.e. bPickAChallenge(1,3,0) will pick either 1,2 or 3. Note that this is slightly different from what the Ardino's built-in "random" does. "random(1,3)" will only return 1 or 2, not 3. The last parameter defines a number that may NOT be returned. It is used to provide a mechanism, which in conjunction with other code, allows the programmer to ensure that users do not see the same challenge twice in a row.*/ { byte bTmp; bHiInc=bHiInc+1;//to allow for the different range setting //conventions of my bPickAChallenge and the Arduino's "random()"; do {bTmp=random(bLowInc,bHiInc);} while(bTmp==bPrev); return bTmp; }//end of bPickAChallenge
That's it for now! Sorry... but I want to get the rest of the tutorial material converted from the raw text that it is at the moment to the html the web needs... but I thought I'd show you that this "under construction" site IS actually going somewhere... eventually!
Happy Arduino work!
The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
SPELL your search term properly. When I review search logs, it is amazing how many people ask the engine to search for something meaningless.
Why does this site cause a script to run? I have my web-traffic monitored for me by eXTReMe tracker. They offer a free tracker. If you want to try it, check out their site. And if there are Google ads on the page, they are run with scripts, too.
Here is how you can contact this page's editor. This page, and the software it references, ©TK Boyd, 1/2010.
Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org