forum.mcontrollers.com - hlavní stránka forum.mcontrollers.com - fórum

 

.: fórum - hlavní stránka :.
Technology Stronghold by Rudolf Vesely
How to build Microsoft System Center hosted cloud series
FAQFAQ HledatHledat Seznam uživatelůSeznam uživatelů Uživatelské skupinyUživatelské skupiny RegistraceRegistrace
ProfilProfil StatistikaStatistika Soukromé zprávySoukromé zprávy PřihlášeníPřihlášení

 
C a flagy

 
Přidat nové téma   Zaslat odpověď    Obsah fóra mcontrollers.com -> Elektronika s mikrokontroléry, procesory
 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 718

PříspěvekZaslal: 22 listopad 2016, 21:41    Předmět: C a flagy Citovat

Pro ostřílené Cčkaře asi nebudu psát nic nového, ale jsou mezi námi i takoví, kteří s Cčkem teprve začínají a těm by tohle povídání mohlo usnadnit práci. Při použití timeru nebo přerušení, případně i při jiných činnostech prováděných mikrokontrolerem je někdy šikovné používat flagy. Vzhledem k tomu, že flagy (neboli příznaky) jsou jednobitové informace, může být použití celého bytu pro jeden příznak celkem plýtvání RAMkou. Obzvlášť u menších procesorů. Ale konec s teorií, ukažme si, jak na ně.

První možnost je tato :
kód:
unsigned char ProgramStatus;

#define Bit0 0
#define Bit1 1
#define Bit2 2
#define Bit3 3
#define Bit4 4
#define Bit5 5
#define Bit6 6
#define Bit7 7


Použití je pak následující :
kód:
ProgramStatus |= (1<<Bit6); // Nastavení bitu 6
ProgramStatus &= ~(1<<Bit4); // Vynulování bitu 4

if ((ProgramStatus & (1<<Bit6)) != 0) ; // Pokud bit 6 = 1
if ((ProgramStatus & (1<<Bit6)) == (1<<Bit6)) ; // Pokud bit 6 = 1

if ((ProgramStatus & (1<<Bit2)) == 0) ; // Pokud bit 2 = 0


Jak vidíte, použití je trošku komplikované, ale naštěstí se dá celkem výrazně zjednodušit.
Bohužel se tento způsob nedá použít pro PORTx, DDRx apod. - tedy alespoň ne přímo (viz. dále) - tuto informaci beru zpět - viz následující příspěvek od Radiuse.
kód:
struct
{
   unsigned char Bit0 : 1;
   unsigned char Bit1 : 1;
   unsigned char Bit2 : 1;
   unsigned char Bit3 : 1;
   unsigned char Bit4 : 1;
   unsigned char Bit5 : 1;
   unsigned char Bit6 : 1;
   unsigned char Bit7 : 1;
}ProgramStatus;

nebo varianta s definicí typu:
kód:
typedef struct
{
   unsigned char Bit0 : 1;
   unsigned char Bit1 : 1;
   unsigned char Bit2 : 1;
   unsigned char Bit3 : 1;
   unsigned char Bit4 : 1;
   unsigned char Bit5 : 1;
   unsigned char Bit6 : 1;
   unsigned char Bit7 : 1;
}ProgramStatusTyp; // 1 byte

typedef struct
{
   unsigned char Bit0 : 1;
   unsigned char Bit1 : 1;
   unsigned char Bit2 : 1;
   unsigned char Bit3 : 1;
   unsigned char Bit4 : 1;
   unsigned char Bit5 : 1;
   unsigned char Bit6 : 1;
   unsigned char Bit7 : 1;
   unsigned char Bit8 : 1;
   unsigned char Bit9 : 1;
   unsigned char Bit10 : 1;
}ProgramStatusTyp; // 2 byty

ProgramStatusTyp ProgramStatus;



Takto nadefinované flagy se pak používají takto :
kód:
ProgramStatus.Bit6 = 1; // Nastavení bitu 6
ProgramStatus.Bit4 = 0; // Vynulování bitu 4

if (ProgramStatus.Bit6 == 1) ; // Pokud bit 6 = 1
if (ProgramStatus.Bit2 == 0) ; // Pokud bit 2 = 0


Výsledný překlad je pro unsigned char i použití struktury shodný.
Výhodou je, že program pracuje pouze s tím bytem, ve kterém se nalézá bit, se kterým se pracuje.

Nulování celého statusu najednou se dělá následnovně :
kód:
memset((void*)&ProgramStatus, 0, sizeof(ProgramStatus));

Tohle byl nejčistší způsob a funguje na jakékoliv množství flagů ve statusu. Překladač totiž alokuje pro status proměnou tolik bytů, aby se vešly všechny bity. Lze jej však vynulovat i takto :
kód:
*(unsigned char *)&BitStatus = 0; // pro 1 byte
*(unsigned int *)&BitStatus = 0; // pro 2 byty

Nevýhodou je, že je potřeba znát, kolik bytů status vlastně zabírá (i když nepředpokládám, že by programátor potřeboval více, než 2 byty).

Status se dá i vyslat na nějaký port. Nevýhodou je ale to, že na port se vyšle vždy jenom prvních 8/16 bitů.
kód:
PORTA = *(unsigned char *)&BitStatus;
TCNT1 = *(unsigned int *)&BitStatus;


Použití flagů jako pojmenování LED nebo signálů na portu je tedy možné, jen je to naopak vyváženo trošku menším komfortem zápisu.

Lze nadefinovat ale i čítač (v tomto případě 2-bitový) :
kód:
typedef struct
{
   unsigned char Bit0 : 1;
   unsigned char Bit1 : 1;
   unsigned char Bit2 : 1;
   unsigned char Bit3 : 1;
   unsigned char Bit4 : 1;
   unsigned char Bit5 : 1;
   unsigned char Citac : 2;
}ProgramStatusTyp; // 1 byte

ProgramStatusTyp ProgramStatus;


Když by se pak provádělo :
kód:
ProgramStatus.Citac++; // čítá 0-1-2-3-0-1-...

V případě zápisu :
kód:
ProgramStatus.Citac = 5; // nepřeteče, ale zapíše jen hodnotu%4.

V případě definování vícebitových částí ale doporučuju je umístit tak, aby celá vícebitová proměnná byla obsažena jen v jednom bytu, ideálně od bitu 0.


Veškeré zde uvedené střípky kódu jsou vyzkoušené na překlad v AVR Studiu 4.19 + WinAVR a zkontrolované pomocí disassembleru.


Naposledy upravil Balů dne 23 listopad 2016, 0:21, celkově upraveno 1 krát.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Radius
Profesionál
Profesionál


Založen: 22.2.2013
Příspěvky: 471

PříspěvekZaslal: 22 listopad 2016, 23:55    Předmět: Citovat

Vidíš a přesně tenhle způsob já používám pro práci s jednotlivými porty u AVR.

kód:

typedef struct
   {
    unsigned B0: 1;
    unsigned B1: 1;
    unsigned B2: 1;
    unsigned B3: 1;
    unsigned B4: 1;
    unsigned B5: 1;
    unsigned B6: 1;
    unsigned B7: 1;
    } bits;


kód:

#define BITS(p) (*(volatile bits*)&p)


kód:

#define LED1        BITS(PORTA).B0
#define DIR_LED1    BITS(DDRA).B0


kód:


DIR_LED1=1; // Vystup

LED1=1; // Sviti
.
.
.
LED1=0; // Nesviti


_________________
x51 , ARM , XILINX
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Odeslat e-mail Zobrazit autorovy WWW stránky
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 718

PříspěvekZaslal: 23 listopad 2016, 0:10    Předmět: Citovat

Super - díky za rozšíření. Zase jsem o něco moudřejší. A navíc je to přeloženo jako jedna jediná instrukce procesoru (CBI/SBI). To se mi moc líbí.

Beru tedy zpět informaci o tom, že se to nedá použít přímo pro PORTx, DDRx apod.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 718

PříspěvekZaslal: 24 listopad 2016, 22:49    Předmět: Citovat

Doplním ještě Radiusovo info :
kód:
typedef struct
   {
    unsigned B0: 1;
    unsigned B1: 1;
    unsigned B2: 1;
    unsigned B3: 1;
    unsigned B4: 1;
    unsigned B5: 1;
    unsigned B6: 1;
    unsigned B7: 1;
    } bits;

#define BITS(p) (*(volatile bits*)&p)

#define LED1        BITS(PORTA).B0
#define DIR_LED1    BITS(DDRA).B0


Když funguje tohle :

kód:
DIR_LED1=1; // Vystup

LED1=1; // Sviti
.
.
.
LED1=0; // Nesviti


Vyzkoušel jsem i následující :
kód:
#define KEY1        BITS(PINA).B2
#define DIR_KEY1        BITS(DDRA).B2
#define PORT_KEY1        BITS(PORTA).B2

DIR_KEY=0; // Vstup
PORT_KEY=1; // Zapnout Pull-up

if (KEY1==0) LED1=1; else LED1=0;


Funguje to také.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Radius
Profesionál
Profesionál


Založen: 22.2.2013
Příspěvky: 471

PříspěvekZaslal: 25 listopad 2016, 2:48    Předmět: Citovat

Tohle funguje taky Wink


kód:
LED1=KEY1;


nebo

kód:
LED1=!KEY1;

_________________
x51 , ARM , XILINX
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Odeslat e-mail Zobrazit autorovy WWW stránky
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 718

PříspěvekZaslal: 25 listopad 2016, 8:34    Předmět: Citovat

Vidíš, to jsem zapomněl napsat.

Doplním tedy, co jsem včera ještě zjistil :

kód:
if (KEY1==0) LED1=1; else LED1=0;


zabere jenom 10 bytů (5 instrukcí), kdežto

kód:
LED1 = KEY1;
LED1 = (KEY1==1) ? 1 : 0;

LED1 = !KEY1;
LED1 = (KEY1==0) ? 1 : 0;


zabere paměti více a záleží i na vzájemné poloze bitů v bytu o kolik.


Čekal bych, že zápis LED1 = (KEY1==0) ? 1 : 0; bude mít stejný překlad jako if (KEY1==0) LED1=1; else LED1=0;, ale nemá, překládá se stejně jako LED1 = !KEY1;.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

Zobrazit příspěvky z předchozích:   
Zobrazit předchozí téma :: Zobrazit následující téma  
Přidat nové téma   Zaslat odpověď    Obsah fóra mcontrollers.com -> Elektronika s mikrokontroléry, procesory Časy uváděny v GMT + 2 hodiny
 
Strana 1 z 1
Přejdi na:  
Můžete přidat nové téma do tohoto fóra.
Můžete odpovídat na témata v tomto fóru.
Nemůžete upravovat své příspěvky v tomto fóru.
Nemůžete mazat své příspěvky v tomto fóru.
Nemůžete hlasovat v tomto fóru.
Můžete k příspěvkům připojovat soubory
Můžete stahovat a prohlížet přiložené soubory
 



Num Lock Holder - app to hold Numlock
Copyright © 2017 Rudolf Veselý, mcontrollers.com.
Je zakázáno používat části tohoto webu bez souhlasu autora. || Powered by phpBB © 2001, 2002 phpBB Group - with RedSquare DoubleJ(Jan Jaap)