Generator Liczb losowych na Atmega 328p

Generator Liczb losowych na Atmega 328p

Witam!

Dzisiaj zaprezentuję kolejny projekt stworzony na mikrokontrolerze AVR i zaprogramowany w C. 

Tym razem jest to generator liczb losowych na mikrokontrolerze Atmega328p. 

Generalnie celem projektu jest generowanie :

a) 15 cyfrowej liczby całkowitej 

b) 14 cyfrowej liczby niecałkowitej ( 7 liczb przed przecinkiem i 7 po ) 

Dodatkowo generator musi generować liczby w oparciu o losowe lub zbliżone do losowości źródło entropii. 

Nie jest to oczywiście urządzenie kryptograficzne ale postanowiłem się postarać w tej kwestii. 

Lista części 

  • Atmega 328p-PU
  • 4 przyciski typu tact-switch
  • 1 potencjometr 10 K
  • 1 wyświetlacz LCD (ze sterownikiem kompatybilnym z HD44780)
  • 1 rezonator kwarcowy 8 MHz
  • 2 kondensatory 22 pF
  • 6 kondensatorów 100 nF
  • 1 dławik 100 uH
  • 1 kondensator 47uF
  • 2 kondensatory 100 uF 
  • 1 stabilizator L7805CV
  • 1 odbiornik radiowy ( jako źródło losowości) ( ja użyłem odbiornika z tego zestawu : https://botland.com.pl/moduly-radiowe/3191-modul-radiowy-nadajnik-fs100a-odbiornik-433-mhz.html?search_query=FS100A&results=2
  • Płytka stykowa/ kable stykowe 
  • Źródło zasilania 9V. 
  • Oprogramowanie do wgrania programu do mikrokontrolera i ustawienia fusebitów (np. avrdude).
  • Programator usbasp lub inny 

Do artykułu dołączony jest skompilowany plik .hex. 

W przypadku chęci własnoręcznego skompilowania kodu potrzebny będzie edytor IDE, kompilator i parę innych rzeczy. Szczegóły na ten temat można znaleźć w artykule 5 prostych projektów AVR C część 1. 

Schemat 

 Schemat całego projektu dzieli się na 4 bloki

  • Zasilanie 
  • Mikrokontroler
  • Przyciski
  • Wyświetlacz LCD

Zasilanie : 

Zasilane składa się z regulatora liniowego L7805CV oraz 2 kondesatorów po 100 uF. Jeden jest na wejściu i jeden na wyjściu. Regulator przyjmuje napięcie z zakresu 7 V – 30 V i zamienia je w stabilne 5V zasilające układ. 

Notatka: Przy wyższym napięciu zasilania może być potrzebny radiator w celu zwiększenia rozpraszania ciepła z regulatora. Przy 9V regulator jest ciepły. Jednak przy wyższym napięciu może zrobić się gorący.

Podblokiem zasilania jest “zasilanie mikrokontrolera”. Jest to dodatkowy filtr składający się z kondesatora 47uF oraz dławika 100 uF. Jego celem jest filtracja zasilania bloku mikrokontrolera. 

Mikrokontroler : 

Najbardziej skomplikowany i jednocześnie najważniejszy blok. 

Sercem układu jest mikrokontroler Atmega 328p, taktowany z zewnętrznego oscylatora kwarcowego 8 MHz. 

Zasilanie do AVCC i VCC pochodzi z dodatkowo filtrowanej szyny dVCC. Dodatkowo na każdym pinie zasilającym znajduje się kondensator 100 nF. 

Pin Reset jest wyposażony w kondensator 100 nF ( zgodnie z dokumentacją, jest on wyposażony w wewnętrzny rezystor podciągający 10 K). Podłączyłem do niego też przycisk który zwiera go do masy resetując mikrokontroler. 

W skład bloku mikrokontrolera wchodzi odbiornik radiowy będący źródłem entropii dla generatora liczb. Jest  to prosty odbiornik na częstotliwość 430 MHz. Co istotne nie jest on wyposażony w dekoder więc na jego wyjściu cały czas powstaje losowy szum cyfrowy :

Sygnał ten jest wykorzystany do taktowania wbudowanego w mikrokontroler timera 1. Powoduje to, że licznik tego timera produkuje losową 16 bitową liczbę całkowitą która następnie jest wykorzystywana jako ziarno dla generatora liczb losowych. 

W skład bloku mikrokontrolera wchodzi też brzęczyk, użyty do pikania. Brzęczyk nie ma wbudowanego generatora. Co jest istotne bo pozwala wygenerować miły dla ucha dźwięk który nie będzie brzmiał jak alarm przeciwpożarowy. 

W skład tego bloku wchodzą również kondensatory filtrujące dla przycisków. Każdy z przycisków jest wyposażony w kondensator 100nF co dość skutecznie zabezpiecza przed drganiami styków. 

Kolejnym istotnym blokiem jest wyświetlacz LCD. 

Wyświetlacz którego użyłem to JHD162A-B-W. Ma on dwie linijki po 16 znaków każda. 

Jednak w tym projekcie powinien zadziałać każdy wyświetlacz zgodny ze sterownikiem HD44780. 

Podłączenie jest wykonanie w trybie 4 bitowym co pozwala oszczędzać piny cyfrowe mikrokontrolera. 

Podłączone są tylko piny RS,  E oraz 4 ostatnie piny danych. Do pinu regulującego kontrast podłączony jest potencjometr. Kręcąc nim możemy regulować kontrast. (: 

Ponieważ wyświetlacz jest niebiesko biały, podświetlenie jest włączone na stałe. Inaczej nie było by na nim nic widać. 

Ostatnim i najprostszym blokiem są przyciski. 

Układ wyposażony w 4 przyciski (w tym 3 kontrolowane przez program).

  • Reset – Resetuje układ. 
  • Up – Przechodzi do wyższej pozycji w menu.
  • Down – przechodzi do niższej pozycji w menu.
  • Enter – Uruchamia wybrane losowanie. 

Oba przyciski są podłączone między pinem cyfrowym mikrokontrolera oraz masą układu. 

Więc kiedy są wciśnięte odpowiedni pin cyfrowy jest zwierany do masy. 

Kiedy nie są wciśnięte, na pinie sterującym panuje stan wysoki zagwarantowany przez uruchomione programowo, wewnętrzne rezystory podciągające.

Ponieważ układ ten został wykonany w celu ćwiczenia języka C, postanowiłem nie wytrawiać dla niego płytki drukowanej. Całość jest zmontowana na płytce prototypowej. 

Fusebity które ustawiłem to :

Program

Notatka : Cały projekt został zaprogramowany w języku C i skompilowany za pomocą kompilatora GCC AVR. W załączniku znajduje się archiwum zawierające skompilowany, gotowy do wgrania program oraz projekt code::blocks ( 16.02). 

Cały projekt składa się z 5 plików + zewnętrznej biblioteki do obsługi wyświetlacza ( http://radzio.dxp.pl/hd44780/hd44780_avr_4-bit_norw_c.htm)

Pliki wchodzące w skład projektu :

  • main.c – Plik główny 
  • menu.c – Plik zawierający kod źródłowy do wyświetlania różnych rzeczy oraz do menu. 
  • random_gen.c – Plik zawierający kod źródłowy do generowania liczb losowych. 
  • menu.h – Plik nagłówkowy do menu.c
  • random_gen.h – Plik nagłówkowy do random_gen.c

Pliki z biblioteki HD44780.h z radzio.dxp.pl 

  • HD44780.h – Plik nagłówkowy biblioteki.
  • HD44780.c – Plik z kodem źródłowym biblioteki. 

Oto kod źródłowy wszystkich plików projektu : 

main.c

menu.h

menu.c

random_gen.h

random_gen.c

Dodatkowo zmodyfikowałem funkcję odpowiedzialną za czyszczenie wyświetlacza z zewnętrznej biblioteki. 

Zmieniłem (w pliku HD44780.c): 

Na:

Teraz działa lepiej z moim wyświetlaczem. 

Poprzednio występowały błędy związane z czyszczeniem tylko jednej linijki 

Dodatkowo modyfikacji wymagają definicje portów i pinów w pliku HD44780.h :

Poprawne definicje dla tego podłączenie : 

Kody są opatrzone dużą ilością komentarzy więc zamieszczę tu tylko opis tworzenie losowej liczby: 

W generowaniu liczby losowej, układ bazuje na funkcji rand() z biblioteki stdlib.h .

Funkcja ta  bazuje na losowym “ziarnie” dostarczanym za pomocą funkcji srand().

Ziarnem jest 16 bitowa liczba typu unsigned int .

Ziarno jest generowane w oparciu o losowy szum cyfrowy generowany na podstawie szumu radiowego.

Ten losowy szum jest użyty jako sygnał zegarowy dla timera/licznika 1 ( timer jest 16 bitowy). Na każdym zboczu wznoszącym sygnału, licznik zwiększa swoją wartość o 1. Kiedy licznik się przepełnia (przy wartości  4294967295), jego wartość jest automatycznie zerowana. 

Ponieważ sygnał wejściowy jest losowy (oparty na szumie radiowym) więc i wartość tej liczby jest losowa co powoduje, że dane wyjściowe z funkcji rand() również są losowe, a przynajmniej bardzo zbliżone do losowych. 

Program nie losuje jednak całej liczby na raz.

Każda cyfra jest losowana osobno (choć przy użyciu tego samego ziarna), a następnie wyświetlana na wyświetlaczu. Znak jest również losowany osobno. 

I tak to generalnie działa. 

Reszta w komentarzach od programu (: 

Działanie

Teraz mała galeria na temat działania urządzenia : 

Po włączeniu przywita nas taki oto ekran powitalny:

A następnie pokarze się główne menu : 

Używając przycisków można wybrać jeden z dwóch trybów losowania :

  • Losowanie 15 cyfrowej liczby całkowitej.
  • Losowanie 14 cyfrowej liczby rzeczywistej ( 7 cyfr przed przecinkiem i 7 po ). 

Aktualnie wybrana opcja jest sygnalizowana znakiem “<“. 

Po wciśnięciu enter, program wylosuje liczbę, która będzie następnie wyświetlona na wyświetlaczu. 

Liczba całkowita : 

Liczba rzeczywista : 

Akurat miałem szczęście i kiedy robiłem zdjęcia, obie liczby wyszły ujemne. Kiedy liczba jest dodatnia to zamiast “-“jest pusta przerwa.

Zdjęcie układu w całości : 

Kilka słów na koniec

W załączniku znajduje się archiwum zawierające cały projekt codeblocks wraz ze wszystkimi kodami źródłowymi oraz skompilowanym plikiem .hex. 

Plik ten znajduje się w folderze bin/release. 

Projekt zawiera również zmodyfikowaną bibliotekę do obsługi wyświetlacza. 

No i to tyle (:

Jak zwykle, komentarze pozytywne i negatywne mile widziane (: 

Pliki załączone do artykułu:

Ocena: 5/5 (głosów: 1)

Podobne posty

5 komentarzy do “Generator Liczb losowych na Atmega 328p

    • Rzeczywiście
      Najprawdopodobniej odbiornik łapie jakieś losowe transmisje cyfrowe na paśmie 430 MHz i to jest przyczyną regularności w odczycie.

      Myślę jednak, że po pobraniu większej próbki sygnału, jego entropia okazałaby się znacznie wyższa niż jest widoczna na screenie z oscyloskopu.

      Ale oczywiście mogę się mylić bo nie znam schematu odbiornika.

      Odpowiedz
      • Licz po jednym bicie tak jak w generatorach opartych na liczniku Geigera.
        Liczysz impulsy w jakiejś jednostce czasu, potem zerujesz licznik i liczysz drugi raz. Jeśli pierwsza ilość jest większa to bit jest jedynką, jeśli jest mniejsza to zerem, jeśli są równe to powtarzasz oba odczyty. I tak n razy dla n-bitowej liczby.
        To tak w uproszczeniu.
        W Geigerach liczy się po prostu czas między dwoma kolejnymi impulsami, ale w przypadku rozpadu atomowego impulsy są nieco bardziej losowe niż w przypadku radia…

        Odpowiedz
      • To mam jeszcze kilka pytań:
        – na ile Twój generator jest lepszy od wbudowanej w Arduino funkcji random()?
        – czy badałeś/analizowałeś “jakość” wygenerowanych liczb? Tzn rozkład, wartości średnie, powtarzalność?
        – czy Twoim zdaniem nie byłoby lepiej zamiast odbiornika radiowego, za pomocą którego generowana jest liczba, a więc potencjalnie można “sterować” sygnałem z niego otrzymanym, pokusić się o inne, bardziej “niezależne” źródło? Choćby antenka podpięta pod ADC1, cewka pod ADC2, millis() i odczyt ostatniej cyfry z każdej tych wartości?

        Odpowiedz
  • 1) Funkcja random() jest na podobnym poziomie co mój generator. Jedyną zaletą mojego generatora jest to, że jest napisany w C więc zajmuje mniej miejsca (coś koło 2-3 KB ).

    2) Nie testowałem go pod tym kątem ):
    Rozważałem wykorzystanie Quick Check https://hackage.haskell.org/package/QuickCheck ale
    musiałbym wygenerować większą próbkę co byłoby trudne.

    3) Możliwe, że byłoby to lepsze rozwiązanie ze względu na brak konieczności wykorzystania timera.
    W sumie jak teraz sobie myślę to nie jest to najlepsze rozwiązanie, najlepiej byłoby wykorzystać schemat opisywany tutaj https://blog.cryptographyengineering.com/2012/02/21/random-number-generation-illustrated/
    Podłączyć taki układ do pinu cyfrowego i a następnie odczytywać stan pinu i zapisywać go do jako kolejne bity danej zmiennej.
    Wtedy można by równieź było użyć większej liczby takich generatorów aby odczytywać kilka bitów na raz co przyspieszyłoby cały proces.

    Tak generalnie to był kolejny projekt zrobiony w celu ćwiczenia programowania AVR w C

    Odpowiedz

Odpowiedz

anuluj

Masz uwagi?