aansturen 8 relais

Beste,

Laat ik me eerst even voorstellen. Mijn naam is Jos Govaarts.
Ik gebruik de uno en alles wat er omheen zit om kleine projectjes (vooral aansturen led's en servo's) voor mijn modeltreinbaan te maken.
Nu heb ik een wat ander project, nl het sequentieel aan- en uitzetten van de verschillende trafo's omdat er dan minder pieken op het lichtnet komen.
Dat wil ik doen met 8 relais: na een druk op de aan-knop de relais per seconde inschakelen en deze weer na een druk op de uit-knop per seconde uitschakelen.
Nu kan ik wel met een schakelaar één relais schakelen, maar meer dan één relais niet.
Ik heb op het internet een programma gevonden dat acht relais sequentieel schakelt (dat werkt prima), maar dat is een loop, en kan ik verder niet beinvloeden, wat ik ook doe.

Heeft een van jullie een idee, waarmee ik verder kan. Ik heb het programma bijgevoegd. Hierbij gaan de 8 relais aan en vervolgens weer uit, op welke knop ik ook druk.
Alvast hartelijk dank voor het meedenken.

Jos

_8_relais_met_knop.ino (3.05 KB)

Ik zou mijn probleem uit elkaar trekken en een paar vragen vooraf beantwoorden voordat je begint met programmeren:

a) Moet de knop losgelaten worden voordat hij weer actief word. Anders kan men de knop minuten lang ingedrukt houden. En wat doe je dan?
b) Moet het een aparte aan en aparte uit knop worden?
c) gaat uitschakelen in een keer of ook sequentieel? En indien sequentieel met dezelfde tussenpozen?
d) Als hij bezig is met aanschakelen cq uitschakelen wil je dan op de button(s) reageren of gewoon negeren? Dat laatste zou betekenen dat je tijdens het inschakelen alweer gaat uitschakelen.

Je ziet het allemaal kleine vragen die mogelijk wat zeikerig overkomen maar wel bepalend zijn voor de vorm van jouw programma. Daarnaast zou ik het probleem opsplitsen in het lezen van de button(s) en het in serie inschakelen/uitschakelen van relais.

beste Jos

Er zitten er een paar fundamentele fouten in dit voorbeeld.

  1. in de setup. Eerst moet je de pinmode definieren en daarna kun je pas een digitalWrite of digitalRead doen.

  2. in de loop. Je moet eerst de status van je input pin lezen voordat je deze in een if statement gebruikt.
    Dus
    stateButton_on = digitalRead(pinButton_on);
    en
    stateButton_off = digitalRead(pinButton_off);
    voor de betreffende if statements plaatsen.

Verder is het af te raden om (overvloedig) gebruik te maken van #define statements.

Er staat ook nog een " } " op de verkeerde plaats.

In je voorbeeld staan er 3 stuks aan het eind, een van die 3 moet omhoog als afsluiting van de eerste if.

cartoonist:
Verder is het af te raden om (overvloedig) gebruik te maken van #define statements.

Wat is er mis met #define? Ik ben juist een fervent voorstander :slight_smile:

nicoverduin:
Wat is er mis met #define? Ik ben juist een fervent voorstander :slight_smile:

Het toont jouw/onze leeftijd.
Java heeft #define uit zijn taal geschrapt (alle bij de conversie van c++->java is het geschrapt). Java deed dat niet omdat #define algemeen aanvaard is als een slecht ding; maar omdat het door de preprocessor behandeld wordt en dat maakt het moeilijk bij refactoring werk. En refactoring is een wezenlijk onderdeel van java.
Daarom is er nu een hele generatie die met java opgegroeid is en die vindt dat #define slecht (waarom weten ze niet) is en in de arduio ide programmeert waarin je niet kan refactoren.
Gelukkig hebben ze nog niet gehoord van meervoudig ouderschap :-D; want dat heeft java ook geschrapt.

Och ja.... het zal de leeftijd wel zijn.

Met vriendelijke groet
Jantje

Dat verklaart een hoop...... one trick pony's

Beste allen,

Hartelijk dank voor jullie antwoorden.

De opmerkingen over #define laat ik maar even zitten, want dat is mij nu even te moeilijk, ik sta per slot van rekening nog maar aan het begin van mijn arduino-uitdaging. Ik weet ook niet wat refactoring is. Voor zover ik begrijp kan ik #define vervangen door int . Klopt dat? en vooral de ; niet vergeten. Dit even terzijde.

De vragen van Nico:
[a) Moet de knop losgelaten worden voordat hij weer actief word. Anders kan men de knop minuten lang ingedrukt houden. En wat doe je dan?
De bedoeling is dat een druk op de aanknop de serie relais aantrekt, met telkens 1 sec tussenpauze. Dus niet de knop vasthouden totdat alles is aangeschakeld.

b) Moet het een aparte aan en aparte uit knop worden?
Het is in eerste instantie de bedoeling dat er twee knoppen komen, maar ik heb nu bedacht dat het eventueel ook kan gebeuren zonder aan-knop, dus al meteen bij het aanzetten van het systeem gaan de relais aan. Er is dan alleen een uit-knop.

c) gaat uitschakelen in een keer of ook sequentieel? En indien sequentieel met dezelfde tussenpozen?
Het uitschakelen moet eveneens sequentieel gebeuren, maar dan in omgekeerde volgorde. Dat heeft te maken dat op het eerste relais de hoofdbediening van de modeltrein (EcosII) zit.

d) Als hij bezig is met aanschakelen cq uitschakelen wil je dan op de button(s) reageren of gewoon negeren? Dat laatste zou betekenen dat je tijdens het inschakelen alweer gaat uitschakelen.
Daar had ik nog niet aan gedacht, eerlijk gezegd. Het zou handig kunnen zijn om het opschakelen te kunnen stoppen, en eventueel ook weer terug te kunnen laten lopen.

Cartoonist: dank voor je opmerkingen, en ik heb deze meteen ter harte genomen en de sketch aangepast. Ook de } is verplaatst. De #define heb ik nog even laten staan.

Het volgende gebeurt nu: bij het aanzetten gaan de 8 relais sequentieel aan. En blijven aan. Dat is al winst, vindt ik. Echter drukken op de uit-knop geeft soms reactie, de relais blijven aangetrokken of gaan uit.
vervolgens gaan ze na 4 seconden weer aan. Daarna is er geen reactie meer in te krijgen. Dus ze gaan ook niet meer uit.

Hebben jullie nog suggesties?

Jos

_8_relais_met_knop.ino (3.2 KB)

hoe zin die buttons geschakeld? Met een pull-up naar VCC en dan de datapin schakeld naar GND
OF
Pulldown weerstand waarijn de datapin schakelt naar VCC
Of
zonder weerstand en de datapin schakelt naar VCC
OF
zonder weerstand en de datapin schakelt naar GND

Overigens ik heb een programma voor je klaar liggen maar je bent nog ff lekker bezig dus die verklappen we nog niet.

if(stateButton_on == HIGH && previous_on == LOW && millis() - time > debounce);
  {

Ik denk dat je nog wat moet bestuderen wat de bedoeling is van de accollades. Je doet het volgende:

Ik stel een vraag en ongeacht de uitkomst doe ik verder niets..... Immers de ";" sluit het verder af. Dus wat erna komt wordt altijd uitgevoerd.

Een if opdracht test een of meerdere conditie(s) af. Daarna komt er een open accolade waarin staat welke opdrachten uitgevoerd moeten worden als de condities waar zijn. Daarna komt er altijd een sluit accolade. Mocht de conditie niet waar zijn en dan wil je wat doen, dan komt er na de sluit accolade een else en komt er weer een open accolade met daarna de opdrachten die uitgevoerd moeten worden als de conditie dus NIET waar is. Tenslotte gevolgd door een sluit accolade.

de C/C++ taal is een lastige omdat veel kan. Zorgvuldigheid en goed inspringen zijn belangrijke opsporingsmiddelen om fouten op te sporen. Gebruik eens de "format" functie van de IDE om het source netjes te formatteren om het voor jezelf beter leesbaar te houden.

En als je de ; had weggehaald had je gezien dat je al een stuk verder was :grin:

Hoi JosG, en welkom nog.

Ik zie in de sketch die je bij de laatste post hebt gevoegd, dat je wat dingen gekopieerd en aangepast hebt.
Daarbij heb je de aanpassingen gedaan zodat je iets kunt toevoegen, maar het commentaar dat er bij staat heb je niet aangepast.
Dat zie ik heel vaak als er hier vragen komen.
Wanneer je commentaar gebruikt, moet je er echt voor zorgen dat dat commentaar ook klopt.
Anders heeft het helemaal geen zin om dat te doen.
Ik zie dit op regels 14 en 15.

Het zal je weinig verrassen als ik je vertel dat Nico die vraag over het indrukken van de knop niet voor niets stelde.
Ik vermoed dat je er nog niet bij stil gestaan hebt hoe snel alles gaat in Aduino-land.
Als je een handeling gaat doen telkens wanneer je ziet dat er op dat moment op een knop word gedrukt, dan ga je mogelijk honderdduizenden malen per seconden die handeling uitvoeren.
Want de Arduino voert 16 miljoen commando's per seconde uit, en dat betekent dat het allemaal heel snel gaat.

Je geeft ook aan dat, nu je er over nadenkt, de mogelijkheid om de cyclus te stoppen (of wellicht te pauzeren, das niet hetzelfde) zou kunnen waarderen.

Dit is allemaal mogelijk, met slechts 1 enkele toets.
Maar om dat voor mekaar te krijgen, moet je heel goed gaan bijhouden wat je op dat moment aan het doen bent.
Doe je dat niet, dan kun je ook niet anticiperen op wat een volgende toetsdruk betekent en wat je dan moet gaan doen.

Als eerste is het een goed idee om elk antwoord dat a gegeven is, apart te lezen met je sketch ernaast.
Je kunt de gegeven tips dan meteen uitvoeren.
Sla je werk op telkens als je iets veranderd hebt, en met een net iets andere naam (een versienummer erbij).
Dan kun je altijd terug naar een vorige stap.

Eerder in dit antwoord heb ik het gehad over een enorme hoeveelheid commando's die per seconde kunnen worden uitgevoerd door de Arduino.
Maar als je een delay() gebruikt, vertel je je Arduino om een bepaalde tijd vrijwel niets te doen.
Niets betekent ook dat er dan niet gekeken word of er op een knopje gedrukt word.
Je kunt ook op een andere wijze een bepaalde toestand aanhouden.
Dat is de methode die toegepast word in het voorbeeld 'blink without delay'.

Het valt me op dat die methode al word toegepast in je sketch.
Namelijk in het gedeelte waar de toetsen worden ingelezen, en de betrouwbaarheid daarvan word gecontroleerd (debounce).
Of dat gedeelte wel helemaal werkt zoals bedoeld waag ik te betwijfelen, maar het zit er wel in.

Wanneer je deze methode gaat toepassen moet je dus meer dingen bijhouden.
Zoals wat je op dat moment aan het doen bent, en hoe lang.
Maar daarmee kun je dus met 1 enkele toets meerdere dingen regelen.

Doe het wel stapje voor stapje, zodat je het overzicht behoud.

Buiten de discussie van coderen om..... zijn programma werkt wel als je de ; eruit haalt. Ledjes (bij mij) lopen keurig op en bij indrukken van uitzetten weer keurig af. Hij reageert niet altijd gelijk (gevolg van de delay() functie). Maar niet om hem geheel te ontmoedigen... zijn programma werkt wel in de basis..

Even een snelle reaktie, nu nog met mijn pc. Kan de rest van de dag dit forum wel lezen op een smartphone maar reakties intypen op zo'n klein schermpje is niet te doen.

nicoverduin:
Wat is er mis met #define? Ik ben juist een fervent voorstander :slight_smile:

@ Nico.
Ik bedoelde niet te zeggen dat #define fundamenteel fout is maar wel gevaarlijk kan zijn. Overvloedig gebruik zoals in het relais programma is een slecht voorbeeld geven. Dat lijkt meer op misbruik van #define.
Neem nu: digitalWrite(Relay_1, RELAY_OFF); dat lijkt wel spagetti-code omdat je dan eerst terug moet kijken naar de #define statement om te weten wat er geschreven moet worden. digitalWrite(Relay_1,LOW) of digitalWrite(Relay_1, HIGH) is veel duidelijker omdat dit door praktisch iedereen consequent wordt gebruikt. Zijn de LOW en HIGH hier al niet impliciet #define statements van de IDE ? dubbel-op dan.
Op dit forum (engels) en op het web is er volop discussie over het gebruik van #define versus const variabele.

@ Jantje
Is Java niet prachtig dan ?
De Arduino programmeer omgeving is immers ook in Java geschreven waardoor de IDE er voor iedereen , of die nu Linux een MAC of een Windows pc gebruikt, exact hetzelfde is.
Ik ben zelf geen java-programmer, gelukkig heb ik in mijn vriendenkring iemand die voor mij wel eens een java probleem oplost.

@Jos
Ongetwijfeld kunnen Nico, Jantje en vele anderen hier in een paar minuten een werkend voorbeeld voor jouw relais probleem maken wat veel duidelijker is dan jouw voorbeeld programma. Maar is het niet beter dat je het programma begrijpt en het dan zelf kan wijzigen/schrijven ?.

Nico,

Het is niet mijn bedoeling om meteen jouw oplossing te hebben, want ik wil er ook van leren.
Ik vind de programmeertaal sowieso een hele uitdaging en beschouw dit ook maar weer als een leer-moment.
Ik heb een schema bijgevoegd hoe het een en ander is geschakeld, ook een fotootje van de testopstelling. De schakelaar trekt pin 11 of 12 naar Vcc.
Helaas heb ik vandaag en morgen geen gelegenheid om verder uit te proberen, maar ga er daarna mee aan de slag. Met de accolades bijvoorbeeld..... :wink:

Jos

knop schema.jpg

Beste cartoonist, Jantje en MAS3,

Mijn antwoord op Nico's eerdere mail, heeft jullie reacties gekruist.
Ik ga over 2 dagen jullie suggesties bestuderen en laat dan weten hoe ver ik verder ben gekomen.

Jos

Jos
De schakelaars zijn duidelijk. Een switch met pull-down weerstanden. Is prima geschikt en zoals ik al eerder zij. Pas die punt-comma aan (weghalen) en je bent een stuk verder met jouw programma.

cartoonist:
@ Nico.
Ik bedoelde niet te zeggen dat #define fundamenteel fout is maar wel gevaarlijk kan zijn. Overvloedig gebruik zoals in het relais programma is een slecht voorbeeld geven. Dat lijkt meer op misbruik van #define.
Neem nu: digitalWrite(Relay_1, RELAY_OFF); dat lijkt wel spagetti-code omdat je dan eerst terug moet kijken naar de #define statement om te weten wat er geschreven moet worden. digitalWrite(Relay_1,LOW) of digitalWrite(Relay_1, HIGH) is veel duidelijker omdat dit door praktisch iedereen consequent wordt gebruikt. Zijn de LOW en HIGH hier al niet impliciet #define statements van de IDE ? dubbel-op dan.
Op dit forum (engels) en op het web is er volop discussie over het gebruik van #define versus const variabele.

Ik zal maar niet zeggen hoeveel ik define gebruik :grin:
Verder heb je wel een bijzondere kijk op "spagetti code". Maar zoals Jantje al eerder zei..... Wij behoren tot de "oude" categorie.....

Voor jezelf is het prima als je met die schakelaar zo werkt (je krijgt een "plus" als de schakelaar word ingedrukt).
Voor de Arduino maakt het helemaal niets uit als het een "min" word wanneer die word ingedrukt.
Maar dan kun je gebruik maken van een extraatje dat is ingebouwd in de Arduino, namelijk de pull up weerstand.
Je hebt in je schakeling al een pull down weerstand in gebruik, die er voor zorgt dat als er geen plusje is, het dan een minnetje word.
Door de pull up in te schakelen, bespaar je je wat weerstanden en ruimte waar je die zou moeten laten in je eindproduct.
Dat maakt voor twee stuks niet erg veel uit, maar het gaat om het concept.

Zoals eerder gezegd, het is allebei prima en je hoeft helemaal niets te veranderen.
Maar je weet nu dat er meerdere mogelijkheden zijn.

beste Jos

op deze site bovenaan in de olijf-groene balk onder de 'knop' Learning staat een menu'tje waarmee je Reference kan kiezen.
Dan krijg je de 'language Reference' pagina. Daarop staan alle commando's/statements met een eigen link naar meer uitleg en voorbeeldjes.
Dit menu item heet niet voor niets 'taal-referentie' omdat daar exact wordt beschreven hoe je de diverse commando's kan/moet gebruiken.
Bij digital I/O staat ,digitalWrite(pin,value) Hier wordt als mogelijke waarde(value) van de meegegeven parameter ofwel de waarde HIGH ofwel de waarde LOW gegeven.
Om (voor mij) onbegrijpelijke redenen heb jij hier d.m.v. de #define statements <#define RELAY_ON 0>
en <#define RELAY_OFF 1> de waarde '0' of '1' aan gegeven. Dat werkt in dit specifieke geval wel maar het maakt jouw programma eerder onduidelijker dan duidelijker. Ik vind de plaats/vorm waarin je hier #define hebt gebruikt eerder misbruik dan verduidelijkend gebruik van #define. Het lijkt mij ,zonder dwingende redenen, onverstandig om af te wijken van de vorm die de referentie pagina aangeeft.

Dus in jouw geval:
De twee bovenste #define statements weghalen en in alle digitalWrite() regels de waarde meegeven als 'HIGH' of als 'LOW' en niet als 'RELAY_OFF' of 'RELAY_ON'. Dit vergemakkelijkt later eventueel foutzoeken omdat je aan een arduino_pin direct met een voltmeter of logic_analyser kunt zien of die HIGH(meestal 5 volt) of LOW(meestal 0 volt) is.

Het goed lezen van de uitleg bij de diverse commando's zal de meeste beginnersvragen beantwoorden.

cartoonist:
...
Dan krijg je de 'language Reference' pagina. Daarop staan alle commando's/statements met een eigen link naar meer uitleg en voorbeeldjes.
....

Dit hoort alle arduino commando's/statements te zijn. Naast deze heb je ook de bijna volledige C/C++ bibliotheken ter beschikking (vb float mist hier en daar).
Ik vermeld dit even omdat ik in men begindagen met arduino dat feit niet door had. Dit voornamelijk door de verwijzingen naar processing als moedertaal van de arduino taal.
Voor meer info over de C/C++ bibiotheken verwijs ik naar het internet.

Met vriendelijke groet
Jantje

ps voor er een discussie onstaat over de verschillen tussen C/C++ en het arduino taaltje in verband met main versus setup en loop.
Dit is een extract uit de file main.cpp die in de arduino core folder zit.

int main(void)
{
...
	
	setup();
    
	for (;;) {
		loop();
		...
	}
        
	return 0;
}