Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Embedded 12. 05. 2015, 08:55:37

Název: C kód v MCU
Přispěvatel: 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:
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...).
Název: Re:C kód v MCU
Přispěvatel: hu 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.
Název: Re:C kód v MCU
Přispěvatel: Embedded 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.
Název: Re:C kód v MCU
Přispěvatel: Mirek 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.
Název: Re:C kód v MCU
Přispěvatel: mik 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: