Arduino If Statement Clarification - arduino-uno

Need help with this code. It says error compiling for board. I know the problem is in the if statement.
I'm trying to program if the distance from the ultrasound is between 1 and 150 cm, send a tone to the piezo, else I want it to continue with the main loop.
// Include the library:
#include <NewPing.h>
// Define Trig, Echo pin and Piezo pin:
#define trigPin 3
#define echoPin 5
#define piezoPin 9
// Define maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-600 cm:
#define MAX_DISTANCE 400
// NewPing setup of pins and maximum distance.
NewPing sonar = NewPing(trigPin, echoPin, MAX_DISTANCE);
void setup() {
// Open the Serial Monitor at 9600 baudrate to see ping results:
Serial.begin(9600);
}
void loop() {
// Wait 1s between pings. 29ms should be the shortest delay between pings:
delay(1000);
// Measure distance and print to the Serial Monitor:
Serial.print("Distance = ");
// Send ping, get distance in cm and print result (0 = outside set distance range):
Serial.print(sonar.ping_cm());
Serial.println(" cm");
if ((sonar.ping_cm() >= 1) && (sonar.ping_cm() <= 150)) {
tone(piezoPin, 1000, 500);
} else {
}
}
Thanks

As #Juraj mentioned, possibly tone and NewPing.h use the same resources from the AVR.
Particularly, the NewPing.h library uses timer interrupts.
I would suggest trying with a short PWM pulse for driving the piezo instead of using tone.
Try with different PWM-capable pins. Here you have one example of how to do it. You could adapt it to your needs.

Related

how to flush write to raspberry pi gpio pins

I have a program written in C++ on a Raspberry Pi 3. I mmap /dev/gpiomem to access the GPIO registers directly in user mode. Here is my function to write to output pins:
static uint32_t volatile *gpiopage; // initialized by mmap() of /dev/gpiomem
static uint32_t lastretries = 0;
void PhysLib::writegpio (uint32_t value)
{
uint32_t mask = 0xFFF000; // [11:00] input pins
// [23:12] output pins
// all the pins go through an inverter converting the 3.3V to 5V
gpiopage[GPIO_CLR0] = value;
gpiopage[GPIO_SET0] = ~ value;
// sometimes takes 1 or 2 retries to make sure signal gets out
uint32_t retries = 0;
while (true) {
uint32_t readback = ~ gpiopage[GPIO_LEV0];
uint32_t diff = (readback ^ value) & mask;
if (diff == 0) break;
if (++ retries > 1000) {
fprintf (stderr, "PhysLib::writegpio: wrote %08X mask %08X, readback %08X diff %08X\n",
value, mask, readback, diff);
abort ();
}
}
if (lastretries < retries) {
lastretries = retries;
printf ("PhysLib::writegpio: retries %u\n", retries);
}
}
Apparently there is some internal cache or something delaying the actual updating of the pins. So I'm wondering if there is some magic MRC or MCR or whatever that I can put so I don't have to read the pins to wait for the update to actually occur.
I'm quite sure this is happening because this code is part of a loop:
while (true) {
writegpio (0x800000); // set gpio pin 23
software timing loop for 1uS
writegpio (0); // clear gpio pin 23
software timing loop for 1uS
}
Sometimes Linux timeslices during the software timing loops on me and I get a delay longer than 1uS, which is ok for this project. Before I put in the code that loops until it reads the updated bit, sometimes the voltage on the pin stays high for longer than 1uS and is then low for correspondingly less than 1uS, or vice versa, implying that there is a total of 2uS delay for the two timing loops but the update of the actual pin is being delayed by the hardware. After inserting the corrective code, I always get at least 1uS of high voltage and 1uS of low voltage each time through the loop.

how to use ultrasonic sensor hc sr04 and gps neogps 6m and gsm sim900 on arduino uno

I’m trying to send an sms with the location when the ultrasonic sensor measures a certain distance but when I add the gpsSerial(9600) line in the void setup, the ultrasonic sensor readings become inconsistent such as it reads 24 cm then skips to 18 cm then back to 24 cm. i would really appreciate it if anyone familiar with arduino or has faced this problem before would help me out. here is my code:
#include <TinyGPS.h>
#include <SoftwareSerial.h>
#include "NewPing.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
SoftwareSerial gsmSerial(2, 3);
SoftwareSerial gpsSerial(5, 4);
TinyGPS gps; //Creates a new instance of the TinyGPS object
bool newData = false;
void setup()
{
Serial.begin(9600);
gsmSerial.begin(9600);
gpsSerial.begin(9600);
}
void loop()
{
// Send ping, get distance in cm
distance = sonar.ping_cm();
if (distance < 4 )
{
//sendSMS();
Serial.println("Bin is full!!, SMS SENT!!");
Serial.println(distance);
delay(1200);
}
else
{
Serial.println(distance);
delay(2000);
}
delay(2000);
}
void sendSMS(){
// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (gpsSerial.available())
{
char c = gpsSerial.read();
//Serial.print(c);
if (gps.encode(c))
newData = true;
}
}
if (newData) //If newData is true
{
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
gsmSerial.print("AT+CMGF=1\r");
delay(400);
gsmSerial.println("AT + CMGS = \"+26xxxxxxxx\"");// recipient's mobile
number
delay(300);
gsmSerial.print("BIN IS FULL!, PLEASE COLLECT # https://www.google.com
/maps/?q=");
gsmSerial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
gsmSerial.print(",");
gsmSerial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
delay(200);
gsmSerial.println((char)26); // End AT command with a ^Z, ASCII code
26
delay(2000);
gsmSerial.println();
}
}
I've tried to reproduce your problem on Arduino Uno with HC SR04, but with no success – my measurements were stable (more than 100 same measurements in a row). I have even set the sensor to 24 cm distance from the measured obstacle. I used a code derived from what you have provided:
#include <SoftwareSerial.h>
#include "NewPing.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
SoftwareSerial gsmSerial(2, 3);
SoftwareSerial gpsSerial(5, 4);
void setup() {
Serial.begin(9600);
gsmSerial.begin(9600);
gpsSerial.begin(9600);
}
void loop() {
// Send ping, get distance in cm
distance = sonar.ping_cm();
if (distance < 4 ) {
Serial.println("Bin is full!!, SMS SENT!!");
Serial.println(distance);
}
else {
Serial.println(distance);
}
delay(2000);
}
My conclusion is your code is fine and the problem is HW related. Check the wiring and if possible, try to use another HC-SR04 sensor.
BTW1: During testing, I was sending data to gpsSerial (rx) just to be sure, it is not caused by the GPS module sending some periodic data.
BTW2: How do you power the GPS and GSM module? Are you using Arduino to power these? If yes, this also can be the source of your problems since these modules could drain large peak currents and Arduino as source is not powerful enough ...

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.

Execution time of a while loop in Arduino Due doesn't match what expected

I wrote the following infinite loop consisting principally of five high-level instructions and ran it on an Arduino Due. Assuming one clock cycle per instruction I was expecting the LED to flash about every 5/6 second. Instead the time is above 30 seconds. Is there something slowing down the execution of this code?
#define LED_PIN 13
/////////////////////////////////////////////////////////////////////////
void setup()
{
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
/////////////////////////////////////////////////////////////////////////
noInterrupts();
}
/////////////////////////////////////////////////////////////////////////
void loop()
{
int cnt = 0;
/////////////////////////////////////////////////////////////////////////
noInterrupts();
while(true) // infinite loop
{
if(cnt == 0) // if cnt == 0 turn off led
{
interrupts();
digitalWrite(LED_PIN, LOW);
noInterrupts();
}
// clock rate 84000000 cycles per second
if(cnt == VARIANT_MCK) // if cnt is equal to clock rate flash on led
{
interrupts();
delay(10);
digitalWrite(LED_PIN, HIGH);
delay(10); // turn on led for a small amount of time
noInterrupts();
cnt = - 1; // reset counter
}
cnt ++ ; // increment counter
}
}
/////////////////////////////////////////////////////////////////////////
I were expecting the number of seconds roughly shows, how many clock ticks it takes to do
while (true) {
cnt++;
if (cnt == 0) {/* signalTheStart(); */}
if (cnt == VARIANT_MCK) {/* signalTheEnd(); */}
}
One 32-bit int increment, two failing int comparisons, and a jump back.
Not sure how often the variable is moved to / from memory and how a comparison with a 32 bit constant (?) is actually performed, and I do not know the ARM internals. But I agree, 30 ticks is a bit more than I expected. I guess by 5/6you mean "five or six" and not a bit less than one, but both interpretations are too optimistic.
Michael Zhilin's hint "Check assembler code" from the compiled binary is the way to go...
And, why do you need that? You already noticed that you need to inhibit interrupts, so this measurement is not applicable to real world scenarios at all...
Writing the code in assembler solved the problem. By comparing the on-off period of the led, the compiler generate about ten time the instructions i wrote directly in assembler.

ARDUINO Buzzer playing sound when it shouldn't

So I made this kind of a temperature/humidity sensor and decided to add a fire sensor feature. So it all works fine, right? No, I also decided I want a buzzer to that. Tested it, works well, so I thrown it into my project.
Started it up [project], lit up a lighter, works fine, LEDs blink, a text is shown, buzzer plays an alarm. But then, after the fire was out, the buzzer continued to play one of two tones, even though there was no fire. Here's the code, to make it all clear:
#include <LiquidCrystal.h>
#include <dht.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
dht DHT;
#define FLAME 13
#define DHT11_PIN 8
#define ALARM A5
const int a9 = 9, a10 = 10, a11 = 11, a12 = 12;
byte z[8] = {
B00100,
B00000,
B11111,
B00001,
B00010,
B00100,
B11111,
B00000,
};
byte st[8] = {
0b00110,
0b01001,
0b01001,
0b00110,
0b00000,
0b00000,
0b00000,
0b00000,
};
void setup(){
lcd.begin(16, 2);
lcd.createChar(0, st);
lcd.createChar(1, z);
Serial.begin(9600);
pinMode((a9, a10, a11, a12), OUTPUT);
pinMode(FLAME, INPUT);
pinMode(ALARM, OUTPUT);
}
void loop() {
// Flame sensor code for Robojax.com
int fire = digitalRead(FLAME);// read FLAME sensor
if(fire == HIGH)
{
analogWrite(a9, 255);
analogWrite(a10, 255);
lcd.setCursor(5, 0);
lcd.print("Po");
lcd.print(char(1));
lcd.print("ar!");
tone(ALARM, 4300);
delay(150);
analogWrite(a9, 0);
analogWrite(a10, 0);
lcd.clear();
tone(ALARM, 3500);
delay(150);
} else {
lcd.createChar(0, st);
int chk = DHT.read11(DHT11_PIN);
lcd.home();
lcd.print("Temp.: ");
lcd.print(DHT.temperature);
if(DHT.temperature >= 20.00 && DHT.temperature < 25) {
analogWrite(a11, 255);
delay(750);
analogWrite(a11, 0);
delay(750);
} else if(DHT.temperature >= 25 && DHT.temperature < 30) {
analogWrite(a10, 255);
delay(250);
analogWrite(a10, 0);
delay(250);
} else if(DHT.temperature >= 30) {
analogWrite(a9, 255);
}
lcd.print(char(0));
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Wilg.: ");
lcd.print(DHT.humidity);
if(DHT.humidity >= 45.00 && DHT.humidity < 60.00) {
digitalWrite(a12, HIGH);
delay(250);
digitalWrite(a12, LOW);
delay(250);
} else if(DHT.humidity >= 60.00) {
digitalWrite(a12, HIGH);
}
lcd.print(" %");
delay(750);
}
delay(200);
}
So, what I mean is that even though fire is changed from HIGH to LOW and other part of the code is executed, the buzzer continues to play.
What am I doing wrong?
Check the documentation for tone:
A duration can be specified, otherwise the wave continues until a call
to noTone().
So, you probably need to reset your tone on every loop beginning before checking the values of the sensors (or explicitly invoke notone on the LOW branch), or use the 3-arg version of tone.
I have no idea how tone and delay might interact, though.
I'd probably make the actual tone sounding routine its own task. The idea is that you would start the alarm task and then reset it when appropriate. But for now make sure your state is reset at the beginning of every loop, or each branch resets anything it has to explicitly, if tasks sound too advanced.
Make sure you learn the basic "print" debugging in the Arduino world. Simple write logging to the serial port where it can be read on the IDE is invaluable.
Finally: use functions! If you put everything in loop your programs will get unreadable as they grow. For example, if you have some state you want to reset every time (e.g., running tasks like tones, values, flags) then create an init() function that loop calls first so any given loop has good starting state.
Limitations of the Piezo Buzzer
Here are some things to consider when using the piezo buzzer:
You can’t use tone() while also using analogWrite() on pins 3 or 11

Resources