Problemen met vergelijken strings

Hallo lezer,

Ik ben nog steeds een redelijke beginner o.b.v. het programmeren. Voor school ben ik bezig met een project waarbij ik een app heb gemaakt (eigenlijk moet ik ook nog de software serial library is onderzoeken, maar tot nu toe werkt dit helemaal). Nu loop ik tegen een paar dingen aan:

Met de Serial.print() kan ik de data via de HC-05 naar mn app sturen. Hoe kan ik iets printen zonder dat hij dat stuurt, dit wil ik voor het demofilmpje om bijvoorbeeld te printen dat je geconnect bent of dat de training is gestart.

Ik heb nog totaal geen ervaring met het gebruik van Strings. Ik heb allereerst de String Name = "" aangemaakt, vervolgens de app zo geprogrammeerd dat hij een naam moet sturen en dan als Name != "" is je verder kan met de loop, dit heb ik een beetje getest en de eerste keer deed hij dat prima volgens mij. Daarna heb ik het zo geprogrammeerd dat als hij niet meer connected is dat wanneer die pin weer HIGH wordt dus connectie is hij Name weer set naar "". Voor een of andere reden lijkt die dit eigenlijk niet te herkennen en kan ik gwn mn test doen en print die de data wat eigenlijk dus niet de bedoeling is aangezien hij niet in die loop hoort te kunnen komen.

Ik heb mijn code hierin geplakt, ik hoop dat deze duidelijk is en ook mijn denk proces duidelijk beschreven is. Ik zou graag een steuntje in de rug willen om de eerste wens maar vooral mijn tweede probleem op te lossen, aangezien ik niet kan vinden waarom mijn probleem niet werkt.

Groetjes,
Bram

// Connect the HC-05 TX to Arduino pin 0 RX. 
// Connect the HC-05 RX to Arduino pin 1 TX through a voltage divider.
const byte BTpin = 3;// connect the STATE pin of the HC-05 to Arduino pin D3
const byte PotPin = A0;// connect the potentiometer to Arduino pin A0
const byte PunchButton = 2;// connect the button to Arduino pin D2


//// Add variables
long Val = 0;// value of potentiometer
unsigned long Timer = 0;// varbiable to work with the timer


float SpeedOfPunch = 0;
float PowerOfPunch = 0;
int TimesPunched = 0;
float AVGPunchingSpeed = 0;
float AVGPunchingPower = 0;


String Name = "";// string which contains the name of the player


//// Add Errors
boolean SDerror = false;
boolean Systemerror = false;


//// Make the punch button work
boolean ButtonState = LOW;
boolean DebouncePunchButton(boolean State)
{
  boolean NewState = digitalRead(PunchButton);
  if (State != NewState)
  {
    delay(10);
    NewState = digitalRead(PunchButton);
  }
  return NewState;
}


void setup() 
{
  pinMode(BTpin, INPUT);
  pinMode(PunchButton, INPUT);
  Serial.begin(9600);
  while (digitalRead(BTpin) == LOW) // can't move on unless you connect
  {
    if (digitalRead(BTpin) == HIGH)
    {


    }
  }
  delay(500);
}


void loop() 
{ 
  if (digitalRead(BTpin) == HIGH)
  {
    if (Serial.available() != 0) 
    {
      Name = Serial.readString();                                                // read the name send
    }
  
    if (Name != "" && SDerror == false && Systemerror == false)     
    {
      if (TimesPunched == 0)
      {
        if(DebouncePunchButton(ButtonState) == HIGH && ButtonState == LOW)       // the first punch will start the timer
        { 
          TimesPunched++;                                                        // add 1 punch 
          Val = analogRead(PotPin);                                                                                       
          SpeedOfPunch = map(Val, 0, 1023, 5, 10) + SpeedOfPunch;                // boxers generaly punch between 5 and 10 m/s 
          PowerOfPunch = map(Val, 0, 1023, 440, 1100) + PowerOfPunch;            // olympic boxers punch between 440 an 1100 pounds
          ButtonState = HIGH;
          Timer = millis();
        }
        
        else if (DebouncePunchButton(ButtonState) == LOW && ButtonState == HIGH) 
        {
          ButtonState = LOW;
        }
      }  
      else if (TimesPunched >= 1)
      {
        if(DebouncePunchButton(ButtonState) == HIGH && ButtonState == LOW)       // when the button is pushed
        { 
          TimesPunched++;                                                        // add 1 punch 
          Val = analogRead(PotPin);                                                                                       
          SpeedOfPunch = map(Val, 0, 1023, 5, 10) + SpeedOfPunch;                // boxers generaly punch between 5 and 10 m/s 
          PowerOfPunch = map(Val, 0, 1023, 440, 1100) + PowerOfPunch;            // olympic boxers punch between 440 an 1100 pounds
          ButtonState = HIGH;
        }


        else if (DebouncePunchButton(ButtonState) == LOW && ButtonState == HIGH)
        {
          ButtonState = LOW;
        }
    
        else if ((millis() - Timer) >= 10000)                                    // check if 10 seconds have past to simulate the training is done and print the information
        {
          AVGPunchingSpeed = SpeedOfPunch/TimesPunched;                          // calc the average speed
          AVGPunchingPower = PowerOfPunch/TimesPunched;                          // calc the average power
          Serial.print(TimesPunched);
          Serial.print("|");
          Serial.print(AVGPunchingSpeed, 2);
          Serial.print(" m/s");
          Serial.print("|");
          Serial.print(AVGPunchingPower, 2);
          Serial.print(" N");
          Serial.println();
          delay(10000);
          Serial.print("Break done");
          Serial.println();
          TimesPunched = 0;
          SpeedOfPunch = 0;
          PowerOfPunch = 0;
        }
      }
    }
    if (SDerror == true)                                                         // print the error once for the app to recieve
    {
      Serial.print("SD error");
      Serial.println();
    }


    if (Systemerror == true)                                                     // print the error once for the app to recieve
    {
      Serial.print("System error");
      Serial.println();
    }
  }
  
  else if (digitalRead(BTpin) == LOW)
  {
    if (digitalRead(BTpin) == HIGH)                                              // reset the variables to their default
    {
      TimesPunched = 0;
      SpeedOfPunch = 0;
      PowerOfPunch = 0;
      Name = "";
    }
  }
}

Je uitleg en code begrijp ik niet helemaal :frowning:

Welk Arduino board gebruik je ?

Het eenvoudigste is een board met een extra hardware serial poort, zoals de Leonardo, (Pro) Micro, Zero, MKR boards, enzovoorts.
Sommigen gebruiken SoftwareSerial, maar dat neemt bijna de hele Arduino in beslag.

Of je een beginner bent of gevorderd, het is beter om altijd iets naar de seriële monitor te kunnen sturen. Dus bij een Arduino Uno kun je beter de pinnen 0 en 1 niet voor iets anders gebruiken.

Een millis-timer loopt altijd in het main level van de loop(). Soms binnen een 'enable' en soms binnen een Finite State Machine, maar eigenlijk nooit binnen een paar if-statements zoals jij hebt.
Dus je start de millis-timer, en daarna kijk je er niet meer naar om en laat je die millis-timer lopen in de loop(). Zoals in mijn voorbeeld millis_single_delay.ino.

Ik gebruik een arduino uno, volgens mij heb ik het naam gedeelte al werkend gekregen. Weet niet precies wat er in de loop fout is gegaan bij het onderste gedeelte van mn loop. Wanneer de connectie niet verbonden is zegmaar en er een nieuwe connectie komt daar heb ik staan dat hij Name weer set naar "" (dat is het onderste gedeelte if BTpin == low ) en dan in mijn loop dat Name geen "" mag zijn (de if Name != ""), later even naar gekeken en wat geprobeerd en volgens mij doet dat het nu wel, weet alleen niet precies wat ik daar eerst fout had gedaan.

Wat betreft de millis snap ik niet precies wat je bedoelt, ik heb een if statement namelijk als die TimesPunched 0 is daar blijft hij in vast hangen tot dat ik in mijn test geval een button in klik dat is mijn punch zegmaar. Dan set ik Timer gelijk aan millis() zodat de timer start. Misschien is de code een beetje rommelig dus ik maak even een nieuwe wat minder rommelige zodat het wat makkelijker te lezen is wat ik doe (zal waarschijnlijk wel wat dingen vergeten zijn omdat ik snel heb gewerkt maar het gaat om mijn gedachte proces), want het werkt in ieder geval wel dus never change a winning team zou ik zeggen xD

Mijn probleem met de naam is dus opgelost, nu had ik nog een wens dat ik kan printen naar de serial monitor zonder dat de TX pin aangestuurd wordt eigenlijk. Ik wil bijvoorbeeld kunnen printen "Connected" maar met Serial.println() gaat hij dat versturen en dan stuurt hij dus die line naar mijn app maar dat wil ik in sommige gevallen niet hebben, dan wil ik wel iets printen maar niet sturen eigenlijk maar ik weet niet of het mogelijk is?

Maar het is dus ook prima mijn code zonder SoftwareSerial te laten werken heeft niet veel voordeel eigenlijk?

Hoop dat dit wat duidelijker is, al heb ik daar mijn twijfels aangezien ik daar niet zo goed in ben. Zelf snap ik het wel helemaal maar overbrengen in tekst is een stuk lastiger, mocht het nou toch weer opgeschreven zijn als de eerste beste dorpsgek hoor ik graag wat er niet duidelijk is, bedankt in ieder geval voor de reactie zover.

groeten, Bram

int Timer = 0;
int TimesPunched = 0;
boolean Punched = false;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}


void loop() {
  // put your main code here, to run repeatedly:
  if (TimesPunched == 0) // State waar er nog niet geslagen is dus de training nog niet gestart is
  {
    if(Punched == true) // Er wordt geslagen
    {
      TimesPunched++; // Hierdoor wordt TimesPunched = 1 zodat hij naar de volgende loop kan
      Timer = millis(); // Snel Timer gelijk stellen aan millis() omdat anders natuurlijk de timer niet werkt aangezien millis() dan al een voorsprong heeft
    }
  }
  if (TimesPunched >= 1) // verdere training
  {
    if(Punched == true)
    {
      TimesPunched++;
    }
    if (millis() - Timer >= 2000) // Na 2 sec is de timer klaar
    {
      Serial.println(TimesPunched); // Print hoevaak er geslagen is
      TimesPunched = 0; // Zet TimesPunch terug naar 0 zodat hij terug naar de andere loop gaat waar hij weer niets doet tot er geslagen wordt
    }
  }
}

Laten we de twee dingen goed gescheiden houden: er is een "serial monitor" en er is "bluetooth".
Je kunt die niet op dezelfde pinnen zetten. Dat is onmogelijk.

Met een Arduino Uno zit er niets anders op dan SoftwareSerial te gebruiken.

Eventueel kun je AltSoftSerial gebruiken. Dat gebruikt vaste pinnen voor RX en TX maar bij 9600 baud loopt het beter dan SoftwareSerial.

Gebruik "Serial" voor de serial monitor, zoals iedereen doet.
Maak een SoftwareSerial met een goede naam voor bluetooth, bijvoorbeeld "SerialBluetooth", "SerialHC05" of zo iets. Het gaat er om dat je in je sketch meteen ziet welke het is. Sommigen gebruiken "Serial1", maar dan is een foutje snel gemaakt.

Met millis() zie ik nu geen problemen 8) De millis-timer loopt zolang 'TimesPunched' groter dan 1 is. Als de tijd om is zet de millis-timer zichzelf uit door 'TimesPunched' 0 te maken. Prima.
Je eerste sketch geeft mij het gevoel dat het teveel in elkaar is gedraaid. Probeer code zoveel mogelijk uit elkaar te trekken en apart te houden.
Bijvoorbeeld:

void loop()
{
  // 1: verzamel alle gegevens van sensors en drukknoppen

  // 2: verwerk de gegevens

  // 3: uitvoer van de gegevens.
}

Deel 2 en 3 is vaak gecombineerd. In deel 1 kun je eenmalig kijken of een knop is ingedrukt.

Oke denk dat ik die AltSoftSerial dan wel snap als je dan tx en rx voor mn bluetooth op pin 9 en 8 zet en dan Serial.print gebruikt paktie gewoon de pins 0 en 1 ervoor dus interfeert hij niet en als je dan AltSoftSerial print, print hij over 9 en 8 en zendt hij dus wel gewoon over bluetooth. Ik neem aan dat je niet hoeft op te letten dat die pins met uploaden nog niet verbonden zijn aangezien dit niet de daardwerkelijke rx en tx pins zijn?

Voor je opmerking teveel in elkaar gedraaid denk ik dat je bedoeld dat het al best wel wat statements zijn die dan ook nog veel dingen bevatten zoals het vele printen misschien waardoor door de vele informatie die er eigenlijk staat het nogal omslachtig wordt zegmaar denk dat je dat bedoeld of niet? Dit is dan 1 stukje van ons project (het is tevens ook een demo dus dit is niet wat heel het systeem moet gaan doen), maar ik wilde gaan kijken hoe het zit met extra tabs maken sowieso voor de daadwerkelijke hoofdcode. Denk dat als ik wat tabs maak om de functies en vars voor de verschillende componenten in te zetten en die verwerk in de hoofdcode i.p.v een hele lap in een keer erin zetten, dan is alles wat duidelijker georiënteerd en ik denk dat je daarmee zat dat het nu wel veel info op je beeldscherm ineens is of niet?

En misschien wat meer enters om delen wat meer gescheiden te houden kan misschien ook wel geen kwaad nee.

Aangezien bij het eindproduct ik geen aparte Serial monitor hoef te hebben aangezien de arduino toch in de bokszak gaat zal ik daarvoor die library ook niet gebruiken en dus wel pins 0 en 1. Hij is puur voor de demo om te laten zien wanneer je begint, dat je daadwerkelijk zolang slaat of om te laten zien dat hij inderdaad een naam heeft ontvangen. Beetje extra verduidelijken voor tijdens het filmpje dat het wat makkelijker is allemaal te laten zien dat alles goed werkt

Bedankt in ieder geval voor de replies hebben me goed geholpen.

Het uploaden gaat vanzelfsprekend via pin 0 en 1. Die zijn altijd verbonden met de usb-serial chip via weerstanden. Vanwege die weerstanden is het mogelijk om ze ook voor iets anders te gebruiken.
Digitale pinnen die nog niet in gebruik zijn, die zijn INPUT bij het aanzetten van de Arduino Uno. Dat is veilig.

Met "dat het teveel in elkaar is gedraaid" bedoel ik dat je verschillende functionaliteit door elkaar heen weeft. Dat is gevoelsmatig, dus ik heb niet opeens een betere oplossing klaar liggen :wink:

Het is echter wel netter om in de loop() maar één keer de knoppen op te vragen.

Je hebt dit:

if(DebouncePunchButton(ButtonState) == HIGH ...
...
else if (DebouncePunchButton(ButtonState) == LOW ...

Je vraagt twee keer de knop op. Het is lastig om in je sketch er rekening mee te houden dat de knop tussendoor kan wijzigen.

Bij dit frons ik mijn wenkbrauwen: boolean NewState = digitalRead(PunchButton);
Als je digitalRead() leest, dan staat er dat de return een HIGH of LOW is. Een boolean is echter true of false. Dat zijn twee verschillende werelden.
Er staat nergens in de officiële Arduino documentatie dat het is toegestaan.

Het is misschien beter om nog niet aan het eindproduct te denken. Je sketch optimaliseren doe je pas als alles goed werkt.

Is het niet zo dat bij boolean false = 0 en true > 0 en aangezien HIGH = 1 en LOW = 0, maakt dat volgens mij niet uit. Maar ik kan dat ook wel naar true en false aanpassen hoor lervert denk ik geen probleem op.

Die 2de else if is nodig om mijn buttonstate te resetten anders gaat hij niet meer naar zijn oorspronkelijke positie, aangezien buttonstate dan niet meer LOW kan worden en dus ook niet meer terug in de andere loop kan vallen. Ik zie eigenlijk ook geen weg dat aan te passen.

Als je dit doet:

void loop()
{
  // 1: verzamel alle gegevens van sensors en drukknoppen

  // 2: verwerk de gegevens

  // 3: uitvoer van de gegevens.
}

dan verzamel je eerst alle gegevens en die zet je in variabelen. Bij deel 2 kunnen dan beslissingen genomen worden op basis van die variabelen.

Stel dat je de debounce wilt aanpassen of iets anders wilt doen met de knop. Dan is het netter om slechts één keer in de loop() de knop op te vragen.

Mag ik een beetje vaag worden ? Kijk van een afstand eens naar de data-flow van alle gegevens.
Een data-flow kan de temperatuur van een sensor zijn, maar ook een knop die aan of uit is.
Als je kijkt hoe de data door je sketch stroomt dan kan er maar een punt zijn waar de gegevens van iets binnenkomen. Een knop levert een data-stroom op, die vervolgens door je sketch stroomt.

Ja, true en HIGH en 1 zijn zo ongeveer hetzelfde, net als false en LOW en 0. Daar wordt heel veel gebruik van gemaakt, maar ik doe dat niet. Bewijs maar eens dat het is toegestaan en bij ieder board in de toekomst zal werken :smiley_cat:

Bedoel je dit meer met maar 1x aanroepen dat je de if TimesPunched juist in de if debouncebutton verwerkt zodat je maar een keer die if deboucebutton hoeft te doen? Verder met de dataflow begrijp ik inderdaad niet echt wat je bedoeld :sweat_smile:

En dan die millis timer moet eruit en in deel 2 verwerkt worden en dan printen in deel 3 dat bedoel je denk he?

void loop() 
{
  // put your main code here, to run repeatedly:
    if(DebouncePunchButton(ButtonReady) == true && ButtonReady == false)// The first punch will start the timer
    { 
      if (TimesPunched == 0)
      {
        TimesPunched++;// Add 1 punch 
        ButtonReady = true;
        Timer = millis();
        Serial.println("Training has started");
      }


      else if (TimesPunched >= 1)
      {
        TimesPunched++;// Add 1 punch 
        ButtonReady = true;
        else if ((millis() - Timer) >= 10000)// Check if 10 seconds have past to simulate the training is done and print the information
        {
          Serial.print(TimesPunched);
          delay(5000);
          Serial.print("Break done");
          Serial.println();
          TimesPunched = 0;
        }
      }
    
    else if (DebouncePunchButton(ButtonReady) == false && ButtonReady == true) 
    {
      ButtonReady = false;
    }
  }
}

Ik bedoel dat je bezig bent met deel 2 (het verwerken van de gegevens en beslissingen nemen) en in dat deel twee keer de functie DebouncePunchButton() aanroept, dus twee keer de knop leest. Je verzamelt dus gegevens terwijl je bezig bent om beslissingen te nemen. Als je dat kunt scheiden is het beter en duidelijker.
Als je sketch werkt, dan kun je het zo laten.

Ik kan proberen het nog eens uit te leggen, maar dan wordt ik nog vager :o

"code-flow": Je kunt een sketch zien als: doe dit, doe dat, als dit dan dat. Dan vraag je in de code de stand van de knop op.

"data-flow": Je kunt een sketch ook zien als: hoe loopt de data door de sketch. De informatie van de knop (aan of uit) is een data-stroom en die wordt je sketch ingestuurd. De sketch moet die informatie verwerken.

Leun eens achterover, en visualiseer ballonnen die met elkaar verbonden zijn.
Er is een ballon die de knop leest en waar de debounce in zit. Er is een ballon die de millis-timer doet. Daar tusen zit een ballon die het aantal punches telt en die verbonden met die twee andere ballonnen.

Dan is er geen ruimte om nog een extra ballon toe te voegen die ook de knop leest en precies hetzelfde doet als de eerste ballon.

Programmeren is niet naar je scherm kijken wat je daar in die regel nodig hebt. Programmeren is achterover leunen ;D

Wellicht kun je me hier ook mee helpen. We moeten nu die codes een beetje combineren en dit is de code van een groepsgenoot. Die code doet het wel, nu is het probleem alleen dat de baudrate eigenlijk op 57600 moet zoals ik ergens ooit gelezen hebt gaat dat over sneller data kunnen ontvangen dus ben je met een hogere baudrate meer accuraat zegmaar.

Nu is het zo dat we dan Serial.begin (57600) (in de code hieronder niet daar staat 9600 maar dat leg ik dadelijk uit) zeggen en dan "Starting..." printen, hij liet het vanochtend even zien maar dan print hij op de eerste lijn rare tekens zegmaar en dan daarna zegt hij wel "Starting..." terwijl we zeggen dat de baudrate op 57600 moet en de serial monitor ook gewoon op 57600 staat. Wij kunnen alleen niet plaatsen waar die tekens ineens vandaan komen, het lijkt wel of de loadcell of amp even zichzelf moet aanpassen naar de baudrate ofzo, als we begin en de monitor naar 9600 aanpassen doet hij dit bijvoorbeeld niet.
Ik heb er helaas geen screenshot van dus ik hoop dat de uitleg wel voldoende is.

om nog even te visualiseren:
Serial.begin(57600);
monitor op baudrate 57600

print:
[]!!?![[!]
Starting...

Serial.begin(9600);
monitor op baudrate 9600

print:
Starting...

We zouden die baudrate graag op 57600 houden waar de code ook eerst mee instond maar met de bluetooth module kunnen we die rare print niet gebruiken, dus de vraag is hoe kunnen we die baudrate gebruiken maar niet die onzin eerst printen. Maar ik snap niet waarom hij dat überhaupt doet

#include <HX711_ADC.h>
#include <EEPROM.h>


//pins:
const int HX711_dout = 4;            //mcu > HX711 dout pin
const int HX711_sck = 5;             //mcu > HX711 sck pin


unsigned long Punch = 0;             //De kracht van de slag die gemeten wordt
float Punchmax = 0;                  //De maximale kracht die 1 slag heeft geleverd
boolean Ready4Punch = false;         //Een controle die zorgt dat hij weer meet als loadcell klaar is
int TimesPunched = 0;                //Aantal keren dat je hebt geslagen
float PowerOfPunch = 0;              //De totale kracht van alle slagen bij elkaar in 1 sessie
unsigned long Offset = 200;          //Minimaal gewicht waar de punch aan moet voldoen om gemeten te worden. In grammen
float AVGPowerOfPunch = 0;
unsigned long Timer = 0;


//HX711 constructor:
HX711_ADC LoadCell(HX711_dout, HX711_sck);


const int calVal_eepromAdress = 0;
long t;


void setup() 
{
  Serial.begin(9600); 
  delay(10);
  Serial.println("Starting...");
  
  LoadCell.begin();
  float calibrationValue; // calibration value (see example file "Calibration.ino")
  calibrationValue = 200.0; // uncomment this if you want to set the calibration value in the sketch
  EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom
  long stabilizingtime = 2000; // preciscion right after power-up can be improved by adding a few seconds of stabilizing time
  boolean _tare = true; //set this to false if you don't want tare to be performed in the next step
  LoadCell.start(stabilizingtime, _tare);
  if (LoadCell.getTareTimeoutFlag()) 
  {
    Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
    while (1);
  }
  else 
  {
    LoadCell.setCalFactor(calibrationValue); // set calibration value (float)
    Serial.println("Startup is complete");
  }
}


void loop() 
{
  static boolean newDataReady = 0;
  const int serialPrintInterval = 0; //increase value to slow down serial print activity
  
  // check for new data/start next conversion:
  if (LoadCell.update()) newDataReady = true;


  // get smoothed value from the dataset:
  if (newDataReady) 
  {
    if (millis() > t + serialPrintInterval) 
    {
      Punch = LoadCell.getData();
      newDataReady = 0;
      t = millis();
    }


    
    if (Punch < Offset)                                                 //Kijkt of de loadcell weer kan meten
    {
      Ready4Punch = true;                                               //Staat klaar om te meten
    } 
    
    if (Punch >= Offset && Ready4Punch == true && Punch < 100000)       //Vergelijkt of Punch groter is dan minimale waarde om te meten dan kijkt hij of loadcell eerst onder ofset is geweest en dus gereset is en 
    {                                                                   //als laatste kan het niet groter zijn dan 100 kg aangezien de loadcell maar 100kg aan kan(voorkomen van bugs)
      if(Punch > Punchmax)                                             
      {
        Punchmax = Punch;                                               //Zet maximale kracht van slag vast
      }
      else if ((Punch + Ofset) < Punchmax)            
      {
        if(Timespunched == 0)
        {
          Timer = millis();
          Serial.println("Training started");
        }
        Ready4Punch = false;                          //Reset de waarde om te meten
        TimesPunched++;                               //Houd bij op welke slag je zit
        Punchmax = Punchmax * (9.807/1000.);          //Rekent Punchmax van gewicht naar Newton
        PowerOfPunch = Punchmax + PowerOfPunch;       //Rekent de totale kracht uit van alle slagen bij elkaar
        Punch = 0;                                    //Reset de gemeten slag waarde naar 0. Staat klaar om opnieuw te meten
        Punchmax = 0;                                 //Reset de maxiamele slag waarde naar 0. Kan opnieuw meten naar nieuwe maximale waarde
      }
    }
    if (Timespunched >= 1)
    {
      if(millis() - Timer >= 60000)
      {
         AVGPowerOfPunch = PowerOfPunch / TimesPunched;
         Serial.print("Punch nummer: ");
         Serial.println(TimesPunched);                 //Laat aantal slagen zien in serial monitor. Laat zien op welke slag je zit
         Serial.print("AVG Punch: ");
         Serial.println(AVGPowerOfPunch);
         Serial.println();      
         Timespunched = 0;
         PowerOfPunch = 0;
         Punchmax = 0;
         Punch = 0;
      }
    }
  }
}

Dit is niet correct: millis() > t + serialPrintInterval
De millis() waarde telt tot 0xFFFFFFFF en rolt dan door naar 0x00000000. Om "rollover" problemen te voorkomen mag je geen tijd in de toekomst berekenen. Neem de millis-waarde van dit moment en sla die op in 'previousMillis' en doe dan later: millis() - previousMillis. Dat gaat zelfs goed als de millis-waarde bezig is met een rollover.

In bepaalde situaties krijg je tekens voordat de sketch start. Ik vermoed dat er dan nog iets in een buffer zit. Die seriële poort wordt ook gebruikt om de sketch te uploaden. Dat omschakelen geeft soms wat rare dingen.

Je kunt het testen:

void setup()
{
  Serial.begin( 115200);   // of 9600 of iets anders.
  Serial.println( "Hallo allemaal, de sketch is begonnen !");
}

void loop()
{
}

Als je bij het uploaden vreemde tekens ziet, druk dan eens op de reset-knop. Als het goed is zie je dan geen vreemde tekens.

Ik heb een dingetje met de I2C communicatie.
Ik heb wat filmpjes gezien en ik snap hoe het aangesloten moet worden, maar ik mis telkens hoe je het moet programmeren.

bv:
ik gebruik een MPU6050 en een INA219 beide gaan via de I2C bus, maar verschillende addresses

ik snap niet echt hoe ik het moet programmeren dat het programma ook weet vanaf welk address het komt bv in de code hieronder. Hoe moet het programma weten dat deze data van de INA komt bijvoorbeeld moet ik extra dingen toevoegen van het komt van dit address bijvoorbeeld af en zo ja hoe doe ik dat?

      if(millis() - previousMillis >= 100)
      {
        previousMillis = millis();
        shuntvoltage = ina219.getShuntVoltage_mV();
        busvoltage = ina219.getBusVoltage_V();
        stroom_mA = ina219.getCurrent_mA();
        spanning_V = busvoltage + (shuntvoltage/1000);


        vermogen = spanning_V*stroom_mA;                                  // Het vermogen uitrekenen dmv U*I
        energie = energie + vermogen*(0.1/3600);                          // energie uitrekenen door vermogen*interval in uren te doen
      }

Dat gaat vanzelf.

Een sensor reageert alleen op zijn eigen I2C adres.
De communicatie met een sensor gaat altijd via dat I2C adres. Dat is altijd het eerste byte bij elke lees- of schrijfactie.

Iedere library gebruikt dus ook iedere keer dat I2C adres. Iedere functie van de library laat de I2C bus netjes achter, zodat anderen van de I2C bus gebruik kunnen maken.

Het komt er op neer dat je in de sketch de functies van de verschillende libraries door elkaar heen kunt gebruiken, en dat gaat altijd goed.
Het is natuurlijk wel nodig dat de library het juiste I2C adres gebruikt. Stel dat de library 0x68 gebruikt en jouw MPU-6050 zit op 0x69. Dat zit die library zomaar een beetje in de lucht te praten. Meestal is er een soort van "init" of "begin" functie in die library waar dat I2C adres ingevuld kan worden.

ik bedoel ook meer dat als de ina nou data verstuurd over die bus hoe weet de pin zelf dat hij van de ina komt en niet van de mpu.

stel ik heb deze code en plak er meteen de code van de mpu achter hoe weet het systeem dat het ene data is van de ina en de andere van de mpu, moet ik eerst nog addresses ervoor definen of zit ik te moeilijk te denken en gaat dit vanzelf?

ervan uitgaande dat ze in losse tests ook werken zonder addresses te definen ervoor, moeten ze als ze bij elkaar in een sketch komen wel defined worden. ik vind het gewoon een beetje een raar idee dat de arduino alsnog zomaar weet wat van waar af komt aangezien ze allebei wel dezelfde pin hebben maar dat kan met ervaring natuurlijk te maken hebben.

Meestal heeft de MPU-6050 het I2C adres 0x68. Die staat dus meestal als default in de library.
Adafruit heeft bijvoorbeeld 0x40 als default in hun library voor de INA219 (Adafruit_INA219/Adafruit_INA219.h at master · adafruit/Adafruit_INA219 · GitHub).

Iedere functie van een library communiceert bij elke lees- en schrijfactie via dat I2C adres.
Iedere functie wacht ook totdat de data van de sensor helemaal geschreven en gelezen is.

Misschien denk je teveel aan een gewone seriële bus ? Bij het versturen via een seriële bus komt het in een buffer, en ooit wordt dat verzonden.
De I2C bus werkt totaal anders. Er wordt gewerkt met pakketjes van data. De data wordt niet zomaar op de bus losgelaten. Er is constant heen en weer communicatie tussen Master en Slave tijdens een lees- of schrijfactie. De SDA en SCL signalen zijn bi-directioneel, de gegevens gaan dus beide kanten op.

Een sensor is altijd een I2C Slave. Die doet nooit iets uit zichzelf. De Master kan data opvragen van een Slave en de Master kan data sturen naar een Slave. Meer mogelijkheden zijn er niet.

De Master is meestal de Arduino, die weet dus bij elk byte (en eigenlijk bij elk bit) precies wat de Slave doet. De Slave volgt het clock signaal SCL van de Master en moet dat ook bij houden. Ze houden elkaar dus heel de tijd in de gaten, bij elk bit.

Als dat hele gebeuren eindelijk is afgerond, dan pas is een functie uit een library afgelopen. Als je in de sketch de volgende functie aanroept, dan is het vorige dus helemaal afgerond.

Het toverwoord is hier datasheet (er vanuit gaande dat de fabrikant van de hardware daar ook een beetje hun best op heeft gedaan).
In de MPU 6050 datasheet (klik !) staat op pagina 36 precies uitgelegd hoe de master (je Arduino) bij de slave data per register (zie dat als een kleine lade uit een grote ladekast) opeist, en hoe de slave dan doorgeeft dat ie begrepen heeft dat ie aangesproken word, en aan de eis voldoet.

Je zult zien dat andere chips / sensoren ook op een dergelijke manier werken.