How do you call a funcion inside a for loop in Arduino? [closed] - function

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 days ago.
Improve this question
I am programming my Arduino Uno with an ultrasonic sensor to sense the distance from it and print that on the serial plotter / monitor, at the same time 4 LEDS are blinking. I am not having any problems with them doing their thing at the same time, but I want the ultrasonic sensor to sense more than one time after the LEDS blink once. Here is the code:
const int red1 = 4;
const int red2 = 5;
const int yellow1 = 6;
const int yellow2 = 7;
const int echo = 10;
const int trig = 9;
const int buzzer = 11;
int maxCmAway = 50;
float duration_us, distance_cm;
void setup() {
Serial.begin (9600);
pinMode(red1, OUTPUT);
pinMode(red2, OUTPUT);
pinMode(yellow1, OUTPUT);
pinMode(yellow2, OUTPUT);
pinMode(trig, OUTPUT);
pinMode(echo, INPUT);
}
void loop() {
digitalWrite(yellow1, LOW);
digitalWrite(yellow2, LOW);
digitalWrite(red1, HIGH);
digitalWrite(red2, HIGH);
for(int i=0; i<6; i++) {
if (checkDist() > maxCmAway) {
blip();
} else {
noTone(buzzer);
delay(250);
}
}
digitalWrite(red1, LOW);
digitalWrite(red2, LOW);
digitalWrite(yellow1, HIGH);
digitalWrite(yellow2, HIGH);
for(int i=0; i<6; i++) {
if (checkDist() > maxCmAway) {
blip();
} else {
noTone(buzzer);
delay(250);
}
}
int checkDist() {
// generate 10-microsecond pulse to TRIG pin
digitalWrite(trig, HIGH);
delayMicroseconds(10);
digitalWrite(trig, LOW);
// measure duration of pulse from ECHO pin
duration_us = pulseIn(echo, HIGH);
// calculate the distance
distance_cm = 0.017 * duration_us;
// print the value to Serial Monitor
if (distance_cm < maxCmAway) {
Serial.print("distance: ");
Serial.print(distance_cm);
Serial.println(" cm");
Serial.print("real: ");
Serial.print(distance_cm);
Serial.println(" cma");
} else {
Serial.println("distance: 0 cm");
Serial.print("real: ");
Serial.print(distance_cm);
Serial.println(" cma");
}
return distance_cm;
}
int blip() {
tone(buzzer, 800);
delay(50);
tone(buzzer, 600);
delay(100);
tone(buzzer, 800);
delay(100);
noTone(buzzer);
return 1;
}
The code that is messing up is after all the digitalWrites in the loop() function in the for loop where it says if (checkDist() > maxCmAway). The error is " 'checkDist' was not declared in this scope " I know what this error means, but I don't know any other way to fix it besides copying and pasting the if statement 5 times.
When I look this up on Google, it just shows a bunch of things about the setup() and loop() functions.
And the other thing I tried is putting the word 'global' before the function I am calling, but 'global' does not look like it is a keyword.
Thanks!

You are missing a closing bracket for void loop()
If you look at the other error messages above "Compilation error", you should see one that says error: expected '}' at end of input. If not, you can go to preferences and enable verbose out for compilation.

Related

UPDATED: memory leak with WiFiClientSecure (Telegram) and WiFiClient (MQTT)

The title is quite self explanatory, just like the other question I have posted at Exception 28 thrown on ESP8266-01 when connected to Adafruit MQTT and Telegram
Somebody might say this is the same question, but it's actually a follow-up of it, and I deem this as worthy of a standalone question, since it might help other people as well and it is not really covered anywhere else on the internet. I am also going to post the entirety of my code (just like I did on the previous question), although StackOverflow recommends posting the bare minimum to replicate the error, since I feel like it is needed in its entirety to fully replicate it. (Private data is replaced by the word PRIVATE)
#include "UniversalTelegramBot.h"
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>
#define BOTtoken "PRIVATE"
#define fanPin 2
#define myChatId "PRIVATE"
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883
#define AIO_USERNAME "PRIVATE"
#define AIO_KEY "PRIVATE"
char ssid[] = "PRIVATE";
char password[] = "PRIVATE";
bool fanState;
unsigned long lastTimeBotRan = 0;
unsigned long checkTime = 1000;
int numNewMessages;
unsigned long timerStartPoint = 0;
bool timerStart;
String chat_id;
String text;
int messagesNumber;
String timerString;
String Request;
const unsigned long rst = 300000;
boolean MQTT_connect();
WiFiClientSecure telegramClient;
WiFiClient MQTTClient;
UniversalTelegramBot bot(BOTtoken, telegramClient);
Adafruit_MQTT_Client mqtt(&MQTTClient, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Subscribe PRIVATE = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/PRIVATE");
void checkUpdates(int numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
chat_id = String(bot.messages[i].chat_id);
text = bot.messages[i].text;
String from_name = bot.messages[i].from_name;
if (chat_id != myChatId) {
bot.sendMessage(chat_id, "Unauthorized user, please refrain from texting this bot again.", "");
continue;
}
if (text == "/start") {
bot.sendMessage(chat_id, "Welcome " + from_name + "!\n"
"Control your fan remotely!\n\n"
"/fanon: switch the fan ON\n"
"/fanoff: switch the fan OFF\n"
"/state: get the current state of the fan"
"/timer15: run fan for 15 minutes"
"/timer30: run fan for 30 minutes"
"/timer60: run fan for 1 hour"
"/timer: run fan for the amount of time you specify", "Markdown");
}
if (text == "/fanon") {
digitalWrite(fanPin, HIGH);
Serial.println("Fan on");
fanState = true;
bot.sendMessage(chat_id, "Your fan is ON", "");
}
if (text == "/fanoff") {
fanState = false;
timerStart = false;
digitalWrite(fanPin, LOW);
Serial.println("Fan off");
bot.sendMessage(chat_id, "Your fan is OFF", "");
}
if (text == "/state") {
if (digitalRead(2) == HIGH) {
bot.sendMessage(chat_id, "Your fan is ON", "");
} else {
bot.sendMessage(chat_id, "Your fan is OFF", "");
}
}
if (text == "/timer15") {
timerStartPoint = millis();
digitalWrite(fanPin, HIGH);
timerStart = true;
Serial.print("(/timer15) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(chat_id, "Your fan will run for 15 minutes", "");
launchTimer(15);
}
if (text == "/timer30") {
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(/timer30) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(chat_id, "Your fan will run for 30 minutes", "");
launchTimer(30);
}
if (text == "/timer60") {
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(/timer60) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(chat_id, "Your fan will run for 1 hour", "");
launchTimer(60);
}
if (text == "/timer") {
messagesNumber = bot.last_message_received + 1;
bot.sendMessage(chat_id, "How long do you want the fan to run for? (in minutes)", "");
Serial.println(messagesNumber);
while (messagesNumber == (bot.last_message_received + 1)) {
checkUpdates(bot.getUpdates(bot.last_message_received + 1));
timerString = bot.messages[i].text;
yield();
}
if (messagesNumber < (bot.last_message_received + 1)) {
unsigned long timer = timerString.toInt();
Serial.println(timer);
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(/timer) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(chat_id, "Your fan will run for " + timerString + " minutes", "");
launchTimer(timer);
}
}
text = "";
}
}
void launchTimer(unsigned long timeInMinutes) {
unsigned long timeInMillis = timeInMinutes * 60 * 1000;
while (timerStart) {
checkUpdates(bot.getUpdates(bot.last_message_received + 1));
if (MQTT_connect()) {
Adafruit_MQTT_Subscribe *subscription_name;
while ((subscription_name = mqtt.readSubscription(4000))) {
if (subscription_name == &PRIVATE) {
Request = ((char *)PRIVATE.lastread);
if (Request == "fanon") {
digitalWrite(fanPin, HIGH);
Serial.println("(Control panel) Fan on");
fanState = true;
bot.sendMessage(myChatId, "Fan turned on through Control Panel", "");
}
if (Request == "fanoff") {
fanState = false;
timerStart = false;
Serial.println("(Control panel) Fan off");
digitalWrite(fanPin, LOW);
bot.sendMessage(myChatId, "Fan turned off through Control Panel", "");
}
if (Request == "timer15") {
timerStartPoint = millis();
digitalWrite(fanPin, HIGH);
timerStart = true;
Serial.print("(CP /timer15) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(myChatId, "Fan turned on for 15 minutes through Control Panel", "");
launchTimer(15);
}
if (Request == "timer30") {
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(CP /timer30) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(myChatId, "Fan turned on for 30 minutes through Control Panel", "");
launchTimer(30);
}
if (Request == "timer60") {
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(CP /timer60) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(myChatId, "Fan turned on for 1 hour through Control Panel", "");
launchTimer(60);
}
}
}
}
if (millis() - timerStartPoint > timeInMillis) {
digitalWrite(fanPin, LOW);
timerStart = false;
Serial.print("Timer run out at ");
Serial.println(millis());
bot.sendMessage(myChatId, "Fan turned off because timer ran out", "");
}
yield();
}
}
boolean MQTT_connect() {
int8_t ret;
if (mqtt.connected()) {
return true;
} uint8_t retries = 3;
while ((ret = mqtt.connect()) != 0) {
mqtt.disconnect();
delay(2000);
retries--;
if (retries == 0) {
return false;
}
} return true;
}
void setup() {
Serial.begin(115200);
telegramClient.setInsecure();
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.print("Connecting Wifi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
pinMode(fanPin, OUTPUT);
delay(10);
digitalWrite(fanPin, LOW);
Request = "";
mqtt.subscribe(&PRIVATE);
if (MQTT_connect()) {
Serial.println("mqtt connected");
}
else {
Serial.println("mqtt connection failed");
}
}
void loop() {
if (millis() - lastTimeBotRan > checkTime) {
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
checkUpdates(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
lastTimeBotRan = millis();
}
delay(1000);
if (MQTT_connect()) {
Adafruit_MQTT_Subscribe *subscription_name;
while ((subscription_name = mqtt.readSubscription(4000))) {
if (subscription_name == &PRIVATE) {
Request = ((char *)PRIVATE.lastread);
if (Request == "fanon") {
digitalWrite(fanPin, HIGH);
Serial.println("(Control panel) Fan on");
fanState = true;
bot.sendMessage(myChatId, "Fan turned on through Control Panel", "");
}
if (Request == "fanoff") {
fanState = false;
timerStart = false;
Serial.println("(Control panel) Fan off");
digitalWrite(fanPin, LOW);
bot.sendMessage(myChatId, "Fan turned off through Control Panel", "");
}
if (Request == "timer15") {
timerStartPoint = millis();
digitalWrite(fanPin, HIGH);
timerStart = true;
Serial.print("(CP /timer15) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(myChatId, "Fan turned on for 15 minutes through Control Panel", "");
launchTimer(15);
}
if (Request == "timer30") {
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(CP /timer30) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(myChatId, "Fan turned on for 30 minutes through Control Panel", "");
launchTimer(30);
}
if (Request == "timer60") {
digitalWrite(fanPin, HIGH);
timerStart = true;
timerStartPoint = millis();
Serial.print("(CP /timer60) Fan on at ");
Serial.println(timerStartPoint);
bot.sendMessage(myChatId, "Fan turned on for 1 hour through Control Panel", "");
launchTimer(60);
}
}
}
}
if (!mqtt.ping()) {
mqtt.disconnect();
}
}
Now, here is the issue: I would like to instantiate both WiFiClient (to connect to Adafruit MQTT) and WiFiClientSecure (to connect to my Telegram bot) without ending up with a crash, followed by an Exception 28 stacktrace (of which I have already posted a "normal" and decoded version in the other question at the link). I know for a fact, after hours of research, that I cannot instantiate two instances of WiFiClientSecure because it would exceed the available heap on an ESP01, and I also know that WiFiClient alone, or WiFiClientSecure alone, never happen to throw said exception.
Nothing that I have found says that WiFiClient and WiFiClientSecure cannot be used together, but maybe I am missing something. Therefore my question is: is it possible to use both WiFiClient and WiFiClientSecure, for two different purposes (respectively, MQTT and Telegram), in the same code?
I look forward to reading any piece of advice, since I am currently at a loss for ideas. Thanks in advance to everybody who will help.
EDIT: for anybody who is interested, here are my latest findings:
Overclocking the CPU of the ESP01 from 80 MHz to 160 MHz helps mitigate the crashes, in fact it only crashed once over the course of 8 hours. Going from a crash every 30 minutes to 8 hours sure is a step forward;
I found out (thanks to romkey for the advice), that it WiFiClient and WiFiClientSecure are NOT incompatible, the problem was caused by the free heap. Freeing up the heap, by removing Strings and turning them to char arrays, got the program not to crash over the course of 13 whole hours. I might test this further and leave it on for even more than 24 hours, to see if it is really solved. In case, I will update.
UPDATE: found the problem and changed the title. The problem lies entirely in heap use of both the libraries. Both the libraries use an enormous amount of heap space and after a while it runs out and causes exception 28, because, as far as I know, the ESP tries to read from the wrong part of its memory, causing it to crash. I will attach the Serial output of the heap throughout just 3 minutes:
41552
19448
20008
20120
20312
20200
20120
20120
20120
20312
20120
20120
20120
20312
20312
20312
20312
20312
20312
20504
20312
20312
19640
As you can see, the first instance has the heap show more than 40k, which is normal, as 51k-ish is the maximum. Then it jumps down to 20000, and later runs out, even though the ESP reclaims its own memory after a couple of minutes.
I also do use both WiFiClient and WiFiClientSecure in my ESP8266 multisensors checking and publishing project.
And while my WifiClient is up all the time (for MQTT and ThingSpeak), secured connection (needed for publishing to GoogleSheets more rarely - every 30 minutes) I decided to put into the function.
The whole project code is too large (there's 5570 lines), so here's a part of it with comments introducing heap usage:
// heap size before call of the function: 37112
int SendGSCRPT() {
showHeap(); // 35312
WiFiClientSecure GoogleClient;
showHeap(); // 27512
GoogleClient.setInsecure();
if (!GoogleClient.connect("script.google.com", 443)) {
GoogleClient.stop();
return 0;
}
showHeap(); // 9840 !!!
char sGog[200];
snprintf(sGog, sizeof(sGog), "GET %s HTTP/1.1\r\nHost: script.google.com\r\nUser-Agent: PRIVATE\r\nConnection: close\r\n\r\n", "PRIVATE");
GoogleClient.print(sGog);
Serial.println("request sent!");
int res = 1;
GoogleClient.stop();
showHeap(); // 30104
return res;
}
// heap size after function releases all the memory taken: 37112 again !!!

Multitasking in Arduino using millis() function

I'm thinking of building a DIY gokart-offroad type of car from scrap vehicle parts. And as electronics, I'm planning on using my Arduino Uno for controlling basically everything. So I just made a gear display which lets me know which gear I'm currently on. And a simple parking sensor.
If I'm too close to an object the parking sensor buzzer will blink. And I can't blink with delay() functions because if I try to shift up when it's blinking, the input won't register because delay is a blocking function. So I tried to use millis instead but seems like it also doesn't register.
The concept is easy. I will have two buttons on each side of my shiftstick. And when I shift up the button gets pressed therefore the 7 segment display adds one. And another one for downshifting.
I have not added the reverse gear yet, but still when the parking sensor function is working, I still can't push the buttons for a good amount of time.
I hope you guys could understand what I'm trying to say. I just started coding in Arduino so I don't have enough experience. I'm leaving the .ino file as a code block. I tried to explain everything in the code. Hopefully someone knows the solution for this. Thanks in advance...
// Setting up the pins for 7-Segment-Display.
const int E = 13;
const int D = 12;
const int C = 11;
const int DP = 10;
const int G = 9;
const int F = 8;
const int A = 7;
const int B = 6;
// Setting up the counter for gear shifting.
int gearCount = 0;
// Setting up the button states and button pin for state-change detectors.
int buttonAddPin = 5;
int buttonAddState = 0;
int previousButtonAddState = 0;
// And this is for downshifting.
int buttonSubstractPin = 4;
int buttonSubstractState = 0;
int previousButtonSubstractState = 0;
// Adding buzzer for parking sensor.
const int buzzerPin = 3;
int buzzerTone = 0;
// Adding parking sensor.
const int trigPin = 2;
const int echoPin = 1;
long duration;
int distance;
// Adding non-delay blinker with millis for buzzer to blink when sensor detects an object.
unsigned long previousTime = 0;
/*---------------------------------- FUNCTIONS FOR SHIFTING -------------------------------------------------*/
// "zero" function is the series of commands for displayıng 0 on the 7-Segment corresponding to neutral gear.
void zero()
{
digitalWrite(A, LOW);
digitalWrite(B, LOW);
digitalWrite(C, LOW);
digitalWrite(D, LOW);
digitalWrite(E, LOW);
digitalWrite(F, LOW);
digitalWrite(G, HIGH);
digitalWrite(DP, HIGH);
}
// "one" function is the series of commands for displaying 1 on the 7-Segment-Display corresponding to 1st gear.
void one()
{
digitalWrite(A, HIGH);
digitalWrite(B, LOW);
digitalWrite(C, LOW);
digitalWrite(D, HIGH);
digitalWrite(E, HIGH);
digitalWrite(F, HIGH);
digitalWrite(G, HIGH);
digitalWrite(DP, HIGH);
}
// "two" function is the series of commands for displaying 2 on the 7-Segment-Display corresponding to 2nd gear.
void two()
{
digitalWrite(A, LOW);
digitalWrite(B, LOW);
digitalWrite(C, HIGH);
digitalWrite(D, LOW);
digitalWrite(E, LOW);
digitalWrite(F, HIGH);
digitalWrite(G, LOW);
digitalWrite(DP, HIGH);
}
// "three" function is the series of commands for displaying 3 on the 7-Segment-Display corresponding to 3rd gear.
void three()
{
digitalWrite(A, LOW);
digitalWrite(B, LOW);
digitalWrite(C, LOW);
digitalWrite(D, LOW);
digitalWrite(E, HIGH);
digitalWrite(F, HIGH);
digitalWrite(G, LOW);
digitalWrite(DP, HIGH);
}
// And now the main function that we are going to call in "void loop" to determine which gear we are on.
void gearDisplay()
{
buttonAddState = digitalRead(buttonAddPin); // And now the button state change detector for shifting up is ready. As you can see when I push the button
// program adds 1 to gearCount variable. So now gearCount is 1. Therefore the 7-Segment-Display will show
if(buttonAddState != previousButtonAddState){ // 1 on it. We will do this a bit later.
if(buttonAddState == HIGH){
gearCount++;
}
delay(50);
}
previousButtonAddState = buttonAddState;
// Now for downshifting.
buttonSubstractState = digitalRead(buttonSubstractPin);
if(buttonSubstractState != previousButtonSubstractState) {
if(buttonSubstractState == HIGH){
gearCount--;
}
delay(50);
}
previousButtonSubstractState = buttonSubstractState;
// Now we will call one of the 7-Segment-Display number functions according to the gearCount variable.
if(gearCount == 0){
zero();
}
else if(gearCount == 1){
one();
}
else if(gearCount == 2){
two();
}
else if(gearCount == 3){
three();
}
else if(gearCount > 3){ // Just making sure if we press buttons accidentally more than enough, it sets gearCount back to closest gear available.
gearCount--;
}
else if(gearCount < 0){ // Same with this one.
gearCount++;
}
}
// That was al for the gear panel. Now the hard part. The parking sensor.
/*---------------------------------------------- SHIFTING DONE ----------------------------------------------------*/
/*--------------------------------------------- PARKING SENSOR ------------------------------------------------------*/
void parkingSensor()
{
digitalWrite(trigPin, LOW); // Resetting trigPin
delayMicroseconds(2); // Delaying to prevent any issiues. ( I saw this online, most people do it like this so I also did.)
digitalWrite(trigPin, HIGH); // Creating a short soundwave.
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH); // Detecting the time that passes for the soundwave to reach back to the receiver.
distance = duration*0.034/2; // Simple math for calculating the distance between the obstacle and sensor.
unsigned long currentTime = millis(); // Store the current time for blinking the buzzers.
if((distance > 0) && (distance < 31)){ // If the distance is in between 0-31 buzz non-stop.
buzzerTone = 1000;
tone(buzzerPin, buzzerTone);
}
else if((distance > 30) && (distance < 76)){ // If the distance is between 30-76 buzz every 100 miliseconds.
if(currentTime - previousTime >= 100){
previousTime = currentTime;
if(buzzerTone == 1000){
buzzerTone = 0;
}
else {
buzzerTone = 1000;
}
tone(buzzerPin, buzzerTone);
}
}
else if((distance > 75) && (distance < 101)){ // If the distance is between 75-101 buzz every 300 miliseconds.
if(currentTime - previousTime >= 300){
previousTime = currentTime;
if(buzzerTone == 1000){
buzzerTone = 0;
}
else {
buzzerTone = 1000;
}
tone(buzzerPin, buzzerTone);
}
}
else if(distance > 100){ // If the distance is more than 100 don't buzz.
buzzerTone = 0;
tone(buzzerPin, buzzerTone);
}
}
/*------------------------------- PARKING SENSOR DONE -----------------------------------*/
// And this was, I guess, all I had to do but unfortunately it's not working...
void setup() {
pinMode(A, OUTPUT);
pinMode(B, OUTPUT);
pinMode(C, OUTPUT);
pinMode(D, OUTPUT);
pinMode(E, OUTPUT);
pinMode(F, OUTPUT);
pinMode(G, OUTPUT);
pinMode(DP, OUTPUT);
pinMode(buttonAddPin, INPUT);
pinMode(buttonSubstractPin, INPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
gearDisplay();
parkingSensor();
}
EDIT: Turns out that pulseIn()'s default duration is 1 second. And it's also a blocking function which blocks the buttons from registering inputs on every loop for 1 second. Changing that to smaller values, for example 10ms in my case, was enough and solved the issue. All credit goes to #CherryDT who solved this. Thanks a lot.
btw this is how the code should look like for 10ms:
pulseIn(echoPin, HIGH, 10000)
// Note that the duration in pulseIn() is in microsconds.
EDIT: Turns out that I misunderstood the question. Anyway, leaving this answer here because it answers "how to blink without blocking" which may be useful too.
The answer for the main problem would be: You are using pulseIn which also blocks until the pulse is received. The default timeout for pulseIn is one second, so if there is no object in view of your parking sensor, you are blocking for 1s every time! Since you are probably only interested in reasonably small distances anyway, you could just set a timeout of, say, 10ms (10000us):
pulseIn(echoPin, HIGH, 10000)
If this doesn't fit your requirements or is still too much of a delay though, consider writing your own code instead which measures the time without blocking, processing the button presses in the meantime. See this answer where someone had the exact same issue and solved it this way.
Basically, you could do something like this:
unsigned long pulseTimer = 0;
int lastEchoState = HIGH; // Initially HIGH so that the actual LOW triggers a "change"
void loop () {
int currentEchoState = digitalRead(echoPin);
// To set a timeout of the pulse, simulate a pulse if already waiting for too long
if (lastEchoState == LOW && micros() - pulseTimer > 1000000ul) {
currentEchoState = HIGH;
}
if (currentEchoState != lastEchoState) {
lastEchoState = currentEchoState;
if (currentEchoState == LOW) {
// Echo pulse over (or it's the initial loop iteration)
// Start counting time until echo
// We do this before sending the trigger because pulseIn would
// normally measure until the pulse is *over*, but for simplicity
// we measure until the pulse *starts*, so this implicitly shifts
// the result by our pulse duration, as trigger and echo pulse are
// usually of the same length
pulseTimer = micros();
// Send new trigger pulse
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
} else {
// Pulse came in, measure time
unsigned long pulseDelayTime = micros() - pulseTimer;
// **** DO SOMETHING WITH pulseDelayTime HERE! ****
}
}
// **** DO YOUR REGULAR BUTTON PROCESSING HERE! ****
}
You would do the blinking by setting the LED output to:
(millis() / 500) % 2
...to blink it, on every loop iteration*.
This would basically be LOW for 500ms and HIGH for 500ms, because dividing millis() by 500 (which won't have any fractional part because we are in integer world here) would give a number that increments every 500ms, and % 2 takes it modulo 2, i.e. it'd be 1 for odd and 0 for even numbers. And 1 and 0 are the same as HIGH and LOW for Arduino.
Example:
+----------+--------------+------------------+
| millis() | millis()/500 | (millis()/500)%2 |
+----------+--------------+------------------+
| ... | | |
| 1499 | 2 | 0 (LOW) |
| 1500 | 3 | 1 (HIGH) |
| 1501 | 3 | 1 (HIGH) |
| ... | | |
| 1999 | 3 | 1 (HIGH) |
| 2000 | 4 | 0 (LOW) |
| 2001 | 4 | 0 (LOW) |
| ... | | |
| 2499 | 4 | 0 (LOW) |
| 2500 | 5 | 1 (HIGH) |
| 2501 | 5 | 1 (HIGH) |
| ... | | |
+----------+--------------+------------------+
Cool project, by the way.
*: If you wanted to squeeze a bit more performance out of this, you could save the last pin state in a separate variable and do digitalWrite only when it changed. That's because digitalWrite is pretty slow actually, so you could avoid calling it every time unless an actual change is needed.

Can I send tone() function wirelessly?

I have a simple RPM Simulator (opensource) that generates values through the tone() function.
I need to send the RPM wirelessly through an nrf24l01 to a second Arduino that uses the RPM as a shiftlight, both come from chippernut.
The tone() function only sends to the pin, trying to read the values did not work.
How can i get the value of x (RPM) after it leaves the tone function?
I have tried reading it through analogRead, digitalRead, BitRead, tried printing the value of x which stays constant, to no avail, and it updates very slowly if it reads the output pin.
This is the code:
float RPM_MIN = 2500;
float RPM_MAX = 8000;
int Accel_Rate = 20;
float pulses_per_rev = 2.0; // make sure to keep the decimal
boolean accel = false;
float x;
long previousMillis = 0;
unsigned long currentMillis=0;
//float RPM_PRINT; //my addition to get a value to print
void setup() {
Serial.begin(57600);
pinMode(5, OUTPUT);
RPM_MIN = (RPM_MIN / 60);
RPM_MAX = (RPM_MAX / 60);
x = RPM_MIN;
}
void loop() {
while (accel==false){
currentMillis = millis();
if(currentMillis - previousMillis > Accel_Rate) {
previousMillis = currentMillis;
x++;
tone(5,x*pulses_per_rev);
if (x>RPM_MAX){accel=true;}
}
}
while (accel==true){
currentMillis = millis();
if(currentMillis - previousMillis > Accel_Rate) {
previousMillis = currentMillis;
x--;
tone(5,x*pulses_per_rev);
if (x<RPM_MIN){accel=false;}
}
}
//RPM_PRINT = x*pulses_per_rev;
//RPM_PRINT = digitalRead(5);
//RPM_PRINT = analogRead(5);
//Serial.println(RPM_PRINT);
}
Expected Result is a Value between 2000-8000 that is constantly changing
actual result is 1/0 or 81,33 or 4,1 or 900-980 updating once every few seconds.
How can I solve?

Reading JSON from Serial port missing part of the starting data

When reading a JSON string from the serial port on an ESP8266 it cuts off the beginning of the data.
I have tried reading data from the Serial port and printing each character, however it is cutting off part of the begging of the data.
void setup() {
Serial.begin(115200);
while (!Serial) {
;
}
}
void loop() {
int curSize = 30;
char* buffer = new char[curSize];
std::fill_n(buffer, curSize, 0);
int pos = 0;
Serial.print("Sending: ");
while(Serial.available() == false) delay(500);
while (Serial.available()) {
char c = Serial.read();
Serial.print(c);
if(pos == curSize-1){
char* newBuffer = increaseBuffer(buffer, curSize, curSize + 30);
curSize += 30;
delete[] buffer;
buffer = newBuffer;
}
if(c == '\n'){
buffer[pos] = 0;
pos = 0;
break;
}
buffer[pos++] = c;
}
if(buffer[0] != 0) {
sendBuffer(buffer);
}
delete[] buffer;
}
char* increaseBuffer(char* orig, int oldSize, int newSize){
char* data = new char[newSize];
std::fill_n(data, newSize, 0);
for(int i = 0; i < newSize; i++){
if(i < oldSize) data[i] = orig[i];
else data[i] = '\0';
}
return data;
}
JSON data used (and expected output)
{"type":0,"ver":"0.0.1","T":[28,29,29,29,29,29,29,29,29,29],"H":[59.1608,59.1608,60,59.1608,60,60,60,59.1608,59.1608,59.1608],"DP":[20.36254,20.36254,20.59363,20.36254,20.59363,20.59363,20.59363,20.36254,20.36254],"HI":[30.90588,30.90588,31.0335,30.90588,31.0335,31.0335,31.0335,30.90588,30.90588]}
examples of what is actually output
Example 1: 9,29,29,29,29,29,29,29,29],"H":[59.1608,59.1608,60,59.1608,60,60,60,59.1608,59.1608,59.1608],"DP":[20.36254,20.36254,20.59363,20.36254,20.59363,20.59363,20.59363,20.36254,20.36254],"HI":[30.90588,30.90588,31.0335,30.90588,31.0335,31.0335,31.0335,30.90588,30.90588]}
Example 2: 29,29,29,29,29,29,29,29,29],"H":[59.1608,59.1608,60,59.1608,60,60,60,59.1608,59.1608,59.1608],"DP":[20.36254,20.36254,20.59363,20.36254,20.59363,20.59363,20.59363,20.36254,20.36254],"HI":[30.90588,30.90588,31.0335,30.90588,31.0335,31.0335,31.0335,30.90588,30.90588]}
Try making the delay 1 instead of 500 in the blocking loop that's waiting for data to start coming in. I'm going to guess what happens is that on one iteration of that loop Serial.available() is false and during the delay you start to get data coming in that ends up getting written over by the time your delay ends to check again.
What I'm picturing is the following. If you were to expand out that delay(500) to be delay(1) called 500 times.
while(Serial.available() == false){
delay(1);
delay(1);
// ...
delay(1); // first character comes in
delay(1);
delay(1); // second character comes in
// ...
delay(1); // n character comes in
}
Then after the delay is over you start actually collecting the characters that are coming in.

shuffle card deck issues in language agnostic [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
Not so long ago I was in an interview, that required solving two very interesting problems. I'm curious how would you approach the solutions.
Problem 1 :
Product of everything except current
Write a function that takes as input two integer arrays of length len, input and index, and generates a third array, result, such that:
result[i] = product of everything in input except input[index[i]]
For instance, if the function is called with len=4, input={2,3,4,5}, and index={1,3,2,0}, then result will be set to {40,24,30,60}.
IMPORTANT: Your algorithm must run in linear time.
Problem 2 : ( the topic was in one of Jeff posts )
Shuffle card deck evenly
Design (either in C++ or in C#) a class Deck to represent an ordered deck of cards, where a deck contains 52 cards, divided in 13 ranks (A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K) of the four suits: spades (?), hearts (?), diamonds (?) and clubs (?).
Based on this class, devise and implement an efficient algorithm to shuffle a deck of cards. The cards must be evenly shuffled, that is, every card in the original deck must have the same probability to end up in any possible position in the shuffled deck.
The algorithm should be implemented in a method shuffle() of the class Deck:
void shuffle()
What is the complexity of your algorithm (as a function of the number n of cards in the deck)?
Explain how you would test that the cards are evenly shuffled by your method (black box testing).
P.S. I had two hours to code the solutions
First question:
int countZeroes (int[] vec) {
int ret = 0;
foreach(int i in vec) if (i == 0) ret++;
return ret;
}
int[] mysticCalc(int[] values, int[] indexes) {
int zeroes = countZeroes(values);
int[] retval = new int[values.length];
int product = 1;
if (zeroes >= 2) { // 2 or more zeroes, all results will be 0
for (int i = 0; i > values.length; i++) {
retval[i] = 0;
}
return retval;
}
foreach (int i in values) {
if (i != 0) product *= i; // we have at most 1 zero, dont include in product;
}
int indexcounter = 0;
foreach(int idx in indexes) {
if (zeroes == 1 && values[idx] != 0) { // One zero on other index. Our value will be 0
retval[indexcounter] = 0;
}
else if (zeroes == 1) { // One zero on this index. result is product
retval[indexcounter] = product;
}
else { // No zeros. Return product/value at index
retval[indexcounter] = product / values[idx];
}
indexcouter++;
}
return retval;
}
Worst case this program will step through 3 vectors once.
For the first one, first calculate the product of entire contents of input, and then for every element of index, divide the calculated product by input[index[i]], to fill in your result array.
Of course I have to assume that the input has no zeros.
Tnilsson, great solution ( because I've done it the exact same way :P ).
I don't see any other way to do it in linear time. Does anybody ? Because the recruiting manager told me, that this solution was not strong enough.
Are we missing some super complex, do everything in one return line, solution ?
A linear-time solution in C#3 for the first problem is:-
IEnumerable<int> ProductExcept(List<int> l, List<int> indexes) {
if (l.Count(i => i == 0) == 1) {
int singleZeroProd = l.Aggregate(1, (x, y) => y != 0 ? x * y : x);
return from i in indexes select l[i] == 0 ? singleZeroProd : 0;
} else {
int prod = l.Aggregate(1, (x, y) => x * y);
return from i in indexes select prod == 0 ? 0 : prod / l[i];
}
}
Edit: Took into account a single zero!! My last solution took me 2 minutes while I was at work so I don't feel so bad :-)
Product of everything except current in C
void product_except_current(int input[], int index[], int out[],
int len) {
int prod = 1, nzeros = 0, izero = -1;
for (int i = 0; i < len; ++i)
if ((out[i] = input[index[i]]) != 0)
// compute product of non-zero elements
prod *= out[i]; // ignore possible overflow problem
else {
if (++nzeros == 2)
// if number of zeros greater than 1 then out[i] = 0 for all i
break;
izero = i; // save index of zero-valued element
}
//
for (int i = 0; i < len; ++i)
out[i] = nzeros ? 0 : prod / out[i];
if (nzeros == 1)
out[izero] = prod; // the only non-zero-valued element
}
Here's the answer to the second one in C# with a test method. Shuffle looks O(n) to me.
Edit: Having looked at the Fisher-Yates shuffle, I discovered that I'd re-invented that algorithm without knowing about it :-) it is obvious, however. I implemented the Durstenfeld approach which takes us from O(n^2) -> O(n), really clever!
public enum CardValue { A, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, J, Q, K }
public enum Suit { Spades, Hearts, Diamonds, Clubs }
public class Card {
public Card(CardValue value, Suit suit) {
Value = value;
Suit = suit;
}
public CardValue Value { get; private set; }
public Suit Suit { get; private set; }
}
public class Deck : IEnumerable<Card> {
public Deck() {
initialiseDeck();
Shuffle();
}
private Card[] cards = new Card[52];
private void initialiseDeck() {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 13; ++j) {
cards[i * 13 + j] = new Card((CardValue)j, (Suit)i);
}
}
}
public void Shuffle() {
Random random = new Random();
for (int i = 0; i < 52; ++i) {
int j = random.Next(51 - i);
// Swap the cards.
Card temp = cards[51 - i];
cards[51 - i] = cards[j];
cards[j] = temp;
}
}
public IEnumerator<Card> GetEnumerator() {
foreach (Card c in cards) yield return c;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
foreach (Card c in cards) yield return c;
}
}
class Program {
static void Main(string[] args) {
foreach (Card c in new Deck()) {
Console.WriteLine("{0} of {1}", c.Value, c.Suit);
}
Console.ReadKey(true);
}
}
In Haskell:
import Array
problem1 input index = [(left!i) * (right!(i+1)) | i <- index]
where left = scanWith scanl
right = scanWith scanr
scanWith scan = listArray (0, length input) (scan (*) 1 input)
Vaibhav, unfortunately we have to assume, that there could be a 0 in the input table.
Second problem.
public static void shuffle (int[] array)
{
Random rng = new Random(); // i.e., java.util.Random.
int n = array.length; // The number of items left to shuffle (loop invariant).
while (n > 1)
{
int k = rng.nextInt(n); // 0 <= k < n.
n--; // n is now the last pertinent index;
int temp = array[n]; // swap array[n] with array[k] (does nothing if k == n).
array[n] = array[k];
array[k] = temp;
}
}
This is a copy/paste from the wikipedia article about the Fisher-Yates shuffle. O(n) complexity
Tnilsson, I agree that YXJuLnphcnQ solution is arguably faster, but the idee is the same. I forgot to add, that the language is optional in the first problem, as well as int the second.
You're right, that calculationg zeroes, and the product int the same loop is better. Maybe that was the thing.
Tnilsson, I've also uset the Fisher-Yates shuffle :). I'm very interested dough, about the testing part :)
Trilsson made a separate topic about the testing part of the question
How to test randomness (case in point - Shuffling)
very good idea Trilsson:)
YXJuLnphcnQ, that's the way I did it too. It's the most obvious.
But the fact is, that if you write an algorithm, that just shuffles all the cards in the collection one position to the right every time you call sort() it would pass the test, even though the output is not random.
Shuffle card deck evenly in C++
#include <algorithm>
class Deck {
// each card is 8-bit: 4-bit for suit, 4-bit for value
// suits and values are extracted using bit-magic
char cards[52];
public:
// ...
void shuffle() {
std::random_shuffle(cards, cards + 52);
}
// ...
};
Complexity: Linear in N. Exactly 51 swaps are performed. See http://www.sgi.com/tech/stl/random_shuffle.html
Testing:
// ...
int main() {
typedef std::map<std::pair<size_t, Deck::value_type>, size_t> Map;
Map freqs;
Deck d;
const size_t ntests = 100000;
// compute frequencies of events: card at position
for (size_t i = 0; i < ntests; ++i) {
d.shuffle();
size_t pos = 0;
for(Deck::const_iterator j = d.begin(); j != d.end(); ++j, ++pos)
++freqs[std::make_pair(pos, *j)];
}
// if Deck.shuffle() is correct then all frequencies must be similar
for (Map::const_iterator j = freqs.begin(); j != freqs.end(); ++j)
std::cout << "pos=" << j->first.first << " card=" << j->first.second
<< " freq=" << j->second << std::endl;
}
As usual, one test is not sufficient.