So I'm writing this little function for some pot pins. The pot sends a value only when its being turned, at rest, it sends nothing. Which is how I want it to function.
It works fine with one pin.
I've gotten it to a point where it half works with multiple pins. So if I call it twice in the loop with two pins, I get back the right values on both those pins. But I loose the functionality of the if statement. Basically I can't figure out the last half of this. Arrays have been suggested I'm just unsure of how to proceed.
Suggestions? Thank you.
byte pots[2] = {A0, A2};
int lastPotVal = 0;
void setup(){
Serial.begin(9600);
}
void loop(){
// get the pin out of the array
rePot(pots[0]);
rePot(pots[1]);
delay(10);
}
void rePot(const int potPin){
// there is probably an issue around here somewhere...
int potThresh = 2;
int potFinal = 0;
int potVal = 0;
// set and map potVal
potVal = (analogRead(potPin));
potVal = map(potVal, 0, 664, 0, 200);
if(abs(potVal - lastPotVal) >= potThresh){
potFinal = (potVal/2);
Serial.println(potFinal);
lastPotVal = potVal;
} // end of if statement
} // end of rePot
This uses a struct to mange a pot and the data associated with it (the pin it's on, the last reading, threshold, etc). Then, the rePot() function is changed to take one of those structs as input, instead of just the pin number.
struct Pot {
byte pin;
int threshold;
int lastReading;
int currentReading;
};
// defining an array of 2 Pots, one with pin A0 and threshold 2, the
// other with pin A2 and threshold 3. Everything else is automatically
// initialized to 0 (i.e. lastReading, currentReading). The order that
// the fields are entered determines which variable they initialize, so
// {A1, 4, 5} would be pin = A1, threshold = 4 and lastReading = 5
struct Pot pots[] = { {A0, 2}, {A2, 3} };
void rePot(struct Pot * pot) {
int reading = map(analogRead(pot->pin), 0, 664, 0, 200);
if(abs(reading - pot->lastReading) >= pot->threshold) {
pot->currentReading = (reading/2);
Serial.println(pot->currentReading);
pot->lastReading = reading;
}
}
void setup(){
Serial.begin(9600);
}
void loop() {
rePot(&pots[0]);
rePot(&pots[1]);
delay(10);
}
A slightly different take on this is to change rePot() into a function that takes the whole array as input, and then just updates the whole thing. Like this:
void readAllThePots(struct Pot * pot, int potCount) {
for(int i = 0; i < potCount; i++) {
int reading = map(analogRead(pot[i].pin), 0, 664, 0, 200);
if(abs(reading - pot[i].lastReading) >= pot[i].threshold) {
pot[i].currentReading = (reading/2);
Serial.println(pot[i].currentReading);
pot[i].lastReading = reading;
}
}
}
void loop() {
readAllThePots(pots, 2);
delay(10);
}
Related
Need to update potentiometer values all time not only once, try different ways but nothing works :(
I think that main problem is that this function while(digitalRead(gotoPositionAPin)); blocks
Now it's read value and save speed
workflow of code
press button right save position a
press button left save position b
update pot speed (set speed)
update pot acceleration (set accel)
press button go to position A (its going with previous set of speed and acceleration)
press button go to position B (its going with previous set of speed and acceleration)
#include <AccelStepper.h>
// Define some steppers and the pins the will use
AccelStepper stepper1(1, 12, 11);
#define stepsPerRev 1600
#define stepPin 12
#define dirPin 11
#define ledPin 13
#define rotateLeftPin 7
#define rotateRightPin 6
#define savePositionAPin 5
#define savePositionBPin 4
#define gotoPositionAPin 3
#define gotoPositionBPin 2
#define maxSpeedPin 0
#define accelPin 1
// Set this to zero if you don't want debug messages printed
#define printDebug 0
// These are the constants that define the speed associated with the MaxSpeed pot
#define MAX_STEPS_PER_SECOND 1000 // At 200 s/r and 1/8th microstepping, this will be 333 rev/minute
#define MIN_STEPS_PER_SECOND 27 // At 200 steps/rev and 1/8th microstepping, this will be 1 rev/minute
// Change this value to scale the acceleration pot's scaling factor
#define ACCEL_RATIO 1
int buttonState = 0;
int stepNumber = 0;
int curSpeed = 100;
int dir = 0;
int maxSpeed = 0;
int accel = 0;
long savedPosA = 0;
long savedPosB = 0;
int loopCtr = 0;
float fMaxSpeed = 0.0;
float fStepsPerSecond = 0.0;
void setup()
{
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(rotateLeftPin, INPUT);
pinMode(rotateRightPin, INPUT);
pinMode(savePositionAPin, INPUT);
pinMode(savePositionBPin, INPUT);
pinMode(gotoPositionAPin, INPUT);
pinMode(gotoPositionBPin, INPUT);
if (printDebug)
{
// Initialize the Serial port
Serial.begin(9600);
}
// blink the LED:
blink(2);
stepper1.setMaxSpeed(800.0);
stepper1.setAcceleration(600.0);
// Grab both speed and accel before we start
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
accel = analogRead(accelPin)/ACCEL_RATIO;
}
void loop()
{
// First, we need to see if either rotate button is down. They always take precidence.
if(digitalRead(rotateLeftPin))
{
stepper1.setSpeed(-fStepsPerSecond);
while(digitalRead(rotateLeftPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(-fStepsPerSecond);
}
}
else if (digitalRead(rotateRightPin))
{
stepper1.setSpeed(fStepsPerSecond);
while(digitalRead(rotateRightPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(fStepsPerSecond);
}
}
// Go see if we need to update our analog conversions
CheckPots();
// Check to see if user is trying to save position A or B
if(digitalRead(savePositionAPin))
{
savedPosA = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved A at :");
Serial.println(savedPosA);
}
while(digitalRead(savePositionAPin));
}
if(digitalRead(savePositionBPin))
{
savedPosB = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved B at :");
Serial.println(savedPosB);
}
while(digitalRead(savePositionBPin));
}
// Check to see if the user wants to go to position A or B
if (digitalRead(gotoPositionAPin))
{
if (printDebug)
{
// Yup, let's go to position A
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to A = ");
Serial.println(savedPosA);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosA);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionAPin));
}
else if (digitalRead(gotoPositionBPin))
{
// Yup, let's go to position B
if (printDebug)
{
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to B = ");
Serial.println(savedPosB);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosB);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionBPin));
}
}
// Blink the reset LED:
void blink(int howManyTimes)
{
int i;
for (i=0; i < howManyTimes; i++)
{
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
}
void CheckPots(void)
{
loopCtr++;
// Only read these once in a while because they take a LONG time
if (loopCtr == 100)
{
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
}
// Read in the acceleration analog value
// This needs to be scaled too, but to what?
if (loopCtr >= 200)
{
accel = analogRead(accelPin)/ACCEL_RATIO;
loopCtr = 0;
}
}
If you're looking into "continuous operation" but don't want to introduce interrupts into your code (which will have special requirements in and of itself) there are a couple of things you need to get rid of:
Endless loops like: while(digitalRead(savePositionAPin));
System waits like: delay(200); as in your blink()
and instead use state variables. State variables are more or less what the name says: variables that hold the state of something, so you know what value the button, or timer, or counter had last time.
So, instead of a while-loop waiting for a button to be released, just set a global or static boolean that knows what state you were in the last time loop() ran, so you don't trigger the button action again. You need one boolean flag for each button.
And instead of delays, either create a state variable that holds "passed time" which you can get from millis() for example. So don't wait but instead you should just check if a certain amount of time has passed so you can toggle the state of the LED.
Adding a blinking LED to loop() - (untested example):
#define LEDWAIT 300
unsigned long myTime = 0;
bool onoff = false;
loop()
{
if (myTime == 0)
myTime = millis();
if ((millis() - myTime) > LEDWAIT) {
digitalWrite(ledPin, onoff ? HIGH : LOW);
onoff = !onoff;
myTime = millis();
}
// do other things
}
It is not entirely clear to me what your program is supposed to do and what the error is, so please correct me if I am wrong: You want to update a value based on which button is pressed? What is your opinion on using interrupts for triggering the updates?
You may want to edit the formating of your question.
I'm trying to build a tachometer in C++ for my ESP32. When I uncomment Serial.printf("outside rev: %d \n", rev); outside of the conditional it works, but when I comment it I get values that are orders of magnitude greater than they should be (700 revolutions without, vs 7 revolutions with). My best guess is that the print statement is slowing the loop() down just enough for incrementRevolutions() to toggle the global variable passedMagnet from true to false before the next loop. That would make sense, since a delay in updating passedMagnet would allow newRevCount++; to be triggered multiple times. But this is obviously something I can't debug with either print statements or step-through debugging given the time-sensitive nature of the race condition.
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
Is this a known gotcha with Arduino or C++ programming? What should I do to fix it?
I think the test is to blame. I had to rename and move things a bit to visualize the logic, sorry about that.
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
You could also write it as...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
But the most economical (and fastest) way of doing what you want would be:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
It's reusable, and saves both stack space and unnecessary assignments.
If you cannot get clean transitions from your sensor (noise on positive and negative edges, you'll need to debounce the signal a bit, using a timer.
Example:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}
I want make function like void loop or void setup like arduino main function which that function can input another execution code.
unsigned long NOW;
void setup() {
}
void loop() {
void doEvery(2){ //do Every 2 second
//Put Code that Execute every 2 second
}
void doEvery(4){ //do Every 4 second
//Put Code that Execute every 4 second
}
}
How to declare/define function doEvery?
i think that function must contain
if(millis()-NOW>=EVERY){
NOW=millis();
//THE LINE CODE
}
Taking THIS as initial idea:
unsigned long previousMillis2 = 0, previousMillis100 = 0;
void setup() {
}
void loop() {
unsigned long currentMillis = millis();
//doEvery 2
if (currentMillis - previousMillis2 >= 2) {
previousMillis2 = currentMillis; //stores last execution's timestamp
//CODE EVERY 2 millis
}
//doEvery 100
if (currentMillis - previousMillis100 >= 100) {
previousMillis100 = currentMillis; //stores last execution's timestamp
//CODE EVERY 100 millis
}
}
With this, you will use millis() to ask for how many millis passed since initialization of Arduino. Then you store last time you executed your code and compare how many time passed since it.
It's not a dynamic function for defining new intervals but if you only need a pair of it, you can code it easily.
EDIT:
If you need something more dynamic, you should use anonymous functions. SEE THIS or THIS The point here is function as parameter.
I've made an animation library out of this for the WS2812 ledstrip:
https://github.com/laurijssen/ledstripanimator/blob/master/ledanim.c
The timing stuff that jabujavi describes happens in the UpdateFrame function where every animation in the list advances to the next frame after it's configured milliseconds.
class AnimList
{
Animation *first = NULL;
Adafruit_NeoPixel strip;
public:
AnimList(int nleds) : strip(nleds, 9, NEO_GRB + NEO_KHZ800)
{
strip.begin();
}
void UpdateFrame()
{
strip.clear();
Animation **anim = &first;
while (*anim)
{
if (millis() - (*anim)->last >= (*anim)->ms)
{
if (!(*anim)->UpdateFrame(strip))
{
*anim = (*anim)->next;
}
else
{
(*anim)->last = millis();
anim = &(*anim)->next;
}
}
}
}
};
Now you just call AnimList::UpdateFrame as fast as possible inside loop()
void loop() {
list->UpdateFrame();
list->Render();
if (!list->Find(&r1))
{
r1 = Rain (rand() % NUMLEDS, rand() % NUMLEDS, {BRIGHTNESS, 0, 15 }) ;
list->AddFirst(&r1);
}
}
edit
So if you want to execute code every 2 seconds you create a class which inherits from Animation and override Updateframe. Then put ms variable at the time you want to pass between frames.
Of course remove all Adafruit and animation references if you just want a task based lib.
class TaskA : public Task
{
public:
TaskA() { ms = 2000; }
bool UpdateFrame()
{
Serial.println("2 seconds passed");
return true;
}
};
TaskA t;
void setup()
{
list->AddTask(&t);
}
void loop()
{
list->UpdateTasks();
}
So im working on a project making a safety and monitoring system for a bike and im sending the monitored data to Blynk
which is working perfectly.
Im trying to send an SMS when a value is triggered ,I recieve the SMS through Clicksend
but i cant figure out how i can send my values to IFTTT so that it can write those in the Alert SMS
Here is the code:
#include <SoftwareSerial.h>
#include <RH_NRF24.h>
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266HTTPClient.h>
char auth[] = "AUTH_ID";
char ssid[] = "SSID";
char pass[] = "PASS";
const char* iftttURL = "http://maker.ifttt.com/trigger/{event}/with/key/{key}";
BlynkTimer timer;
// Singleton instance of the radio driver
RH_NRF24 nrf24(2, 4); //D4,D2 on esp //nrf24L01
int led = 15; //D8 on esp
int acc;
int touch;
int headtemp;
static const int RXPin = 5, TXPin = 16; //D1,D2 on esp //gps
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
float lati;
float lon;
const int analogInPin = A0; //Pt100 Bike Temp
const int SensorValueLow = 463;
const int SensorValueDiff = 36; // differance between high and low sensor value
const int TempValueDiff = 32; // differance between high and low Temp value
const int TempValueLow = 0;
int sensorValue = 0;
int Temp = 0;
// Calibration: // //RPM
const byte PulsesPerRevolution = 10; // Set how many pulses there are on each revolution. Default: 2.
const unsigned long ZeroTimeout = 100000; // For high response time, a good value would be 100000
// Calibration for smoothing RPM:
const byte numReadings = 2; // Number of samples for smoothing. The higher, the more smoothing, but it's going to
// Variables:
/////////////
unsigned long kmh;
int d=50.8; //diameter of wheel in cm
volatile unsigned long LastTimeWeMeasured; // Stores the last time we measured a pulse so we can calculate the period.
volatile unsigned long PeriodBetweenPulses = ZeroTimeout+1000; // Stores the period between pulses in microseconds.
volatile unsigned long PeriodAverage = ZeroTimeout+1000; // Stores the period between pulses in microseconds in total, if we are taking multiple pulses.
unsigned long FrequencyRaw; // Calculated frequency, based on the period. This has a lot of extra decimals without the decimal point.
unsigned long FrequencyReal; // Frequency without decimals.
unsigned long RPM; // Raw RPM without any processing.
unsigned int PulseCounter = 1; // Counts the amount of pulse readings we took so we can average multiple pulses before calculating the period.
unsigned long PeriodSum; // Stores the summation of all the periods to do the average.
unsigned long LastTimeCycleMeasure = LastTimeWeMeasured; // Stores the last time we measure a pulse in that cycle.
unsigned long CurrentMicros = micros(); // Stores the micros in that cycle.
unsigned int AmountOfReadings = 1;
unsigned int ZeroDebouncingExtra; // Stores the extra value added to the ZeroTimeout to debounce it.
// Variables for smoothing tachometer:
unsigned long readings[numReadings]; // The input.
unsigned long readIndex; // The index of the current reading.
unsigned long total; // The running total.
unsigned long average; // The RPM value after applying the smoothing.
void myTimerEvent()
{
// You can send any value at any time.
// Please don't send more that 10 values per second.
Blynk.virtualWrite(V1, average);
Blynk.virtualWrite(V2, kmh);
Blynk.virtualWrite(V3, Temp);
}
WidgetMap myMap(V5);
void setup()
{
Serial.begin(9600);
Blynk.begin(auth, ssid, pass);
timer.setInterval(1000L, myTimerEvent);
ss.begin(GPSBaud); //GPS
Serial.println(F("DeviceExample.ino"));
Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
pinMode(led, OUTPUT); //D8 of node mcu //nrf24L01
Serial.begin(9600);
while (!Serial)
; // wait for serial port to connect. Needed for Leonardo only
if (!nrf24.init())
Serial.println("init failed");
// Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
if (!nrf24.setChannel(1))
Serial.println("setChannel failed");
if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
Serial.println("setRF failed");
attachInterrupt(digitalPinToInterrupt(0), Pulse_Event, RISING); //RPM // Enable interruption pin 2 when going from LOW to HIGH.
}
void loop()
{
Blynk.run();
timer.run();
smsonaccident();
while (ss.available() > 0) //GPS
if (gps.encode(ss.read()))
displayInfo(); //GPS function
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
NRF24L01(); //NRF24L01 Function
BikeTemp(); //Bike Temprature Function
BikeRPM(); //Bike Wheel RPM
}
void NRF24L01()
{
if (nrf24.available()) //nrf24L01
{
// Should be a message for us now
uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (nrf24.recv(buf, &len))
{
Serial.println("*****Got Signal*****");
acc = buf[0];
touch = buf[1];
Serial.print("Accelerometer State: ");
Serial.print(buf[0]);
Serial.print(" , Touch State: ");
Serial.print(buf[1]);
if(touch == 1 || acc ==1)
{digitalWrite(led,HIGH);}
else
{digitalWrite(led,LOW);}
}
}
}
void BikeTemp()
{
sensorValue = analogRead(analogInPin); //Pt100 BikeTemp
Temp = sensorValue-SensorValueLow;
Temp = Temp/SensorValueDiff;
Temp = Temp*TempValueDiff;
Temp = Temp+TempValueLow;
Serial.print("Temp= ");
Serial.println(Temp);
}
void BikeRPM()
{
LastTimeCycleMeasure = LastTimeWeMeasured; // RPM+Km/h
CurrentMicros = micros(); // Store the micros() in a variable.
if(CurrentMicros < LastTimeCycleMeasure)
{
LastTimeCycleMeasure = CurrentMicros;
}
// Calculate the frequency:
FrequencyRaw = 10000000000 / PeriodAverage; // Calculate the frequency using the period between pulses.
// Detect if pulses stopped or frequency is too low, so we can show 0 Frequency:
if(PeriodBetweenPulses > ZeroTimeout - ZeroDebouncingExtra || CurrentMicros - LastTimeCycleMeasure > ZeroTimeout - ZeroDebouncingExtra)
{ // If the pulses are too far apart that we reached the timeout for zero:
FrequencyRaw = 0; // Set frequency as 0.
ZeroDebouncingExtra = 2000; // Change the threshold a little so it doesn't bounce.
}
else
{
ZeroDebouncingExtra = 0; // Reset the threshold to the normal value so it doesn't bounce.
}
FrequencyReal = FrequencyRaw / 10000; // Get frequency without decimals.
// Calculate the RPM:
RPM = FrequencyRaw / PulsesPerRevolution * 60; // Frequency divided by amount of pulses per revolution multiply by
RPM = RPM / 10000; // Remove the decimals.
// Smoothing RPM:
total = total - readings[readIndex]; // Advance to the next position in the array.
readings[readIndex] = RPM; // Takes the value that we are going to smooth.
total = total + readings[readIndex]; // Add the reading to the total.
readIndex = readIndex + 1; // Advance to the next position in the array.
if (readIndex >= numReadings) // If we're at the end of the array:
{
readIndex = 0; // Reset array index.
}
// Calculate the average:
average = total / numReadings; // The average value it's the smoothed result.
kmh = d*average*0.001885; // calculate km/h ,where d(in cm) is diameter of wheel
Serial.print("RPM: ");
Serial.print(average);
Serial.print(" , KM/h: ");
Serial.println(kmh);
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
// Serial.print(gps.location.lat(), 6);
lati = gps.location.lat() ;
Serial.print(lati, 6);
Serial.print(F(","));
// Serial.print(gps.location.lng(), 6);
lon = gps.location.lng() ;
Serial.print(lon, 6);
}
else
{
Serial.print(F("Invalid"));
}
int index = 5;
myMap.location(index, lati, lon, "Bike location");
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10) Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}
ICACHE_RAM_ATTR void Pulse_Event() //RPM Data // The interrupt runs this to calculate the period between pulses:
{
PeriodBetweenPulses = micros() - LastTimeWeMeasured; // Current "micros" minus the old "micros" when the last pulse happens.
LastTimeWeMeasured = micros(); // Stores the current micros so the next time we have a pulse we would have something to compare with.
if(PulseCounter >= AmountOfReadings) // If counter for amount of readings reach the set limit:
{
PeriodAverage = PeriodSum / AmountOfReadings; // Calculate the final period dividing the sum of all readings by the
PulseCounter = 1; // Reset the counter to start over. The reset value is 1 because its the minimum setting allowed (1 reading).
PeriodSum = PeriodBetweenPulses; // Reset PeriodSum to start a new averaging operation.
int RemapedAmountOfReadings = map(PeriodBetweenPulses, 40000, 5000, 1, 10); // Remap the period range to the reading range.
RemapedAmountOfReadings = constrain(RemapedAmountOfReadings, 1, 10); // Constrain the value so it doesn't go below or above the limits.
AmountOfReadings = RemapedAmountOfReadings; // Set amount of readings as the remaped value.
}
else
{
PulseCounter++; // Increase the counter for amount of readings by 1.
PeriodSum = PeriodSum + PeriodBetweenPulses; // Add the periods so later we can average.
}
}
void smsonaccident()
{
if (acc>=1) // You can write any condition to trigger e-mail sending
{
Serial.println("Alert!!! Accident Happens see location. "); // This can be seen in the Serial Monitor
HTTPClient http; // Declare an object of class HTTPClient
http.begin(iftttURL); // Specify request destination
int httpCode = http.GET(); // Send the request
Serial.println("Done");
if (httpCode > 0) {
String payload = http.getString(); // Get the request response payload
Serial.println(payload); // Print the response payload
}
http.end(); // Close connection
acc=0;
delay(10000); // delay for 5 min if accident happens
}
}
Now im trying to find a way so that i can send my GPS values to the "iftttURL" but whatever i try or whatever i know doesnt work
either the value just doesnt get recieved or if it does then the SMS fails to send as it cant validate the values
what do i need to add
or what do i need to change to send my GPS values "lati" and "lon" to my ifttt url where it can recognize it as values that i can put into the alert message
I'm trying to use a pointer in a function argument to read a variable from a class, like this:
void Function(int (*Argument)) {
Variable = Object*Argument.ClassVariable;
}
Note: the reason I want to do this is so that I can set the value of a rotary encoder position equal to the value a class variable was previously at, prior to allowing the user to change that class variable value. This way, when the user cycles through the class variables to set them, the starting position for each variable is the saved value.
Class objects are named Object1, Object2, etc.
The variable I want to read from each object is named ClassVariable.
When I call the function, i will useFunction(ClassNumber);
If ClassNumber is 13 at the time the function is called, I want Variable to be made equal to Object13.ClassVariable
Is this possible?
Further Info:
The entire class is public.
Constructor for class objects (note, this is arduino, byte is 8-bit unsigned):
Modes(byte hue, byte sat, byte val, int del, bool hROal, bool hset, bool sset, bool vset, bool dset) {
hueVal = hue;
satVal = sat;
valVal = val;
delVal = del;
hueROallow = hROal;
hSet = hset;
sSet = sset;
vSet = vset;
dSet = dset;
}
Each class object is a separate 'mode' that the user can select. The Argument i intend using in the function is the 'mode number' currently selected.
FULL CODE (very much a work in progress)
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
const byte Button2 = 8;
const byte EncApin = 3; // EncApin **MUST BE interrupt**
const byte EncBpin = 4; // These are the three pins the encoder A/B & button are connected to
const byte EncButt = 2; //
static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // array to set encoder H/L sequence
byte encVal; // initialises reading from encoder
Adafruit_SH1106 display(0); // Initialise display? (On SPI OLED screens this sets the MOSI/CLK/DC/RST/CS pins)
int displayVal; // to store the current output value for display
String displayMode;
byte mode = 1; // set mode 0 at beginning
byte qtyModes = 3; // set number of modes that may be selected here
byte setMode = 1;
byte qtySetModes = 4; // set number of sub-modes for setting values
///// FUNCTION PROTOTYPES ///////// must be declared here to allow the class to use them
void EncReading();
void EncReadingRO();
////////////////////////////////////////////////////////
////////////// ******** CLASSES ********* //////////////
////////////////////////////////////////////////////////
class Modes {
public: // everything in the class below this will be available to the program outside of the class
// Class Member Variables
// These are initialized at startup
byte hueVal;
byte satVal;
byte valVal;
int delVal;
bool hueROallow;
bool hSet;
bool sSet;
bool vSet;
bool dSet;
byte CLdisplayVal;
String displayDesc;
// These maintain the current state
unsigned long prevMillis; // will store last time LED was updated
// Constructor - creates a Mode & initializes the member variables and state
// additional options for whether rollover of values allowed needed
Modes(byte hue, byte sat, byte val, int del, bool hROal, bool hset, bool sset, bool vset, bool dset) {
hueVal = hue;
satVal = sat;
valVal = val;
delVal = del;
hueROallow = hROal;
hSet = hset;
sSet = sset;
vSet = vset;
dSet = dset;
}
void Update() {
switch (setMode) {
case 1: // case 1 for hue update
if (hSet == 0) {
displayDesc = F(" HUE (FIXED)");
CLdisplayVal = hueVal;
break;
}
if (hueROallow == 1) EncReadingRO();
else EncReading();
hueVal = encVal;
CLdisplayVal = encVal;
displayDesc = F(" HUE");
break;
case 2: // saturation update
if (sSet == 0) {
displayDesc = F(" SATURATION (FIXED)");
CLdisplayVal = satVal;
break;
}
EncReading();
satVal = encVal;
CLdisplayVal = encVal;
displayDesc = F(" SATURATION");
break;
case 3: // value update
if (vSet == 0) {
displayDesc = F(" BRIGHTNESS (FIXED)");
CLdisplayVal = valVal;
break;
}
EncReading();
valVal = encVal;
CLdisplayVal = encVal;
displayDesc = F(" BRIGHTNESS");
break;
case 4: // delay update
if (dSet == 0) {
displayDesc = F(" TIMING (FIXED)");
CLdisplayVal = delVal;
break;
}
EncReading();
delVal = encVal;
CLdisplayVal = encVal;
displayDesc = F(" TIMING");
break;
}
displayReading();
}
void displayReading() {
unsigned long currMillis = millis(); // These four lines are to
static unsigned long prevMillis; // act as a delay, except
if (currMillis - prevMillis >= 100) { // without holding the execution // note: encoder reading sensitive to delal changes, 100 not bad
prevMillis = currMillis; // of other code
display.fillRect(39, 30, 54, 24, BLACK);
display.fillRect(0, 0, 128, 18, WHITE);
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(1,1);
display.println(displayMode);
display.setCursor(1,10);
display.println(displayDesc);
display.setTextSize(3);
display.setTextColor(WHITE);
display.setCursor(39,30);
display.println(CLdisplayVal);
display.display();
}
}
};
////////// Construct objects - this sets up the objects we want of the class 'Modes'
// Modes modex(Hue0-255, Sat0-255, Val0-255, Del0-255, Hue rollover0/1, Hue settable0/1, Sset0/1, Vset0/1, Dse0/1
Modes mode1(50, 100, 150, 100, 1, 1, 1, 1, 1); // object 'mode1', initializing with H50, S100, V150, D100, hue rollover & settable options ON
Modes mode2(55, 105, 155, 105, 0, 1, 1, 1, 1);
Modes mode3(63, 73, 83, 93, 0, 1, 1, 1, 1);
////////////////////////////////////////////////////////
////////// ******** SETUP / LOOP ********* /////////////
////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
display.begin(SH1106_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64)
display.clearDisplay();
display.display();
pinMode(EncApin, INPUT_PULLUP); // Turn on internal pullup resistors for encoder pins & buttons
pinMode(EncBpin, INPUT_PULLUP);
pinMode(Button2, INPUT_PULLUP);
pinMode(EncButt, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EncApin), read_encoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(EncButt), encButtPress, FALLING);
pciSetup(Button2); // set up encApin for pin change interrupt
encVal = mode1.hueVal; // initialize the encoder to the mode1 setmode1 value
}
void loop() {
switch(mode) {
case 1:
displayMode = F("MODE:Call it anything");
mode1.Update();
// add call to the mode 1 LED display function here, using mode1.xyz variables
break;
case 2:
displayMode = F("MODE:Second");
mode2.Update();
// add call to the mode 2 LED display function here, using mode2.xyz variables
break;
case 3:
displayMode = F("MODE:Third");
mode3.Update();
// add call to the mode 2 LED display function here, using mode2.xyz variables
break;
}
Serial.print(F("Enc: "));
Serial.print(encVal);
Serial.print(F(" M1 H: "));
Serial.print(mode1.hueVal);
Serial.print(F(" S: "));
Serial.print(mode1.satVal);
Serial.print(F(" V: "));
Serial.print(mode1.valVal);
Serial.print(F(" D: "));
Serial.print(mode1.delVal);
Serial.print(F(" M2 H: "));
Serial.print(mode2.hueVal);
Serial.print(F(" S: "));
Serial.print(mode2.satVal);
Serial.print(F(" V: "));
Serial.print(mode2.valVal);
Serial.print(F(" D: "));
Serial.println(mode2.delVal);
// Serial.print(F("freeMemory()="));
// Serial.println(freeMemory());
}
////////////////////////////////////////////////////////
//////////// ******** FUNCTIONS ********* //////////////
////////////////////////////////////////////////////////
///// Function to set encVal, 0-255, NO rollover
void EncReading() {
int8_t encoderdata;
encoderdata = read_encoder(); // returns the +- value from the read_encoder function
if (encoderdata) { // if not equal to zero
if (encVal+encoderdata>255 || encVal+encoderdata<0); // these if/else statements clamp encVal to prevent byte rollover
else {
encVal += encoderdata;
} // end else
}
}
///// Function to set encVal, 0-255, WITH rollover
void EncReadingRO() {
int8_t encoderdata;
encoderdata = read_encoder(); // returns the +- value from the read_encoder function
if (encoderdata) { // if not equal to zero
encVal += encoderdata;
}
}
////////////////////////////////////////////////////////
//////////// ******** INTERRUPTS ********* /////////////
////////////////////////////////////////////////////////
/////// Pin Change Interrupt Setup Function /////////// called in void setup to set the selected pin as a PCI
void pciSetup(byte pin)
{
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
//////////// PCI Interrupt Sub Routines////////
// ISR (PCINT0_vect) is ISR for D8-13 // ISR (PCINT2_vect) is ISR for A0-5 // ISR (PCINT2_vect) is ISR for D0-7 //
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here, depending on which are set in void setup
{
if(digitalRead(Button2) == LOW)
buttonPress();
}
//////// Func for ENCODER button press ISR ****** CHANGE 'setMode' ***** ///////////////
void encButtPress() {
static unsigned long prevInterrTime = 0;
unsigned long interrTime = millis();
if (interrTime - prevInterrTime > 200) {
setMode++;
// *** ADD HERE *** need to set encVal to whatever the existing value is in the setMode being switched to
if (setMode > qtySetModes) setMode = 1;
prevInterrTime = interrTime;
setPrevEncVal(mode);
}
}
void setPrevEncVal(byte (*modeNum)) {
switch (setMode) {
case 1: encVal = mode&modeNum.hueVal; break;
case 2: encVal = mode1.satVal; break;
case 3: encVal = mode1.valVal; break;
case 4: encVal = mode1.delVal; break;
}
}
//////// Func for button press ISR ****** CHANGE 'mode' ***** ///////////////
void buttonPress() {
static unsigned long prevInterrTime = 0;
unsigned long interrTime = millis();
if (interrTime - prevInterrTime > 200) {
mode++; // increment 'mode'
setMode = 1; // reset 'setMode'
}
if (mode > qtyModes) mode = 1;
prevInterrTime = interrTime;
}
//////// Func for +1/-1 encoder reading ISR ///////
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder() {
static uint8_t old_AB = 0;
old_AB <<= 2;
old_AB |= ((digitalRead(EncBpin))?(1<<1):0) | ((digitalRead(EncApin))?(1<<0):0);
return ( enc_states[( old_AB & 0x0f )]);
}
To answer the question:
You can't, because C++ is a compiled language, and as such, the names of the functions, objects and variables become meaningless (instead, they become just addresses)
For example, you may see in your code
int myVariable = 6;
but the compiler sees:
mov [6], [0x6874]
Read Compiled vs. Interpreted Languages for more reference.
[For your particular case]
You'll be better off if you use interfaces and a factory.
class Mode {
virtual int getAttribute() = 0;
}
class AMeaningfulName : public Mode {
int getAttribute() { return 1; }
}
class SelectAnotherMeaningfulNamePlease : public Mode {
int getAttribute() { return 2; }
}
class ModeFactory {
Mode getMode(int userSelectedMode) {
if (userSelectedMode == MODE_1) {
return new AMeaningfulMode();
} else if (userSelectedMode == MODE_2) {
return new SelectAnotherMeaningulNamePlease();
} else {
//send an exception so the user knows he selected something invalid
}
}
}
///now, in your main or elsewhere
ModeFactory factory = new ModeFactory();
Mode mode = factory.getMode(userSelectedValue);
int theAtttributeIWanted = mode.getAttribute();
Take a look at virtual functions
https://en.wikipedia.org/wiki/Virtual_function
And also at factory pattern
https://www.tutorialspoint.com/design_pattern/factory_pattern.htm