C kód v MCU

Embedded

C kód v MCU
« kdy: 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:
Kód: [Vybrat]
struct S_main main;

while(1)
{
//Kód...
}

main.h:
Kód: [Vybrat]
#include "file1.h"
#include "file2.h"
#include "conf.h"

struct S_main {
//Proměnné...
};

struct S_main main;

//Hlavičky funkcí...

file1.c:
Kód: [Vybrat]
#include "file1.h"
//Funkce

file1:h
#include "conf.h"

struct S_file1 {
//Proměnné...
};

extern struct S_file1 file1;

//Hlavičky funkcí...

file2:c
Kód: [Vybrat]
#include "file2.h"
//Funkce

file2.h:
Kód: [Vybrat]
#include "conf.h"

struct S_file2 {
//Proměnné...
};

extern struct S_file2 file2;

//Hlavičky funkcí...

#conf.h:
Kód: [Vybrat]
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...).


hu

Re:C kód v MCU
« Odpověď #1 kdy: 12. 05. 2015, 09:43:40 »
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.

Embedded

Re:C kód v MCU
« Odpověď #2 kdy: 12. 05. 2015, 11:31:00 »
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.

Mirek

Re:C kód v MCU
« Odpověď #3 kdy: 13. 05. 2015, 18:17:09 »
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.

mik

Re:C kód v MCU
« Odpověď #4 kdy: 13. 05. 2015, 23:39:24 »
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):
Kód: [Vybrat]
#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):
Kód: [Vybrat]
#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)
Kód: [Vybrat]
#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)