Bit logica (PLC-stijl) overzichtelijk programmeren in C (µC)

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • honda4life
  • Registratie: Januari 2007
  • Laatst online: 12-08 12:14
Hoi iedereen,

Ik ben bezig met een zeer simpel automatiseringsprojectje thuis.
Namelijk een rolluiksturing, stelt niet veel voor.
1 uitgang omhoog, 1 naar beneden per rolluik = 4 uitgangen.

Deze worden aangestuurd via een 433 MHz-afstandsbediening, wordt ingelezen in Arduino.
= 4 binnenkomende condities (setje schakelende stopcontacten van Action)

Daar hoort wat intelligentie bij zoals niet gelijktijdig omhoog en naar beneden.
Een korte vertraging tussen omschakelen (traagheid relais).
Relais uit na maximum looptijd, drukken op andere richting tijdens bewegen = stoppen, ...

Ik heb reeds professionele ervaring met PLC's te programmeren, zulke dingen zouden dus een fluitje van een cent moeten zijn.

In C wordt dit een onoverzichtelijk drama van haakjes, accolades, ... gewoonweg verschrikkelijk om aan te zien.

Ik heb dit geprobeerd met een switch case in stappen op te splitsen maar was niet helemaal tevreden over het resultaat. Met if, ... wordt het ook een gedoe met hulpbits setten, resetten, ... ik vond het ook afgrijselijk.

Ik kan me niet voorstellen dat er geen overzichtelijkere manier bestaat, vermoedelijk ben ik vastgeroest in het PLC-concept.

Heeft er iemand nuttige ervaring / tips hoe hij/zij dit overzichtelijk aanpakt?

Ik vind microcontrollers fantastisch hé, maar intensief met bits werken is gewoonweg knoeien.

Beste antwoord (via honda4life op 25-04-2020 21:23)


  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Ok, bij gebrek aan code zet ik de glazenbol modus aan
Volgens mij hoef je helemaal niets met bits te pielen.

- Je hebt een afstandsbediening met knoppen omhoog / omlaag.
- De luiken worden blijkbaar gestuurd, door een relais aan te zetten, even te wachten en dan de motor in een richting te laten draaien
- Na een tijdje stopt die (luik is helemaal open of dicht, of door een tegengestelde knop richting)
- Na een bepaalde tijd kan het relais dus weer uit, omdat het luik stil zou moeten staan.

Ik denk dat je dat met een paar array's beter kan oplossen
Een array voor de knoppen (niets ingedrukt, omhoog, omlaag), met de laatste knop opdracht (zolang het relais aanstaat)
En een array met de luik status (relais uit, omhoog, omlaag)
Een array met relais tijden wanneer die uit kan.

- Als je een knop indrukt, controleer je of het nieuwe knop opdracht is
- Als het relais uit staat, zet je die eerst aan. En bepaal je de stop tijd
- Dan geef je de motor de opdracht
- Zet het luik status gelijk aan de knop status
Na een tijdje kan het relais weer uit en zet je de statussen van het luik en knop weer op "uit"
Zoiets dus:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#define KNOP_NIET_INGEDRUKT 0
#define RELAIS_UIT 0
#define OMHOOG 1
#define OMLAAG 2
#define GESTOPT 4

int knop_status[aantal_luiken];
int luik_status[aantal_luiken];
tijd relais_tijd[aantal_luiken];

for (i = 0; i < aantal_luiken; i++) {
    knop_status[i] = KNOP_NIET_INGEDRUKT;
    luik_status[i] = RELAIS_UIT;
    relais_tijd[i] = 0;
}

while (true) {
    // Ga alle knoppen op de afstandsbediening af
    knop_status[i] = KNOP_NIET_INGEDRUKT;
    if (knop_luik_1_omhoog_ingedrukt) {
        knop_status[0] = OMHOOG;
    |
    if (knop_luik_1_naar_beneden_ingedrukt && !knop_luik_1_omhoog_ingedrukt) {
        knop_status[0] = OMLAAG;
    }
    // en zo voor alle knoppen op de afstandsbediening

    // controle nieuwe opdracht
    for (i = 0; i < aantal_luiken; i++) {
        if (knop_status[i] == KNOP_NIET_INGEDRUKT && (luik_status[i] | GESTOPT)) {
            // Als je een tegengestelde beweging hebt ingedrukt,
            // dan, als je de knop weer loslaat, de richting van het luik vergeten
            luik_status[i] = GESTOPT;
            *** doe hier een kleine wachtlus ***
            // Als je namelijk 2x snel de tegengestelde richting klikt, wil je toch
            // die richting op, maar de motor moet wel tijd hebben om dat ook te
            // kunnen volgen
            continue;
        }
        
        if ((knop_status[i] == KNOP_NIET_INGEDRUKT) ||
            (knop_status[i] & luik_status[i] & OMHOOG + OMLAAG)) {
            // niets ingedrukt, of dezelfde knop nog steeds / opnieuw ingedrukt
            continue; 
        }

        // Er is een knop ingedrukt en het is een nieuwe opdracht
        // Controleer of het relais aan staat
        if (luik_status[i] == RELAIS_UIT)) {
            *** Zet het juiste relais aan en wacht even ***
        }

        // zet de uiterste relay tijd (na elke nieuwe knop opdracht)
        relais_tijd[i] = nu + maximale looptijd

        if (knop_status[i] == OMHOOG) {
            *** Schakel de uitgaande lijn voor motor omhoog ***
        }

        if (knop_status[i] == OMLAAG) {
            *** Schakel de uitgaande lijn voor motor omlaag ***
        }
        if (luik_status[i] == RELAIS_UIT) {
            // Nieuwe beweging
            luik_status[i] = knop_status[i];
        } else {
            // Tegengestelde beweging, daarmee zou de motor moeten stoppen
            if (luik_status[i] == OMHOOG) {
                luik_status[i] = OMLAAG;
            } else {
                luik_status[i] = OMHOOG;
            }
            luik_status[i] += GESTOPT; // stop, maar onthoud wel de richting
        }
    }

    // Kan een relais uit
    for (i = 0; i < aantal_luiken; ++) {
        if ((luik_status[i] != RELAIS_UIT) && (nu > relais_tijd[i])) {
            // Luik zou gestopt moeten zijn
            // (helemaal beneden, boven, of door tegengestelde knop)
            *** Zet het relais uit ***
            luik_status[i] = RELAIS_UIT;
            knop_status[i] = KNOP_NIET_INGEDRUKT;
        }
    }

    // Ga even een paar tiende seconde uit je neus vreten of zo
}

Sowieso vind ik dit nog best lastig om goed in mijn hoofd te krijgen.
Aangezien je geen feedback van de motor krijgt, moet je de status maar aannemen.
Daar gaat 100 jaar PLC programmeer ervaring je nog niet bij helpen.

Klik eens snel op-neer-op, dat gaat de motor niet altijd bijhouden en geen idee wat de status is (omhoog of nog steeds in stilstand?)
Of als het luik al open is en je drukt op-neer (luik gaat naar beneden, programma denkt: gestopt)

Hoe dan ook zal je programma dus aan elkaar hangen van aannames.
En gaat af en toe (tot het relais weer uitschakelt) iets niet doen, wat jij wil.

-edit tig-
@farlane hieronder (en om niet onder creepy te posten en toch antwoord)
Hmm, ja misschien heb je gelijk
Ok, dan een voorbeeldje met bit AND, OR, NOT en shift (en haakjes en accolades):
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
             luik
              3 1
             4 2 
sig_up   = 0b0101 // luik 3 en 1 gaan omhoog
sig_down = 0b0010 // luik 2 gaat naar beneden

bit_nr = 0; // Luik 1

// Zet signaal van een luik naar omlaag
set_sig_down(bit_nr) {
    // sig_up bit van luik uit (just to be sure):
    // NOT luik bit en AND die hele waarde met de oude
    sig_up &= ~(1 << bit_nr); // sig_up: 0b0100, alleen 3 omhoog
    // sig_down bit van luik aan (of aanlaten als dat al zo was)
    // OR waarde met luik bit
    sig_down |= 1 << bit_nr; // sig_down: 0b0011, 2 en 1 omlaag
}

// Zet signaal van een luik naar omhoog
set_sig_up(v) {
    sig_down &= ~(1 << bit_nr); // bit down uit
    sig_up |= 1 << bit_nr; // bit up aan
}

// Zet signaal van een luik uit
reset_sig(bit_nr) {
    sig_up &= ~(1 << bit_nr); // bit up uit;
    sig_down &= ~(1 << bit_nr); // bit down uit
}


Of alle signalen in 1 waarde:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
                     luik
                  3 1     3 1
                 4 2     4 2 
                 DOWN     UP
signal   = 0bxxxx0010xxxx0101 // luik 3 en 1 gaan omhoog, 2 omlaag

LSB_UP = 0
LSB_DOWN = 8
index = 0; // luik 1 

set_sig_down(index) {
    signal &= ~(1 << (index + LSB_UP)); // bit up uit
    signal |= 1 << (index + LSB_DOWN); // bit down aan
}

set_sig_up(index) {
    signal &= ~(1 << (index + LSB_DOWN)); // bit down uit
    signal |= 1 << (index + LSB_UP); // bit up aan
}

Of desnoods nog met een macro
C:
1
2
3
4
5
#define BITVALUE(bit_nr) (1 << (bit_nr))
set_sig_down(index) {
    signal &= ~BITVALUE(index + LSB_UP); // bit up uit
    signal |= BITVALUE(index + LSB_DOWN); // bit down aan
}

[ Voor 43% gewijzigd door Vaan Banaan op 26-04-2020 18:27 ]

500 "The server made a boo boo"

Alle reacties


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12-08 12:13

Creepy

Tactical Espionage Splatterer

Ik denk dat het wel handig is om wat code te laten zien die je verschikkelijk vindt. Je zou niet de eerste zijn die de bitwise operators niet kent, maar dat kunnen we zo niet zien.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Marber
  • Registratie: Juni 2014
  • Laatst online: 12:38
intensief met bits werken is gewoonweg knoeien
Dan doe je iets fout. Werken met bits en bitwise operators is juist erg duidelijk

Acties:
  • 0 Henk 'm!

  • honda4life
  • Registratie: Januari 2007
  • Laatst online: 12-08 12:14
Bitwise operators ken ik en gebruik ik zo veel mogelijk.
Post m'n code vanavond.

Niet vergeten dat je in een µC niet wil knoeien met schaars geheugen.
(ga het later nog nodig hebben verder te automatiseren)

[ Voor 44% gewijzigd door honda4life op 24-04-2020 11:32 ]


Acties:
  • 0 Henk 'm!

  • Wintervacht
  • Registratie: December 2016
  • Laatst online: 07-08 10:04

Wintervacht

☉ ‿ ⚆

Vergeet ook niet een paar microswitches boven- en onder je rolluik te plaatsen die feedback geven wanneer hij op z'n eind is.

Weet een beetje van veel dingen en veel van een paar dingen.


Acties:
  • 0 Henk 'm!

  • honda4life
  • Registratie: Januari 2007
  • Laatst online: 12-08 12:14
Wintervacht schreef op vrijdag 24 april 2020 @ 11:32:
Vergeet ook niet een paar microswitches boven- en onder je rolluik te plaatsen die feedback geven wanneer hij op z'n eind is.
Deze motoren bevatten een eindeloop, microswitches voorzien heeft geen meerwaarde.
Zou in ieder geval m'n code wat eenvoudiger maken ipv. timers te moeten voorzien.

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
honda4life schreef op vrijdag 24 april 2020 @ 11:33:
[...]
Zou in ieder geval m'n code wat eenvoudiger maken ipv. timers te moeten voorzien.
??? Je moet hier absoluut geen timers in willen hebben, dan zit je echt op een verkeerde denkwijze...

Met timers heb je over een half jaar een rolluik wat half open en dicht gaat, omdat het allemaal wat stroever gaat etc, maar je actie duurt even lang...

En vergis je niet in dat een rolluik mechanisme in de praktijk toch best wel wat extra functionaliteit vraagt, bijv stoppen bij x tegenkracht zodat er niet een kind of een auto geplet wordt als die er per ongeluk tussen staat.

Acties:
  • 0 Henk 'm!

  • honda4life
  • Registratie: Januari 2007
  • Laatst online: 12-08 12:14
Gomez12 schreef op vrijdag 24 april 2020 @ 12:32:
[...]

??? Je moet hier absoluut geen timers in willen hebben, dan zit je echt op een verkeerde denkwijze...

Met timers heb je over een half jaar een rolluik wat half open en dicht gaat, omdat het allemaal wat stroever gaat etc, maar je actie duurt even lang...

En vergis je niet in dat een rolluik mechanisme in de praktijk toch best wel wat extra functionaliteit vraagt, bijv stoppen bij x tegenkracht zodat er niet een kind of een auto geplet wordt als die er per ongeluk tussen staat.
Wat kan ik meer doen dan de buismotor van de voorzetrolluik van spanning te voorzien? Maak het niet moeilijker dan het is.
Timers is meer om de stuurrelais uit te schakelen, geen spanning op de motor te laten staan als het niet nodig is, en klein verbruik van die relais te besparen.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 13-08 12:56
Gomez12 schreef op vrijdag 24 april 2020 @ 12:32:
[...]
En vergis je niet in dat een rolluik mechanisme in de praktijk toch best wel wat extra functionaliteit vraagt, bijv stoppen bij x tegenkracht zodat er niet een kind of een auto geplet wordt als die er per ongeluk tussen staat.
Een kind of *auto* geplet door een rolluik? Rare parkeerplaats imho ....

Anyways, dit rolluik is duidelijk van de eenvoudige soort en schakelt zelf af op het eind. Als je de timer ruim genoeg zet werkt dat dus best aardig, ook na een paar jaar. (Niet als je een auto in je vensterbank parkeert trouwens)

Anyways, tov ladder of functieblok diagram zijn bitwise operators C vrij spartaans (doordat het niet grafisch is voornamelijk), ik ben het met je eens.

Al met al gaat het wel aardig hoor:
C:
1
2
3
4
if (putton_pushed && !timer_running ) {
    timer_start( ... );
}
output = timer_running() 


Ik denk wel dat op de plekken waar je in C een temporary nodig hebt om het behapbaar te houden voor je brein, je in ladder of fbd dat ook zou moeten hebben.

Bedenk ook dat een if statement alleen (zonder else) meer vergelijkbaar is met een set/reset ipv een directe output. In die gevallen vind ik de ternary operator compact en goed leesbaar:
C:
1
2
3
4
5
if ( .. some condition ... ) {
    a = 1;
} else { 
    a = 0;
}

Kun je omschrijven als:
C:
1
a = .. some condition ... ? 1 : 0;

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • +1 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
farlane schreef op vrijdag 24 april 2020 @ 23:23:
[...]
Een kind of *auto* geplet door een rolluik? Rare parkeerplaats imho ....
Hmmm, foutje mijnerzijds ik las het als een garagedeur ipv rolluik...

Simpel rolluik voor de ramen kan idd simpel zijn en blijven :)

Acties:
  • Beste antwoord
  • +2 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Ok, bij gebrek aan code zet ik de glazenbol modus aan
Volgens mij hoef je helemaal niets met bits te pielen.

- Je hebt een afstandsbediening met knoppen omhoog / omlaag.
- De luiken worden blijkbaar gestuurd, door een relais aan te zetten, even te wachten en dan de motor in een richting te laten draaien
- Na een tijdje stopt die (luik is helemaal open of dicht, of door een tegengestelde knop richting)
- Na een bepaalde tijd kan het relais dus weer uit, omdat het luik stil zou moeten staan.

Ik denk dat je dat met een paar array's beter kan oplossen
Een array voor de knoppen (niets ingedrukt, omhoog, omlaag), met de laatste knop opdracht (zolang het relais aanstaat)
En een array met de luik status (relais uit, omhoog, omlaag)
Een array met relais tijden wanneer die uit kan.

- Als je een knop indrukt, controleer je of het nieuwe knop opdracht is
- Als het relais uit staat, zet je die eerst aan. En bepaal je de stop tijd
- Dan geef je de motor de opdracht
- Zet het luik status gelijk aan de knop status
Na een tijdje kan het relais weer uit en zet je de statussen van het luik en knop weer op "uit"
Zoiets dus:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#define KNOP_NIET_INGEDRUKT 0
#define RELAIS_UIT 0
#define OMHOOG 1
#define OMLAAG 2
#define GESTOPT 4

int knop_status[aantal_luiken];
int luik_status[aantal_luiken];
tijd relais_tijd[aantal_luiken];

for (i = 0; i < aantal_luiken; i++) {
    knop_status[i] = KNOP_NIET_INGEDRUKT;
    luik_status[i] = RELAIS_UIT;
    relais_tijd[i] = 0;
}

while (true) {
    // Ga alle knoppen op de afstandsbediening af
    knop_status[i] = KNOP_NIET_INGEDRUKT;
    if (knop_luik_1_omhoog_ingedrukt) {
        knop_status[0] = OMHOOG;
    |
    if (knop_luik_1_naar_beneden_ingedrukt && !knop_luik_1_omhoog_ingedrukt) {
        knop_status[0] = OMLAAG;
    }
    // en zo voor alle knoppen op de afstandsbediening

    // controle nieuwe opdracht
    for (i = 0; i < aantal_luiken; i++) {
        if (knop_status[i] == KNOP_NIET_INGEDRUKT && (luik_status[i] | GESTOPT)) {
            // Als je een tegengestelde beweging hebt ingedrukt,
            // dan, als je de knop weer loslaat, de richting van het luik vergeten
            luik_status[i] = GESTOPT;
            *** doe hier een kleine wachtlus ***
            // Als je namelijk 2x snel de tegengestelde richting klikt, wil je toch
            // die richting op, maar de motor moet wel tijd hebben om dat ook te
            // kunnen volgen
            continue;
        }
        
        if ((knop_status[i] == KNOP_NIET_INGEDRUKT) ||
            (knop_status[i] & luik_status[i] & OMHOOG + OMLAAG)) {
            // niets ingedrukt, of dezelfde knop nog steeds / opnieuw ingedrukt
            continue; 
        }

        // Er is een knop ingedrukt en het is een nieuwe opdracht
        // Controleer of het relais aan staat
        if (luik_status[i] == RELAIS_UIT)) {
            *** Zet het juiste relais aan en wacht even ***
        }

        // zet de uiterste relay tijd (na elke nieuwe knop opdracht)
        relais_tijd[i] = nu + maximale looptijd

        if (knop_status[i] == OMHOOG) {
            *** Schakel de uitgaande lijn voor motor omhoog ***
        }

        if (knop_status[i] == OMLAAG) {
            *** Schakel de uitgaande lijn voor motor omlaag ***
        }
        if (luik_status[i] == RELAIS_UIT) {
            // Nieuwe beweging
            luik_status[i] = knop_status[i];
        } else {
            // Tegengestelde beweging, daarmee zou de motor moeten stoppen
            if (luik_status[i] == OMHOOG) {
                luik_status[i] = OMLAAG;
            } else {
                luik_status[i] = OMHOOG;
            }
            luik_status[i] += GESTOPT; // stop, maar onthoud wel de richting
        }
    }

    // Kan een relais uit
    for (i = 0; i < aantal_luiken; ++) {
        if ((luik_status[i] != RELAIS_UIT) && (nu > relais_tijd[i])) {
            // Luik zou gestopt moeten zijn
            // (helemaal beneden, boven, of door tegengestelde knop)
            *** Zet het relais uit ***
            luik_status[i] = RELAIS_UIT;
            knop_status[i] = KNOP_NIET_INGEDRUKT;
        }
    }

    // Ga even een paar tiende seconde uit je neus vreten of zo
}

Sowieso vind ik dit nog best lastig om goed in mijn hoofd te krijgen.
Aangezien je geen feedback van de motor krijgt, moet je de status maar aannemen.
Daar gaat 100 jaar PLC programmeer ervaring je nog niet bij helpen.

Klik eens snel op-neer-op, dat gaat de motor niet altijd bijhouden en geen idee wat de status is (omhoog of nog steeds in stilstand?)
Of als het luik al open is en je drukt op-neer (luik gaat naar beneden, programma denkt: gestopt)

Hoe dan ook zal je programma dus aan elkaar hangen van aannames.
En gaat af en toe (tot het relais weer uitschakelt) iets niet doen, wat jij wil.

-edit tig-
@farlane hieronder (en om niet onder creepy te posten en toch antwoord)
Hmm, ja misschien heb je gelijk
Ok, dan een voorbeeldje met bit AND, OR, NOT en shift (en haakjes en accolades):
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
             luik
              3 1
             4 2 
sig_up   = 0b0101 // luik 3 en 1 gaan omhoog
sig_down = 0b0010 // luik 2 gaat naar beneden

bit_nr = 0; // Luik 1

// Zet signaal van een luik naar omlaag
set_sig_down(bit_nr) {
    // sig_up bit van luik uit (just to be sure):
    // NOT luik bit en AND die hele waarde met de oude
    sig_up &= ~(1 << bit_nr); // sig_up: 0b0100, alleen 3 omhoog
    // sig_down bit van luik aan (of aanlaten als dat al zo was)
    // OR waarde met luik bit
    sig_down |= 1 << bit_nr; // sig_down: 0b0011, 2 en 1 omlaag
}

// Zet signaal van een luik naar omhoog
set_sig_up(v) {
    sig_down &= ~(1 << bit_nr); // bit down uit
    sig_up |= 1 << bit_nr; // bit up aan
}

// Zet signaal van een luik uit
reset_sig(bit_nr) {
    sig_up &= ~(1 << bit_nr); // bit up uit;
    sig_down &= ~(1 << bit_nr); // bit down uit
}


Of alle signalen in 1 waarde:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
                     luik
                  3 1     3 1
                 4 2     4 2 
                 DOWN     UP
signal   = 0bxxxx0010xxxx0101 // luik 3 en 1 gaan omhoog, 2 omlaag

LSB_UP = 0
LSB_DOWN = 8
index = 0; // luik 1 

set_sig_down(index) {
    signal &= ~(1 << (index + LSB_UP)); // bit up uit
    signal |= 1 << (index + LSB_DOWN); // bit down aan
}

set_sig_up(index) {
    signal &= ~(1 << (index + LSB_DOWN)); // bit down uit
    signal |= 1 << (index + LSB_UP); // bit up aan
}

Of desnoods nog met een macro
C:
1
2
3
4
5
#define BITVALUE(bit_nr) (1 << (bit_nr))
set_sig_down(index) {
    signal &= ~BITVALUE(index + LSB_UP); // bit up uit
    signal |= BITVALUE(index + LSB_DOWN); // bit down aan
}

[ Voor 43% gewijzigd door Vaan Banaan op 26-04-2020 18:27 ]

500 "The server made a boo boo"


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 13-08 12:56
Gomez12 schreef op zaterdag 25 april 2020 @ 02:05:
[...]
Hmmm, foutje mijnerzijds ik las het als een garagedeur ipv rolluik...
Dat was duidelijk, ik probeerde grappig te zijn :P
Vaan Banaan schreef op zaterdag 25 april 2020 @ 03:11:
Ok, bij gebrek aan code zet ik de glazenbol modus aan
Volgens mij hoef je helemaal niets met bits te pielen.
Volgens mij was de vraag niet zozeer "Hoe programmeer ik een rolluik?" maar "Hoe kan ik boolean logica in C begrijpelijk houden?"

[ Voor 25% gewijzigd door farlane op 25-04-2020 11:17 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12-08 12:13

Creepy

Tactical Espionage Splatterer

Wat de vraag nu daadwerkelijk is, daar zijn we nog steeds naar aan het gokken. Dus we wachten voorlopig op code die honda4life onoverzichtlijk vindt.....

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • honda4life
  • Registratie: Januari 2007
  • Laatst online: 12-08 12:14
Leuk voorbeeld Banaan, er zitten in ieder geval wat handige truucjes in die ik nog niet overwogen had.

Hier een klein deel waar ik me al dood aan erger:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
if(rfReceived.address == RF_ADDR){
      lastReceivedMillis = millis();
      if(lastReceivedMillis - lastReceivedMillisPv >= 1000){
        if(rfReceived.groupBit == false){
          if(rfReceived.unit == RF_UNIT_SH1){
            if(rfReceived.switchType == 1){
              if(bitRead(bitsShutter, BIT_UP1_OUT)){
                bitSet(bitsShutter, BIT_UP1_OFF);
              }
              else{
                bitSet(bitsShutter, BIT_DOWN1_ON);
              }
            }
            else{
              if(bitRead(bitsShutter, BIT_DOWN1_OUT)){
                bitSet(bitsShutter, BIT_DOWN1_OFF);
              }
              else{
                bitSet(bitsShutter, BIT_UP1_ON);
              }
            }
          }
          else if(rfReceived.unit == RF_UNIT_SH2){
            if(rfReceived.switchType == 1){
              if(bitRead(bitsShutter, BIT_UP2_OUT)){
                bitSet(bitsShutter, BIT_UP2_OFF);
              }
              else{
                bitSet(bitsShutter, BIT_DOWN2_ON);
              }
            }
            else{
              if(bitRead(bitsShutter, BIT_DOWN2_OUT)){
                bitSet(bitsShutter, BIT_DOWN2_OFF);
              }
              else{
                bitSet(bitsShutter, BIT_UP2_ON);
              }
            }
          }
        }
        else{
          if(rfReceived.switchType == 1){
            if(bitRead(bitsShutter, BIT_UP1_OUT)){
              bitSet(bitsShutter, BIT_UP1_OFF);
            }
            else{
              bitSet(bitsShutter, BIT_DOWN1_ON);
            }
            if(bitRead(bitsShutter, BIT_UP2_OUT)){
              bitSet(bitsShutter, BIT_UP2_OFF);
            }
            else{
              bitSet(bitsShutter, BIT_DOWN2_ON);
            }
          }
          else{
            if(bitRead(bitsShutter, BIT_DOWN1_OUT)){
              bitSet(bitsShutter, BIT_DOWN1_OFF);
            }
            else{
              bitSet(bitsShutter, BIT_UP1_ON);
            }
            if(bitRead(bitsShutter, BIT_DOWN2_OUT)){
              bitSet(bitsShutter, BIT_DOWN2_OFF);
            }
            else{
              bitSet(bitsShutter, BIT_UP2_ON);
            }
          }
        }

[ Voor 0% gewijzigd door RobIII op 26-04-2020 01:51 . Reden: Gebruik code-tags ipv quote-tags om code te posten ;-) ]


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12-08 12:13

Creepy

Tactical Espionage Splatterer

Ik vraag me dan af hoe je dit in PLC code anders zou doen, al die losse ifjes. Want als ik het zo bekijk zet je meerdere malen dezelfde bits dus dan zou je je condities ook samen moeten kunnen pakken. Dat moet al een stuk schelen. En ik gok dat je met echte bitwise logica ook nog wel wat kunt winnen ipv de bitSet functie te gebruiken. Ik ga even heel lui zijn er er niet echt in duiken aangezien je code niet geindent is. Daar wordt het nog onoverzichtelijker van. Dus dat mag je zelf doen ;)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • honda4life
  • Registratie: Januari 2007
  • Laatst online: 12-08 12:14
Oké, misschien probeer ik iets te hard de rekenkracht te omtimaliseren
Bitwise kan inderdaad compacter, maar niet leesbaarder helaas.

Acties:
  • +1 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12-08 12:13

Creepy

Tactical Espionage Splatterer

Ik heb nog steeds het vermoeden van wel, maar in je code is niet te zien welke bits er nu geset moeten worden. Je kan wat indenting winnen door een fail fast te gebruiken:

code:
1
2
3
4
5
6
if (rfReceived.address != RF_ADDR) 
  return;

lastReceivedMillis = millis();
if (lastReceivedMillis - lastReceivedMillisPv < 1000)
  return


En je ifs lijken deels hetzelfde doen, maar dan voor andere units. Als die in dezelfde set met bits zitten, dan kan je de logica ook 1 keer doen en vervolgens de bits shiften zodat ze voor de juiste unit staan bijv. Dat is wat ik o.a. bedoel met de bitwise logica.

Dus als je eerste 4 bits voor unit 1 zijn, en de 4 bits daarna voor unit 2. Dan zet je in een losse variabele altijd de bits voor unit 1, en schuif je het geheel 4 bits op als het voor unit 2 is bedoeld. Vervolgens samenvoegen met de daadwerkelijke bits en gaan.

En voor de bits uitlezen kan uiteraard hetzelfde. Eerst shiften indien het unit 2 betreft en daarna kan je voor unit 1 en 2 dezelfde logica gebruiken.

Edit: overigens zie ik geen enkele bitwise operator in je code. Je zegt dat je ze kent, maar hier gebruik je ze niet.

[ Voor 35% gewijzigd door Creepy op 25-04-2020 21:59 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 13-08 12:56
honda4life schreef op zaterdag 25 april 2020 @ 21:22:
Leuk voorbeeld Banaan, er zitten in ieder geval wat handige truucjes in die ik nog niet overwogen had.

Hier een klein deel waar ik me al dood aan erger:

[...]
Da's gewoon copy-paste code, da's in een PLC net zo goed bad practice.

Als je al eens de gemeenschappelijke stukken voor een shutter naar een functie brengt ziet het er al heel anders uit.

Overigens, als dit Arduino is (aan je millis() te zien) is het C++ en niet C.

[ Voor 4% gewijzigd door farlane op 26-04-2020 10:23 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

honda4life schreef op zaterdag 25 april 2020 @ 21:45:
Oké, misschien probeer ik iets te hard de rekenkracht te omtimaliseren
Nee, je code is nu niet goed gestructureerd.
Sowieso, als je een relais of motor moet schakelen, reageert dat pas na een aantal milliseconden. Dan maakt die ene microseconde extra in je code echt niet uit.
Bitwise kan inderdaad compacter
De bitRead en bitSet functies zijn macro's
https://github.com/arduin...r/cores/arduino/Arduino.h
code:
1
2
3
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))

Die doen dus exact dezelfde bit AND, OR, NOT en shift meuk. Alleen is de code "verstopt" in een header file.
, maar niet leesbaarder helaas.
Dan moet je op die plekken commentaar toevoegen.

500 "The server made a boo boo"


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 13-08 12:56
honda4life schreef op zaterdag 25 april 2020 @ 21:22:
Leuk voorbeeld Banaan, er zitten in ieder geval wat handige truucjes in die ik nog niet overwogen had.

Hier een klein deel waar ik me al dood aan erger:
Een paar kleine refactoring acties, en ik kom voor de essentie op dit: ( vermoedelijk is er nog wel meer generieker te maken tussen de twee units ).

Dit maakt het al een stuk leesbaarder en daardoor ook weer makkelijker verder te refactoren.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
uint32_t received_unit_1( const received_t& received, uint32_t bits )
{
    if( received.switchType == 1 ) {
        if( bitRead( bits, BIT_UP1_OUT ) ) {
            bitSet( bits, BIT_UP1_OFF );
        } else {
            bitSet( bits, BIT_DOWN1_ON );
        }
    } else {
        if( bitRead( bits, BIT_DOWN1_OUT ) ) {
            bitSet( bits, BIT_DOWN1_OFF );
        } else {
            bitSet( bits, BIT_UP1_ON );
        }
    }
    return bits;
}

uint32_t received_unit_2( const received_t& received, uint32_t bits )
{
    if( received.switchType == 1 ) {
        if( bitRead( bits, BIT_UP2_OUT ) ) {
            bitSet( bits, BIT_UP2_OFF );
        } else {
            bitSet( bits, BIT_DOWN2_ON );
        }
    } else {
        if( bitRead( bits, BIT_DOWN2_OUT ) ) {
            bitSet( bits, BIT_DOWN2_OFF );
        } else {
            bitSet( bits, BIT_UP2_ON );
        }
    }

    return bits;
}

void some_logic()
{
    if( rfReceived.address == RF_ADDR ) {
        lastReceivedMillis = millis();
        if( lastReceivedMillis - lastReceivedMillisPv >= 1000 ) {
            if( rfReceived.groupBit == false ) {
                if( rfReceived.unit == RF_UNIT_SH1 ) {
                    bitsShutter = received_unit_1( rfReceived, bitsShutter );
                } else if( rfReceived.unit == RF_UNIT_SH2 ) {
                    bitsShutter = received_unit_2( rfReceived, bitsShutter );
                }
            } else {
                bitsShutter = received_unit_1( rfReceived, bitsShutter );
                bitsShutter = received_unit_2( rfReceived, bitsShutter );
            }
        }
    }
}

[ Voor 12% gewijzigd door farlane op 26-04-2020 10:51 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Sissors
  • Registratie: Mei 2005
  • Niet online
honda4life schreef op zaterdag 25 april 2020 @ 21:45:
Oké, misschien probeer ik iets te hard de rekenkracht te omtimaliseren
Bitwise kan inderdaad compacter, maar niet leesbaarder helaas.
Maar die bitsets enzo zijn toch leesbaar? Het probleem zijn de 7 lagen if statements die genest zitten, maar dat lijkt mij ongerelateerd aan de bitwise logica.

Acties:
  • +2 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12-08 12:13

Creepy

Tactical Espionage Splatterer

code:
1
2
3
4
5
6
7
8
9
10
 if( rfReceived.groupBit == false ) {
                if( rfReceived.unit == RF_UNIT_SH1 ) {
                    bitsShutter = received_unit_1( rfReceived, bitsShutter );
                } else if( rfReceived.unit == RF_UNIT_SH2 ) {
                    bitsShutter = received_unit_2( rfReceived, bitsShutter );
                }
            } else {
                bitsShutter = received_unit_1( rfReceived, bitsShutter );
                bitsShutter = received_unit_2( rfReceived, bitsShutter );
            }

Kan denk ik ook zo:
code:
1
2
3
4
5
6
if( rfReceived.groupBit || rfReceived.unit == RF_UNIT_SH1 ) {
  bitsShutter = received_unit_1( rfReceived, bitsShutter );
}
if( rfReceived.groupBit || rfReceived.unit == RF_UNIT_SH2 ){
  bitsShutter = received_unit_2( rfReceived, bitsShutter );
}

En met refactoring moet je received_unit_1() en received_unit_2() ook nog wel kunnen samenpakken want die doen precies hetzelfde maar dan voor een andere unit.


Daarnaast gaan mijn nekharen altijd overreind staan als ik zoiets zie
code:
1
 if( rfReceived.groupBit == false )

Want dan zie je te vaak dat uiteindelijk ook deze vorm wordt gebruikt:
code:
1
 if( rfReceived.groupBit == true )

Of nog ergers (imho dan)
code:
1
 if( rfReceived.groupBit != true )

Ik zie veel liever
code:
1
 if( !rfReceived.groupBit )

en
code:
1
 if( rfReceived.groupBit)

[ Voor 17% gewijzigd door Creepy op 26-04-2020 16:13 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 13-08 12:56
Eens met alle punten. Wil de rest van de refactoring aan de TS laten, maar op een of andere manier denk ik niet dat de strekking van het verhaal aan die kant indaalt.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1