Drukknop configureren geeft een fout

Hoi mensen,

Ik wil graag een drukknop configureren op mijn adruino.
En dat gaat een stuk lastiger dan ik ooit met PIC's gewend was.
Nu had ik deze code, maar hij geeft foutmeldingen.
Mis ik iets?

const byte Startknop = 3;                              //Startknop op poort 3
pinMode (Startknop, INPUT_PULLUP);          //poort 3 (Startknop) is een input
while ((Startknop != 1) and (int X <= 100)){ //als drukknop niet is ingedrukt, 100 loopjes van 10ms
 int X++;
 delay 10;}

Er zit natuurlijk veel meer omheen, maar het gaat me even om die drukknop.
Waarom krijg ik deze fout:

exit status 1
expected primary-expression before 'int'

Waarbij de While regel gehighlight wordt.

MvG
FTMZ

Hoi.

Als je doet:

int X

Dan maak je een nieuwe integer met de naam X.
Ik moet aannemen dat je X al eerder in je code had aangemaakt, en dus gaat dat hier niet meer.
Wat wel kan, is een lokale integer maken die alleen binnen een lus geldt, en dat probeer je schijnbaar dan ook te doen voor je while lus, alleen kan dat niet op die manier (en krijg je daarom een foutmelding).
Ik snap ook niet waarom je het op deze manier wil doen (dus waarom niet meteen een pauze van 1000 mS).
Zoek in de reference database eens naar de for lus.
Daar zie je een heel andere aanpak van zo'n lus.
Dan doe je dus deze aanpak zolang (while) de knop niet werd ingedrukt, wat overigens jouw commentaar wel is, maar niet wat de code zegt*.
Aangezien je hier een snippet hebt geplaatst, is het onmogelijk je een antwoord te geven dat je werkelijk verder kan helpen.

*:
Je maakt een ingang met _PULLUP.
Dat betekent dat de interne hardware dusdanig word opgezet dat de ingang hoog gehouden word, tot jij m met je drukknop laag maakt.
Dus je als je kijkt of de waarde van die pin !=1, dan kijk je dus of de knop wel is ingedrukt.
En om de knop te zien, moet je naar de knop kijken (copyright J.Cruijff).
Dat doe je met een digitalRead.
In de voorbeeldsketch Button, die is meegeleverd met de Arduino IDE, staat precies uitgelegd hoe je dat doet.

from: MAS3 Tue Mar 23 2021 00:03:36 GMT+0100 (Midden-Europese standaardtijd)
Hoi.
Als je doet:

int X

Dan maak je een nieuwe integer met de naam X.
Ik moet aannemen dat je X al eerder in je code had aangemaakt, en dus gaat dat hier niet meer.

Oei! Is dat wat de foutcode aangeeft?
Ik kan het me niet herinnneren, maar het zou kunnen. Ik ga het nakijken.

Wat wel kan, is een lokale integer maken die alleen binnen een lus geldt, en dat probeer je schijnbaar dan ook te doen voor je while lus, alleen kan dat niet op die manier (en krijg je daarom een foutmelding).
Ik snap ook niet waarom je het op deze manier wil doen (dus waarom niet meteen een pauze van 1000 mS).
Zoek in de reference database eens naar de for lus.
Daar zie je een heel andere aanpak van zo'n lus.

Ik ben erg slecht in die For loopjes. Daarom doe ik bijna alles met de while loops.
Ik wil dat het programma een x tijd wacht, voor hij een handeling opnieuw uitvoert.
Maar binnen dat wachten moet hij wel reageren op het drukken op de button. (De tijden zijn nu wat gefigneerd, uiteindelijk zal het programma elke minuut de handeling opnieuw uitvoeren, en intussentijd "op scherp" staan, wachtende op een druk op de knop.
Tijden zijn niet critisch. En ja... Met een port change interrupt was het allemaal nog wat beter geworden, maar ik wil dit eerst wat meer in de vingers krijgen :slight_smile:

Dan doe je dus deze aanpak zolang (while) de knop niet werd ingedrukt, wat overigens jouw commentaar wel is, maar niet wat de code zegt*.

Oei... Ik dacht het zo gemaakt te hebben. Er is een loop van 100 cycles, waarna hij "iets" doet.
Maar druk je de knop in, wordt ook niet meer aan de voorwaarde voldaan en begint het ook met "iets".

while (drukknop != 1) and ( X <= 100) toch?

Als hij uit die loop springt wordt er nog een keer gekeken naar de status van die drukknop en daar wordt het verloop verder bepaald.

Aangezien je hier een snippet hebt geplaatst, is het onmogelijk je een antwoord te geven dat je werkelijk verder kan helpen.

Dat is inderdaan lastig. Ik ben wat aan het rommelen om te zien wat er zus en wat er zo gebeurt.
En ik meende dit goed te hebben gedaan.

*:
Je maakt een ingang met _PULLUP.
Dat betekent dat de interne hardware dusdanig word opgezet dat de ingang hoog gehouden word, tot jij m met je drukknop laag maakt.
Dus je als je kijkt of de waarde van die pin !=1, dan kijk je dus of de knop wel is ingedrukt.
En om de knop te zien, moet je naar de knop kijken (copyright J.Cruijff).
Dat doe je met een digitalRead.
In de voorbeeldsketch Button, die is meegeleverd met de Arduino IDE, staat precies uitgelegd hoe je dat doet.

Ach ja natuurlijk!!
Stom, ik trek hem juist laag!

Die voorbeeldsketch had ik al even doorgenomen, maar daar staan nogal wat stappen in.
En ook die omslachtigheid is lastig om mijn kop omheen te krijgen.
Zeg ik het zo goed?:

const int buttonPin = 2; // the number of the pushbutton pin
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH) {

-Je hebt een constante(2) met een naam (buttonpin),
-Dan zeg je middels pinMode dat die "buttonpin" een INPUT is.
-Vervolgens is er een variabele "buttonstate", die de waarde van die "buttonpin" onthoudt.
-En dáár wordt weer naar gekeken met en vergelijking waarbij men kijkt of de buttonstate high is.

Ik vind dat nogal omslachtig, maar so be it (daar heb ik al eens een topic aan gewijd :slight_smile: )
Kan ik niet gewoon stellen via "if (digitalRead(2) == 0) {"
Ik zal het te simpel bekijken hoor. Misschien te onoverzichtelijk of zo?
Ik hoop daarmee wat omslachtigheden over te slaan.
Jullie mogen schieten hoor. :slight_smile: Als ik het niet goed zie...

Inmiddels wat wijzer...

const byte Startknop = 3; //Startknop op poort 3
pinMode (Startknop, INPUT_PULLUP); //poort 3 (Startknop) is een input
while ((Startknop != 1) and (int X <= 100)){ //als drukknop niet is ingedrukt, 100 loopjes van 10ms
int X++;
delay 10;}

Ik had de delay niet tussen haakjes, en was het niet zo dat als die X nog niet gedeclareerd is en ik doe dat binnen die loop (while), kan ik er niets mee búiten die loop?
Ik lijk hem inderdaad 2x gedeclareerd te hebben.
Het is nu zo:

const byte Startknop = 3; //Startknop op poort 3
pinMode (Startknop, INPUT_PULLUP); //poort 3 (Startknop) is een input
int X
while ((Startknop != 1) and (X <= 100)){ //als drukknop niet is ingedrukt, 100 loopjes van 10ms
X++;
delay (10);}

Van hieraf zal ik wat verder rommelen...

@FTMZ,
Je kan dit inderdaad,het hangt een beetje af van je voorkeur.

const byte startKnop = 3;//Startknop op poort 3

void setup() {
    pinMode (startKnop, INPUT_PULLUP);//poort 3 (Startknop) is een input

}

void loop() {
    if (digitalRead(startKnop) == LOW) {
      // De Startknop is ingedrukt, doe hier je ding !
    }
}

Ik heb er overheen gelezen, maar het woord and doet ook niet wat jij verwacht.
Je bedoelde hier natuurlijk && te typen.

 while (digitalRead(Startknop) && (X <= 100)){ //als drukknop niet is ingedrukt, 100 loopjes van 10ms
 X++;
 delay (10);}

Nu kijk je dus wel naar de startknop (en niet naar een waarde die je schijnbaar vroeger ooit eens uitgelezen hebt)
Omdat je die waarde niet ergens anders nodig hebt, hoef je het resultaat van de digitalRead niet op te slaan in een tijdelijke variabele.
De digitalRead is dus een voorwaarde.
Aan de voorwaarde word wel of niet voldaan, daar is geen andere mogelijkheid voor.
Wanneer er niet word voldaan aan de voorwaarde, is het resultaat van de vergelijking 0 (een nul).
Wanneer er wel word voldaan aan de voorwaarde, is het resultaat 1 en kan daarna de volgende stap of de handeling die daarvan afhangt worden uitgevoerd.
Maar hier doe je een digitalRead.
Dus dan kan er ook alleen maar een nul of een 1 uitkomen.
Daarom hoef je in dit geval geen verdere vergelijking meer te doen.
Dus kun je wat overslaan: (digitalRead (Startknop)==1) de ==1 kun je weglaten, want het resultaat is hetzelfde.
Dat geldt dan weer niet wanneer je een andere waarde als voorwaarde wil stellen; (digitalRead (Startknop)==0) heeft wel de ==0 nodig, of je zet er een ! (betekent NOT) voor.

Je kunt dan nog steeds voor de while doen:

int X = 0;

Zo zet je X op nul voor je je while lus ingaat, zodat je zeker weet dat je niet al een eind onderweg was van de vorige keer dat je deze while lus doorlopen hebt.
Deze X is dan dus alleen geldig binnen loop(), en word dan telkens wanneer loop() weer van voor af aan begint gereset.

Vergeet ook niet dat je na delay, de betreffende vertragingstijd ook tussen (haakjes) zet.

Het is 101 loopjes als X bij nul begint :smiley:

Maar goed, dit is mijn voorkeur als het eenmalig is na een reset.

#define ISPRESSED LOW

const byte Startknop = 3;                              //Startknop op poort 3

void setup()
{
  pinMode (Startknop, INPUT_PULLUP);

  // variable to keep track if button is pressed
  bool isPressed = false;

  // start time
  unsigned long startTime = millis();

  // one second to press the button
  while (millis() - startTime < 1000)
  {
    // if the button is pressed
    if (digitalRead(Startknop) == ISPRESSED)
    {
      // update flag
      isPressed = true;
      // get out of while-loop so we don't wait unnecessary
      break;
    }
  }

  // if the button was pressed in the wait period
  if (isPressed == true)
  {
    do something;
  }
}

void loop()
{
}

ftmz heeft nog steeds het probleem dat er geen digitalread in zijn programma staat en 3 is geen 1. ofwel 3!= 1 en dat is waar dus true en dus....

Ja FTMZ heeft ook (al vaker) aangegeven bekend te zijn met PIC spul en vergelijkt dat met C++ wat bij Arduino gebruikt word.
Ik heb geen idee wat er bij piccies gangbaar is, maar daar hoef je schijnbaar alleen maar naar een pin te wijzen om een digitalRead te doen, en gebruik je woorden in plaats van wiskundige notaties voor een bewerking of vergelijking.
Persoonlijk vind ik dat laatste alleen maar verwarrend, maar als je het zo gewend bent zal het vast lastig zijn dat af te wennen voor C++.

Hetzelfde geldt voor de for.. en while.. loops (beide blokkerend, wat men hier dus te slim af wil zijn); ik zie er eigenlijk weinig verschil in voor wat betreft het gebruik er van.

Daar heb ik dan wel een heel grijs verleden iets anders geleerd voor een for.. loop bij commodore basic (ja, echt heel lang geleden).
Dat was for.. (step) next.
Step en next gebruiken we bij C++ helemaal niet, in plaats daarvan bewerken we tijdens de loop de betreffende waarde, en sluiten we de code op tussen {} haakjes waardoor de next overbodig geworden is.
Maar ik heb er weinig last van gehad het op de C++ manier te leren moet ik zeggen.

Ik heb mn. met de for-loop grote moeite gehad, en vind het nog steeds een knullige constructie. In bv. Clipper en Basic schrijf je For I = 1 To 10 etc., en daarmee is het verloop van de acties exact bepaald. Maar in C++heb je te maken met een while-conditie, die daar mi. absoluut niet thuishoort, en mij drie keer zoveel tijd kost om te bedenken. Vooral bij een terugtellende loop is het lastig, en een bron van mogelijke fouten. In Basic schrijf je gewoon Step - 1. Klaar, no-brainer.

step-- :smiley:

Geen idee wat je allemaal wel en niet kunt doen in Clipper en Basic.

Hetzelfde als met elke universele hogere programmeertaal, maar de syntax is logischer en eenvoudiger waardoor de leercurve veel minder steil is. Verder prima foutmeldingen van de compiler zowel als de runtime-engine. Met Visual Basic kun je ook inhaken op de Windows' API, waardoor echt alles mogelijk wordt. NB.: Clipper is eigenlijk bedoeld voor (dBase III+) databases.

Rare toestanden als 255 + 1 = 0 of 0 - 1 = -128 komen in die wereld (mi. terecht) niet voor. De onhandige constructie met een break na elke case is ook niet nodig, en case x mag een variabele of functie zijn (wat de mogelijkheden enorm vergroot!). Over het gezeur met strings in C++ begin ik maar niet eens.

Goed, met C++ kun je alles wat je wilt, maar het is wel erg primitief. Gelukkig heb ik wat ervaring met assembler (6502, 8088 etc.), dat scheelt.

Ik vermoed dat in PICBASIC de resutaten van bovenstaande berekeningen hetzelfde zijn als in C/C++ op de Arduino. Misschien kan FTMZ dat even voor ons testen :wink:

Op een PC gooit 255 + 1 een exception in een moderne VB :smiley: Geen idee wat er gebeurde in Basic in de DOS dagen.
0 - 1 gooit ook een exception :wink:

Ik zie de newbies al komen. Ze zullen dezelfde vragen stellen als bij het gebruik van C/C++.

Willen jullie aub een nieuwe discussie starten als het over for next gaat want dat zit er echt gewoon in zelfs terugtellen is gewoon met -34 ofzo

Sorry jongens.
Mijn afwezigheid helpt hier ook niet bij. :slight_smile:
Ik lig even in de lappenmand. Een of ander virus wat globaal rondwaard en wat mijn schoolgaande jeugd mee naar huis heeft genomen.

On Topic...
Wat ik vooral lastig vind in tutorials, voorbeelden, curussen en uitleg, is dat er soms kreten voorbij komen waarvan ik niet weet of het nu een slecifieke code is of de naam van een variabele die de poster zelf verzonnen heeft.
Een die zo in mij opkomt is bv "MyServo". Wie heeft dat verzonnen? De schrijver van de tutorial of degene die deze code (of library) heeft geschreven? :slight_smile:
Dat is wel eens lastig.

En in het voorbeeld van de poorttoewijzingen:
Bij PICBasic geef je op voorhand aan welke pinnen output zijn en welke input.
(TRISA 00010) geeft aan dat van de A-poort (toevallig 5 bits) de poorten A4, A3, A2 en A0 output zijn, en A1 een input.
Dus dat is al getackeld.
Vervolgens ken je een naam toe aan de betreffende poort (wat men bij Arduino een pin noemt, trouwens.) waaraan je een alias toekent dus (ik meende) Symbol portA.1 ingangspin (al dan niet tussen haakjes, accolades of brackets. Dat weet ik zo niet uit mij hoofd)

Maar hier bij C++ ken je een naam toe aan het nummer van de poort. Die naam wordt elders weer gekoppeld aan de status van de button. Dat wordt ook weer met een alias verpakt. "ButtonState" betekent dus eigenlijk de digitalRead van de naam van een pin die ook weer een andere naam had gekregen.
(Daarbij is ButtonState weer zo'n fancy naam die ik ook zomaar zou kunnen zien als een codewoord of het verzinsel van de maker van een Library.)

Kijk... Als ik dat maar in mijn hoofd heb én het vaak gebruik, dan zal het best blijven hangen.
Vooralsnog sla ik een paar hernoemingen (aliassen, wat je wilt) over, zodat ik dus rechtstreeks stel:
while (digitalRead(1) = High), waarbij ik dus enkele zaken oversla.
Het wordt pas spannend als ik met een logische 1 juist de poort laag wil hebben.
Dan is het wel handiger om er wat meer herkenbare kreten aan te hangen.

OK, die pinMode [pinnummer] INPUT_PULLUP zal niet onbelangrijk zijn en die moet er uiteindelijk nog wel bij.
Ik zou het anders genoemd hebben, maar vooruit. Er zijn ergere dingen. :slight_smile:

De Arduino IDE wil je juist van abstractie af helpen.
Daarom zijn er al een heleboel zaken voorgedefinieerd.
Een analoge pinnummer die je kunt benaderen met bijvoorbeeld A0 is zo'n voorgedefinieerde waarde.

Sommige zaken zijn nou eenmaal bedacht en toegepast.
Daar verander je niets aan.
Alleen wanneer slechte benamingen tot grote problemen zouden leiden, kan met gaan overwegen het anders te doen.
Want wanneer je in opeenvolgende 3 versies hetzelfde een andere naam geeft, weet bij de 4e versie niemand meer waar het over gaat.

Een port is geen pin.
Een port is een verzameling pins, en dat geldt dus ook voor piccies.
Direct port manipulation is wel mogelijk maar zie je maar heel zelden (want het maakt het lastiger voor jezelf en de kans op fouten groter).
pinMode en wat daar ingevuld word is toch best duidelijk, en veel minder abstract dan TRISA 00010.
pinMode geef je ook aan voor je de pin gaat gebruiken, en voor de loop waar je 'm gebruikt.

buttonState is een variabele die als tussenopslag word gebruikt, deze naam zie je heel vaak want erg duidelijk maar zulke variabelen zijn naar eigen inzicht te benoemen.
Zorg er dan voor dat je heel duidelijke namen kiest.
Bij 1 knop kun je best buttonState gebruiken, maar bij meer knoppen is het niet slim op buttonState, buttonState2, buttonState3 te gebruiken.
Beter zou dan zoiets als upState, downState, enterState zijn, je neemt dan de functie van de betreffende knop mee in de naam en dat maakt een en ander heel veel duidelijker.
Deze tussenopslag heb je nodig wanneer je op 1 regel een waarde binnenhaalt, en elders in je code wil gebruiken.
Wil je de actie laten afhangen van een vorige actie, dan moet je ook die vorige waarde opslaan (en updaten wanneer van toepassing).
Dan krijg je dus bijvoorbeeld previousUp, previousDown, previousEnter.
Door de termen in het Engels te houden, is de kans dat een niet Nederlander ook meteen door heeft wat bij elkaar hoort en wat er zou moeten gebeuren.

Dus even voor de duidelijkheid:

"ButtonState" betekent dus eigenlijk de digitalRead van de naam van een pin die ook weer een andere naam had gekregen

Nee, dat is niet waar.
In "ButtonState" sla je de waarde op die je met de digitalRead hebt bemachtigd.
Je leest dus op 1 plaats de waarde uit, en om er mee te werken sla je die waarde tussentijds op.
Zou je iedere keer wanneer je een waarde wil verwerken de betreffende pin uitlezen, kun je dus een andere status tegenkomen dan waar je mee begonnen was en meestal is dat ongewenst.
Wil je wel een verse waarde, moet je dus een read doen.
Als jij dat met de pinnummer wil doen is dat geen enkel probleem.
Maar je mag het ook doen met een naam die staat voor dat pinnummer.
Door die namen te gebruiken maak je je code weer veel eenvoudiger te volgen, want veel minder abstract.

Waar je voor op moet passen is hoe het mechanisme werkt bij vergelijkingen / voorwaarden.
Wanneer je doet:

while (3)

Dan is het resultaat altijd true en zal de code tussen de accolades er na (of de rest van de regel wanneer er niet meteen accolades volgen) worden uitgevoerd.
While en if kijken alleen maar of het resultaat van de voorwaarde niet nul is.
1 is niet nul, maar 3 is ook geen nul, en dus word er aan de voorwaarde voldaan.
Wanneer je met die 3 niet de waarde drie bedoelt maar het niveau op pin nummer 3, dan moet je dus een Read doen op die pin.

MyServo is geen plicht, en word gebruikt als verbinding met een library.
De naam is geheel aan jou.
Wanneer je de servo gebruikt voor een wijsvinger van een robothand (veel gebruikte toepassing), kun je m dus wijsvinger noemen, wijsvingerRechts, of index als je Engels prefereert.
Voor een vliegtuigje zou je 'm dan bijvoorbeeld rudder of yaw kunnen noemen.
Als het voor jou en/of voor mensen die je willen helpen maar duidelijk is.
Uiteraard moet je dat dan wel dusdanig instellen.

Trouwens, beterschap en ik hoop dat het jou beter afgaat dan mij.

Ik zie dat je PICBasic bent gewend, en Basic is dus wel anders dan C++.
Dus daar zul je de vertaalslag in gaan moeten maken en zul je je de verschillen meester moeten maken.
Dus heb ik ff gezocht naar wat voorbeelden die ik vond op picbasic.nl (met een zeer matige vertaling van de teksten naar het Engels).
Ik zie dat je daar een constante declareert met het woord symbol.
Bij C++ begin je meteen met het type const en vul je de betreffende waarde in.
Ook hier neemt een const geen programmaruimte in, en word het alleen voor de compiler gebruikt.
Een variabele heet daar DIM, en daar kun je een beperkt aantal soorten voor kiezen.
Veel verder kom ik daar niet, wil ook niet de hele variant gaan leren.

Ik raad je nog wel aan om niet zozeer naar de verschillen te kijken, maar naar de overeenkomsten want daar zijn er ook veel van.

Hoi MAS3,

Je verwarde mijn cynische vergelijking met vragen. :wink:

Ik ben intussen al langere tijd bezig met Arduino. En hoewel ik PICbasic beter te behappen vind, zou ik niet weer terug gaan. Want het minder simplistische karakter van de Arduino komt vooral omdat het meer compatible is. Tot zover snap ik dat.
En de "tekortkomingen" zijn te verklaren. En ook hier... Als je er wat aan gewent bent, red ik dat wel.

"ButtonState" betekent dus eigenlijk de digitalRead van de naam van een pin die ook weer een andere naam had gekregen

Nee, dat is niet waar.

Dat was in deze context het geval. :wink:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.