Skapa ett programvalsystem i C

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

sodjan skrev:Sen så lär man varken köra Javascript eller Python i en liten
processer inbyggd i en pannlampa. Det verkar som att några
har tappat fokus lite här på vad problem faktiskt var.

Jag är inte helt med på vad som är så krångligt. Du måste ju ändå ha
en rutin som känner av knappen regelbundet. Och om den har varit
intryckt 5 sek eller mer så kör du rutinen för "programval" (vilket ju
sannolikt inte kommer att vara "program" i den vanliga betydelsen, utan
bara en variabel/flagga som senare kommer att styra ditt enda program).

Sedan, när din knapp-rutin ser ett vanligt "klick" på knappen så stegar du
bara upp en variabel som sedan tillsammans med "program" variabeln styr
vad som ska hända med pannlampan. Några tabeller (de olika "programmen")
och lite logik för att stega igenom tabellerna vid varje tryck.

Bestäm först vilka olika "modes" som du vill ha, t.ex.:

0: av
1: halvljus
2: helljus
3: SOS (menar du kort-kort-kort-lång-lång-lång-kort-kort-kort ?)
4: Ett kort nöd-blink var 10s.

Sedan gör du några "programtabeller":

0: 0-1-2
1: 0-1-2-3

O.s.v.

Långa trycket roterar mellan de 2 "programmen" och korta tryck
roterar mellan de olika "modes" inom valt program. Kalla det gärna
"state machine" om du behöver ett namn på det...

Fast jag ser inte riktigt nyttan med att ha olika "program" över huvud
taget här, verkar bara onödigt komplicerat den gång man behöver "SOS"
funktionen och man inte råkar ha det "programmet" aktiverat...

"Funktionspekare" och annat lull-lull har sannolikt ingenting i denna applikation att göra.
Du får det att låta precis så enkelt jag önskar det skulle vara, men jag får inte till "tänket" får att börja knacka kod.
Det är absolut inte mer avancerat än så men jag vill ha möjligheten att välja vilket "program" lampan ska följa, då denna ska användas vid lite olika tillfällen.

Ska läsa ditt inlägg några fler gånger men det är en mycket bra grund till det jag vill göra.

@datajompa:
Sökte lite på "tree structure in c" med mera och hittar också mycket relevant.
Just nu är det så mycket information på en gång så jag måste läsa ikapp lite :wink:

Ps. Citerade senaste inlägget då det blev sidbyte och inlägget blir mer lättförståeligt om man samtidigt kan se vad jag svarar på. Ds
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43151
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Skapa ett programvalsystem i C

Inlägg av sodjan »

OK... :-)

Kan då säga lite mer om vad det ska köras på?
Storlek och modell/typ av processor kan vara relevant.

En annan sak, om det är långt mellan "programbyte" så
kanske det ska in i EEPROM så att den startar upp med samma
"program" efter batteribyte eller att den har varit avstängd på
annat sätt. Eller ska processorn fortfarande gå om den är "av"?

Och en sak till kan vara att köra processorn på så låg hastighet
som möjligt, det spar ström...
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Självklart sodjan! Och du är en av personerna bakom att jag redan tänkt på allt det här :)

Processorn är en PIC12F1840 (8 pin av storleksskäl och kan lätt drivas på neråt 3V av lipo-acken). När batterier sätts i så kommer avläsning från inbyggt flash ske för att se om tidigare program matats in. Om inte, så sätts ett "default" program och sedan går µC i sleep. När lampan stängs av så går också µC:n i sleep.
Varje gång ett nytt program sätts så sparas detta i flash/EEPROM.

Till en början så kalkylerar jag timers/interrupts etc med 8 MHz (intern klocka), men min tanke är att sänka denna så lågt som går, men vidhålla önskad PWM/timer tider. Detta är dock under "utveckling".
Sen är det lite kräm i lampan så att spara ström genom att snåla med processorn är lite överdrivet.

Det är inte riktigt här som mitt huvudbry ligger, utan att få till "flödet" i koden.
Återkommer med ett utkast inom dom närmsta dagarna så får vi se vad ni säger.
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Inte för att vara sån, men om du läst koden sodjan så hade du sett att den gjorde precis det du sa, på precis det vis du sa, och att funktionspekarna gjorde koden enklare att läsa och att modifiera, och dessutom genererar mer kompakt binärkod för att passa på en uC, det vill säga knappast lull-lull.

Mina övriga funderingar gällde snarare frågan om tänket kring menyer, tänk om man vill ha en komplex meny som t.ex. konfigurationsskärmen i en modern telefon?
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Skapa ett programvalsystem i C

Inlägg av lillahuset »

Sodjans invändning gällde nog att en nybörjare kan ha svårt att fatta funktionpekare.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43151
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Skapa ett programvalsystem i C

Inlägg av sodjan »

Ja, lite så. Men sen så vet knappt jag heller vad det är (mer än att
man på något sätt är ett dynamisk sätt att peka ut funktioner vid
run-time), så jag är nog ingen direkt expert på det. Det ger säkert
en ytterligare flexibilitet i koden men även en sak till att förstå. Om
funktionspekare gör koden lättare att läsa eller inte beror ju helt på
vad man är van vid att läsa. Begreppet "programvalsystem" i titeln
på tråden låter lite mer komplicerat än vad som sannolikt behövs.

> tänk om man vill ha en komplex meny...

Jo, det var lite så jag läste det, att det var så som du tänkte... :-)
Vilket alltså är ointressant i det aktuella fallet och bara rör till det.
Det finns ju massor att säga kring menyer i allmänhet som inte har
speciellt mycket med styrningen av en pannlampa att göra.
Användarvisningsbild
Jan Almqvist
Inlägg: 1580
Blev medlem: 1 oktober 2013, 20:48:26
Ort: Orust

Re: Skapa ett programvalsystem i C

Inlägg av Jan Almqvist »

Alternativ lösning: Lägg till en ESP8266 som körs som AP, seriell kommunikation till PIC:en och lägg programvalet i något annat. Eller ersätt helt enkelt din PIC med en ESP8266.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Nej, det är inget alternativ då hårdvaran är klar.

@sodjan:
Har du något exempel på enkelt menysystem du gjort. Eller vill förklara hur du gick till väga?
Användarvisningsbild
rvl
Inlägg: 5721
Blev medlem: 5 april 2016, 14:58:53
Ort: Helsingfors

Re: Skapa ett programvalsystem i C

Inlägg av rvl »

Har du tänkt ha nån feedback från lampan, när man stegar igenom programlistan? Så att man vet var man är. T.ex. ett kort blink för program 1 osv.
Zkronk
Inlägg: 1423
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: Skapa ett programvalsystem i C

Inlägg av Zkronk »

Jan Almqvist skrev:Eller ersätt helt enkelt din PIC med en ESP8266.
Varför ska han ha en WiFi-uppkopplad pannlampa? :lol:
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

@rvl:
Jo, jag har satt dit en liten piezo-buzzer som kommer agera låg battvarning och även litet pip för att säga till att nytt program valt.

Nu drar diskussionen iväg lite för mycket åt hårdvaruhållet. Det vore väldigt intressant att se hur någon annan löst ett "menysystem" för en µC.
Funktionspekare är något jag inte ens hört talas om innan men klart värt att läsa vidare om.
Användarvisningsbild
Jan Almqvist
Inlägg: 1580
Blev medlem: 1 oktober 2013, 20:48:26
Ort: Orust

Re: Skapa ett programvalsystem i C

Inlägg av Jan Almqvist »

Jag tror att du ska fokusera på logiken. Glöm allt vad programkod och funktionspekare heter till att börja med.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Skapa ett programvalsystem i C

Inlägg av hanpa »

Det här med "meny" förbryllar lite. Ser ut som vanlig systemlösning och en fullt normal programmeringsuppgift.

Är du osäker på vilken funktion du vill ha?
Eller är det mer att du inte vet var du ska börja med koden?

Ett sätt att komma vidare är att prototypa med ett program som körs på vanlig dator, i skal eller enklare grafisk miljö. Känn av en knapp, gör tillståndsmaskiner eller liknade för att prova ut lämpliga fördröjningar etc så att du kan enkelt simulera funktionen tills du är nöjd. Du kan ju skriva ut på skärmen vad som händer i programmet. Den koden kan du sen lätt modifiera lite och köra på målplattformen.
Användarvisningsbild
Lennart Aspenryd
Tidigare Lasp
Inlägg: 12607
Blev medlem: 1 juli 2011, 19:09:09
Ort: Helsingborg

Re: Skapa ett programvalsystem i C

Inlägg av Lennart Aspenryd »

Simulera!
I sin enklaste form har jag simulerat programflödet för ett helt automatlager med hjälp av papperslappar.
Borde vara gångbart här också!
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Vilken kompilator använder du? Kör du Linux eller Windows? Kompilerar min kod?

Här är ett exempel som inte har något med din specifika applikation (pannlampa) att göra utan som demonstrerar dels hur man kan göra meny som är enkel att ändra, och dels varför C är onödigt krångligt. Jag har bara testat med gcc i Ubuntu.

Koden är naturligtvis onödigt komplex för en meny med 5 olika val, men det handlar ju om hur man gör ett menysystem.

Med bara 5 enkla val fungerar det naturligtvis bra med en switch(), men vad händer i en mer realistisk situation där du har 200 menyval, eller 2000, och du behöver kunna köra speciell logik för vissa av valen?

Nästan allting går naturligtvis att skriva med ett jättelikt if-else-monster eller switch() men det är inte någon bra ide. Varje gång du skriver else if(){} eller case: så är det kodduplikation.

I största möjliga mån bör saker som väljs ur en tabell matas in i datorn som just en tabell. Varje sak ska endast definieras på ett ställe, och det gäller även logiken.

I exemplet nedan blir det ett antal rader med initialisering av menyträdet, och en del kodduplikation, men detta beror på att C bara har primitiva datastrukturer och inte som t.ex. Javascript har tuples.

Som du kan se så behöver man bara lägga till menyalternativ i denna initialiseringsblobb, allt annat sköts där det ska, men du kan lägga speciell logik i callback-funktionerna om det behövs, något som det ofta gör i en realistisk situation, särskilt när man ändrar i menyträdet i efterhand och lägger till nya saker.

Jag höll allting så förenklat det gick för läsbarheten, så exempelvis datapekarargumentet är inte realistiskt utan man skulle skicka en pekare till en struktur eller liknande. Det visar ändå hur du kan använda samma kod för flera menyval (undvika duplikation).

Kod: Markera allt

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __linux__
    #include <curses.h>
#else
    #include <conio.h>
#endif

typedef void (*menu_funcptr(char *data));

typedef struct NODE_S {
    char *name;
    void *parent;
    void **children_or_callback; /* points to either a function or an array of child nodes, of length childcount */
    int childcount; /* zero means it's a leaf node */
} node_s;

void generic_menu_func(char* data) {
    printf("Mitt namn är %s; James %s.\r\n", data, data);
}

void menu_10_func(char *data)
{
    puts("\tVrooom\r");
};

void menu_11_func(char *data)
{
    puts("\t*gnissel* *host* *plonk*\r");
};

void menu_2_func(char *data)
{
    puts("\tMjau\r");
}

void init_nodes(node_s *c, node_s *parent)
/* Set up pointers to parent so we don't have to do that explicitly */
{
    int j;
    int cc = c->childcount;
    if(NULL != parent) {
        c->parent = parent;
    }

    if(cc>0) {
        for(j=0; j<cc; j++) {
            node_s *t = c->children_or_callback[j];

            if(NULL != t) {
                init_nodes(t,c);
            }
        }
    }
}

/* This is a global that points to the current selected menu node.
   I thought a global makes the code shorter and easier to read. */
node_s *current_menu_item;

void print_current_menu_level(void)
/* print the submenues at the current selected level */
{
    node_s *c = current_menu_item;

    printf("-%s-\r\n", c->name);

    for(int i=0; i<c->childcount; i++) {
        node_s *t = c->children_or_callback[i];
        if(t->childcount > 0) {
            printf("\t%d %s >>\r\n", i+1, t->name);
        } else {
            printf("\t%d %s\r\n", i+1, t->name);
        }
    }
    printf("\n");
}

void init_data(node_s *tree) {
    /* this is just a bunch of data initialization, but I thought
       writing it out in full demonstrates the problem with C not
       having any nice way of defining inline data. In a real
       situation you would use macros or load it from a binary file.

       Remember, data defined in a function needs to be static so that
       it will not go out of scope when the function exits.

       Childcount could be derived from the init arrays but that seems
       to require non-standard compiler language extensions. */

    static node_s menu_00, menu_01, menu_10, menu_11;

    menu_00.name = "Banan";
    menu_00.children_or_callback = (void *)&generic_menu_func;
    menu_00.childcount=0;

    menu_01.name = "Persika";
    menu_01.children_or_callback = (void *)&generic_menu_func;
    menu_01.childcount=0;

    menu_10.name = "Porsche";
    menu_10.children_or_callback = (void *)&menu_10_func;
    menu_10.childcount=0;

    menu_11.name = "Lada";
    menu_11.children_or_callback = (void *)&menu_11_func;
    menu_11.childcount=0;

    static node_s menu_0_children[] = {&menu_00, &menu_01};
    static node_s menu_1_children[] = {&menu_10, &menu_11};

    static node_s menu_0, menu_1, menu_2;
    menu_0.name = "Frukter";
    menu_0.childcount = 2;
    menu_0.children_or_callback = &menu_0_children;

    menu_1.name = "Bilar";
    menu_1.childcount = 2;
    menu_1.children_or_callback = &menu_1_children;

    menu_2.name = "Katt";
    menu_2.childcount = 0;
    menu_2.children_or_callback = &menu_2_func;

    tree->name = "Menu";
    tree->childcount = 3;
    static node_s treechildren[] = {&menu_0, &menu_1, &menu_2};
    tree->children_or_callback = treechildren;

    init_nodes(tree, NULL); //traverse tree, set parents
}

int main(void)
{
    node_s tree; /* the top node of the menu tree */

    init_data(&tree); /* edit init_data to set menu items */

    current_menu_item = &tree;

#ifdef __linux__
    // make ncurses play nice
    initscr();
    timeout(-1);
    noecho();
    refresh();
#endif

    printf("1-9 to select, backspace to go back, q to quit\r\n\n");

    while(1) { /* main loop */
        print_current_menu_level();
        char choice = getch();

        switch (choice) {
        case 127: /* backspace key goes up in menu hierarchy */
            if(NULL != current_menu_item->parent) {
                current_menu_item = current_menu_item->parent;
            }
            break;
        case 27:
        case 'Q':
        case 'q':
#ifdef __linux__
            endwin();
#endif
            exit(0);
        default:
            if(choice >= '1' && choice <= '9') {
                int selected = choice - '1'; /* get index 0-8 */

                if(selected >= 0 && selected < current_menu_item->childcount) {
                    node_s *t = current_menu_item->children_or_callback[selected];

                    if(t->childcount > 0) { /* if node is not a leaf */
                        current_menu_item = t;
                    } else { /* else execute leaf node's function */
                        menu_funcptr *f = t->children_or_callback;
                        (*f)(t->name);
                    }
                }
            }
        }
    }
}
Skriv svar