Skapa ett programvalsystem i C
- Magnus_K
- EF Sponsor
- Inlägg: 5854
- Blev medlem: 4 januari 2010, 17:53:25
- Ort: Skogen mellan Uppsala-Gävle
Skapa ett programvalsystem i C
Hej!
Skulle behöva lite vägledning från er o programmeringsgurus.
Jag vill skapa ett menysystem med programval i C och skulle behöva en knuff i rätt riktning. Här kommer lite mer ingående förklaring:
Min enhet har en knapp och när denna hålls nere länge (säg 5+ sek) så går enheten in i "programvalsläge". När enheten är i detta läge så innebär ett snabbt knapptryck nästa program. När man knappat sig till rätt program så hålls knappen in länge igen och detta nya program låses.
Att sätta enheten i programvalsläge genom ett långt knapptryck kan jag nog lösa men jag vet inte vilket tänk jag ska använda mig av när det kommer programmen.
Min idé är att ha en "programvariabel", där varje bit i variabeln har en funktion. Genom att kombinera olika bitar så skapas dom olika programmen.
En switch() case kan sedan stegas runt genom att maska av bit för bit för att veta vilken funktion i programmet som ska köras.
Hur skulle ni gjort? Hur gör ni allmänt när det kommer till "menyhantering" och liknande i kod? Är det här en typisk situation där goto används?
Väldigt svårt att förklara sånt här i skrift för det blir snabbt en massa text som ingen orkar läsa. Men fråga gärna!
Skulle behöva lite vägledning från er o programmeringsgurus.
Jag vill skapa ett menysystem med programval i C och skulle behöva en knuff i rätt riktning. Här kommer lite mer ingående förklaring:
Min enhet har en knapp och när denna hålls nere länge (säg 5+ sek) så går enheten in i "programvalsläge". När enheten är i detta läge så innebär ett snabbt knapptryck nästa program. När man knappat sig till rätt program så hålls knappen in länge igen och detta nya program låses.
Att sätta enheten i programvalsläge genom ett långt knapptryck kan jag nog lösa men jag vet inte vilket tänk jag ska använda mig av när det kommer programmen.
Min idé är att ha en "programvariabel", där varje bit i variabeln har en funktion. Genom att kombinera olika bitar så skapas dom olika programmen.
En switch() case kan sedan stegas runt genom att maska av bit för bit för att veta vilken funktion i programmet som ska köras.
Hur skulle ni gjort? Hur gör ni allmänt när det kommer till "menyhantering" och liknande i kod? Är det här en typisk situation där goto används?
Väldigt svårt att förklara sånt här i skrift för det blir snabbt en massa text som ingen orkar läsa. Men fråga gärna!
Re: Skapa ett programvalsystem i C
Förstår jag syftet rätt här? Du har en apparat som bara har en knapp vilket gör den krånglig att använda. Du vill tillverka en manick som låter dig välja olika menyalternativ på ett mer naturligt sätt, och sedan simulerar knappnedhållning osv. för att styra apparaten?
- 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
Nej, inte riktigt, men det är jag som är otydlig.
Kan ta mitt aktuella projekt och försöka göra det tydligare:
Jag har en pannlampa som jag moddat lite och nu sitter det en µC i lampan. Lampan vill jag ha olika program för. Tex med program 1 inställt så slår av/på-knappen enbart lampan fullt på eller fullt av.
Har man tex program 2 inställt så växlar lampan mellan hel, halv och av. Program 3 kanske är hel, halv, S.O.S och av osv.
Det är alltså detta programsystem jag försöker få till. Vill man ha ett nytt program (eller mönster) som ett knapptryck ska växla mellan så håller man inne av/på-knappen för att sätta den i "programvalsläge", knappar fram till nytt program, håller inne knappen igen för att låsa programmet.
Jag behöver en liten spark i rätt riktigt om hur ett lämpligt flöde i koden skulle kunna se ut.
Kan ta mitt aktuella projekt och försöka göra det tydligare:
Jag har en pannlampa som jag moddat lite och nu sitter det en µC i lampan. Lampan vill jag ha olika program för. Tex med program 1 inställt så slår av/på-knappen enbart lampan fullt på eller fullt av.
Har man tex program 2 inställt så växlar lampan mellan hel, halv och av. Program 3 kanske är hel, halv, S.O.S och av osv.
Det är alltså detta programsystem jag försöker få till. Vill man ha ett nytt program (eller mönster) som ett knapptryck ska växla mellan så håller man inne av/på-knappen för att sätta den i "programvalsläge", knappar fram till nytt program, håller inne knappen igen för att låsa programmet.
Jag behöver en liten spark i rätt riktigt om hur ett lämpligt flöde i koden skulle kunna se ut.
Re: Skapa ett programvalsystem i C
Nåt sådant här? Helt otestat, har inte kodat C på evigheter heller.
Kod: Markera allt
#define MILLISECOND_CONSTANT (123.4) /* ticks / millisecond */
#define PROGMODE_THRESHOLD (5000 * MILLISECOND_CONSTANT)
typedef enum { false, true } bool;
#define MIN_BUTTON_LENGTH (10 * MILLISECOND_CONSTANT)
#define MAX_BUTTON_LENGTH (1000 * MILLISECOND_CONSTANT) /* only presses shorter than this counts as regular button presses */
bool key_is_down (void) {
// insert code here
}
void toggle_light_onoff(void) {
// insert code here
}
int main(void) {
typedef enum {
apelsin, banan, citron
} menu_state_e;
menu_state_e menu_state = apelsin;
bool progmode_active = false;
int key_down_count = 0;
while(1) { /* main loop */
if(key_is_down()) {
key_down_count++;
} else {
if(key_down_count >= PROGMODE_THRESHOLD) {
progmode_active = !progmode_active;
} else if (key_down_count >= MIN_BUTTON_LENGTH && key_down_count <= MAX_BUTTON_LENGTH) {
if(progmode_active) {
menu_state ++;
if(menu_state > citron) menu_state=apelsin;
} else {
toggle_light_onoff();
}
}
key_down_count = 0; /* reset keypress counter. I'm assuming hardware debounce is present. */
}
}
}
Senast redigerad av datajompa 26 mars 2017, 18:27:50, redigerad totalt 1 gång.
Re: Skapa ett programvalsystem i C
Jag följde inte din spec alls i kodsnutten ovan... Bara tänkt som en lös "skiss". Det finns säkert syntaxfel också.
- 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
Tackar datajompa!
Förstår i stort hur du skulle "lagt upp det", och det tackar jag för.
Är nyfiken på hur man i regel resonerar när man ska göra menysystem och annat i kod.
Vill man helst sätta programmet i olika "states" eller kan man även göra koden så programmet skickas till olika loopar, beroende på vart i menyn man är?
Äsch, svårt att förklara men är jättetacksam om någon vill ventilera lite hur just reat resonemang låter.
Förstår i stort hur du skulle "lagt upp det", och det tackar jag för.
Är nyfiken på hur man i regel resonerar när man ska göra menysystem och annat i kod.
Vill man helst sätta programmet i olika "states" eller kan man även göra koden så programmet skickas till olika loopar, beroende på vart i menyn man är?
Äsch, svårt att förklara men är jättetacksam om någon vill ventilera lite hur just reat resonemang låter.
Re: Skapa ett programvalsystem i C
Att använda en tillståndsmaskin är väldigt bra. Då kan man på ett relativt enkelt sätt verkligen testa varenda rad kod!
Re: Skapa ett programvalsystem i C
Försökte mest göra nåt kort och enkelt att läsa, fortfarande svårt att veta EXAKT vad du frågar efter?
Jag skulle ha gjort nåt mer som nedanstående med funktionspekare. Denna gång testkört under Ubuntu, funkar endast i riktig virtual terminal (Ctrl+Alt+F1). Jag hade ingen Windowsmaskin att testa en lämplig key_is_down() på men det borde ju vara enkelt. Jag tror dock inte att kbhit() räcker för den signalerar väl bara lägesväxlingar?
Vänster Ctrl simulerar din knapp som jag förmodar ska vara hårdvara på en uC, shift avslutar. Så på en uC så borde key_is_down() kunna vara bara typ
Måste länkas med ncurses på linux,
Jag skulle ha gjort nåt mer som nedanstående med funktionspekare. Denna gång testkört under Ubuntu, funkar endast i riktig virtual terminal (Ctrl+Alt+F1). Jag hade ingen Windowsmaskin att testa en lämplig key_is_down() på men det borde ju vara enkelt. Jag tror dock inte att kbhit() räcker för den signalerar väl bara lägesväxlingar?
Vänster Ctrl simulerar din knapp som jag förmodar ska vara hårdvara på en uC, shift avslutar. Så på en uC så borde key_is_down() kunna vara bara typ
Kod: Markera allt
return *0xABCD;
Kod: Markera allt
gcc pannlampameny.c -o pannlampameny -lncurses
Kod: Markera allt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
typedef enum { false, true } bool;
#define MILLISECOND_CONSTANT (10.1) /* ticks / millisecond */
#define PROGMODE_THRESHOLD (5000 * MILLISECOND_CONSTANT)
#define MIN_BUTTON_LENGTH (10 * MILLISECOND_CONSTANT)
#define MAX_BUTTON_LENGTH (1000 * MILLISECOND_CONSTANT) /* only presses shorter than this counts as regular button presses */
#ifdef __linux__
bool key_is_down (void)
{
char shift_state;
shift_state = 6;
if (ioctl(0, TIOCLINUX, &shift_state) < 0) {
perror("ioctl TIOCLINUX 6 (get shift state)");
exit(1);
}
if(shift_state == 1) {
exit(1); // lshift quits, ctrl is key
}
return shift_state == 4; // Returns true if pressed otherwise false
}
#elif _WIN32
#error Implement your own non-blocking key-down code, must return true _while_ target key is _held down_
#else
#error Implement your own non-blocking key-down code, must return true _while_ target key is _held down_
#endif
/* callbacks gives maximum flexibility with regards to what different menu programs can do */
#define NEXT_STATE(x,y) x++;if(x>=y)x=0;
void do_prog1(void)
{
typedef enum {on, off, num_states} state_e;
static state_e state = 0;
switch(state) {
case on:
printf("Prog1 on\n");
break;
case off:
printf("Prog1 off\n");
break;
}
NEXT_STATE(state,num_states);
}
void do_prog2(void)
{
typedef enum {full, half, off, num_states} state_e;
static state_e state = 0;
switch(state) {
case full:
printf("Prog2 hel\n");
break;
case half:
printf("Prog2 halv\n");
break;
case off:
printf("Prog2 av\n");
break;
}
NEXT_STATE(state,num_states);
}
void do_prog3(void)
{
typedef enum {full, half, sos, off, num_states} state_e;
static state_e state = 0;
switch(state) {
case full:
printf("Prog3 hel\n");
break;
case half:
printf("Prog3 halv\n");
break;
case sos:
printf("Prog3 S.O.S.\n");
break;
case off:
printf("Prog3 off\n");
break;
}
NEXT_STATE(state,num_states);
}
int main(void)
{
void (*functions[])(void) = {&do_prog1, &do_prog2, &do_prog3};
int menu_length = sizeof(functions) / sizeof(functions[0]);
int menu_state = 0;
bool progmode_active = false;
int key_down_count = 0;
printf("LCtrl simulates GPIO button. Press to shift states. Hold down 5 secs to activate programming mode. LShift quits.\r\n");
while(1) { /* main loop */
usleep(1); // slow things down, for testing purposes
if(key_is_down()) {
key_down_count++;
if(key_down_count == PROGMODE_THRESHOLD) {
progmode_active = !progmode_active;
printf("Progmode: %d\n", progmode_active);
}
} else {
// if(key_down_count != 0) printf("ms%f\n", key_down_count / (MILLISECOND_CONSTANT)); //uncomment to tune MILLISECOND_CONSTANT
if (key_down_count >= MIN_BUTTON_LENGTH && key_down_count <= MAX_BUTTON_LENGTH) {
if(progmode_active) {
NEXT_STATE(menu_state,menu_length);
printf("Selected menu item: %d\n", menu_state);
} else {
(*functions[menu_state])();
}
}
key_down_count = 0; // reset keypress counter. I'm assuming hardware debounce is present.
}
}
}
Senast redigerad av datajompa 27 mars 2017, 16:31:03, redigerad totalt 6 gånger.
Re: Skapa ett programvalsystem i C
Mer allmänt så finns det inga enkla och snygga lösningar i C. Det du pratar om är när du vill ha menyer i flera nivåer, i en hierarki osv? I C vill måste du nog bita i det sura äpplet och göra det med funktionspekare, ungefär som i mitt ovanstående exempel, fast med mer indirekta pekare till strukturer osv.
Om du använt ett språk med vettiga inbyggda strukturer så är det ju enkelt att göra t.ex.
i Javascript, Python, osv.
Ska man göra något liknande i C så blir det alltid hisnande någonstans. Antingen hisnande komplexa och fragila #define-grejer, eller hisnande "kluriga" lösningar som man inte förstår veckan efter att man skrev dem.
Om du använt ett språk med vettiga inbyggda strukturer så är det ju enkelt att göra t.ex.
Kod: Markera allt
var menu = [[("Meny1 alt 1",m1a1func),("Meny1 alt 2", m1a2func)],[("Meny2 alt 1",m2a1func)]]
Ska man göra något liknande i C så blir det alltid hisnande någonstans. Antingen hisnande komplexa och fragila #define-grejer, eller hisnande "kluriga" lösningar som man inte förstår veckan efter att man skrev dem.
- 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
Verkligen himla snällt att du lagt ner sån här tid på att svara.
Suttit och klurat en del på koden och jag har lite svårt att läsa precis vad den gör. Vad händer tex här -> state = (state<num_states-1) ? state+1:0; ?
Du skriver "eller hisnande "kluriga" lösningar som man inte förstår veckan efter att man skrev dem.". Exakt så känner jag.
Kläcker en "smart" lösning en dag, och antecknar denna. Ett par dagar efteråt så undrar jag hur i hela friden jag kunde komma fram till det resultatet.
Men enligt din erfarenhet så är blir det alltså ganska lätt rörigt att göra det här i C?
Suttit och klurat en del på koden och jag har lite svårt att läsa precis vad den gör. Vad händer tex här -> state = (state<num_states-1) ? state+1:0; ?
Du skriver "eller hisnande "kluriga" lösningar som man inte förstår veckan efter att man skrev dem.". Exakt så känner jag.
Kläcker en "smart" lösning en dag, och antecknar denna. Ett par dagar efteråt så undrar jag hur i hela friden jag kunde komma fram till det resultatet.
Men enligt din erfarenhet så är blir det alltså ganska lätt rörigt att göra det här i C?
-
- Inlägg: 87
- Blev medlem: 29 november 2010, 00:32:55
Skapa ett programvalsystem i C
Jag hävdar att det går alldeles utmärkt att göra menysystem i C.
State machines är brukligt .. och i mina ögon både enkelt och snyggt.
Det som är bra med state machines tycker jag är att det är lätt att hoppa ur och avbryta inmatningen. Bara resetta alla states.
Samt överskådligt om man vill implementera undo eller konfigurera "offline" parametrar.
Googla state machine och C om du vill se hur det brukar se ut.
Jag har verkligen inget emot Javascript och Python. Men jag lovar att det är minst lika lätt att skriva en callbacktrasslig sörja som är totalt oläslig som att trassla till det med funktionspekare etc.
Beklagar det schizofrena term-språkbruket.
State machines är brukligt .. och i mina ögon både enkelt och snyggt.
Det som är bra med state machines tycker jag är att det är lätt att hoppa ur och avbryta inmatningen. Bara resetta alla states.
Samt överskådligt om man vill implementera undo eller konfigurera "offline" parametrar.
Googla state machine och C om du vill se hur det brukar se ut.
Jag har verkligen inget emot Javascript och Python. Men jag lovar att det är minst lika lätt att skriva en callbacktrasslig sörja som är totalt oläslig som att trassla till det med funktionspekare etc.
Beklagar det schizofrena term-språkbruket.
- 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
Googlar "state machine c" för fulla muggar och får bra resultat!
Får för mig att hittar man bara rätt "tänk" så borde det gå att få till på ett ganska ok sätt.
Tackar för tipsen. Ska försöka få ihop en psuedo-kod nu!
Får för mig att hittar man bara rätt "tänk" så borde det gå att få till på ett ganska ok sätt.
Tackar för tipsen. Ska försöka få ihop en psuedo-kod nu!
Re: Skapa ett programvalsystem i C
Oj det var ju lite dumt, det där är en oneliner som gör samma som detta:Magnus_K skrev:Vad händer tex här -> state = (state<num_states-1) ? state+1:0; ?
Kod: Markera allt
state++;
if(state >= num_states) {
state = 0;
}
Kod: Markera allt
void (*functions[])(void) = {&do_prog1, &do_prog2, &do_prog3};
Så om man skriver
Kod: Markera allt
(functions[2])();
Kod: Markera allt
do_prog3();
Det rätta sättet att göra detta i C är att använda ett färdigt bibliotek, för det blir snabbt väldigt komplext om man ska skriva ut all kod för hand.
Jag försökte faktiskt göra detta med en liten 2-nivås hierarkiell meny för att visa, men jag körde fast på pekarkonverteringarna någonstans...
Jag gnäller mest lite på C för att det är så primitivt och omständigt, så alla exempel kommer bli långa. Men det är klart att det går att göra.Men enligt din erfarenhet så är blir det alltså ganska lätt rörigt att göra det här i C?
Du vill använda datastrukturen Tree i alla fall.
Re: Skapa ett programvalsystem i C
Mitt exempel är för övrigt en state machine, med tillstånden definierade i en tabell.
Re: Skapa ett programvalsystem i C
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.
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.