Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Embedded 12. 05. 2015, 08:55:37
-
Zdravím.
Měl bych dotaz na to, jak správně psát Cčkovej kód (CodeWarrior) v MCU (Freescale), které má 32kB paměti a 1kB ram.
Nyní to mám tak, že:
main.c:
struct S_main main;
while(1)
{
//Kód...
}
main.h:
#include "file1.h"
#include "file2.h"
#include "conf.h"
struct S_main {
//Proměnné...
};
struct S_main main;
//Hlavičky funkcí...
file1.c:
#include "file1.h"
//Funkce
file1:h
#include "conf.h"
struct S_file1 {
//Proměnné...
};
extern struct S_file1 file1;
//Hlavičky funkcí...
file2:c
#include "file2.h"
//Funkce
file2.h:
#include "conf.h"
struct S_file2 {
//Proměnné...
};
extern struct S_file2 file2;
//Hlavičky funkcí...
#conf.h:
ifdef...
Ve strukturách jsou proměnné, které se v jednotlivých .c souborech používají...
Je to správně? Dá se to udělat jinak? Líp?
C++ kód nemůžu použít, protože není dost RAM (Kdyby se použily třídy s metodama, jak bych si to přál...).
-
Mňo, moc nevím, proč cpeš proměnné sémanticky patřící k jednotlivým TU do struktur (neuvažuješ-li více instancí), ale budiž. Já to většinou řeším tak, že v headeru deklaruju jenom funkce (a případně datové typy) které tvoří veřejné API příslušného modulu a všechno ostatní mám staticky v implementačním souboru.
Taky jsi patrně nepochopil, k čemu je paměťová třída extern. Ta označuje externí linkování - ve zkratce říká překladači, že instance proměnné není v dané TU, ale v nějaké jiné, která se přilinkuje k programu později. Ty ale nikde file1 nemáš deklarovanou s interním linkováním - tzn. linker ti při pokusu o sestavení executable chcípne.
A propos, proč bys nemohl použít C++? Když nepoužiješ virtuální metody, nemají třídy oproti céčkovým POD + funkcím žádný overhead.
-
Mňo, moc nevím, proč cpeš proměnné sémanticky patřící k jednotlivým TU do struktur (neuvažuješ-li více instancí), ale budiž. Já to většinou řeším tak, že v headeru deklaruju jenom funkce (a případně datové typy) které tvoří veřejné API příslušného modulu a všechno ostatní mám staticky v implementačním souboru.
Protože úplně to samé se pak použije v jiném projektu. Kdyby to bylo jako knihovna, tak si to sebou taky všechno ponese.
Taky jsi patrně nepochopil, k čemu je paměťová třída extern. Ta označuje externí linkování - ve zkratce říká překladači, že instance proměnné není v dané TU, ale v nějaké jiné, která se přilinkuje k programu později. Ty ale nikde file1 nemáš deklarovanou s interním linkováním - tzn. linker ti při pokusu o sestavení executable chcípne.
Extern tam je proto, že bez toho to nefunguje. Popravdě si nejsem jistý, jak se to dělá Cčkově správně, protože v CodeWarrior to funguje takto, v AVR studiu to fungovalo zase trochu jinak. Ale bez externu to s takovýmto rozložením, kdy data jsou vždy v každém .h nefungovalo nikdy.
A propos, proč bys nemohl použít C++? Když nepoužiješ virtuální metody, nemají třídy oproti céčkovým POD + funkcím žádný overhead.
C++ testnu teda ještě jednou a pak kdyžtak napíšu, na čem to skončí...
Pokud by jsi měl nějakou ukázku, rád se podívu :-) Díky.
-
Klidně tímhle způsobem pokračuj.
Použití jedné struktury obsahující globální proměnné danného modulu je trochu neobvyklé, ale proč ne. Ničemu to nevadí a určitým způsobem je to zajímavý nápad.
V *.h si drž deklarace globálních proměnných a funkcí + definice typů a konstant - jinými slovy to, ce je potřeba znát veřejně i v ostatních modulech a nevyhrazuje paměť.
V *.c následně definice globálních proměnných a funkcí.
Pokud jde o extern, tam se použití liší dle překladače (C/C++). C++ extern vyžaduje u deklarací u C není nutné. Může to ale záviset na konkrétní implementaci. Zkontroluj si to v dokumentaci překladače a linkeru.
-
mozno blba poznamka, ale ak tie premenne nie su sucastou rozhrania toho modulu, tak ich daj _len_ do *.c suboru z pamatovou triedou static. Rovnako aj funkcie, ktore su interne pre ten modul.
Bezny program v C vyzera asi takto (trochy vyumelkovany, ale nie az tak moc):
header (switch_led.h):
#ifndef LED_H
#define LED_H
/* pin na ktorom je pripojena LED-ka, toto by mal uzivatel nastavit a menit len ked je LED-ka vypnuta */
extern int the_led_pin;
/* ak je aktualne LED-ka zapnuta, tak ju vypne a naopak */
void switch_led();
/* vrati ci je LED-ka zapnuta */
int is_led_on();
#endif
implementacia (switch_led.c):
#include "switch_led.h"
int the_led_pin = 0;
static char is_on = 0; /* dame char, pac setrime pamat, zjavne len globalnu a na stacku moc nie */
static void digital_write(int pin, int value) { /* ...poslat na pin hodnotu 0 alebo 1... */ }
void switch_led() { is_on = !is_on; digital_write(the_led_pin, (int)is_on); }
int is_led_on() { return (int)is_on; }
main (main.c)
#include "switch_led.h"
void main() {
the_led_pin = 5;
while(1) {
/*...nieco */
switch_led();
/*..blabla */
switch_led();
/* este nieco */
}
}
poznamky:
- extern je pouzite spravne, a skvele ze je v *.h subore, videl som kopec kodu, kde deklaraciu chlapci pastovali do kazeho *.c suboru! :-)
- main.h som este v zivote nevidel fungovat to bude ale main vacsinou pouziva veci z ostatnych modulov
- keby mi zacalo dochadzat miesto na MCU, tak by som funkciu is_led_on nahradil globalnou premennou ale potom riskujem ze mi tam blby pouzivatel mojho modulu nieco zapise a cele sa rozsype...
- ako uz bolo spominane c++ ma identicku reziu a velkost vysledneho kodu ako c. Navyse ma inline funkcie (!!). Samozrejme opatrne z virtual, template, dynamic_cast, typeid, throw a podobnymi featurami (na MCU polovica aj tak nebude)