How to code Arduino used countdown timer (buzzer), 4 pir sensors, and relay? They worked parallel but what I need is work sequentially - arduino-uno

How do you program Arduino to do a countdown timer 10 times using a buzzer, then after that, the light will turn on (relay). In addition, 4 PIR sensors will detect movement, if there is movement, the light will turn off for 10 seconds after which the light will turn on again. I already try to code but something feels off because the light is on at the start and the sensor detects when the timer is still running.
Here is the code that I try to code:
#define relayPin 12
#define pirPin1 8
#define pirPin2 9
#define pirPin3 10
#define pirPin4 11
int val1 = 0,val2 = 0, val3 = 0, val4 = 0 ;
long buzzerFrequency = 1000;
float buzzerDuration = 100;
int startNumber = 9; //countdown starts with this number
int endNumber = 0; //countdown ends with this number
const int buzzerPin = 6;
void setup() {
// put your setup code here, to run once:
pinMode(buzzerPin,OUTPUT);
pinMode(relayPin,OUTPUT);
pinMode(pirPin1, INPUT);
pinMode(pirPin2, INPUT);
pinMode(pirPin3, INPUT);
pinMode(pirPin4, INPUT);
Serial.begin(115200);
}
void buzzer(){
if (startNumber >= endNumber) {
for (int i = 0; i <= 1; i++){
tone(buzzerPin,buzzerFrequency,buzzerDuration);
}
delay(1000);
startNumber--;
}
}
void allPir(){
val1 = digitalRead(pirPin1);
val2 = digitalRead(pirPin2);
val3 = digitalRead(pirPin3);
val4 = digitalRead(pirPin4);
if(val1 == HIGH || val2 == HIGH || val3 == HIGH || val4 == HIGH){
digitalWrite(relayPin, HIGH);
Serial.println("Movement! delay 10 second");
Serial.println("Light off");
delay(10000);
}else{
digitalWrite(relayPin, LOW);
Serial.println("No Movement");
Serial.println("Light on");
}
}
void loop() {
// put your main code here, to run repeatedly:
buzzer();
allPir();
}
The countdown should have finished first with a buzzer sound, then the light will turn on, then the PIR sensor will check the environment. How to fix it? and what do I need to add?

Related

How can I modify the program so that the delay for every interval the led turns On and Off increases by 1 seconds Everytime the loop restarts

It's my first time learning arduino uno and I do not know what to do
const int ledPin = LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 1000;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
for(int interval = 500; interval >= 20; interval++)
previousMillis = currentMillis;
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(ledPin, ledState);
}
}
The delay for every interval the led turns On and Off increases by 1 seconds everytime the loop restarts.
Please make sure you ask your question in the question itself, not the title and also give us some more information about what you're trying to accomplish, what's working and what isn't working so we can help.
If I understand correctly, you want the LED to stay on longer and longer each time it blinks. First cycle 1 second, second cycle 2 seconds, third cycle 3 seconds, etc. You are pretty close, just need some tweaking of your logic.
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) { //Check if LED duration has expired
//Toggle LED
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
interval += 1000; //Increase the interval by 1 second
digitalWrite(ledPin, ledState); //Set the LED
previousMillis = currentMillis; //Set the time of the last transition to now
}
}

How to code a servomotor with two buttons in arduino?

I wanted to make a servomotor oscilate between 0-90 degrees when i push a button, but when i push another one, it stops oscillating and then remains in its latest position.
i started with this:
#include <Servo.h>
Servo myservo;
int pos = 0;
const int button1 = 5;
const int button2 = 6;
int lastpos = pos;
void setup() {
myservo.attach(3);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
}
void loop() {
if(digitalRead(button1) == HIGH)
{for(pos = 0; pos <= 90; pos += 1)
{myservo.write(pos);
for(pos = 90; pos >= 0; pos -= 1)
{myservo.write(pos);
delay(36);
} } if(digitalRead(button2) == HIGH){ myservo.write(lastpos);}}}
To start, take a look at how to format code inside a question. It makes it a lot easier to read and help you out. See below for how I formatted for the site, but also readability.
Servo myservo;
int pos = 0;
const int button1 = 5;
const int button2 = 6;
int lastpos = pos;
void setup() {
myservo.attach(3);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
}
void loop() {
if(digitalRead(button1) == HIGH) {
for(pos = 0; pos <= 90; pos += 1) {
myservo.write(pos);
for(pos = 90; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(36);
}
}
if(digitalRead(button2) == HIGH) {
myservo.write(lastpos);
}
}
}
There are several issues with your code based on your description of what you are trying to achieve. First, let's start with the button presses. You are ready the button state, but your code will only detect the button if it is pressed at the exact moment you are doing the digital read. Here's a good resource for reading up on how to properly implement buttons on Arduino: https://www.logiqbit.com/perfect-arduino-button-presses
The second objective is to have the servo sweep back and forth, but stop when you press a button. Your for loops won't let that happen. As currently written, you will always do a sweep to one end and back and then check the next button.
You should update the position of the servo once each time through the loop so you can check on the status of the buttons. In pseudo-code, what I suggest you do is:
void loop() {
//Check button statuses
if(button1), start sweep
if(button2), stop sweep
//Update sweep position
if(ascending && pos < 90) {
//You should be increasing in angle and you haven't reached 90 yet
ascending = TRUE;
pos += 1
myservo.write(pos);
delay(36); //Or whatever delay you need for the servo
} else if(pos > 0) {
//You already reached 90 and are coming back down to 0
ascending = FALSE;
pos -= 1;
delay(36);
}

how use the MPU 6050 in ultra low power mode

I'm currently trying to set up a fermentation specific gravity monitor, using a tilt sensor. The process can take several weeks, and must be contained in a sterile container, so must be battery powerered. I'm using a slightly modified ESP8266-01, which enters sleep mode then wakes once an hour to take a measurement, transmit the data, and return to sleep mode. I'm using an MPU6050 for the tilt sensor. Firstly, I can't seem to put the mpu into sleep mode when the esp is off, it always seems to take around 4mA, and secondly, I only need one axis, is it possible to disable everything else to limit power consumption further? I can't seem to find anything in the manual to disable axis, only to calibrate them. my code is below
experimenting with the registers below seem to make no difference, adding them, taking them out altogether, still takes around 4mA. Tried setting to 1 to put the mpu to sleep at the end of the cycle but makes no difference.
Wire.write(0x6B);
Wire.write(0);
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650. Any advice would be greatly appreciated!
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "MPU6050.h"
#include "I2Cdev.h"
#include "Wire.h"
// Update these with values suitable for your network.
const char* ssid = "****";
const char* password = "******";
IPAddress server(192, 168, 1, 90);
WiFiClient espClient5;
PubSubClient client(espClient5);
long lastMsg = 0;
char msg[50];
const uint8_t scl = 5; //D1
const uint8_t sda = 4; //D2
int val;
int prevVal = 0;
String pubString;
char gravity[50];
MPU6050 mpu;
const int sleepTimeS = 10; //only 10 seconds for testing purposes, set to
1hr when operational
int counter=0;
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) { //not
required in this application
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "test";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("AliveRegister", "FermentMon");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
#define ONE_WIRE_BUS 2 // D4 on physical board
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
float prevTemp = 0;
void setup() {
counter = 0;
Serial.begin(9600);
Wire.begin(0,2);
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(0); // set to zero wakes teh 6050
Wire.endTransmission(true);
delay(100);
setup_wifi();
client.setServer(server, 1883);
client.setCallback(callback);
if (!client.connected()) {
reconnect();
}
Serial.println("Initialize MPU");
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connected" : "Connection failed");
float temp;
DS18B20.requestTemperatures();
temp = DS18B20.getTempCByIndex(0); // first temperature sensor
char buff[100];
dtostrf(temp, 0, 2, buff);
temp = temp + 0.5;
int tRound = int(temp);
client.publish("Fermenter/temperature", buff);
Serial.print("Fermenter Temperature: ");
Serial.println(temp);
prevTemp = tRound;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
val = map(ax, -17000, 17000, 0, 180);
pubString = String(val);
pubString.toCharArray(gravity, pubString.length() + 1);
client.publish("Fermenter/angle", gravity);
Serial.print("Gravity angle: ");
Serial.println(val);
delay(500);
// counter = counter+1;
Serial.println("sleep mode");
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(1); // set to zero wakes teh 6050
// sleep
ESP.deepSleep(sleepTimeS * 1000000);
delay(2000);
}
void loop() {
client.loop();
}
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
Setting a bit is simple.
Use the follow functions to avoid any brain storming.
// Write register bit
void writeRegisterBit(uint8_t reg, uint8_t pos, bool state)
{
uint8_t value;
value = readRegister8(reg);
if (state)
{
value |= (1 << pos);
}
else
{
value &= ~(1 << pos);
}
writeRegister8(reg, value);
}
// Write 8-bit to register
void writeRegister8(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(MPU_addr);
#if ARDUINO >= 100
Wire.write(reg);
Wire.write(value);
#else
Wire.send(reg);
Wire.send(value);
#endif
Wire.endTransmission();
}
Example Usage: writeRegisterBit(MPU6050_REG_INT_PIN_CFG, 5, 1); //Register 37;Interrupt Latch Enable
For your application:
void acclSetSleepEnabled(bool state)
{
writeRegisterBit(MPU6050_REG_PWR_MGMT_1, 6, state);
}
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650
To enter low power accelerometer mode use the following function:
void lowPowerAccel(uint8_t frequency) {
uint8_t value;
value = readRegister8(MPU6050_REG_PWR_MGMT_2);
value &= 0b00111000;
value |= (frequency << 6) | 0b111;
writeRegister8(MPU6050_REG_PWR_MGMT_2, value);
value = readRegister8(MPU6050_REG_PWR_MGMT_1);
value &= 0b10010111;
value |= 0b00111000;
writeRegister8(MPU6050_REG_PWR_MGMT_1, value);
}
This lowPowerAccel function also puts the gyro to standy mode. The function needs a wake up frequency parameter.
This is defined as follows:
/*
* LP_WAKE_CTRL | Wake-up Frequency
* -------------+------------------
* 0 | 1.25 Hz
* 1 | 2.5 Hz
* 2 | 5 Hz
* 3 | 10 H
*/
#define LP_WAKE_CTRL_1_25 0x00
#define LP_WAKE_CTRL_2_5 0x01
#define LP_WAKE_CTRL_5 0x02
#define LP_WAKE_CTRL_10 0x03
I hope, I could answer some of your questions.
Good luck! :)
Are you using a breakout board for the MPU6050? e.g. GY-521. Often they use linear regulators and leds which will consume additional power. It may be necessary to remove these and run the IMU from a direct power source.
Each register in the MPU6050 is 8 bits wide. When setting an individual bit to a desired value you can either use bitwise manipulation (not practical here as we aren't directly interacting with the registers) or directly set all of the bits in the register to the register's new state e.g. 0b00100000 ~ 0x20. Instead of writing a 1 to 0x6B when attempting to put the MPU6050 to sleep you should be writing 0x20.
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
Referencing page 40-42, if you want to take things a step further you can disable the temperature sensor, accelerometers, and redundant gyroscope axes to save power while the device is active.

Stopwatch fails to reset

I am working on an Arduino stopwatch, where it needs a start, stop, and reset button. To reset it, I am using a variable called starttime that is updated to equal to millis(), and then take the difference to display time. However, past thirty seconds, the starttime does not update correctly, and the resulting difference between starttime and millis() is equivalent to 65 seconds. Can someone explain why this is happening?
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int start = 8;
const int stp = 9;
const int reset = 10;
int seconds;
int minutes;
int timedif;
int starttime = -1;
int timestall = 0;
bool onoff = true;
void setup()
{
pinMode(start, INPUT);
pinMode(stp, INPUT);
pinMode(reset, INPUT);
lcd.begin(16, 2); //Initialize the 16x2 LCD
lcd.clear(); //Clear any old data displayed on the LCD
Serial.begin(9600);
}
void loop()
{
int bsta = digitalRead(start);//sees if start switch is pressed
int bstp = digitalRead(stp);//records if stop switch is pressed
int bres = digitalRead(reset);//records if reset switch is pressed
lcd.setCursor(0,0);
lcd.print("Stopwatch");//prints stopwatch top row
lcd.setCursor(0,1);
if (starttime == -1) { //if running first time, time dif is initiated
starttime = millis();
}
timedif = (millis() - starttime )/1000 + timestall; //will get difference in terms of seconds
minutes = floor(timedif/60); // divides by sixty, drops decimal
seconds = timedif%60; //gets remainder of divided by 60
lcd.print(minutes);
lcd.print(":");
lcd.print(seconds);
if (seconds < 10) {
lcd.setCursor(3,1);
lcd.print(' ');
}
if (bstp == HIGH) {
onoff = false;
while(onoff == false) {
if (digitalRead(start) == HIGH) {
onoff = true;
}
}
timestall = timedif;
starttime = millis();
}
if (bres == HIGH) {
delay(100);
timestall = 0;
starttime = millis();
timedif = 0;
lcd.clear();
Serial.println("stall:");
Serial.println(timestall);
Serial.println("dif");
Serial.println(timedif);
Serial.println("start");
Serial.println(millis() - starttime);
}
}
You should use long or unsigned long instead if int to declare variables that hold time values.
A int variable can only hold 32,767 millisecond hence the 32 sec. where a long variable can hold 2,147,483,647 millisecond which is something like 48 days. A unsigned long can hold double of that but can not hold a negative value.

Issues with Arduino Timing

I am working with an Arduino on a project for which timing is very important. I use TimerOne to trigger timer interrupts and use micros() for delays (delayMicroseconds() was causing problems worse than the one explained below). The program is sending a manual PWM signal to an LED and it is very important that the signal is sent with an error that is less than 8 microseconds (ideally, the signal is sent at the same time in each period). My test code is shown below:
#include <TimerOne.h>
#include <SPI.h>
const int LED_PIN = 3;
const int CHIP_SELECT = 12;
const int PERIOD = 4000;
const double DUTY_CYCLE = .5;
const int HIGH_TIME = PERIOD * DUTY_CYCLE;
const int LOW_TIME = PERIOD - HIGH_TIME;
const int INITIAL_SIGNAL_DELAY = LOW_TIME / 2;
const int HIGH_TIME_TOTAL_DELAY = INITIAL_SIGNAL_DELAY + HIGH_TIME;
const int RESISTOR_VALUE = 255;
boolean triggered = false;
boolean data = false;
unsigned long triggeredTime;
unsigned long s;
unsigned long e;
boolean found;
int i = 0;
void setup()
{
s = micros();
Timer1.initialize(PERIOD);
Timer1.attachInterrupt(trigger);
pinMode(LED_PIN, 3);
pinMode(CHIP_SELECT, OUTPUT);
SPI.begin();
digitalWrite(CHIP_SELECT, LOW);
SPI.transfer(B00010001);
SPI.transfer(RESISTOR_VALUE);
digitalWrite(CHIP_SELECT, HIGH);
e = micros();
Serial.begin(115200);
Serial.print("s: ");
Serial.println(s);
Serial.print("e: ");
Serial.println(e);
}
void loop()
{
if(triggered)
{
while(micros() - triggeredTime < INITIAL_SIGNAL_DELAY)
{ }
s = micros();
digitalWrite(LED_PIN, data);
while(micros() - triggeredTime < HIGH_TIME_TOTAL_DELAY)
{ }
digitalWrite(LED_PIN, LOW);
data = !data;
triggered = false;
e = micros();
//micros();
if(s % 100 > 28 || s % 100 < 12)
{
found = true;
}
if(!found)
{
Serial.print("s: ");
Serial.println(s);
}
else
{
Serial.print("ERROR: ");
Serial.println(s);
}
//Serial.print("e: ");
//Serial.println(e);
}
}
void trigger()
{
triggeredTime = micros();
triggered = true;
}
(it should be noted that the first signal sent is always xx20, usually 5020).
So, with this code, I eventually get an error. I am not sure why, but this error occurs at the same point every single time:
.
.
.
s: 1141020
s: 1145020
s: 1149020
ERROR: 1153032
ERROR: 1157020
ERROR: 1161020
.
.
.
Now, the really weird part is if I remove the comments before micros() (the micros() right after e = micros()), there is no error (or at least there is not an error within the first 30 seconds). I was wondering if anybody could provide an explanation for why this happens. I have dedicated many hours trying to get the timing working properly and everything was working well until I encountered this error. Any help would be very much appreciated. Thank you!

Resources