AVR Studio - Projekt s více soubory - jak includovat

Zdravím.
Mám trochu problém, a nemohu se zorientovat v tom jak v AVR Studiu napsat projekt obsahující více souborů. Jedná se o GCC.
Když mám hlavní soubor, dejme tomu main.c, vevnitř to bude obsahovat asi:

[code]#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include “mujsoubor.c”

…samotny program…
[/code]

a uvnitř souboru mujsoubor.c bude toto:

[code]#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

…pridavna cast programu, knihovna…
[/code]

Jde (šlo) mi to, napsat si vlastní knihovnu pro grafické LCD, která by se dala includovat, ale využití by se našlo i spousta jiného. Problém mám v tom, že když se takto psaný program pokusím přeložit, kompilátor mi vyhodí bobek, že nějaký object file nebyl nalezen.
Je v mém přístupu includování souborů nějaká zjevná chyba, kterou jako začátečník nevidím?
Díky,
Honza

Zdar,
poslední díl o C na builderu jsi četl?
builder.cz/art/cpp/prgmodul.html
Je to tam hodně stručně, ale mělo by to pomoci.

Tvůj způsob by měl v určitých jednoduchých konstrukcích fungovat také, ale běžně se nepoužívá. Má jistá nepřjemná omezení.
Vhodnější je vkládat pouze soubory “xxx.h”, které obsahují veřejné proměnné, prototypy veřejných funkcí a ochranu proti vícenásobnému vložení.
Kdybys to podle builderu nedal dokupy, tak ti sem nějaký kus kódu hodim. A kdyby jo, tak se pochlub ať ti to případně doladíme :slight_smile:.

Díky za odkaz n abuilder, ale nic nového jsem se tam orpavdu nedozvěděl.
Mohl by m iteda někdo napsat prosím příkald toho, jak vložit soubor do souboru tak, aby mi to AVR Studio sežralo? Nebo aspoň, co mám dát do souboru main, a co do toho vkládaného.
Díky.

Pracovní kódy sem dát nemůžu a ve starých mám v těchto věcech chyby (ikdyž to fungovalo), tak jsem ti spáchal takovej hodně umělej příklad :slight_smile:.
Snad k něčemu bude. Pokud bys to chtěl krokovat, zakomentuj v .c souborech"delay", jinak si v tom moc neposkáčeš.
C_viceModulu.zip (16 KB)

No, udělal si mi v tom ještě větší guláš, ale díky.
Nejdřív mi prosím vysvětli, co znamená

asm volatile("nop\n\t");

A pak k tomu includování… co dělá static, extern a podobné, je mi jasný.
Ale nechápu, kde dělám chybu, když mám program napsaný tak jak uvádím v příkladu v mojem prvním příspěvku zde v tématu. Proč mě potom kompilátor mlátí nějakými (mě) nicneříkajícími chybovými hláškami, o chybějcím object file.
Nebo jsou k otmu includování nějak nutné ty h(lavičkové) soubory? Já sem tu někde měl něčí knihovnu pro LCD, kde tušm, že ani ždáný H soubor nebyl, jen main, a “knihovnalcd.c”. Možná se pamatuju blbě. Najít se mě to nepovedlo, někam sem to asi zahrabal, takže mi to nepomůže.
Ale díky za ten příklad, aspoň něco jsem tam zajímavého a užitečného objevil.

To "asm volatile… " neřeš, to je jen vložení instrukce nop, používám to aby se dal program lépe zkoumat v simulátoru. Díky optimalizacím nejsou někdy části kódu v C krokovatelné, tohle občas pomáhá.

Vkládání přímo C souborů do jiných opravdu není dobrý nápad. Občas se totiž stane, že potřebuješ modul použít ve více souborech a pak se ti pokaždé definuje všechno znova. Pokud budeš mít hodně velkou kliku, tak to přeložíš, ale budeš mít kolize v proměnných, funkcích a další vychytávky. Ve větším projektu je tento způsob (pokud to sestavíš správně) prakticky nespravovatelný.
Myslím, že ti opravdu nezbyde, než se poprat s hlavičkovými soubory.
Když ti pojede třeba zmíněná obsluha lcd v 1 souboru, ale už né rozdělená, tak se poděl, ty vazby už dohromady dáme.

to už běží pěkně dolhou dobu… jen to teď se zaťatými zuby plácám všechno v jednom souboru. Před pár hodinami jsem tam ještě naplácal SW ovladač PS/2 PC klávesnice. Začíná tam bejt bordel :slight_smile:

Dyť se musí dát inkludovat bez hlavičkových souborů… nebo to C je takový pitomec, že to nejde? Mě stačí když budu moc jen inkludovat soubory do main.c, nikam jinam. Zatím by mi to stačilo.

Musíš mít vždy něco extra co :slight_smile:.
Určitě to jde, ale v tomhle ti radit nebudu, protože je velmi pravděpodobné, že bychom tě tu měli zanedlouho zpátky a důkladně rozčíleného jak je C stupidní :wink:.

Ano, C je stupidní. Možná je to tím, že jsem vyrůstal na pascalu, a dodnes v něm dělám (Delphi/Lazarus). A stupidní taky proto, že co kompilátor, to jiný widlákov. To, co funguje (dle specifikace) v jednom, v druhém fungovat nemusí. A liší se to i na úrovních vstup/výtup do souboru/obrazovku.

Co je extra na tom, že chci vložit soubor do souboru? Všecky programovací jazyky co znám to normálně umí, jen v Cčku musím jako debil vyrábět hlavičkové soubory, které vůbec třeba nepotřebuju, atd.

a abych tu jen tak netlachal, tak jsem zkoušel i cosi napsat.
Založil jsme v AVR Studiu nový projekt. Hlavní projektový soubor se jmenuje main.c, a obsahuje následující:

[code]#include <avr/io.h>
#define F_CPU 4000000U
#include <util/delay.h>
#include <avr/interrupt.h>

#include “vlozit.c”

int main(void)
{
DDRA = 0x00;
PORTA = 0x00;

while (1);
}[/code]

Soubor, který bych rád vpasoval na místo “#include “vlozit.c”” je ve stejném adresáři jako main.c, obsahuje následující:

[code]#include <avr/io.h>

void Funkce(char parametr)
{
PORTA = parametr;
}[/code]

Připadá mi to jako naprosto banální úkon, který snad v každém programovacím jazyce lze řešit snadno, jen Cčko je lehce zaostalé v tomto směru.
Překlad výšezmíněného projektu skončí následujícím chybovým hlášením:

gcc plug-in: Error: Object file not found on expected location X:\a\b\c\includovat.elf

(přičemž projektový název je právě “includovat”)

Co vlastně jsem tímto zápisem programu udělal tak šaptného, že to nejde ani zkompilovat?

Zkusil jsem něco podobného napsat a v AVR Studiu mi to normálně funguje:
Pokus.zip (10.9 KB)

Díky stando. Ten tvůj výtor přeložit šel, a přišel jsem i na to, proč to šlo.
Ty totiž nemáš soubor “vlozit.c” přidaný do “source files” vlevo v project manageru.
Buď já špatně chápu, k čemu tam ten manažér souborů projektu je, nebo tam je opravdu na h*. Když tam ten soubor nepřidám, přeložit to normálně jde, a chová se to taky normálně. To opravdu nechápu.
Na co tedy souží ta kategorie source files?

Slouží pro standardně použité soubory s kódem (a tedy i .h soubory). Každý soubor .c v projektu je přeložen do objektového .o a linker je pak dá dokupy. Ty jsi ovšem splácal několik fází překladu napřeskáčku a to se mu nezdálo. Když to nemáš ve file manageru, tak to řeší pouze preprocesor a ten má kromě několika málo dalších funkcí hlavně funkci “najít a nahradit” jako v notepadu. Tím, že jsi vyřadil linker se teď provede vložení a teprve pak překlad. Mimochodem kdybys při tvém způsobu načetl (.h souborem) nějakou méně dokonalou knihovnu bez ochrany proti vícenásobnýmu vložení, byl bys (jednou asi budeš) z toho zase na větvi.

Je spíš škoda, že tuhle prasárnu C dovolí. Je to asi jako když sedneš ze škodovky do renaultu a neuvěřitelně tě vytočí, že je zpátečka jinak. Prostě jsi v C a né v pascalu. Buď si zvykni, nebo si to pak užij, protože takový kód ti bude těžko někdo upravovat aby chodil ve “tvém” formátu.

Když sem to strčil okategoii níž, do eader files, tak to chodí v pořádku. Proč to dráždí překladač, když je to v té kategorii “source files” nevím. Jako laikovi mi to připadá jako demence, ať už doopravdy je nebo neni.

Každopádně nějak mi to funguje, tak jsem spokojen.

Jen jsem nepochopil tvé vysvětlení, proč to v kategorii source files nefunguje.

Musel by ses podívat, jak probíhá překlad programu, tedy trochu víc “pod kapotu”.
Soubory v sekci “source files” se překládají jako samostatné objekty (včetně vložených hlavičkových souborů a ve tvém případě i včetně jiného zdrojáku protože v source files není), kdežto header files se do cílového source file vloží a teprve takto vzniklý kód se přeloží.

V prvním (nefunkčním) případě byly přeloženy samostatné zdrojáky (do .o souborů) a následně se je linker pokusil složit (do výsledného .o), což se mu nepovedlo, protože jsi neměl hlavičkovými soubory vytvořené vazby.

Ve druhém případě se překládal pouze main.c (v source files). Ovšem ještě před překladem nastoupil preprocesor a ten druhý zdroják do toho mainu vložil. Linker pak měl k sestavení kódu jen 1 soubor (druhý není v source files), to provedl a výsledek se podařil.

ahááááááááááááááááá.
Tak teprve teĎ, jsme tě pochopil, co ses mi snažil celou dobu říct. No jsme to blb :smiley:
Už to chápu, takže díky za tvou pomoc, už se v tom konečně orientuju, jak to funguje. Nyní jsme knihovny napsal do hlavičkových souborů, a ty naincludoval do main.c - tak je to správně ne? 8)

No… Správně to sice není, ale je to o stupeň lepší. Řekněme, že z hodnocení “1 z 20ti” jsi to posunul na “2 z 20ti” :slight_smile:. V takto vytvořených “knihovnách” je zbytečné vkládat .h, co jsou v mainu. Jelikož je jejich kód vložen až za ty úvodní includy, tak je překladač uvidí.
Pokud to budeš lepit tímto zvrhlým způsobem, je bezpodmínečně nezbytné tam vytvořit ochranu proti vícenásobnému vložení (viz odkaz na builder a ty #ifdef, #define, #endif v headrech příkladu).

Správně bys měl mít kód v .c souboru a od něho mít také odvozen .h soubor (s hlavičkami funkcí obsažených v .c) a tento .h vkládat do main.c.
Linker si pak provede samostatné překlady obou zdrojáků, ale protože jsou v nich i hlavičkové soubory, umí zavolat i funkce z jiného (ví jak vypadají, jaké mají parametry a to mu zatím stačí). Tyto vazby si uloží ve vytvářených .o souborech (object file).
Nakonec při sestavování konečného .o si tyto vazby projde, oba .o soubory správně spojí a vytvoří výsledný hex, který naleješ do mcu.

Prostě jak to bylo v tom příkladu. V .h souborech taky nebyly žádné výkonné kódy, jen hlavičky funkcí a sdílené proměnné.

Asi ti to moc nepomůže (je to jen heslovitě - přednáška z C na win32), ale třeba budeš z čista jasna osvícen :smiley:
pr11_velke projekty.pdf (551 KB)

Nie som si isty co rozumies pod slovom kniznica. Kniznicou urcite nie je prilinkovany samostatny subor *.c, aj ked sa Ti to moze zdat byt celkom trefne oznacenie.

Kniznice si v AVR studiu prikladas cez Configuration Options sekcia Libraries. Kniznice maju priponu *.a. Podla toho co pises asi budes este dost daleko od toho, aby si si tvoril vlastne kniznice. No mozno sa mylim.

Predpokladam, ze si si vytvoril nejaky c-ckovy subor, v ktorom mas par sikovnych funkcii, ktore chces pouzivat v roznych projektoch.

Tak si v AVR studiu si vytvor novy projekt (od toho su). Napis si suborov *.c kolko chces. Ziaden do ziadneho nevkladaj ani pomocou direktivy #include. Vloz si ich do vytvoreneho adresara projektu.

Klikni pravym tlacidlom mysi na Source Files a vloz si vsetky tie c-ckove subory, ktore sa maju na aplikacii podielat.

To mozes spravit aj v zlozke Header Files. Na rozdiel od Source Files prekladac so subormi vlozenymi do Header Files nerobi nic, iba Ti ich umozni vybrat v editore.

Vsetko co je vlozene do Source Files sa prelozi spolu do jedneho *.hex pomocou automaticky vygenerovaneho make. O to sa postara WinAVR.
Inak vsetko je to aj v helpe v AVR studiu. Zadaj hladat “The Project Tree”.

Pravidla vkladania headrov, rozdiel medzi deklaraciou a definiciou funkcii, co je to static (z hladiska viditelnosti premennej medzi rozymi c-ckami), ako zapuzdrovat premenne a ako deklarovat globalne premenne, ako kedy a co je potrebne vkladat do headrov a hlavne ako ma vyzerat stabna kultura pouzitia headrov a c-ckovych suborov nema zmysel pisat. Bolo to uz napisane 100x a daleko vacsimi kapacitami ako je moja malickost. Rozhodne tuto fazu ucenia sa C-cka nepodcenuj. Je jedno s akym prekladacom robis. Je to celkom slusne popisane aj v klasike od Herouta. Urcite (ak este nemas) si zadovaz prvy diel. Je to tam i s prikladmi a vysvetlenim.

Co sa #include tyka, ja osobne to robim tak, ze samozrejme ku kazdemu c-ckovemu suboru do ktoreho musi byt “vidiet” z funkcii v ostatnych c-ckovych suboroch napisem samostatny header. Vsetky headre pomocou #include vpisem do headrea ktory sa vola include_all.h (samozrejme na jeho mene nezalezi) Do kazdeho c-cka potom na zaciatok iba vpisem riadok

#include include_all.h

Pre rozne projekty ma subor include_all.h rozny obsah, ale samotne c-ckove subory v ktorych netreba menit funkcie ostanu nedotknute editovanim kvoli prilinkovaniu nejakych inych c-cok s ich headrami. Vsetky zmeny okolo headrov robim iba na jednom mieste a ak sa nieco zmeni, nemusim editovat vsetky c-ckove subory. Tych sa neboj pouzivat viac. V projektoch s vyslednym kodom 10-20kB ich mam nezriedka 8-12 a trebars aj 16 headrov. Napriklad samostatny subor C na komunikacny protokol, samostatny subor na driver com1, na driver com2, samostatny driver na SPI so smerovanim (jasne ze nerobi iba odosielanie a prijem jedneho bajtu :slight_smile: ). Nejake slusne navyky tvorby c-ckovych suborov su napisane u Herouta a nie len tam. Vela tu uz toho dobreho bolo spomenute aj v diskusii.

Boha jeho. Je nutný tahat tady každýho za slovíčko?
Je možný, že v C nejsem tak dokonalý, ale pravou knihovnu bych dokázal napsat. Asi ne hned a honem, ale chvíli byhc nad tím koumal. Tenehle zásek s tím includováním, byl jen kvůli tomu nepochopenému oddělenému překladu souborů c.
Na Pavla Herouta mě neodkazuj, mám tu od něj literatury dost - ze školy jsem toho při rušení počítačové knihovny získal dost :slight_smile:
Je m ijasný, že psát výkonný kód dovnitř hlavičkového souboru je asi prasárna, ale podstatný je pro mě to, že to funguje, a je to “jednoduchý”. Profesionálním C programátorem se stát nechci, takže mé výsledky tomu asi také odpovídají.
(Znalosti z programování spíš naháním v oboru desginéra VCL a komponent pro Delphi)

Rozhodně se nemusíš bát, že kdybys dokázal správně rodělit projekt do víc souborů, musel by ses nazývat profesionálem. Z toho by tě určitě někdo rychle vyvedl :wink:. To je dovednost začátečníka, kterej se o C jen trochu zajímá a je ochoten této snadné záležitosti věnovat i jen odpoledne.

Tvou profesionalitu by patrně nikdo nezpochybňoval teprve tehdy, pokud bys dokázal použít následující řádek, který osobně nedokážu ani přečíst :slight_smile: (opět příklad z builderu): double (*GetFunc(int n, double (*pfuncs])(double)))(double);