Multiple pins within a function argument - c

Hello Stackoverflow users!
It's the line trafiksignal(redLed && yellowLed, 1000); I can't get to work, I'm trying to create a trafic signal using a function, and my idea was to use this picture as a guide: http://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Traffic_lights_4_states.png/220px-Traffic_lights_4_states.png
(can't post pictures due to rep < 10)
My code: http://pastebin.com/MTGsYeXs
/*
* #Author: Kristian Nymann
* #Date: 2014-09-25 22:46:39
* #Last Modified by: Kristian Nymann
* #Last Modified time: 2014-09-25 23:23:19
* #Description: Lav et program der får de tre lysdioder til at skifte som et trafiklys. Du kan brugeprogrammet "Blink" som eksempel.
*/
const byte greenLed = 2;
const byte yellowLed = 3;
const byte redLed = 4;
void setup() {
pinMode(greenLed, OUTPUT);
pinMode(yellowLed, OUTPUT);
pinMode(redLed, OUTPUT);
}
void loop() {
trafiksignal(redLed, 3000);
trafiksignal(redLed && yellowLed, 1000);
trafiksignal(greenLed, 3000);
trafiksignal(yellowLed, 1000);
}
void trafiksignal(byte pin, unsigned int duration)
{
digitalWrite(pin, HIGH);
delay(duration);
digitalWrite(pin, LOW);
}
Right now what's going on is:
Red led turns on for 3 sec.. then green led turns on for 3 sec, then yellow turns on for 1 sec..
So how can I make the yellow and red Led turn on at the same time? (why doesn't trafiksignal(redLed && yellowLed, 1000); work?)

As far as I am aware && in C is for logical comparison only.
trafiksignal(redLed && yellowLed, 1000);
What this line is basically doing is checking if redLed and yellowLed are true or false, and if they're both true it will send a 1 or if either are false it will send a 0. Since both of them are not 0 it should treat them as both true so you're actually most likely telling pin 1 to go high for 1 second instead of pin 3 and 4.
A few simple work around would be to either create a separate function for turning the red and yellow light off or putting a quick if clause inside trafiksignal functio. Bellow is a quick a dirty if statement to add to trafiksignal that should get you up and running with your current code.
if (pin == 1) {
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
delay(duration)
digitalWrite(3, LOW);
digitalWrite(4, LOW);
}
else {
digitalWrite(pin, HIGH);
delay(duration);
digitalWrite(pin, LOW);
}
Typed the code from my ipad so I would proof read it before copy and pasting.
edited from my computer:
A better solution would be to send the pins to the function as an array, i'm not super experienced in plain C so I'm not sure if what i've done bellow is 100% accurate but it should be fairly close.
const byte greenLed = 2;
const byte yellowLed = 3;
const byte redLed = 4;
const byte redYellow[2] = {redLed, yellowLed} // create an array of 2 pins
void setup() {
pinMode(greenLed, OUTPUT);
pinMode(yellowLed, OUTPUT);
pinMode(redLed, OUTPUT);
}
void loop() {
// the middle number is the number of LEDs the function will need to control.
trafiksignal(redLed, 1, 3000);
trafiksignal(redYellow, 2, 1000);
trafiksignal(greenLed, 1, 3000);
trafiksignal(yellowLed, 1, 1000);
}
void trafiksignal(byte pin[], unsigned int numberOfLeds, unsigned int duration)
{
for (int i =0; i < numberOfLeds; ++i {
digitalWrite(pin[i], HIGH);
}
delay(duration);
for (int i = 0; i < numberOfLeds; ++i) {
digitalWrite(pin[i], LOW);
}
}

Related

Using Pushbutton to toggle a blinking LED

I'm currently working on a mini project to have my pushbutton toggle a blinking LED, meaning: when I press the button, I want the LED to keep blinking until I press the button again.
I managed to toggle the LED without blinking (when I press the button, the LED lights up, and when I press the button again, the LED switches off, but no blinking).
I've appended my code below, and my logic is based on tracking the current button state and the previous button state, which I think is the correct logic (but if I'm wrong please criticise/correct me!!) to cause a change in LED output state, so I'm not sure what's wrong with my thinking/code. The problem I have now is that the LED will only blink twice (according to the line of code I've written in void loop) but it does not keep blinking forever until I want it to stop (what can I do to execute this?)
const int ledPin = 8;
const int buttonPin = 7;
int buttonState;
int ledState = HIGH;
int lastbuttonState = LOW;
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState != lastbuttonState) {
if (ledState == HIGH) {
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
} else {
digitalWrite(ledPin, LOW);
}
}
lastbuttonState = buttonState;
}
Will be extremely grateful if anyone can point out any mistakes!! Thank you!
The most important idea here is use the button to toggle blinkState. When the state indicate the LED should be blinking, use millis() get the current time and calculate when ledState should be toggled. When enough time has passed, calculate the next time, toggle ledState, and loop back.
Note I am using the bounce2 library to debounce the button. You could do button debouncing with timer as well.
#include <Bounce2.h>
#define LED_PIN 13
#define BUTTON_PIN 2
#define DEBOUNCE_DELAY 100
#define BLINK_DELAY 200
uint32_t nextMillis = 0;
bool blinkState = 0, ledState = 0, previousLedState = 0;
Bounce b = Bounce();
void setup() {
Serial.begin(9600);
delay(1000);
pinMode(LED_PIN, OUTPUT);
b.attach(BUTTON_PIN, INPUT_PULLUP);
b.interval(DEBOUNCE_DELAY);
}
void loop() {
b.update();
if(b.fell()){
blinkState = !blinkState;
}
if (blinkState){
if (millis() > nextMillis){
nextMillis = millis() + BLINK_DELAY;
ledState = !ledState;
}
} else {
ledState = 0;
}
//only write to pin if ledState changed
if (ledState != previousLedState){
digitalWrite(LED_PIN, ledState);
previousLedState = ledState;
}
}
This part
(buttonState != lastbuttonState)
is logically incorrect as the state of the push button will immediately become false when you press the push button once and release it. The last state of the push button would be FALSE as per the logic that you have written.
Another way could be to implement would be to increment an counter variable on pressing the push button once and start blinking when the counter value is odd and stop blinking when the counter value is even.
const int ledPin = 8;
const int buttonPin = 7;
int buttonState=HIGH,reading;
int ledState = LOW;
int lastbuttonState = HIGH,icounter;
unsigned long latchMillis,lastDebounceTime;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
unsigned long blinkdelay = 1000,debounceDelay=1;
/***Debounce logic for the input ***/
reading = digitalRead(buttonPin); //Check for the change in PB
if (reading != lastbuttonState)
{
lastDebounceTime = millis(); // reset the debouncing timer
}
lastbuttonState = reading; //Update previous button state
if ((millis()-lastDebounceTime) > debounceDelay) //If debounce has elapsed then accept the input
{
if (buttonState != lastbuttonState)
{
if (buttonState == LOW)
{
icounter = icounter +1; //Increment counter on every rising edge of PB
latchMillis = millis(); //Latch the current millis
}
buttonState = lastbuttonState;
}
}
if ((icounter%2)!= 0)
{
if ((millis() - latchMillis) > blinkdelay)
{
ledState = !ledState;
latchMillis = millis();
digitalWrite(ledPin,ledState);
}
}
else
{
digitalWrite(ledPin, LOW);
}
}
`

Issues with using arrays C++

Sorry to bother you but I have been having issues getting my a motor array to output in this code here.
// initialise motors
// Motor 1
//int in1 = 4;
//int in2 = 2 ;
// Motor 2
//int in3 = 8;
//int in4 = 7;
// Motor 3
//int in5 = 12;
//int in6 = 13;
// Motor 4
//int in7 = 9;
//int in8 = 10;
// Array of PWM's
int thisPin = 0;
uint8_t pwms[] = {3,5,6,11};
byte numberPwms = 4;
// Array for output channels
// Motor 1 (4 = High, 2 = Low)
// Motor 2 (8 = High, 7 = Low)
// Motor 3 (12 = High, 13 = Low)
// Motor 4 (9 = High, 10 = Low)
int mtrpin = 0;
uint8_t motors[] = {4,2,8,7,12,13,9,10};
byte motorPin = 8;
void setup()
{
// pinMode(in1, OUTPUT);
// pinMode(in2, OUTPUT);
// pinMode(in3, OUTPUT);
// pinMode(in4, OUTPUT);
// pinMode(in5, OUTPUT);
// pinMode(in6, OUTPUT);
// pinMode(in7, OUTPUT);
// pinMode(in8, OUTPUT);
for (pwmPin = 0; pwmPin < numberPwms; pwmPin++){
for (mtrPin = 0; mtrpin < motorPin; mtrPin++){
pinMode(motors[mtrPin], OUTPUT);
pinMode(pwms[pwmPin], OUTPUT);
};
};
}
void motorLoop(){
// setting the direction to turn and speed
// digitalWrite(in1, HIGH); // Motor 2
// digitalWrite(in2, LOW);
// digitalWrite(in3, HIGH); // Motor 2
// digitalWrite(in4, LOW);
// digitalWrite(in5, HIGH); // Motor 3
// digitalWrite(in6, LOW);
// digitalWrite(in7, HIGH); // Motor 4
// digitalWrite(in8, LOW);
// Set the speed for the Motors
for(int pwmPin = 0; pwmPin < numberPwms; pwmPin++){
for (mtrPin = 0; mtrpin < motorPin; mtrPin++){
pinMode(motors[mtrPin], LOW);
analogWrite(pwms[pwmPin], 200);
};
};
};
void loop()
{
motorLoop();
delay(500);
}
I have managed to get the initial call to work but I am now turning it all into arrays.
I have managed to get it to work for the PWMs but now after adding the motors array it has stopped working and gives this error message.
In Function 'Void setup()';
41:8: error: 'pwmPin' was not declared in this scope
42:11: error: 'mtrPin' was not declared in this scope
In function 'void motorLoop()';
74:8: error: 'mtrPin' was not declare in this scope.
I know the error will probably be really simple but I can't find to save my life.
Also the for loops have been called as they are now and separate and I am still getting the same errors.
You can see this code at https://www.tinkercad.com/things/fFQKRTjhDrb-motor-initial-turn/editel.
Any help on this would be greatly appreciated :)
In Function 'Void setup()'; 41:8: error: 'pwmPin' was not declared in this scope 42:11: error: 'mtrPin' was not declared in this scope In function 'void motorLoop()'; 74:8: error: 'mtrPin' was not declare in this scope.
As the compiler says: mtrPin has not been declared, and yet, you are using it.
Declarations introduce names in a program, like the name of your variable mtrPin. Other examples are namespaces, functions and classes. A name must be declared before it can be used. You cannot refer to a name which is declared later in the code.
int mtrPin; // this is a (uninitialized) declaration -> mtrPin can be used
int mtrPin { 0 }; // this is a (value) initialization -> mtrPin can be used

Why won't my autoscan scan back and forth?

I'm currently working on a project with a microchip max32 board in C. I need help with a small portion. Here's the portion I'm working on:
if (motor_step == 0){
auto_direction = 1;
}
if (motor_step == step_max){
auto_direction = 0;
}
if(auto_direction == 0){
indexM = indexM + 1;
motor_step++;
}
if(auto_direction == 1) {
indexM = indexM - 1;
motor_step--;
}
Basically my teacher gave us most of the code to work with and told us to figure out the auto-scan portion. If you scroll down, you will see where I need to input my own code. On the project, we control the motor that is holding a laser pointer. The auto-scan is basically supposed to scan up and down and go on continuously. After 16 steps the motor should stop and go the opposite direction(+ for up and - for down.) The problem that I'm having is that when I run my code, the auto-scan is not stopping. If we run the code, the laser will either continue to scan upwards or downwards(depending on what it was doing the last time it turned on) but doesn't stop and do the opposite after 16 steps.
Thanks in advance and hope I was somewhat clear. Towards the end is where you will see what code I'm changing. Here is the remainder of my code for reference:
// EX03_Starter_StepperMotorControl_REVB
// 10-3-2013
//------------------------------------------------
// Status:
// * REVB Starter Template created
//------------------------------------------------
// Author: Coach
// Target Hardware: Digilent chipKITMax32 board + Basic I/O Board
// Development Platform: mpide-0023-windows-20120903
//---------------------------------------------------
// Objective: Provide control logic for stepper motor control
// *** This code can be adapted for chipKITMax32 or Arduino Nano
// Stepper Motor Control Logic:
// ============================
// Stepper Motor Driver keep track of indexM pointing to stepper Motor Drive Table:
// IndexM D3 D2 D1 D0 Hex Value
// ===== == == == == =========
// 0 0 0 0 1 1
// 1 0 1 0 0 4
// 2 0 0 1 0 2
// 3 1 0 0 0 8
// * Wraps around logic is provided by : indexM = indexM & 3
// * To move clockwise, indexM = indexM + 1
// * To move counter clockwise, indexM = indexM - 1
//----------------------------------------
// I/O Assignments:
// ===============
// SW1: Run (SW1 = 0: Stop / SW1 = 1: Run)
// SW2: Direction (SW2= 0: Clockwise/ SW2 = 1: CounterClockWise)
// SW3: Autoscan (SW3 = 0: Manual / SW3 = 1: Autoscan )
// SW4: Timing Control (SW4 = 0: Development, SW4=1: Real)
// LD1: Run Indicator
// LD2: Direction Indicator
// LD3: spare
// LD4: spare
// Simulation:
// LD5: Motor Coil D0
// LD6: Motor Coil D1
// LD7: Motor Coil D2
// LD8: Motor Coil D3
// Physical Motor Drive:
// MotorCoil_0 : pin0
// MotorCoil_1 : pin1
// MotorCoil_2 : pin2
// MotorCoil_3 : pin3
//------------------------------------------
// Functional requirements:
// =======================
// 0. Reflect SW1,SW2,SW3,SW4 to LD1,LD2,LD3,LD4
// 1. When the system is not running (Run = 0), disable all outputs
// 2. When the system is running (Run = 1), read Direction switch
// 2.1 If Direction ==0, run motor clockwise
// 2.2 If Direction ==1, run motor counter clockwise
// 3. Auto scan feature:(Note: to be designed & coded by you)
// SW3: Autoscan (SW3 = 0: Manual / SW3 = 1: Autoscan )
// When in manual mode, execute function 2.1 & 2.2
// When in autoscan mode: stepper motor moves up 16 steps then moves down 16 steps, repeats continuously
// 4. Timing Control (SW4) input:
// 4.1 When in Development mode (SW4 == 0): motorTime = 500 (ms)
// 4.2 When in Real mode (SW4 == 1): motorTime = 10 (ms)
// =======================================================
// Tasks:
// 0. Review "How Stepper Motor Works" power point
// 1. Read & understand this sample code
// 2. Run & verify that it works as written
// 3. *** Design your Autoscan logic using Flow Chart, review with Coach
// 4. *** Add Code for Your Design prescribed in item 3 above
// 5. Verify your code works as prescribed, troubleshoot & fix it as required
// 6. *** Provide optical report to Coach
// 7. *** Verify at System Bench Test with Laser pointer Assembly
//==========================================================================
// set pin numbers:
const int BTN1 = 4; // the number of the pushbutton pin
const int BTN2 = 78; //***** Note: label on the board is for Uno32, this is MAX32, see MAX32 Reference Manual
const int ledPin = 13; // System Operational LED
const int LD1 = 70; //***** Note: label on the board is for Uno32, this is MAX32, see MAX32 Reference Manual
const int LD2 = 71; // ******** LD pins are corrected here.
const int LD3 = 72;
const int LD4 = 73;
const int LD5 = 74;
const int LD6 = 75;
const int LD7 = 76;
const int LD8 = 77;
const int SW1 = 2;
const int SW2 = 7;
const int SW3 = 8;
const int SW4 = 79; //***** Note: label on the I/O board is 35 for uno32 only
// variables:
int BTN1_state = 0; // variable for reading the pushbutton status
int SW1_state = 0;
int SW2_state = 0;
int SW3_state = 0;
int SW4_state = 0;
int motorTime = 1000; // 1000 ms = 1s
// Initial Stepper Motor Coil pattern
int indexM =0;
int step_max = 16;
int motor_step = 0;
int auto_direction = 0;
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
pinMode(LD1, OUTPUT);
pinMode(LD2, OUTPUT);
pinMode(LD3, OUTPUT);
pinMode(LD4, OUTPUT);
pinMode(LD5, OUTPUT);
pinMode(LD6, OUTPUT);
pinMode(LD7, OUTPUT);
pinMode(LD8, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(BTN1, INPUT);
// initialize switches as inputs:
pinMode(SW1, INPUT);
pinMode(SW2, INPUT);
pinMode(SW3, INPUT);
pinMode(SW4, INPUT);
// Turn OFF all LEDs
digitalWrite(LD1, LOW);
digitalWrite(LD2, LOW);
digitalWrite(LD3, LOW);
digitalWrite(LD4, LOW);
// Initial Stepper Motor Coil pattern
digitalWrite(LD5, LOW);
digitalWrite(LD6, LOW);
digitalWrite(LD7, LOW);
digitalWrite(LD8, LOW);
} // end setup()
void loop(){
// System Operation LED ON:
digitalWrite(ledPin, HIGH);
delay(10); // wait for x ms
//----------------------------------------------
// read switches inputs:
SW1_state = digitalRead(SW1);
SW2_state = digitalRead(SW2);
SW3_state = digitalRead(SW3);
SW4_state = digitalRead(SW4);
// Echo switches to LED Indicators:
if (SW1_state == HIGH) {digitalWrite(LD1, HIGH); }
if (SW1_state == LOW) {digitalWrite(LD1, LOW); }
if (SW2_state == HIGH) {digitalWrite(LD2, HIGH); }
if (SW2_state == LOW) {digitalWrite(LD2, LOW); }
if (SW3_state == HIGH) {digitalWrite(LD3, HIGH); }
if (SW3_state == LOW) {digitalWrite(LD3, LOW); }
if (SW4_state == HIGH) {digitalWrite(LD4, HIGH); }
if (SW4_state == LOW) {digitalWrite(LD4, LOW); }
// Arm Logic:
if (SW1_state == LOW) {
// system NOT running:
digitalWrite(LD5, LOW);
digitalWrite(LD6, LOW);
digitalWrite(LD7, LOW);
digitalWrite(LD8, LOW);
} // end if (SW1_State == LOW)
//==============================
if (SW1_state == HIGH) { // system is running
if (SW3_state == LOW) // manual mode
{
// Direction control:
// 2.1 If Direction ==0, run motor clockwise
if (SW2_state == LOW) {indexM = indexM + 1; }
// 2.2 If Direction ==1, run motor counter clockwise
if (SW2_state == HIGH) {indexM = indexM - 1; }
} // end if (SW3_state == LOW)
if (SW3_state == HIGH) // autoscan mode
{
// *** Add your Autoscan codes here *** <---------This is where my code goes.
} // end if (SW3_state == HIGH)
// Timing Control / Speed select processing:
if (SW4_state == LOW) // Development (slow)
{
motorTime = 500; // unit in ms
}
if (SW4_state == HIGH) // Running real motor (fast)
{
motorTime = 10; // unit in ms
}
//=========== Stepper Motor Driver ========
indexM = indexM & 3; // wraps-around logic
switch (indexM)
{
case 0:
digitalWrite(LD5, HIGH);
digitalWrite(LD6, LOW);
digitalWrite(LD7, LOW);
digitalWrite(LD8, LOW);
break;
case 1:
digitalWrite(LD5, LOW);
digitalWrite(LD6, LOW);
digitalWrite(LD7, HIGH);
digitalWrite(LD8, LOW);
break;
case 2:
digitalWrite(LD5, LOW);
digitalWrite(LD6, HIGH);
digitalWrite(LD7, LOW);
digitalWrite(LD8, LOW);
break;
case 3:
digitalWrite(LD5, LOW);
digitalWrite(LD6, LOW);
digitalWrite(LD7, LOW);
digitalWrite(LD8, HIGH);
break;
} // End Switch (indexM)
} // end if (SW1_state == HIGH)
//------------------------------------
// System Operation LED OFF:
digitalWrite(ledPin, LOW);
delay(motorTime); // wait for motorTime ms
} // end loop
//=============================
So far this is what I have come up with:
The problem is with the last 2 if statements; if (auto_direction = 0) and if (auto_direction = 1) will set auto_direction to 0 or 1, not compare against it. You need to use == like you did in the first 2 if statments.

Run the loop when values change - Arduino

I am measuring light, temperature and humidity on a arduino uno, and have programmed the loop to run every minute. Monitoring the values on the serial monitor.
However, what i would like is the code to run once to get the values, then wait, or pause, until one of the values change, and then output this on the serial monitor.
I want to get informed of changes in the sensors immediately, not wait for a minute for the loop to run. Is there a way to do this?
Thanks.
So I would need to add an if/else function to the following code?
int lightPin = A5;
int lightok = 9;
int lighthigh = 10;
void setup()
{
Serial.begin(9600);
pinMode(lightok,OUTPUT);
pinMode(lighthigh,OUTPUT);
}
void loop()
{
delay(600000);
int lightlevel = analogRead(lightPin);
lightlevel = map(lightlevel, 0, 1023, 0, 255);
lightlevel = constrain(lightlevel, 0, 255);
Serial.print("Lightlevel: ");
Serial.println(lightlevel);
//led control for light levels
if (lightlevel < 15 || lightlevel > 125) {
digitalWrite(lighthigh, HIGH);
digitalWrite(lightok, LOW);
} else {
digitalWrite(lighthigh, LOW);
digitalWrite(lightok, HIGH);
}
}
You have to ways of doing this:
you can run your loop faster, say every second or half-second and only output a value to serial if the value is different from the previous one or if the difference is bigger than a specific value
you can setup interrupts run code only when something happens. But I need to know the sensor you are using to be more specific on this one.
Hope this helps! :)
EDIT
Okay, I'd do something like that :
int lightSensorPin = A5;
int lightOkPin = 9;
int lightHighPin = 10;
int currentLightLevel = 0;
int previousLightLevel = 0;
int delta = 0;
int deltaValue = 10; // needs to be changed to suit your needs
void setup() {
Serial.begin(9600);
pinMode(lightOkPin, OUTPUT);
pinMode(lightHighPin, OUTPUT);
}
void loop() {
currentLightLevel = analogRead(lightSensorPin); //read the sensor
currentLightLevel = map(currentLightLevel, 0, 1023, 0, 255); // map the value
currentLightLevel = constrain(currentLightLevel, 0, 255); // not sure this is useful
delta = abs(previousLightLevel - currentLightLevel); // calculate the absolute value of the difference btw privous and current light value
if (delta >= deltaValue) { // if the difference is higher than a threshold
Serial.print("currentLightLevel: ");
Serial.println(currentLightLevel);
//led control for light levels
if (currentLightLevel < 15 || currentLightLevel > 125) {
digitalWrite(lightHighPin, HIGH);
digitalWrite(lightOkPin, LOW);
}
else {
digitalWrite(lightHighPin, LOW);
digitalWrite(lightOkPin, HIGH);
}
}
previousLightLevel = currentLightLevel;
delay(1000);
}

Identified amplitude in secret knock project

I'm doing project like this http://grathio.com/2013/11/new-old-project-secret-knock-drawer-lock/ The project only process time interval between knock, and I try to add amplitude as input, if I just use the code from the link above it works fine but I want to add amplitude (loud and soft knock) as input too. But my code still have problem, it can't recognise knock and the LED acting weird. I need to recognise knock time interval and knock amplitude. Comment 'This is what I add' is the code that I add myself, but the code doesn't work. Could anyone tell me what is wrong with my code?
Below is the code:
#include <EEPROM.h>
const byte eepromValid = 123; // If the first byte in eeprom is this then the data is valid.
/*Pin definitions*/
const int programButton = 0; // Record A New Knock button.
const int ledPin = 1; // The built in LED
const int knockSensor = 1; // (Analog 1) for using the piezo as an input device. (aka knock sensor)
const int audioOut = 2; // (Digial 2) for using the peizo as an output device. (Thing that goes beep.)
const int lockPin = 3; // The pin that activates the solenoid lock.
/*Tuning constants. Changing the values below changes the behavior of the device.*/
int threshold = 3; // Minimum signal from the piezo to register as a knock. Higher = less sensitive. Typical values 1 - 10
const int rejectValue = 25; // If an individual knock is off by this percentage of a knock we don't unlock. Typical values 10-30
const int averageRejectValue = 15; // If the average timing of all the knocks is off by this percent we don't unlock. Typical values 5-20
const int knockFadeTime = 150; // Milliseconds we allow a knock to fade before we listen for another one. (Debounce timer.)
const int lockOperateTime = 2500; // Milliseconds that we operate the lock solenoid latch before releasing it.
const int maximumKnocks = 20; // Maximum number of knocks to listen for.
const int maximumAmp = 20; // This is what i add
const int ampLoud = 10; // This is what i add
const int ampSoft = 20; // This is what i add
const int knockComplete = 1200; // Longest time to wait for a knock before we assume that it's finished. (milliseconds)
byte secretCode[maximumKnocks] = {50, 25, 25, 50, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Initial setup: "Shave and a Hair Cut, two bits."
byte secretAmp[maximumAmp] = {10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // This is what i add
int knockReadings[maximumKnocks]; // When someone knocks this array fills with the delays between knocks.
int ampReadings[maximumAmp]; // This is what i add
int knockSensorValue = 0; // Last reading of the knock sensor.
int amp = 0; // This is what i add
boolean programModeActive = false; // True if we're trying to program a new knock.
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(lockPin, OUTPUT);
readSecretKnock(); // Load the secret knock (if any) from EEPROM.
doorUnlock(500); // Unlock the door for a bit when we power up. For system check and to allow a way in if the key is forgotten.
delay(500); // This delay is here because the solenoid lock returning to place can otherwise trigger and inadvertent knock.
}
void loop() {
// Listen for any knock at all.
knockSensorValue = analogRead(knockSensor);
if (digitalRead(programButton) == HIGH){ // is the program button pressed?
delay(100); // Cheap debounce.
if (digitalRead(programButton) == HIGH){
if (programModeActive == false){ // If we're not in programming mode, turn it on.
programModeActive = true; // Remember we're in programming mode.
digitalWrite(ledPin, HIGH); // Turn on the red light too so the user knows we're programming.
chirp(500, 1500); // And play a tone in case the user can't see the LED.
chirp(500, 1000);
} else { // If we are in programing mode, turn it off.
programModeActive = false;
digitalWrite(ledPin, LOW);
chirp(500, 1000); // Turn off the programming LED and play a sad note.
chirp(500, 1500);
delay(500);
}
while (digitalRead(programButton) == HIGH){
delay(10); // Hang around until the button is released.
}
}
delay(250); // Another cheap debounce. Longer because releasing the button can sometimes be sensed as a knock.
}
if (knockSensorValue >= threshold){
if (programModeActive == true){ // Blink the LED when we sense a knock.
digitalWrite(ledPin, LOW);
} else {
digitalWrite(ledPin, HIGH);
}
knockDelay();
if (programModeActive == true){ // Un-blink the LED.
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
listenToSecretKnock(); // We have our first knock. Go and see what other knocks are in store...
}
}
// Records the timing of knocks.
void listenToSecretKnock(){
int i = 0;
int j = 0;
// First reset the listening array.
for (i=0; i < maximumKnocks; i++){
knockReadings[i] = 0;
}
for (j=0; j < maximumAmp; j++){ // This is what i add
ampReadings[j] = 0;
}
int currentKnockNumber = 0; // Position counter for the array.
int currentAmpNumber = 0;
int startTime = millis(); // Reference for when this knock started.
int now = millis();
do { // Listen for the next knock or wait for it to timeout.
knockSensorValue = analogRead(knockSensor);
//===========================================================================================================
if(knockSensorValue >=3 && knockSensorValue <=75){ // This is what i add
amp = ampSoft; // This is what i add
}
if(knockSensorValue >=76){ // This is what i add
amp = ampLoud; // This is what i add
}
ampReadings[currentAmpNumber] = amp; // This is what i add
currentAmpNumber++; // This is what i add
//===========================================================================================================
if (knockSensorValue >= threshold){ // Here's another knock. Save the time between knocks.
now=millis();
knockReadings[currentKnockNumber] = now - startTime;
currentKnockNumber ++;
startTime = now;
if (programModeActive==true){ // Blink the LED when we sense a knock.
digitalWrite(ledPin, LOW);
} else {
digitalWrite(ledPin, HIGH);
}
knockDelay();
if (programModeActive == true){ // Un-blink the LED.
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
now = millis();
// Stop listening if there are too many knocks or there is too much time between knocks.
} while ((now-startTime < knockComplete) && (currentKnockNumber < maximumKnocks));
//we've got our knock recorded, lets see if it's valid
if (programModeActive == false){ // Only do this if we're not recording a new knock.
if (validateKnock() == true){
doorUnlock(lockOperateTime);
} else {
// knock is invalid. Blink the LED as a warning to others.
for (i=0; i < 4; i++){
digitalWrite(ledPin, HIGH);
delay(50);
digitalWrite(ledPin, LOW);
delay(50);
}
}
} else { // If we're in programming mode we still validate the lock because it makes some numbers we need, we just don't do anything with the return.
validateKnock();
}
}
// Unlocks the door.
void doorUnlock(int delayTime){
digitalWrite(ledPin, HIGH);
digitalWrite(lockPin, HIGH);
delay(delayTime);
digitalWrite(lockPin, LOW);
digitalWrite(ledPin, LOW);
delay(500); // This delay is here because releasing the latch can cause a vibration that will be sensed as a knock.
}
// Checks to see if our knock matches the secret.
// Returns true if it's a good knock, false if it's not.
boolean validateKnock(){
int i = 0;
int currentKnockCount = 0;
int secretKnockCount = 0;
int currentAmpCount = 0; // This is what i add
int secretAmpCount = 0; // This is what i add
int maxKnockInterval = 0; // We use this later to normalize the times.
for (i=0;i<maximumKnocks;i++){
if (knockReadings[i] > 0){
currentKnockCount++;
}
if (secretCode[i] > 0){
secretKnockCount++;
}
if (ampReadings[i] > 0){ // This is what i add
currentAmpCount++; // This is what i add
}
if (secretAmp[i] > 0){ // This is what i add
secretAmpCount++; // This is what i add
}
if (knockReadings[i] > maxKnockInterval){ // Collect normalization data while we're looping.
maxKnockInterval = knockReadings[i];
}
}
// If we're recording a new knock, save the info and get out of here.
if (programModeActive == true){
for (i=0; i < maximumKnocks; i++){ // Normalize the time between knocks. (the longest time = 100)
secretCode[i] = map(knockReadings[i], 0, maxKnockInterval, 0, 100);
}
for (int j = 0; j < maximumAmp; j++){
secretAmp[j] = ampReadings[j];
}
saveSecretKnock(); // save the result to EEPROM
programModeActive = false;
playbackKnock(maxKnockInterval);
return false;
}
if (currentKnockCount != secretKnockCount && currentAmpCount != secretAmpCount){ // Easiest check first. If the number of knocks is wrong, don't unlock. // This is what i add
return false;
}
/* Now we compare the relative intervals of our knocks, not the absolute time between them.
(ie: if you do the same pattern slow or fast it should still open the door.)
This makes it less picky, which while making it less secure can also make it
less of a pain to use if you're tempo is a little slow or fast.
*/
int totaltimeDifferences = 0;
int timeDiff = 0;
for (i=0; i < maximumKnocks; i++){ // Normalize the times
knockReadings[i]= map(knockReadings[i], 0, maxKnockInterval, 0, 100);
timeDiff = abs(knockReadings[i] - secretCode[i]);
if (timeDiff > rejectValue){ // Individual value too far out of whack. No access for this knock!
return false;
}
totaltimeDifferences += timeDiff;
}
// It can also fail if the whole thing is too inaccurate.
if (totaltimeDifferences / secretKnockCount > averageRejectValue){
return false;
}
return true;
}
// reads the secret knock from EEPROM. (if any.)
void readSecretKnock(){
byte reading;
int i;
int j;
reading = EEPROM.read(0);
if (reading == eepromValid){ // only read EEPROM if the signature byte is correct.
for (int i=0; i < maximumKnocks ;i++){
secretCode[i] = EEPROM.read(i+1);
}
for (int j=0; j < maximumAmp ;j++){ // This is what i add
secretAmp[j] = EEPROM.read(j+1); // This is what i add
}
}
}
//saves a new pattern too eeprom
void saveSecretKnock(){
EEPROM.write(0, 0); // clear out the signature. That way we know if we didn't finish the write successfully.
for (int i=0; i < maximumKnocks; i++){
EEPROM.write(i+1, secretCode[i]);
EEPROM.write(i+1, secretAmp[i]); // This is what i add
}
EEPROM.write(0, eepromValid); // all good. Write the signature so we'll know it's all good.
}
// Plays back the pattern of the knock in blinks and beeps
void playbackKnock(int maxKnockInterval){
digitalWrite(ledPin, LOW);
delay(1000);
digitalWrite(ledPin, HIGH);
chirp(200, 1800);
for (int i = 0; i < maximumKnocks ; i++){
digitalWrite(ledPin, LOW);
// only turn it on if there's a delay
if (secretCode[i] > 0){
delay(map(secretCode[i], 0, 100, 0, maxKnockInterval)); // Expand the time back out to what it was. Roughly.
digitalWrite(ledPin, HIGH);
chirp(200, 1800);
}
}
digitalWrite(ledPin, LOW);
}
// Deals with the knock delay thingy.
void knockDelay(){
int itterations = (knockFadeTime / 20); // Wait for the peak to dissipate before listening to next one.
for (int i=0; i < itterations; i++){
delay(10);
analogRead(knockSensor); // This is done in an attempt to defuse the analog sensor's capacitor that will give false readings on high impedance sensors.
delay(10);
}
}
// Plays a non-musical tone on the piezo.
// playTime = milliseconds to play the tone
// delayTime = time in microseconds between ticks. (smaller=higher pitch tone.)
void chirp(int playTime, int delayTime){
long loopTime = (playTime * 1000L) / delayTime;
pinMode(audioOut, OUTPUT);
for(int i=0; i < loopTime; i++){
digitalWrite(audioOut, HIGH);
delayMicroseconds(delayTime);
digitalWrite(audioOut, LOW);
}
pinMode(audioOut, INPUT);
}
I'm guessing that you are wanting to record the knock pattern and knock volume at the same time. So that a similar pattern with softer or louder knocks will not activate the lock. If this is the case, I would suggest that you make the array mySecretKnock a 2 dimensional array.
Then use two variables to record the analog and digital inputs.
Capture them one after the other in the same control structure.
i.e. If the value of one is high enough to trigger the if statement just record the value of the other one on the next line of code.
Keep in mind that the analog input will be lower if processed after the digital one, so you may have to adjust your threshold numbers

Resources