sobota, 12 listopada 2016

C - Rozdzielanie zmiennej 32 bitowej, wyswietlanie w hex

W tym temacie chciałbym pokazać dwa proste programy pozwalające na rozdzielenie liczby dziesiętnej na pojedyncze elementy oraz wyświetlenie tej samej liczby jako wartości szesnastkowej.

Program do wyświetlenia wartości liczbowej po jednej cyfrze:


Poniżej przedstawiam rozwiązanie bez użycia pętli for. Tutaj jako zmienna rozdzielana będzie wykorzystywana 24 bitowa liczba w formacie uint32_t. 

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. #include <stdint.h>
  5. void WypiszWartosc(uint32_t wartosc_wypisz)
  6. {
  7.     uint32_t tablica[10] = {1000000000, 100000000, 10000000, 1000000,
  8.                             100000, 10000, 1000, 100, 10, 1};
  9.     uint32_t tymczasowa = 0;
  10.     tymczasowa = wartosc_wypisz;
  11.     tymczasowa = tymczasowa / tablica[0];
  12.     printf("%d\n", tymczasowa);
  13.     tymczasowa = wartosc_wypisz % tablica[0];
  14.     tymczasowa = tymczasowa / tablica[1];
  15.     printf("%d\n", tymczasowa);
  16.     tymczasowa = wartosc_wypisz % tablica[1];
  17.     tymczasowa = tymczasowa / tablica[2];
  18.     printf("%d\n", tymczasowa);
  19.     tymczasowa = wartosc_wypisz % tablica[2];
  20.     tymczasowa = tymczasowa / tablica[3];
  21.     printf("%d\n", tymczasowa);
  22.     tymczasowa = wartosc_wypisz % tablica[3];
  23.     tymczasowa = tymczasowa / tablica[4];
  24.     printf("%d\n", tymczasowa);
  25.     tymczasowa = wartosc_wypisz % tablica[4];
  26.     tymczasowa = tymczasowa / tablica[5];
  27.     printf("%d\n", tymczasowa);
  28.     tymczasowa = wartosc_wypisz % tablica[5];
  29.     tymczasowa = tymczasowa / tablica[6];
  30.     printf("%d\n", tymczasowa);
  31.     tymczasowa = wartosc_wypisz % tablica[6];
  32.     tymczasowa = tymczasowa / tablica[7];
  33.     printf("%d\n", tymczasowa);
  34.     tymczasowa = wartosc_wypisz % tablica[7];
  35.     tymczasowa = tymczasowa / tablica[8];
  36.     printf("%d\n", tymczasowa);
  37.     tymczasowa = wartosc_wypisz % tablica[8];
  38.     tymczasowa = tymczasowa / tablica[9];
  39.     printf("%d\n", tymczasowa);
  40. }
  41. int main(void)
  42. {
  43.     uint8_t raz = 0xFF;
  44.     uint8_t raz2 = 0xFF;
  45.     uint8_t raz3 = 0xFF;
  46.     uint8_t raz4 = 0xFF;
  47.     uint32_t polaczone = 0x00;
  48.     polaczone = (raz4 | (raz3 << 8) | (raz2 << 16) | (raz << 24));
  49.     printf("%lu\n", polaczone); //jak uint
  50.     printf("%lx\n", polaczone); //szesnastkowo
  51.     printf("Wartosci podzielone: \n");
  52.     WypiszWartosc(polaczone);
  53.     return 0;
  54. }

Najpierw wprowadzane są zmienne, potem następuje ich połączenie oraz podzielenie, po czym za pomocą operacji dzielenia zwykłego oraz dzielenia bez reszty otrzymuje się najwyższą wartość z zdeklarowanej liczby. Dla mniejsze ilości cyfr program będzie działał poprawnie, dla większej natomiast trzeba by było go zmodyfikować. Przez co będę przechodził w następnych częściach tego postu.

Teraz przejdę do rozwiązania zawierającego pętle for, o którą powyższy program aż się prosi:

  1. void WypiszWartosc(uint32_t wartosc_wypisz)
  2. {
  3.     uint32_t tablica[10] = {1000000000, 100000000, 10000000, 1000000,
  4.                             100000, 10000, 1000, 100, 10, 1};
  5.     uint32_t tymczasowa = 0;
  6.     uint8_t i = 0;
  7.     tymczasowa = wartosc_wypisz;
  8.     tymczasowa = wartosc_wypisz / tablica[0];
  9.     for(i=0; i<10; i++)
  10.     {
  11.         printf("%d\n", tymczasowa);
  12.         tymczasowa = wartosc_wypisz % tablica[i];
  13.         tymczasowa = tymczasowa / tablica[i+1];
  14.     }
  15. }

Rozwiązanie problemu poprzez rekurencję:

  1. #define tablica_max 10
  2. uint8_t WypiszWartoscRekurencja(uint32_t wartosc_wypisz)
  3. {
  4.     uint32_t tablica[tablica_max] = {1000000000, 100000000, 10000000, 1000000,
  5.                                 100000, 10000, 1000, 100, 10, 1};
  6.     uint32_t tymczasowa = 0;
  7.     static uint8_t i;
  8.     if(== 0)
  9.     {
  10.         tymczasowa = wartosc_wypisz;
  11.         tymczasowa = wartosc_wypisz / tablica[i];
  12.         printf("%d\n", tymczasowa);
  13.     }
  14.     else if(== (tablica_max-1))
  15.     { return 0; }
  16.     tymczasowa = ( wartosc_wypisz % tablica[i] ) / tablica[i+1];
  17.     printf("%d\n", tymczasowa);
  18.     i++;
  19.     WypiszWartoscRekurencja(wartosc_wypisz);
  20.    
  21.     return 1;
  22. }

Program do wyświetlenia wartości szesnastkowo:


W tej części zajmę się wyświetleniem przedstawionej wartości jako wartość szesnastkowa. W tym celu zmienną 32 bitową będę rozbijał na cztery 8 bitowe. Po czym każdą 8 bitową na dwie wartości 4 bitowe. Wartość 4 bitową będę sprawdzał z wartościami od 0 do F tak aby dobrać do niej odpowiednią daną w hexie. Ostatnim krokiem będzie wyświetlenie informacji na ekran.

Jeśli chodzi o czysty język C wykorzystywany do programowania tą sprawę można rozwiązać wykorzystując funkcję printf i liczbę podać jako %x. Natomiast jeśli chodzi o wykorzystanie mikrokontrolerów to nie jest to za dobre wyjście, zwłaszcza dla układów 8 bitowych ponieważ zabiera ona, tak samo jak funkcja scanf, strasznie dużo zasobów układu. I jest ona mocno nieefektywna jeśli te dane chce się wysłać np. poprzez UART czy na wyświetlacz. Ja natomiast w tym przypadku dla czystego kodu wykorzystam ją do wyświetlenia wartości w postaci znakowej.

Zacznę od funkcji sprawdzającej wartość na podstawie znaków ASCII:

  1. void Sprawdz_Wartosc(uint8_t wartosc)
  2. {
  3.     //0 do 9 jako znaki znajduja sie na pozycji 30 do 39 HEX
  4.      //od A do F od 65 do 70
  5.     if(wartosc >= 0 && wartosc <= 9)
  6.     {
  7.         wartosc += 30;
  8.     }
  9.     else
  10.     {
  11.         wartosc += 65;
  12.     }
  13.     printf("%c", wartosc);
  14. }

Teraz funkcja rozdzielająca dane najpierw na cztery ośmiobitowe, po czym każdą ośmiobitowa na dwie.

  1. uint8_t PodzielWartosc(uint32_t liczba)
  2. {
  3.     uint8_t bit[4] = {liczba>>24, liczba >> 16, liczba >> 8, liczba};
  4.     uint8_t petla = 0;
  5.     uint8_t cztery_bity = 0x00;
  6.     for(petla = 0; petla < 4; petla++)
  7.     {
  8.         cztery_bity = bit[petla] >> 4;
  9.         Sprawdz_Wartosc(cztery_bity);
  10.         cztery_bity = (bit[petla] &0xF0);
  11.         Sprawdz_Wartosc(cztery_bity);
  12.     }
  13.     printf("\n");
  14. }
  15. int main(void)
  16. {
  17.     uint32_t polaczone = 0x12345678;
  18.     printf("%lu\n", polaczone); //jak uint
  19.     printf("%lx\n", polaczone); //szesnastkowo
  20.    
  21.     printf("Wartosci podzielone, wyswietl HEX: \n");
  22.     PodzielWartosc(polaczone);
  23.     return 0;
  24. }