curs de formare

Când programarea microcontroler pentru a lucra în mod constant cu lilieci. Instalați-le, resetați, verificarea prezenței lor într-un anumit registru. De asamblare AVR pentru aceste scopuri, există un număr de echipe. În primul rând, un grup de echipe operațiuni cu lilieci - acestea sunt utilizate pentru a seta sau a reseta biții în diferitele registre ale microcontrolerului, și în al doilea rând, un grup de transfer de comenzi de control - acestea sunt destinate pentru organizarea programelor de ramură. Limbajul C este în mod natural nici o astfel de instrucțiuni, astfel încât începătorii de multe ori se pune întrebarea, cum să lucreze cu biții C. Această temă suntem acum și vom investiga.

În C există 6 operatori pentru a manipula biți. Ele pot fi aplicate la orice număr întreg sau semnat tipuri de variabile nesemnate.


<<- сдвиг влево
>> - deplasarea la dreapta

- bitwise inversiune
| - SAU la nivel de bit
- bitwise ȘI
^ - bitwise SAU exclusiv

Deplasările în numărul de n biți la stânga. Mai vechi n biți, astfel dispar, iar inferior n-biți sunt umplute cu zerouri.


tmp unsigned char = 3; // 0b00000011
tmp = tmp <<1;
// acum în tmp număr variabil 6 sau 0b00000110

tmp = tmp <<3;
// acum în număr variabil tmp de 48 sau 0b00110000

Expresiile că peste variabilă este o tranzacție, iar apoi rezultatul operației este atribuit aceeași variabilă, puteți scrie scurt, folosind instrucțiuni compuse.

tmp = 7; // 0b00000111
tmp <<= 2; //сокращенный вариант записи
// acum în număr variabil tmp de 28 sau 0b00011100

trecerea funcționării la stânga de n biți este echivalentă cu înmulțirea cu 2 a n variabile.

Deplasează numărul corect de n biți. n biți mai tineri sunt pierdute. Umplerea n-biți superiori depinde de tipul variabilei și valoarea sa. n biți mai vechi sunt umplute cu zerouri în două situații - în cazul în care variabila este nesemnate sau dacă variabila semnul și valoarea sa actuală este pozitivă. Atunci când un semn variabilă și valoarea sa este negativă - biți semnificativi sunt ocupate de unități.


Exemplu variabilă unsigned

tmp unsigned char = 255; // 0b11111111
tmp = tmp >> 1;
// acum în număr variabil tmp 127 sau 0b01111111

tmp >> = 3; // scrie o versiune prescurtată
// acum în număr variabil tmp de 15 sau 0b00001111

EXEMPLU tip semn variabil

int tmp = 3400; // 0b0000110101001000
tmp >> = 2;
// acum într-un număr variabil de 850 sau 0b0000001101010010

tmp = -1,200; // 0b1111101101010000
tmp >> = 2;
// acum în numerele TMP -300 sau 0b1111111011010100
// vezi - unități de două MSBs umplute

O operație de deplasare dreapta pe n biți este echivalent cu diviziunea de 2 n. În același timp, există unele nuanțe. În cazul în care a pierdut biți semnificativi unitate de conținut, rezultatul acestei „diviziune“ se transformă dur.

9/4 = 2,5 exemplu și 9 >> 2 (1001 >> 2) este egal cu 2
04/11 = 2,75 și 11 >> 2 (1011 >> 2) este egal cu 2
28/4 = 7 și 28 >> ​​2 (11100 >> 2) este 7


În al doilea caz, eroarea este mai mare, deoarece cele două mai tineri cele cifre. În al treilea caz nu există nici o eroare, pentru că a pierdut biți de la zero.

Bitwise inversează număr. Evacuările, care au fost zero, - unități umplute. Evacuările, care au fost puține - sunt umplute cu zerouri. Bitwise inversiune yavlyatsya Operatorul unar, care este utilizat cu un singur operand.

tmp;
// acum în număr variabil tmp 161 sau 0b10100001

tmp;
// acum în tmp din nou numărul 94 sau 0b01011110

operatorul | efectuează o operație logică OR între biți doi operanzi corespunzătoare. Rezultatul logic sau operațiunea între cei doi biți vor fi 0 numai dacă ambii biți sunt 0. În toate celelalte cazuri, rezultatul va fi 1. Acest lucru este ilustrat în adevăr tabitse.

operatorul | În general, este utilizat pentru a seta biți stabilite în unitatea variabilă.

tmp = 155
tmp = tmp | 4; // setat la o variabilă tmp doilea bit

155 11 0 0b10011
|
4 1 00 0b00000
159 11 ianuarie 0b10011

Utilizați numere zecimale pentru a seta biți destul de incomod. Este mult mai ușor să facă acest lucru cu ajutorul operației de deplasare stânga <<.


tmp = tmp | (1<<4); //устанавливаем в единицу четвертый бит переменной tmp

Citirea de la dreapta la stânga - unitate de deplasare la patru biți la stânga, pentru a efectua operația SAU între numărul și valoarea variabilei tmp, rezultatul este setat la o tmp variabilă rezultată.


Setați câțiva biți în unitatea poate fi atât de

tmp = tmp | (1<<7)|(1<<5)|(1<<0);
// stabilit într-o unitate a șaptea, a cincea și la zero biți de tmp

Utilizați operatorul de atribuire compus | = se poate înregistra mai compact.

operator efectuează o operație logică AND între biți doi operanzi corespunzătoare. Rezultatul logic și funcționarea între cei doi biți vor fi 1 numai în cazul în care ambii biți sunt egale cu 1. În toate celelalte cazuri, rezultatul va fi 0. Acest lucru este ilustrat în tabelul de adevăr.

operator Acesta este de obicei folosit pentru a reseta unul sau mai mulți biți.

tmp = 155;
tmp = tmp 247; // zero afară de al treilea bit tmp variabilă


155 0b1001 1011

247 0b1111 0111
147 0b1001 0011

A se vedea, devenit al treilea bit este 0, iar ceilalți biți nu sa schimbat.

Resetați biții folosind cifre zecimale, este un inconvenient. Dar puteți face viața mai ușoară prin utilizarea operatorilor <<и

tmp = 155;
tmp = tmp (

(1<<3)); //обнуляем третий бит

1<<3 0b0000 1 000

(1<<3) 0b1111 0 111
tmp (

(1<<3)) 0b1001 1 011 & 0b1111 0 111
rezultat 0b1001 0,011

Citirea de la dreapta la stânga - unitate de deplasare în trei categorii stânga, efectuați numărul rezultat inversiune, operația între valoarea tmp variabilă și numărul inversat, rezultatul este setat la o tmp variabilă.


Resetați mai mulți biți poate fi atât de

((1<<3)|(1<<5)|(1<<6))); //обнуляем третий, пятый и шестой биты

Aici, prima operație de schimbare efectuat, apoi la nivel de bit sau operație, atunci inversiunea, și nivel de bit, rezultatul misiunii TMP variabile.


Folosind un operator de atribuire compus =, Putem scrie expresia este mai compact

((1<<3)|(1<<5)|(1<<6)));

Cum de a verifica dacă un bit este setat într-o variabilă? Ai nevoie pentru a reseta toți biții, cu excepția controlului și apoi comparați valoarea la zero

if ((tmp (1<<2)) != 0 ) // блок будет выполняться, только если установлен
// al doilea bit tmp variabilă
>

if ((tmp (1<<2)) == 0 ) // блок будет выполняться, только если не установлен
// al doilea bit tmp variabilă
>

^ Operator efectuează o operație de SAUEXCLUSIV logică între biți corespunzătoare din doi operanzi. Rezultatul XOR operațiune logică este 0, în caz de egalitate de biți. În toate celelalte cazuri, rezultatul va fi 1. Acest lucru este ilustrat în adevăr tabitse.

^ Operatorul nu este folosit la fel de des ca și restul operatorilor de biți, dar, de asemenea, este un loc de muncă pentru el. De exemplu, ea poate fi inversată, folosind unul sau mai mulți biți variabilă.


tmp = 155;
tmp = tmp ^ 8; // inversa schimbare tmp patrulea bit

155 0b1001 1011
^
8 0b0000 1000
147 0b1001 0011

Al patrulea bit și-a schimbat valoarea sa opus, iar biții rămași rămân neschimbate.

tmp = tmp ^ 8; // inversa din nou schimbarea tmp patrulea bit

147 0b1001 0011
^
8 0 0b000 1000
155 0b1001 1011

A se vedea, din nou, al patrulea bit și-a schimbat valoarea sa opus.

Deci, mult mai ușor de a scrie o expresie

tmp = tmp ^ (1<<3); / / инвертируем третий бит переменой tmp

Și atât de convenabil și compact

tmp ^ = (1<<4); //инвертируем четверый бит

Puteți fi inversat mai mulți biți simultan

tmp ^ = ((1<<4)|(1<<2)|(1<<1)); //инвертируем 4,2 и 1 биты

Într-un XOR bitwise, există o altă caracteristică interesantă. Acesta poate fi folosit pentru a modifica valorile a două variabile în locuri. Acest lucru necesită de obicei o a treia variabilă.


tmp = var1;
var1 = var2;
var2 = tmp;

Dar folosind ^ operatorul poate rearanja valorile după cum urmează:

var1 ^ = var 2;
var ^ = var 2 1;
var 1 ^ = var 2;

magie pură, totuși, să fiu sincer, nu am bucurat de o astfel de recepție.

Acum știm cum să setați, reset și inversează biți, știu cum să verifice dacă bitul este setat sau nu. Expresiile de mai sus sunt destul de greoaie, dar cu o #define directivă preprocesor. este posibil pentru a da un aspect mai plăcut.

Directiva #define este folosit pentru a atribui nume simbolice pentru constante și macro-uri. Utilizarea numelor simbolice face programul mai modificabil și portabil.

De exemplu, utilizați o constantă în program, și dintr-o dată pe care doriți să modificați valoarea sa. În cazul în care se găsește în doar trei locuri, și puteți repara manual, și ce să facă în cazul în care are loc în cincizeci de linii? Nu numai că, corecția va lua o lungă perioadă de timp, cu atât mai mult și să facă o greșeală în acest caz este simplu. Iată cum timpul și ajută la Directiva #define. La începutul programului este dat numele simbolic al constantei, care este utilizat în cursul programului. Dacă avem nevoie pentru a schimba această valoare, se face numai într-un singur loc. Un preprocesor înainte de compilare a umple în toate expresiile în loc de o constantă valoarea sa.

programare microcontroler este indisolubil legată cu hardware-ul său și de multe ori cu ham extern. Obțineți cel puțin un buton - intervievarea lor în programul său, ne referim la pinii reale MCU. Și dacă avem nevoie dintr-o dată pentru a utiliza butoane software sondaj într-o altă schemă, în cazul în care butoanele sunt conectate la diferite concluzii? Va trebui să stabilească programul. Din nou, setarea folosind directivele #define numele simbolic pentru concluziile corespunzătoare, pentru a modifica programul va fi la fel de ușor ca placinta

// portul la care butonul Connect
#define PORT_BUTTON PORTA
#define PIN_BUTTON PINA
#define DDRX_BUTTON DDRA

// concluzii, care sunt conectate la un buton
#define DOWN 3
#define CANCEL 4
#define UP 5
#define ENTER 6

int main ()
// configura portul la intrare,
// și includ rezistențe pull-up
DDRX_BUTTON = 0;
PORT_BUTTON = 0xff;


Când specificați un nume simbolic poate fi folosit și expresia

MASK_BUTTONS #define ((1<

Exemplu de utilizare:
tmp = PORTB MASK_BUTTONS;

Utilizarea #define nu regret paranteze pentru a specifica în mod clar secvența de expresii de calcul!

Unele expresii pot fi deghizat ca o „funcție“.

#define ADC_OFF () ADCSRA = 0

Puteți utiliza definiție multi-line, folosind sfârșitul fiecărui caracter din șirul \

#define INIT_Timer () TIMSK = (1< TCCR0 = (1< TCNT0 = 0; \
OCR0 = 0x7d


Ei bine, cel mai puternic utilizarea directivei #define - acest macro loc de muncă (sau macro-uri). Iată cum se utilizează #define, puteți seta macro-uri pentru operațiunile discutate anterior cu lilieci

#define SetBit (reg, bit) reg | = (1< #define ClearBit (reg, bit) reg = (

(1< #define InvBit (reg bit) reg ^ = (1< #define BitIsSet (reg, bit) ((reg (1< #define BitIsClear (reg, bit) ((reg (1<

Exemplu de utilizare:
...
SetBit (PORTB, 0); // setați bit zero portul B
InvBit (tmp, 6); // inversa sasea biți tmp variabilă

Înainte de a putea compila preprocesor pentru a înlocui linia a anunțat expresiile anterioare, înlocuindu-le cu argumente adecvate.

Macro-urile sunt un instrument foarte puternic, dar acestea trebuie să fie utilizate cu atenție. Aici sunt unele comune, greble, care sunt scrise în toate cărțile de programare.

Definim un macro care calculează pătratul numărului:

#define SQUARE (x) x * x

expresie
tmp = SQUARE (my_var);
Acesta dă rezultatul corect.

Și ce se va întâmpla dacă utilizați my_var expresie + 1 ca argument la macro

tmp = SQUARE (my_var +1);

Preprocesorul înlocuiește această linie pe

tmp = my_var + 1 * my_var +1;

dar acest lucru nu este rezultatul pe care ne așteptăm.


Dacă declarați un macro atât

#define SQUARE (x) ((x) * (x))

expresie
tmp = SQUARE (my_var +1);
Acesta dă rezultatul corect, deoarece preprocesorul înlocuiește această linie pe
tmp = ((my_var + 1) * (my_var +1));

macro-uri pentru lucrul cu biți

le scrie în dosarul de proiect, iar la începutul fișierului main.c a pus această #include „bits_macros.h“

articole similare