Avr - cum să scape de numere în virgulă mobilă, avr, programare

Una dintre cele mai puternice restricții AVR (pe platforma MCS51 nu afecteaza) - consumul de memorie rapid atunci când scrieți programe C.

Ce se poate face pentru comoditate și de viteză RISC C, trebuie să plătească. Chiar mai tentante - folosiți pentru calcul (de exemplu, atunci când se măsoară tensiunea prin ADC) float numere (floating point). În ciuda faptului că aceste calcule nu sunt corecte, acestea sunt prea ușor și comod de utilizat - puteți împărți și înmulți fără griji preaplin, și ușor să prezinte rezultatele calculelor într-un format ușor de înțeles pentru om.

Dar taxa pentru float este prea mare - linker-ul adaugă biblioteci de cod, matematică, și memorie de program se termină foarte repede. O altă limitare - calcule float este lent (cu excepția cazului când utilizați un multiplicator hardware de tip [1]). Dacă nu există nici o posibilitate de a implementa algoritmul program cu numere de aplicație float (din cauza limitărilor de mai sus în ceea ce privește codul și viteză), una dintre soluțiile pentru această problemă este de a trece la un număr de puncte fixe. Operațiunile lor matematice (scădere, plus, diviziune, multiplicare) nu diferă de operații matematice simple cu numere întregi, codurile sunt compacte și rapid.

Număr punct fix (de obicei un octet sau cuvânt de doi octeți) constă dintr-o parte întreg (situat în partea superioară a numărului de 8 biți sau 16 biți) și o parte fracționată (stocată în biții cei mai puțin semnificativi). Exemplele numerele cu punct fix indicat în figură, o lungime cuvânt de 8 biți (1 byte).

Înainte de a utiliza numere de punct fix principalul lucru - pentru a alege numărul de biți (octet sau cuvânt), și, de asemenea, selectați poziția punctului zecimal. Cu cifre ca toate clar - dacă luăm cuvântul (16 biți), calculele sunt mai precise, dar viteza va scadea si cantitatea de cod crește (atât cel puțin de 2 ori), iar dacă luăm octetul (8 biți), obținem maximul viteză și cel mai mic cod, dar se va deteriora precizia. Ca de obicei, este nevoie de un compromis, și sarcina dumneavoastră - pentru a lua decizia corectă. Poziția punctului zecimal nu afectează cantitatea de cod și viteza de operații matematice. Ea doar distribuie raportul de precizie între întreg și partea fracționară. De obicei, calculat de câte cifre ar trebui să fie alocate pentru partea întreagă, iar restul se duce la partea fracționară.

De exemplu, numărul nostru de 8 biți este stocată tensiune, care va varia de la 0 la 5 volți. Un număr de la 0 la 5, pot fi codificate prin cel puțin trei cifre, astfel încât biții 7, 6 și 5 va stoca partea întreagă (3 biți) și biți 4, 3, 2, 1 și 0 - să rămână sub partea fracționară (5 biți). Numărul din partea fracționară va arăta cât de multe din 1/32 Volt va fi în partea fracționară. De exemplu, dacă biții 7, 6 și 5 este numărul 4, și biții 4, 3, 2, 1 și 0 - 30 de numere, va codifica tensiune volt 4.9375 (0.9375 = 30/2 ^ 5 = 30/32) . Valoarea Byte în acest caz, se va 100.11110b sau 0x9E.

În calculele de punct fix (ca și cu calcule simple pe numere întregi) ar trebui să se aplice reguli speciale:

1. Ca urmare a adăugarea a două numere pot primi deversări suplimentare. Acest lucru se întâmplă atunci când a avut loc overflow. Dacă trebuie să ia în considerare posibilitatea de depășire, atunci numerele suplimentare 1-bit trebuie să fie depozitate undeva.

2. Rezultatul înmulțirii a două numere de câte 8 biți stocate într-un număr de 16 biți, două 16 biți la 32 de biți și m. P. (Bit prin înmulțirea sumei).

3. Atunci când divizarea (un număr mare de special mici) trebuie să fie pre-multiplica dividendul printr-o constantă. Cel mai simplu - muta numărul la stânga de numărul necesar de ori (fiecare schimb este înmulțit cu 2), rezultatul mutat loc în două ori numărul de biți, și apoi în liniște de partajare. Rezultatul este un număr de punct fix. De exemplu, dacă vom împărți întreg dividendului 8 biți este deplasată la stânga de 5 biți (primit 16 biți dividend) pentru un divizor, fractional obține 16 biți număr punct fix, în care virgula este între 4 și 5 biți.

4. Este mai bine să utilizeze cât mai mult posibil în etapa de constante de compilare prestabilite pentru a curăța cod care le va genera. De exemplu, dacă trebuie să compare tensiunea bateriei la tensiunea de 1,05 volți, Volt tensiune 1.05 este mai bine să prezinte în formatul corect și să identifice # define directivă.

Când doriți să afișeze numărul de puncte fix ca un set de cifre zecimale, acționând pe un algoritm simplu:
- ia mai întâi partea întreagă, și să o transforme într-un fel de caracter în mod obișnuit.
- pentru întreaga parte a virgulei remiză (sau punct).
- ia partea fracționară, duce-l la zecimal, pur și simplu înmulțirea numărătorul și numitorul numărului fracțional parte fracționată (valoarea fracției, după cum știm, nu se schimba) - o constantă. Această constantă este aleasă astfel încât numitorul a fost numărul - zeci de grade, nu de două - în același timp, obține o fracție zecimală. Fraza „prin înmulțirea numărului fracționar“ înseamnă un set de operații întregi (înmulțit inițial un număr întreg constant, și apoi împărțit un număr întreg constant), al cărei rezultat este că acesta poate fi un număr de multiplicare fracționată. În operațiile de înmulțire și împărțire factor este fie chiar sau compas, sau ambele - și multiplicatorul și împărțitor sunt impar (pentru că suntem formând astfel înmulțirea cu un număr întreg). Ca chiar și convenabil de a folosi constantă, care este o putere de două (2, 4, 8, și așa mai departe. D.), deoarece înmulțirea constantă și diviziunea sunt înlocuite printr-o deplasare stânga și la dreapta, respectiv, simplu.
- apoi numărătorul valoarea obținută se traduce în cifre zecimale stabilite și să le atribuie după virgulă.

Pentru a explica această „înțelepciune“ să ia toate același exemplu - traduce fracționată-punct fix 100.11110b (== 0x9E, noastre 4.9375 volți) în reprezentare simbolică:
- parte integrantă a noastră 100b egal, t. e. 4, trage numărul 4
- Tragerea la sorți pentru partea întreagă a punctului de fracționare 4.
- să ia parte 11110b fracționată. Ea este de 30, adică, fracțiunea noastră - .. 30 numărătorul și numitorul 32. Sarcina noastră - de a alege un număr fracționar, astfel încât atunci când acesta este înmulțit cu numitorul 32 obține un număr care poate fi reprezentat zeci de grade, și care a fost gradul de zeci, atât de multe zecimal zecimale și obținem. Lăsați este necesar pentru a obține 3 zecimale, t. E. Numitorul 32 prezent la 1000. numărul la care doriți să multiplice numărătorul și numitorul este egal cu 1000/32 = 31.25. Excelent, dar înmulțită cu un număr fracționar, având doar aritmetică număr întreg? Este simplu - mai întâi se înmulțește cu 125, apoi se împarte la 4 (adică, egală cu 125/4 31,25 ..). În această ordine - la prima multiplicare (veți avea nevoie de un 16 biți pentru a stoca temporar număr întreg rezultatul înmulțirii), și apoi divizia, nu pierde precizie atunci când a aruncat departe restul de divizare. Multiplicată cu 125 ca de obicei, și se împarte la 4, numărul de deplasare 2 biți la dreapta. Astfel * 31.25 = 30 (30 * 125) / 4 = 3750/4 = 937,5, rotunjit la 938. Astfel, fracțiunea 30/32 938/1000 transformat într-o fracție.
- numărătorul 938 adaugă după virgulă, obținem 4938.

În selectarea constante pentru multiplicare / divizare este convenabil de a folosi și ingeniozitate bune vechi foi de calcul Microsoft Excel.