Hur ska man strukturera ett projekt? (arduino, C)

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
xarvox
Inlägg: 137
Blev medlem: 4 augusti 2005, 09:55:07
Ort: växjö

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av xarvox »

Tack för alla svar!
Jag har installerat doxygen och git nu, försöker förstå vad verktygen gör och hur jag använder dem..
Dessa verktyg kommer jag ha stor glädje av, tack och bock för tipsen!!

Jag har börjat jobba en del med doxygen och detta har gjort att jag återgått till arduino IDE, då jag har haft en del problem med övergången till eclipse.
Eclipse har ju annars mycket av strukturen som doxygen erbjuder, som arduino IDE saknar, men det är ändå LÅNGT mycket tydligare att se förklaringar på de olika variabel-namnen och funktionernas förväntade resultat osv

I övrigt, mycket bra råd och förslag, jag noterar och försöker bättra mig! :)

Jag använder separata headers och source-filer och försöker hålla alla funktioner korta och koncisa, men jag misslyckas helt med att inte använda globala variabler...

Jag har en struct global_states där alla olika funktioners nuvarande lägen finns lagrade och de olika funktionerna läser/skriver dit för att slå av/på lampor, tuta osv osv..

Jag läser av knapparna, om knapptryck, slå om knappens funktion (tex hel-ljus eller tuta) och skriver detta till global_states.
Sedan läser jag av global_states för att avgöra vilka lampor som ska vara tända vid nästa "ljus-uppdatering", när jag skriver LED-lampornas status via i2c pin extenders.

..och så håller jag på ungefär hela tiden.. :P


Så hur menar ni bättre vetande att jag borde konstruera kedjan knapp-tryck > belysning_PÅ?
Jag vill ju gärna kunna använda fancy knappfunktioner, bl.a toggle av/på samt kort/lång-klick på vissa knappar, för att exempelvis kunna "artighets"blinka två gånger extra snabbt, vid filbyte och annat.

Jag har även vissa idéer om vad jag vill göra med projektet i framtiden, så en modify-knapp (för kombinationer av knapptryckningar) har också hamnat rätt högt på önskelistan för nästa version..
Tanken här är alltså att använda blinkers höger/vänster-knapparna medan jag håller ner avblända-knappen för att via blåtand säga åt telefonen att byta till föregående/nästa låt, eller höja/sänka volymen osv..


Jag ser just inte hur jag ska kunna undvika att lagra alla fordons-funktionernas statusar som globala variabler, eftersom jag tycker mig behöva kolla vad som ska vara av eller på från flera olika ställen och lampan ska inte nödvändigtvis vara släckt bara för att knappen inte är intryckt..
Användarvisningsbild
arvidb
Inlägg: 4537
Blev medlem: 8 maj 2004, 12:56:24
Ort: Stockholm

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av arvidb »

xarvox skrev:Jag läser av knapparna, om knapptryck, slå om knappens funktion (tex hel-ljus eller tuta) och skriver detta till global_states.
Sedan läser jag av global_states för att avgöra vilka lampor som ska vara tända vid nästa "ljus-uppdatering", när jag skriver LED-lampornas status via i2c pin extenders.
Det låter väl som ett helt OK sätt att göra det, men deklarera din global_states-variabel i main() eller liknande och skicka med den explicit som en parameter till de funktioner som behöver komma åt den. På så sätt blir det tydligt vilken data som används var och på vilket sätt.

Vad gäller modify-knapp och andra fancy funktioner så låter det som att du är på helt rätt väg om du redan hanterar knapparna i en egen källkodsfil. Då kan du ju anropa buttons_update_state(&global_state) eller liknande, och så blir det upp till knapphanteringskoden att lista ut hur t.ex. modify-knapp + vänster blinkers ska påverka tillståndet.

Om du behöver lagra tillstånd specifikt för knapparna, typ tidpunkt för när en viss knapp blev intryckt (för att hantera lång-klick), så är det lämpligt att ha en separat struct för den datan, som du allokerar och skickar med till buttons-funktionerna enligt mitt tidigare battery-kodexempel. Detta för att minimera tillgängligheten för data där det inte behöver vara tillgängligt.
xarvox
Inlägg: 137
Blev medlem: 4 augusti 2005, 09:55:07
Ort: växjö

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av xarvox »

Pointers, reference och de-reference (om minnet inte sviker) är något som jag inte har greppat tyvärr..
Jag förstår att de länkar till en variabels minnes-adress istället för dess värde eller nåt sådant och det ser fint och prydligt ut i exempel-koder, men jag förstår inte alls hur dessa fungerar.. :-/

Från din kodsnutt tolkar jag att strukturen globalStates skickas med när jag kör funktionen buttons_update(&globalStates), med resultatet att globalStates uppdateras innifrån funktionen buttons_update().
Betyder detta att globalStates inte behöver vara global?

Förlåt att jag är lite trög på detaljerna, jag behöver förstå på mitt sätt innan bitarna faller på plats. :)


Jo, jag brukar köra inputs (knappar och interrupts) i separat header och även börjat definiera funktioner i source på sistone.
Jag har också försökt skriva ett bibliotek för knapp-hanteringen, iomed att jag har hårdvaru-debounce (kondensator) och extern pullup-resistor på varje ingång på mina pin-extender-PCB´s som jag ritade för MCP23008 (i2c).
Med andra ord, en lösning som jag kommer använda på flera andra projekt, beställde 10x för en tjuga.. :)
Tyvärr krånglar det ofta ihop sig för mig, jag kan visst inte anropa ett bibliotek ifrån ett bibliotek, vilket gör att jag inte kan använda adafruits lösning för mcp23008.. :(
Att skriva en egen variant av deras bibliotek är långt över min expertis och därmed uteslutet.. jag förstår inte hälften av deras kod ens.. :/


Jag har i varje fall börjat jobba på en fräsh projekt-mapp där jag börjar med den dokumenation ni föreslagit och jobbar uppifrån och ner, med (externa) proof-of-concept-filer med fungerande komponenter som blir byggblock för helheten.
Huvudprojektets kod blir därför mest länkar till del-komponenterna samt en kärna av systemkritiska funktioner som styr anropen till övriga funktioner.


Det är i varje fall mycket som har klarnat efter lite tips och råd från er alla, tack ödmjukast för hjälpen! :)
guckrum
Inlägg: 1671
Blev medlem: 19 juni 2012, 09:04:27
Ort: Lund

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av guckrum »

Git är rätt val. Denna bok innehåller allt du vill veta, och den är gratis

https://git-scm.com/book/en/v2

html samt nedladdningsbar i flera format. Pappersboken är inte dyr och praktisk
för marginalanteckningar :)
Användarvisningsbild
arvidb
Inlägg: 4537
Blev medlem: 8 maj 2004, 12:56:24
Ort: Stockholm

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av arvidb »

xarvox skrev:Pointers, reference och de-reference (om minnet inte sviker) är något som jag inte har greppat tyvärr..
Jag förstår att de länkar till en variabels minnes-adress istället för dess värde eller nåt sådant och det ser fint och prydligt ut i exempel-koder, men jag förstår inte alls hur dessa fungerar.. :-/

Från din kodsnutt tolkar jag att strukturen globalStates skickas med när jag kör funktionen buttons_update(&globalStates), med resultatet att globalStates uppdateras innifrån funktionen buttons_update().
Betyder detta att globalStates inte behöver vara global?
Det stämmer, eftersom globalStates skickas med som parameter så kommer den att vara tillgänglig i funktionen utan att vara global. Vinsten blir då att om du ser till att globalStates inte deklareras som en global variabel så kan inte funktioner som inte har med den att göra vara inne och peta i den, och det blir tydligt för dig som programmerare vilka funktioner som rör datat i globalStates.

Structen globalStates innehåller ju många värden och det vore ineffektivt att skicka med alla dessa till en funktion. Genom att skriva &globalStates ("pointer reference to globalStates") så kan du istället skicka med minnesadressen där det första värdet finns lagrat. Kompilatorn håller reda på hur structen ser ut och räknar ut vilka offset som behövs från startadressen för att komma åt de olika fälten, så den enda skillnaden för dig som programmerare är att du får skriva globalStates->lampa1 istället för globalStates.lampa1 (-> istf .). Och "struct datatyp *variabel" istf "struct datatyp variabel".


Det borde för övrigt inte vara några problem att anropa ett bibliotek ifrån ett bibliotek.
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av adent »

Pekare är i grunden väldigt enkelt. Men kräver lite övning efter att man lärt sig konceptet. Har du vägarna förbi Jönköping någon tisdag så kom förbi Makers Jönköpings lokal så ritar jag och förklarar gärna.

MVH: Mikael
limpan4all
Inlägg: 8195
Blev medlem: 15 april 2006, 18:57:29
Ort: Typ Nyköping

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av limpan4all »

De bästa programmerarna som jag har jobbat med använde sig av två helt olika metoder.

Den "ryska" varianten. Få ihop alla funktioner med spaggetiprogrammering. När skiten väl fungerar lägg till det som saknas såsom användargränssnitt osv. Nu har du en fungerande förlaga. Dokumentera den noga och skriv sedan om allt från början på "rätt" sätt utan att titta på den första koden. Kör båda koderna på "hårdvaran" tills dom fungerar lika bra.

Den "amerikanska" varianten. Börja med att dokumentera all som programmet skall göra. Skapa testkod för alla ingående moduler och även den färdiga koden, se till att all kod exekveras mot ett HAL, låt en PC simulera HAL och se till att all kod exekveras korrekt i alla testfallen (i den simulerade miljön på PC). Självklart så har allt dokumenterats minutiöst. Alla nya funktioner implementeras i kod först efter att adekvata testfall har skapats, sedan skrivs koden, vilken sedan testats automatiskt. Alla andra testfall körs också varje gång ny kod skall in i projektet så att den fortfarande gör det den skall och inget annat,

Vad är då skillnaden.
Båda metoderna fungerar utmärkt.
Den ryska brukar kräva fungerande hårdvara innan kodskapandet börjar och fungerar oftast bättre, men är i stort sett begränsad till endast en programmerare i projektet.
Den amerikanska är mera "tålig" mot juniora programmerare så länge som dom seniora skriver testfallen. Men den tar ca 2,5ggr så lång tid räknat i mantimmar och kräver vanligen ingen fungerande hårdvara innan kodningen lagt ner ungefär halva utvecklingstiden. Den här metoden ger också betydligt mera direkt återanvändbar kod.

Som sagt, jag skriver ingen kod alls själv, jag nöjer mig med att stå vid sidan om och heja på. Men det är mycket intressant att se de olika sätten att jobba på.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av Glattnos »

arvidb: Det var en väldigt bra förklaring av Header-fil och c-fil. Det är dock en detalj som jag aldrig riktigt förstått, kanske logiskt men jag är inte så hemma på detta :) Man inkluderar ju header-filen i sin huvudfil:

Kod: Markera allt

#include "battery.h"
Men hur vet den i sin tur vilken c-fil den ska referera till? Det står ju inte #include "battery.c" eller liknande i H-filen så hur "vet" programmet vilken h- och c-fil som hänger ihop?
Förmodligen är det självklart men förklara gärna det också :)
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43152
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av sodjan »

> Men hur vet den i sin tur vilken c-fil den ska referera till?

Vilken C-fil som H-filen refererar till? Ingen alls, rent tekniskt.
Logiskt hör dock ofta en H och en (eller flera) C filer ihop. H-filen
beskriver det som C filerna implementerar med faktiskt kod.

H-filen innehåller deklarationer (hur anropet ser ut och svaret)
för funktioner (och lite annat) som sedan *något* en C-fil sedan
måste ha implementeringen till, alltså själva koden.

Om du har en battery.h och en battery.c, så inkluderar du
antaglingen battery.h i din main.c (eller vad den heter). Det
betyder att då main.c kompileras så vet kompilatorn hur anropen
till funktionerna i battery.c *ska* se ut. Sedan då main.c är
kompilerad till main.o (eller vad nu objektfilen heter) och den länkas
med battery.o (den kompilerade battery.c), så fungerar det...

Notera att H och C filen självklart inte behöver ha samma namn!
Det viktiga är bara att om en H fil deklarerar en funktion FunkX() så
måste FunkX() finnas någonstans. Det kan vara i en C fil, i en fil i ett
helt annat språk, eller i en färdig kompilerad "lib". Ditt huvudprogram
behöver inte veta hur funktionen är implementerad rent tekniskt, bara
hur anropet och svaret ser ut.
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45176
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av TomasL »

Viktigt att komma ihåg, du skall bara deklarera variabler och funktioner som skall vara tillgängliga i andra moduler i h-filen.
Funktioner och variabler som är lokala för modulen, dvs anropas eller används bara i den egna modulen deklarerar du i c-filen.

En modul i detta fall är en c-fil.
Variabler skall deklareras i den h-fil som tillhör modulen där de initieras.
Används variablerna i andra moduler så deklarerar du variablen med tillägget "extern", till exempel:

Kod: Markera allt

#ifndef FANS_H

	#define FANS_H



		extern uint16 fu_InstalledFans[NUM_MB_FAN]; 	// används i FAN och LoF
		extern uint16 fu_num_InstalledFans_u16;  	// används i FAN och LoF
		extern uint16 fu_num_prio_u16;						// används i FAN
		void getfans(void);
		
#endif
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av Icecap »

En .H-fil anger bara för kompilern att det någonstans i alla programfiler finns någon/några rutiner som kan anropas. Den anger vilka parameter som ska till dessa rutiner och hur det svaras tillbaka.

Och det är allt.

Sedan ska dessa programfiler såklart läggas till i projektet.

Jag har utvecklad MÅNGA hårdvara-rutiner till det styrkort vi använder, ett av mina projekt har 51 källkodfiler i sin lista över vilka filer som hör till projektet - men bara 9 källkodfiler i det bibliotek som innehåller projektet.

Kompilern kompilerar fil för fil och lämnar efter sig delprogram. Linkern tar sedan dessa delprogram och ser till att när delprogram A refererar till en funktion i delprogram B läggs det in rätt adress - varefter alla adressor läggs fast och en HEX-fil (eller liknande) skapas.

Så varje delprogram har INGEN aning om vad som händer i de andra delprogram och av den anledning använder man H.-filer för att berätta att det faktisk finns de funktioner tillgängliga - men VAR de finns är likgiltigt för användaren av dom, de finns någonstans!

Detta betyder alltså att om man gör en funktion för att t.ex. kommunicera med hårdvara, kan man göra en full funktion med ett "standard" interface som kan allt man vill och till detta lägga en H.-fil som ger tillgång till alla funktioner.

Då gör man detta en enda gång och lägger källkoden ett "gemensamt" ställe. Därifrån kan man kalla in (inkludera i projektet) de filer man behöver och man vet att de fungerar perfekt varje gång. Hittar man en bugg kan man fixa den och sedan omkompilera alla projekt som använder denna funktion och alla är uppdaterade.

Detta betyder såklart att man kan behöva testa rutinerna ordentligt innan man använder dom i de olika projekt.
xarvox
Inlägg: 137
Blev medlem: 4 augusti 2005, 09:55:07
Ort: växjö

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av xarvox »

Glattnos skrev:hur "vet" programmet vilken h- och c-fil som hänger ihop?
Jag fick en förklaring som funkar för mig; man #inkluderar headern från huvud-dokumentet, samt i source-dokumentet #inkluderas dess header och compilern känner av denna länkning, oavsett riktning.

alltså:
i proj.ino: #include "stuff.h"
i stuff.c: #include "stuff.h"
Förenklat: proj.ino -> stuff.h <- stuff.c

Stuff.c blir alltså länkat i proj.ino via stuff.h, eftersom stuff.c länkar till stuff.h.

Och eftersom man länkar specifikt till varje dokument så kan de ha vilket namn som helst, även ha en .h-fil och massor .c-filer och vice versa osv.

Ber om ursäkt på förhand ifall något av det ovan sagda inte är korrekt, rätta mig gärna isf! :)



En annan sido-fråga, gällandes bibliotek och liknande;

Jag leker med tanken att skriva det där biblioteket jag tänkt på, som läser i2c-pin extender-knappar via ett buffer (minimera bus-trafik :) ) och som läser av och returnerar knapp-klick-typ på något sätt.
Nuvarande idé är att senaste klick-typen lagras tills programkoden läser av den och nollar variabeln, på så vis reagerar jag bara en gång på en knapp-händelse. (1 = intryckt, 2, kort-klick, osv osv)

Som jag ser det måste jag ju instansiera varje knapp, dvs 8 knappar = 8 instanser.
dvs jag måste ha 8x button[0-7].update(); efter varje buffer-refresh.

Finns det något sätt att automatiskt uppdatera alla instanser, utan att behöva definiera var och en?
Eller borde jag istället skriva biblioteket så att det "samkör" alla knapparna i en instans?



Jag vill än en gång tacka för tipsen om doxygen, jag har börjat använda det som tusan! :)
För er andra amatörer som använder arduino IDE som enda verktyg, SKAFFA DOXYGEN!!!
Det enda som saknas är ett automatiskt script som kör doxygen-scriptet så fort käll-mappen uppdaterats. :P

git är lite knepigare för mig, jag har lyckats få allt att lira nu, har även lyckats jämföra skillnader mellan versionerna osv, men jag är definitivt ingen linux-nörd.. :/
Användarvisningsbild
arvidb
Inlägg: 4537
Blev medlem: 8 maj 2004, 12:56:24
Ort: Stockholm

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av arvidb »

Ytterligare ett sätt att se på detta med hur .h- och .c-filer hänger ihop:

#include tolkas väldigt bokstavligt av kompilatorns preprocessor: i princip funkar det som att den inkluderade filen klipps in i filen där include-direktivet står innan kompileringen (under preprocessningen). Och namnet på själva c-filen skickas ju med till kompilatorn: "gcc -c battery.c" kommer alltså att dra in allt innehåll från alla filer som är #includade i battery.c förutom koden i battery.c. Man kan testa detta själv genom att titta på output från "gcc -E battery.c". Flaggan -E gör att enbart preprocessningen körs, så att man kan se exakt vilken kod som faktiskt blir kompilerad sedan.
Användarvisningsbild
arvidb
Inlägg: 4537
Blev medlem: 8 maj 2004, 12:56:24
Ort: Stockholm

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av arvidb »

xarvox skrev:Ber om ursäkt på förhand ifall något av det ovan sagda inte är korrekt, rätta mig gärna isf! :)
Ok då. :) Var försiktig med terminologin här: länkning har en rätt specifik betydelse som inte alls har med inkludering av headerfiler att göra. Först sker preprocessningen som bl.a. hanterar alla #include-statements, sedan sker kompileringen, sedan (efter att alla källkodsfiler har kompilerats till binära objektfiler) länkas dessa objektsfiler ihop till en exekverbar fil. Länkningen handlar bl.a. om att räkna om och "fylla i" relativa adresser till olika funktioner givet hur de olika binära objektsfilerna bakas ihop till en fil (just detta har jag inte 100 % koll på dock).
Användarvisningsbild
arvidb
Inlägg: 4537
Blev medlem: 8 maj 2004, 12:56:24
Ort: Stockholm

Re: Hur ska man strukturera ett projekt? (arduino, C)

Inlägg av arvidb »

xarvox skrev:Som jag ser det måste jag ju instansiera varje knapp, dvs 8 knappar = 8 instanser.
dvs jag måste ha 8x button[0-7].update(); efter varje buffer-refresh.

Finns det något sätt att automatiskt uppdatera alla instanser, utan att behöva definiera var och en?
Eller borde jag istället skriva biblioteket så att det "samkör" alla knapparna i en instans?
Jag är inte alls säker på att jag förstår frågan, men ett sätt att uppdatera alla instanser enl ovan är ju med en for-sats:

Kod: Markera allt

#define NO_BUTTONS 8
for (int i = 0; i < NO_BUTTONS; i++) {
	button[i].update();
}
Skriv svar