voltagedividerswitch + uniek maken van toets aanraken.(voor LEGO PowerFunctions)

Hallo Arduiners,

met beperkte programmeerkennis toch een heel eind gekomen in het bouwen van een afstandsbediening voor 4 LEGOtreinen te bedienen via het bekende PowerFunctions(PF)-protocol.

Omdat er de nodige switches nodig waren heb ik er voltagedividers van gemaakt om I/O-lijnen te sparen volgens dit principe (en wel op A0 en A1):

+5V
|
R=2k
|
GND switch1 -------- A0 van Arduino
|
R=330
|
GND switch2 –
|
R=620
|
GND switch3 –
|
R=1k
|
GND switch4 –
|
R=3,3k
|
GND switch5 –

Daarvoor heb ik inderdaad met losse switches op unieke Digital-poorten gewerkt en daar heeft het wel gewerkt.

Waar ik niet uit kom is de gebeurtenis als ik een switch indruk dit in de debug-mode de waardes van een switch een hele riedel geven.
Bv ik ben bezig geweest in de code met BUTTON3(via A0)en btnSERVO1:(via A1)
Namelijk bij BUTTON3 (regel 567 t/m 578) moet er een teller 1 waarde omhoog, maar de BUTTON3 produceert een hele riedel dus die teller krijgt nogal wat ophogingen, zodat de waarde in het display een loterij wordt.

case BUTTON3: // Trainselect 1-4
// experiment om de riedel van 3-en uniek te maken tot 1 actie en daarmee een var zetten die de teller 1 ophoogt
if (tmpButtonState3 != lastButtonState3) {
lastDebounceTime3 = millis();
}
if ((millis() - lastDebounceTime3) > debounceDelay3) {
buttonState3 = tmpButtonState3;
hitBUTTON3=1; // set var for acting 1 action elsewhere
}
lastButtonState3 = tmpButtonState3;
delay(20);
break;

Bij btnSERVO1( regel 620 t/m 624) moet hij bij het drukken of de wissel de ene kant opsturen danwel bij de volgende keer drukken de andere kant op.
Maar door die riedel mislukt deze wens.

case btnSERVO1:{ // railswitch2
// doe iets met lastpushed en die van nu en zet dan deze waarde
hitw2sw=1 ;
delay(10);
break;

Wie kan mij een hint geven hoe ik het drukken van een knop in de switch-statement een unieke uitkomst krijg?
Hoe krijg ik

LCD3310treindisplay.ino (23.7 KB)

goeiedag,

ik snap niets van je code maar ik begrijp wel wat je wilt.
en volgens mij moet het op deze manier wel werken.

if (analogread > min && analogread < max) {
    buttonstate = HIGH;
  } else {
    buttonstate = LOW;
  }

  if(buttonstate != Lastbuttonstate){
    if(buttonstate == HIGH){
      counter++; //deze var zal nu 1 er bij optellen elke x dat je de button indrukt.
                 //IPV de lotterij weergeven. als je hem ingedrukt houd.
    }
  }
  Lastbuttonstate = buttonstate;

het valt me ook op dat je heelveel int gebruikt. hierdoor gebruik je onnodig veel Sram.
een int gebruikt 2Bytes, 256 x 256 = 65536 mogelijheden.
een byte gebrijkt maar 1 byte, 256 mogelijkheden. ik zal deze gebruiken voor buttonstates.
wat vaak een 0 of 1 , LOW of HIGH, false of true is.

je krijgt altijd een riedel, want de analoge scanner komt steeds met andere getallen. druk 1 knop in en kijk welke waarde terugkomt, doe dat voor alle mogelijkheden. dan krijg je een vreemd lijstje.

dan maak je een case met bijv. 123..134 dat is dan bijv switch1 en 2 samen. als dat zo is en case3 !=actief dan railswitch en voer andere actiesacties uit, en zet een vlaggetje aan case3 is actief. alle andere vlaggetjes uitzetten.

de juiste methode is eigenlijk dat je moet bepalen: switch 1 open is 1024 switch1 dicht is 0 , maar dat komt omdat je iets overlsaat. switch 2 open is 1024 switch 2 dicht is 800 ongeveer. switch 2 en 3 dicht dan is het 700 switch 3 dicht is 600 etc. zie hiervoor de analoge switch http://www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/step3/The-theory-Multiple-buttons-on-one-pin/ deze tekening klopt beter.

Zoals shooter al zei, je kunt beter naar een range kijken dan naar een bepaalde waarde. Er zijn allerlei redenen waarom de waarde die je op deze manier inleest, varieert en dat is dan ook wat je ziet gebeuren. Dus naar een bepaald bereik in die waardes kijken in plaats van een absolute waarde is dan slim. Verder krijg je dus steeds veranderende waardes maar als je eerst kijkt of er een keer niet meer op een knop gedrukt word, kun je dus zien of er een nieuwe waarde is, of dat er gewoon lang op een knop gedrukt word. Tussen alle knopdrukken moet dan dus steeds een 'niet knopdruk' gezien worden. Zo voorkom je dat je onterecht meerdere knopdrukken registreert. En zo zie je ook dat er werkelijk meerdere malen op dezelfde knop gerukt word als dat inderdaad gebeurt.

Hey MAS3, bedankt, daar is mijn hint:

Niet detecteren zoals in mijn voorbeeld een riedel van 3-en de waarde is, maar de verandering van een 0 naar een 3 bij het maken of bij het loslaten een 3 naar meestal een 0 of anders een lagere waarde in de voltageladder.

Maar ik heb echt nog geen beeld hoe je in code deze gebeurtenis gaat schrijven.

even pseudocode: mogelijke waardes 0,1,2,3,4 (0= geen knop gedrukt en drukken van 1 is dominant/overruled tov 2,3,4. dat geldt voor 2 de waardes 3,4 en voor knop 3 de vierde. Dat komt door de opbouw van deze weerstanden en switches)

Gebeurtenis:
er wordt op een knop gedrukt en hierdoor wordt een waarde veranderd (meestal van 0 naar mijn voorbeeld een 3). Zolang de knop vastgehouden wordt blijft het een drie. Knop los geeft een verandering van 3 naar meestal een 0, maar ook 1,2,4 kunnen.

Pseudocode:
als waarde van button3 (“3”)iets anders wordt dan 3
doe een actie;

code probeersel binnen de :
case BUTTON3
if (BUTTON3 =! 3)
{
doe je gewenste unieke actie/acties;
}
break;

en dit ook voor de andere buttons.

Maar dit gaat niet goed m.i., omdat als de key wordt gehit hij wel door de switch-case van BUTTON3 gaat maar de test is dan false,dus de unieke opdrachten worden niet uitgevoerd.

Toch zal ik ook de hint van Spirit nog eens bekijken want die lijkt op wat MAS3 suggereert.

hmm, ik kom er nog niet helemaal uit. Adviezen zijn welkom. ik zal gaan uitproberen.

En ja, de code is rommelig omdat het een combinatie is van verschillende zaken (Lego PF, LCD3310, voltageladder) en als ik dit probleem heb opgelost kan ik gaan structureren.
Ik zal de hint van spirit ter harte nemen en bezuinigen op “int” variabelen twv 2 byte Sram.
En toch, een .h file maken waar ik ASCII-character en Lego PowerFunctions-definities in kan opbergen is toch lastiger dan ik dacht…

LCD3310treindisplay.ino (23.7 KB)

Hoi.

Ik heb je code nog niet bekeken, alleen die pseudo code. Je probeert volgens mij nu meteen een knopdruk te verwerken. Maar is het niet beter om te registreren welke knop er niet langer gedrukt word ? Ik hoop er stiekem op dat je werkt op de wijze van blink without delay, anders kom je sowieso in problemen waar je niet uit gaat komen. Ga nu registreren dat er een knop gedrukt word, en sla de waarde van de geregistreerde knop op. Het volgende rondje kijk je of er wat veranderd is tussen die knopdrukken. Als er nog niets veranderd is, ga je ook nog niets doen. Als er wel wat veranderd is, sla je die veranderde waarde op, en ga je datgene uitvoeren wat met de knop te maken heeft die net is losgelaten. Daarvoor moet je dus eerst kijken welke knop er verwerkt moet worden, en daarna pas de opgeslagen waarde veranderen.

Hiervoor heb je dus 1 extra variabele nodig, een byte spaart je een beetje ruimte ten opzichte van een int en is meer dan voldoende hiervoor.

zoals mas al zegt, veel scannen en kijken in welke catgorie je waarde valt, als deze anders is dan vorige keer actie, anders lekker niets doen.

OPGELOST: voltageladder switches

ik heb het code-voorstel van spirit gebruikt wat volgens mij in tekst is aangereikt door MAS3.
Volgens mij is het ook de antidender/debounce van een switch wat je hier gebruikt om te krijgen wat ik wilde.

effectief zat ik een niveau te diep bij de switchafvragingen mijn oplossing te zoeken.

De code zal wel te optimaliseren zijn omdat ik voor de 4 switches ieder een eigen if-statement hanteer.

Er is 1 bug / programmeer-bevinding (wellicht nog op te lossen):
Als je de 2e switch indrukt en vasthoudt en onderwijl switch 3 of 4 indrukt worden die bijbehorende taken ook uitgevoerd. Er is (nog) geen softwarematige “lock” dat je maar 1 switch tegelijkertijd kan bedienen. Bij 3 is dat alleen switch4 die dat nog doet. Bij switch 1 speelt dat niet omdat die alles aan massa legt (readanalog = 0).

Bijgevoegd heb ik een gestripte code waarin alleen het LCD-3310 display en de voltageladder op A0 zijn overgebleven.

bedankt voor de hulp

LCD3310voltladder.ino (12.1 KB)

zie de instructable how to use 5 switches, http://http//www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/step3/The-theory-Multiple-buttons-on-one-pin/ dan kun je meerdere toetsen indrukken, en toch bliojven zien welke toetsen allemaal actief zijn. zo kun je bijv trein en sneller tegelijk indrukken die noodstop is wel slim, die kun je trouwens ook in de analoge versie gewoon gebruiken, want die override toch alles.

Shooter, met het testen zie ik inderdaad de beperkingen van de huidige voltageladder.
Die ga ik aanpassen voor de treinbediening naar de variant in de link naar Instructables.

Voor het overzicht en om andere mensen die met het Lego(trein) IR-protocol bezig zijn, de code bijgevoegd+ die met de aangepaste voltageladder.

toch nog een nieuwe versie gemaakt en deze bijgevoegd (servo-sturing en bediening hiervan compleet)

LCD3310treindisplay.ino (27.7 KB)

LCD3310treindisplay-nieuwe V-ladder.ino (33.6 KB)

LCD3310treindisplayV3.ino (32.4 KB)

Onderdeel van voorgaande deel van het draadje was de oudere IR-versie van LEGO voor de CityTrein in te voegen.
Reverse engineering van het protocol heb ik hier weergegeven en een probeersel om dat te gebruiken op een Arduino R3 (bit -wise het protocol kopieren en uitzenden.)

Start = Stop is bitstream 36kHz met 10 bits en pauze 1930 mu s
Uno is bitstream 36kHz met 10 bits en pauze 280 mu s
Zero is bitstream 36kHz met 10 bits en pauze 844 mu s
1 bit heeft een duty-cycle 16 mu s hoog en 11,5 mu s laag

pauze (common factor 18 ms, dus verhoudingen
Channel actie bitstreams blok-pauze-blok-pauze-blok-pauze-blok)
1 up Start 1111 1111 1110 0001 Stop 3+2+2
1000 0111 1111 1110 1001 1000 4+5+3
1 down Start 1111 1111 1101 0010 Stop 2+2+3
Start 0111 1111 1101 1010 Stop 3+2+3
1 stop Start 0111 1111 1111 1000 Stop 3+2+2
Start 1111 1111 1111 0000 Stop --------
1 horn Start 1111 1111 1100 0011 Stop --------
Start 0111 1111 1100 1011 Stop --------
2 up Start 1110 1111 1110 0010 Stop 2+3+5
Start 0110 1111 1110 1010 Stop --------
2 down Start 1110 1111 1101 0011 Stop 5+3+3
Start 0110 1111 1101 1011 Stop --------
2 stop Start 1110 1111 1111 0001 Stop 5+4+4
Start 0110 1111 1111 1001 Stop --------
2 horn Start 1110 1111 1100 0100 Stop --------
Start 0110 1111 1100 1100 Stop --------
3 up Start 1101 1111 1110 0011 Stop 5+4+2
Start 0101 1111 1110 1011 Stop --------
3 down Start 1101 1111 1101 0100 Stop 3+2+2
Start 0101 1111 1101 1100 Stop --------
3 stop Start 1101 1111 1111 0010 Stop 5+4+5
Start 0101 1111 1111 1010 Stop --------
3 horn Start 1101 1111 1100 0101 Stop --------
Start 0101 1111 1100 1101 Stop --------
4 up Start 1100 1111 1110 0100 Stop 2+3+5
Start 0100 1111 1110 1100 Stop --------
4 down Start 1100 1111 1110 0101 Stop 3+2+3
Start 0100 1111 1110 1101 Stop --------
4 stop Start 0100 1111 1111 1011 Stop 3+2+3
Start 1100 1111 1111 0011 Stop 2+3+3
4 horn Start 1100 1111 1100 0110 Stop --------
Start 0100 1111 1100 1110 Stop --------

(STOP- button keeps repeating when hold, all others (UP, DOWN, HORN) send only once a message

1e nibble: bit1 bit2 bit3 bit4
Kanaal 1 toggle 1 1 1
Kanaal 2 toggle 1 1 0
Kanaal 3 toggle 1 0 1
Kanaal 4 toggle 1 0 0

2e nibble 1 1 1 1

3e nibble 1 1
Up 1 0
Down 0 1
Stop 1 1
Horn 1 0

4e nibble toggle ? ? ? (checksum ???)
Togglebit reverse from 1st nibble bit1

LEGORCtrainIRtryout.ino (6.7 KB)