Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 26 cze 2019, o 00:59


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 22 ] 
Autor Wiadomość
PostNapisane: 9 kwi 2019, o 11:59 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Witam.
Mam prośbę o opinię w kwestii poprawności typów zmiennych. Ostatnio wpadło mi w ręce pcb generatora dds na ad9850-popularny "chińczyk". Postanowiłem go ożywić. Udało mi się to i generatorek
działa. Próbowałem różnych metod wysyłania danych po spi od tych "kodo żernych" po bardziej wyszukane i jak twierdzą inni, lepsze. Robiłem wcześniej próby z ad9952 również z podobnym skutkiem.
Przykłady zaczerpnąłem z internetu oczywiście. Ostatnie próby robiłem z użyciem uni. Działa, ale nie do końca jestem pewny poprawności kodu (zakresu zmiennych).

Wygląda to mniej więcej tak:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Dalej wysyłam obliczoną nastawę do dds-a w sekwencji 4 bajtów + potem jeszcze bajt konfiguracyjny.

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



Nastawa jest liczona następująco:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



I teraz po przemyśleniu wychodzi mi tak:

Liczba 4294967296 nie mieści się w unsignet long 32 bity (końcówka 6).
Po przemnożeniu 4294967296 * freq(np. 40000000) = 171798691840000000 ---> bardzo duża liczba.

Po podzieleniu wyniku przez 125000000 otrzymujemy 1374389534,72

Zmienna FTW jest również 32 (ale long co prawda).

Proszę o ocenę, jak to się ma do "całości". Czy jednak należałoby napisać inaczej. Pozdrawiam.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2019, o 13:20 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 sty 2016
Posty: 645
Pomógł: 37

Zawsze możesz mnożniki zmniejszyć do minimalnego rozmiaru np: 4294967296 * freq(np. 40) = 17 179 869 1840 a potem to podzielić przez 125 wynik będzie ten sam ale mikrokontroler szybciej uwinie się z obliczeniami.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2019, o 13:27 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dzięki zubik
Tak na szybko odpisuje, ponieważ muszę odejść od kompa. Bardzo ciekawie to ująłeś. Muszę przemyśleć na spokojnie. Jedyne, co mi się nasuwa na początku, to czy jest to poprawne rozwiązanie w tej konkretnej sytuacji. Na razie dzięki za chęć pomocy. Pozdrawiam.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2019, o 21:22 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 04 lut 2014
Posty: 142
Pomógł: 2

Podłączę się bo przypadkowym trafem też zakupiłem moduł AD9850 i chcę wykonać na nim generator / BFO.
Obliczenia kolegi @zubik wyglądają dobrze. Ja sam brałem pod uwagę konwersję liczby do tablicy ale póki co wykonam testy dla zwykłego obliczania.

Pozdrawiam.

_________________
::::::: C ::::::::::
:::::: C++ :::::::::



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 kwi 2019, o 08:48 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 489
Pomógł: 118

Robert_1967 napisał(a):
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Rozumiem, że ten wzór ma obliczyć wartość przyrostu fazy, jaką trzeba wprowadzić do AD9850 w celu uzyskania częstotliwości wyjściowej o wartości zmiennej frequency.

zubik napisał(a):
Zawsze możesz mnożniki zmniejszyć do minimalnego rozmiaru np: 4294967296 * freq(np. 40) = 17 179 869 1840 a potem to podzielić przez 125 wynik będzie ten sam ale mikrokontroler szybciej uwinie się z obliczeniami.

A jeśli przykładowo będziesz chciał uzyskać częstotliwość np. 6 451 200?
Okazuje się, że "mnożnik" nie może być zawsze taki sam, trzeba by go ustalać indywidualnie dla każdej wartości częstotliwości. Poza tym "mnożnik" równy 100 niewiele zmieni, jeśli chodzi o rozmiar zmiennej.
Pomysł ogólnie dobry, ale można go raczej zastosować w sytuacji, kiedy możemy znaleźć wspólny dzielnik dla stałych zastosowanych w programie.

Myślę, że w tym przypadku, aby uzyskać maksymalną rozdzielczość/dokładność częstotliwości oferowaną przez układ, nie da się uniknąć obliczeń na liczbach 64-bitowych. Oczywiście zmienne mogą pozostać 32-bitowe (tak czy inaczej, wynik przecież musi się zmieścić w 32 bitach), jednak na pewnym etapie obliczeń należałoby je rzutować na zmienne 64-bitowe.

Przykładowo takie obliczenia:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

powinny dać prawidłowy wynik (pod warunkiem oczywiście, że frequency < CLKIN). Czas wykonania obliczeń to ok. 1300 taktów zegara, co przy taktowaniu 16MHz daje niecałe 82us.

Rewelacyjnie nie jest, ale w przypadku generowania częstotliwości stałych takie opóźnienie to nie jest chyba duży problem. Gdyby ktoś chciał użyć modulacji częstotliwości dla przebiegu o kształcie znanym w czasie kompilacji, można użyć tablicy z predefiniowanymi wartościami przyrostu fazy zapisanej np. w pamięci FLASH (odczyt gotowych wartości z pamięci będzie na pewno dużo szybszy niż ich obliczanie). Problemem może być modulacja szybkozmiennym sygnałem zewnętrznym, którego wartości chwilowe są odczytywane przez ADC i przyrost fazy musi być obliczany w czasie rzeczywistym na podstawie wyniku pomiaru.

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 kwi 2019, o 10:24 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dziękuję kolegom za udział w temacie.
Również doczytałem taką informację, że obliczenia można i raczej powinno się (jeśli taka konieczność) wykonywać na dłuższych liczbach, ale docelowo przy wysyłaniu słowa częstotliwości trzeba obciąć do 32 bitów, ponieważ tak ma być dla ad98XX.
Znalazłem wiele przykładów implementacji tego układu, w szczególności na Arduino, ale łatwo można zaadoptować. Jedyne, co mnie na początku denerwowało, to fakt, że częstotliwość wygenerowana
nie do końca pokrywała się z nastawą. Przy zmianie modułu na inny (mam dwie sztuki) różnica była kilkadziesiąt Hz. Doczytałem, że generatorki 125MHz maja rozbieżności i trzeba korygować w programie. Ja mam aktualnie f osc. 124999500 i jest ok.
Drugi problem polega na tym, że mogę osiągnąć max. 20-25MHz na wyjściu. Nie da rady 40MHz. Doczytałem, że te chińskie moduły nie zawsze dobrze działają. Może być podróba AD98XX. Druga sprawa, że używam również płytki stykowej i jak poruszam przewodami, raz generuje szybko, pewnie i stabilnie, a nieraz różnie. Może tu tkwi problem ???. Może ktoś ma doświadczenia z tymi modułami
i podzieli się opinią, co może być nie ok.
Kolego Lex_. U mnie temat jest rozwojowy. Pomału coś tworzę, ale jako, że uczę się wolno i od przypadku, to i efekty są powolne. Pomału będę rozbudowywał o następne funkcje, czyli zmiana f, kroku, zakresy, itd. Zobaczymy, co wyjdzie :D . Może koledzy z forum trochę pomogą ???. Obaczymy.

Moje pcb:

Obrazek



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 kwi 2019, o 09:00 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Mam prośbę o zweryfikowanie kodu.

Postanowiłem wykonać obliczenia na dłuższych liczbach i następnie wysłać nastawę do dds na 32 bitach. Chciałem zastosować jawne rzutowanie. Proszę o opinię, czy słusznie kombinuję, czy
raczej komplikuję sobie zagadnienie. Jeśli droga jest słuszna, to czy kod napisałem prawidłowo. Proszę o wyrozumiałość w moich wypocinach ;) .

Unia wygląda następująco:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Następnie robię takie rzutowanie na 32 bity w funkcji wysyłania czterech bajtów:


Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Czy tak jest poprawnie i metoda jest słuszna ???.


PS

Czy może ktoś wie, jaki popełniam błąd przy wstawianiu kodu SYNTAX C do postu ?. Zawsze na początku mam przesunięcie tekstu i nijak nie mogę tego wyrównać.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 kwi 2019, o 09:31 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 489
Pomógł: 118

Mam wrażeni, że nie przeczytałeś zbyt dokładnie tego, co napisałem w poprzednim moim poście.
Cytuj:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Nie musisz zmieniać typu zmiennych. Możesz mieć tak jak miałeś. Użycie przyrostka ULL wymusi na kompilatorze wykonanie obliczeń na liczbach 64-bitowych, po czym wynik zostanie obcięty do 32 bitów i przypisany do Twojej zmiennej. Jeśli już koniecznie chcesz jawnie rzutować, to wystarczy tak:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


To co zrobiłeś nie ma większego sensu. Tak naprawdę rzutujesz 8-bitowe elementy tablicy na zmienne 32-bitowe i próbujesz je wysłać po SPI. Argument Twojej funkcji send_spi() i tak zostanie najprawdopodobniej obcięty do 8 bitów. Nie miałeś żadnych ostrzeżeń podczas kompilacji?

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 kwi 2019, o 10:07 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dzięki andrew
Dzięki, ze chociaż Ty masz chęć nieraz odpisać. No tak już mam, że nieraz lubię komplikować sobie życie. Ja zawsze czytam i to dokładnie. Problem w tym, że nie zawsze rozumiem. Jako, że poznaję
C całkowicie sam, to trudno mi zrozumieć czasem. Mam książki Mirka, czytam w internecie, ale ze zrozumieniem trochę na bakier. Może mam złą metodę, źle się uczę. Ale to mój kłopot i nie będę nikogo zanudzał. Ok wrócę to początku tak, jak było i idę dalej. Muszę dołożyć przyciski (potem enkoder) i napisać funkcje do przestrajania. Step by step, jak to mówią :) . Pozdrawiam.

-------------------------------

Zapomniałem dopisać, że ostrzeżeń nie było. Kompilacja przebiegała prawidłowo i po wgraniu był normalny przebieg na wyjściu DDS-a.
Ja sądziłem, że jak wykonam taki zapis

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


to zostanie zmienione tylko FTW.u64 na FTW.u32 a tablica pozostanie u8. No ale to wynika z mojej niewiedzy, ponieważ nie wykorzystywałem jawnego rzutowania do tej pory. No może poza
jednym przypadkiem dawno temu i nie mam tego wyuczonego.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 kwi 2019, o 18:28 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 489
Pomógł: 118

Robert_1967 napisał(a):
wrócę to początku tak, jak było i idę dalej
Zauważ tylko różnicę między Twoim kodem, a tym co pokazałem, czyli przyrostki ULL. Dzięki temu masz pewność, że obliczenia będą wykonane na typie unsigned long long (czyli w przypadku AVR 64-bitowym).

Robert_1967 napisał(a):
Ja sądziłem, że jak wykonam taki zapis

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

to zostanie zmienione tylko FTW.u64 na FTW.u32 a tablica pozostanie u8.


Spróbuję jak najprościej.

W przypadku stworzonej przez Ciebie unii:
    FTW.uint8[0] jest typu uint8_t
    FTW.uint64 jest typu uint64_t

Analogicznie, kiedy rzutujesz:
    (uint32_t)FTW.uint8[0] następuje konwersja typu z uint8_t do uint32_t, czyli następuje rozszerzenie o dodatkowe bajty, które w tym przypadku zostaną uzupełnione zerami,
    (uint32_t)FTW.uint64 następuje konwersja typu z uint64_t do uint32_t, czyli następuje obcięcie czterech najbardziej znaczących bajtów.

Zakładając, że Twoja zmienna 64-bitowa jest równa 0000 0000 25AC 56B1 (heksadecymalnie)
to po konwersji:
    (uint32_t)FTW.uint8[0], czyli uint8_t do uint32_t otrzymasz wartość 0000 00B1
    (uint32_t)FTW.uint8[1], czyli uint8_t do uint32_t otrzymasz wartość 0000 0056
    (uint32_t)FTW.uint8[2], czyli uint8_t do uint32_t otrzymasz wartość 0000 00AC
    (uint32_t)FTW.uint8[3], czyli uint8_t do uint32_t otrzymasz wartość 0000 0025
    (uint32_t)FTW.uint64, czyli uint64_t do uint32_t otrzymasz wartość 25AC 56B1

Rzutowanie nie oznacza zmiany typu zmiennej w jakimś sensie permanentnym, czy też globalnym. Poprzez rzutowanie programista mówi tylko kompilatorowi:
    Wiem, że zadeklarowałem zmienną jako inny typ (np. uint8_t), ale w przypadku tej konkretnej operacji (w której zostało użyte rzutowanie) chcę, żebyś potraktował tę zmienną jako typ podany w nawiasie (np. uint32_t).
Wartość i typ rzutowanej zmiennej po takiej operacji pozostaje bez zmian. Poza tym rzutowanie nie musi wcale dotyczyć tylko jakiejś konkretnej zmiennej. Rzutować można także np. wynik jakiejś całej operacji arytmetycznej lub logicznej na kilku zmiennych.

Pisząc tak:
    send_spi((uint32_t)FTW.uint8[0]);
z punktu widzenia kompilatora wyrażasz takie intencje:
  • odczytaj element (typu uint8_t) o indeksie 0 z tablicy będącej elementem unii FTW,
  • odczytaną wartość skonwertuj do typu uint32_t
  • tę skonwertowaną wartość przekaż jako argument do funkcji send_spi()
Problem w tym, że funkcja send_spi() jako argumentu oczekuje zmiennej typu uint8_t, a nie uint32_t. Oczywiście kompilator sobie z tym poradzi, bo albo dokona niejawnej konwersji z powrotem z uint32_t do uint8_t, albo (co chyba bardziej prawdopodobne) w ogóle pominie rzutowanie. W efekcie kod będzie działał prawidłowo, co nie oznacza, że jest prawidłowo napisany.

Robert_1967 napisał(a):
Zapomniałem dopisać, że ostrzeżeń nie było. Kompilacja przebiegała prawidłowo i po wgraniu był normalny przebieg na wyjściu DDS-a.

To jeszcze nie musi oznaczać, że wszystko jest OK. Nie wszystkie ostrzeżenia są standardowo włączone, a kompilator często skutecznie potrafi sprostować niektóre błędy programisty. No ale jednak nie zawsze sobie poradzi, dlatego dobrze jest jednak precyzyjnie i poprawnie przedstawiać mu swoje oczekiwania.

Jeszcze co do jawnego rzutowania - niektórzy traktują je jako panaceum na pozbycie ostrzeżeń kompilatora. Jeśli kompilator wyświetli ostrzeżenia dotyczące typu, to trzeba rzutować jawnie wartość na określony typ i po kłopocie. Taka taktyka sprawdza się niestety tylko wtedy, kiedy przed rzutowaniem programista dobrze przemyśli wszelkie możliwe implikacje takiej decyzji i uzna, że nie doprowadzi ona do jakiejś katastrofy. Rzutowanie może powodować w niektórych przypadkach utratę pewnych informacji (np. obcięcie części ułamkowej w przypadku konwersji float do int), więc trzeba dobrze przemyśleć, jakie to będzie miało skutki i jak one wpłyną na poprawność działania całej aplikacji.

Robert_1967 napisał(a):
Dzięki, ze chociaż Ty masz chęć nieraz odpisać.

Każdy ma jakiegoś bzika... :)


Autor postu otrzymał pochwałę

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 07:28 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dzięki andrew

Dziękuję za wyłożenie tematu.
Nie widzę, jak wstawić cytat "Dzięki, ze chociaż Ty masz chęć nieraz odpisać." Poniekąd rozumiem, że to nie jest forum do nauki C od podstaw. Jeśli ktoś chce się uczyć, to niech idzie do szkoły, a nie szuka korepetycji za darmo :D . Może czasami nadużywam cierpliwości innych i zbyt wiele oczekuję, ale myślałem sobie, że mogę pytać o wszystko i dostanę odpowiedź. Ok kończę te wywody.

Napisałem tak:

W pliku nagłówkowym.h

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


W pliku źródłowym.c unia:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



Dalej w funkcji wysyłającej słowo do dds:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


dalej w main.c w pętli while(1) wywołuje funkcję:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Nie wiem , czy słusznie wstawiłem te _delay_ms(XX); ale tak mam.

W sieci znalazłem inny sposób wysyłania danych:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Jest to najczęściej spotykana metoda, ale jak pisałem wcześniej, to podobno z użyciem uni ten kod działa najszybciej, a więc uparłem się na niego :) .

Osobiście testowałem oba i działają tak samo, ale samopoczucie "lepsze" :D dzięki tej uni.

Jeśli chodzi o dds_a ad9850, to jak pisałem, korzystałem z "chińczyka". Jeśli chodzi o ad9952, to testuję swój własny moduł. Nie jest to mój projekt, ale wprowadziłem małą kosmetykę i przerysowałem płytkę. Montowana prze zemnie "na kolanie", jak wiele innych zresztą. Tak że coś tam potrafię zrobić i całkiem noga nie jestem, ale C idzie mozolnie. Jako ciekawostkę dodam, że
ten dds na ad9952 jest sterowany z innego sterownika, ale ja postanowiłem wykonać coś własnego chociażby w celach edukacyjnych, stąd temat.

Na tym temat chyba zamknę, bo miało być tylko o typach zmiennych i zrobi się bałagan. Jeszcze raz dzięki za poświęcony czas.

Moje pcb:

Obrazek



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 09:44 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 489
Pomógł: 118

Robert_1967 napisał(a):
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Po pierwsze:
Moim zdaniem lepiej jednak jest korzystać z nazw typów, które jasno określają ich szerokość w bitach, czyli:
  • uint8_t zamiast unsigned char
  • uint64_t zamiast unsigned long long int
  • int16_t zamiast int
  • itd.
Typy wbudowane nie są jednoznaczne, ponieważ ich szerokość w bitach jest zależna od platformy sprzętowej (inna będzie dla 8-bitowego AVR, a inna dla STM32). Ja użyłem nazwy typu unsigned long long tylko dlatego, żeby pokazać skąd wziął się przyrostek ULL.

Po drugie:
Nadal masz zmienną 64-bitową w Twojej unii, a w zupełności wystarczy 32-bitowa:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Sprawę wymuszenia obliczeń na liczbach 64-bitowych załatwi przyrostek ULL przy zdefiniowanych stałych.

Robert_1967 napisał(a):
frequency = 25000000ULL;

Zmienna frequency jest typu uint32_t i taka może być, jednak wartości 64-bitowej do niej i tak nie wpiszesz, więc spokojnie możesz tutaj pominąć przyrostek ULL.

Robert_1967 napisał(a):
Jest to najczęściej spotykana metoda, ale jak pisałem wcześniej, to podobno z użyciem uni ten kod działa najszybciej, a więc uparłem się na niego

Wiesz, nie chce mis się teraz tego testować, ale wydaje mi się, że kompilator, po napotkaniu na przesunięcia bitowe podzielne przez 8, przynajmniej wtedy, gdy kompiluje kod dla 8-bitowego mikrokontrolera, nie będzie używał czasochłonnych przesunięć bitowych, tylko odczyta po kolei poszczególne bajty, podobnie jak w przypadku odczytu z tablicy. Jestem tego prawie pewien, choć gwarancji nie dam. Poza tym gdyby ten kod nieco przerobić, to można by go przyspieszyć:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Gdyby napisać w ten sposób, to nawet jeśli przesunięcia bitowe byłyby wykonywane, działoby się to w trakcie transmisji SPI, a i tak czekasz na jej zakończenie, zarówno tutaj, jak i w kodzie z unią. Nie wiem, z jaką prędkością te dane wysyłasz, ale jest szansa, że w trakcie transmisji przesunięcia zdążyłyby się wykonać. Tutaj dane są bezpośrednio wpisywane do rejestru SPDR, w kodzie z unią wywołujesz funkcję wysyłającą, a każde wywołanie i powrót z funkcji pochłania dodatkowe takty zegara. W kodzie z unią cczekasz na wysłanie danych, a dopiero później odczytujesz dane z tablicy, aby wysłać następny bajt, tutaj następny bajt można przygotować w czasie transmisji. W celu uzyskania odpowiedzi, który kod jest szybszy, należałoby wykonać testy, przeliczyć takty, ale nie za bardo mam na to czas.

andrews napisał(a):
Robert_1967 napisał(a):
Dzięki, ze chociaż Ty masz chęć nieraz odpisać.
Każdy ma jakiegoś bzika... :)
Robert_1967 napisał(a):
Nie widzę, jak wstawić cytat "Dzięki, ze chociaż Ty masz chęć nieraz odpisać." Poniekąd rozumiem, że to nie jest forum do nauki C od podstaw. Jeśli ktoś chce się uczyć, to niech idzie do szkoły, a nie szuka korepetycji za darmo

Nie wiem, czy mnie dobrze zrozumiałeś. Nie miałem zamiaru Cię urazić. Niemniej moim zdaniem forum jest jak najbardziej także dla początkujących. Jednak nauka programowania, tak jak wszystkie nauki ścisłe, wymaga zachowania pewnej kolejności w zdobywaniu wiedzy. Problem z początkującymi często polega na tym, że są niecierpliwi i chcą na skróty osiągnąć wysoki poziom, przez co odpowiedzi na ich pytania muszą być bardzo obszerne, a każda odpowiedź rodzi następne pytania. Nie traktuj tego jako złośliwość, tylko jako dobrą radę, żeby uczyć się z zachowaniem odpowiedniej kolejności, systematycznie, nie za szybko zwiększać stopień trudności swoich projektów i uzbroić się w cierpliwość, a efekty na pewno z czasem przyjdą.

Pozdrawiam
   Andrzej

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 11:00 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 15 lut 2017
Posty: 259
Lokalizacja: Gliwice
Pomógł: 21

andrews napisał(a):
Zmienna frequency jest typu uint32_t i taka może być, jednak wartości 64-bitowej do niej i tak nie wpiszesz, więc spokojnie możesz tutaj pominąć przyrostek ULL.


No nie do końca można pominąć. Trzeba zastosować właściwy, w tym wypadku UL, czyli unsigned long (32 bit, bez znaku).
Stosowanie przyrostków UL, ULL jest po to, w mojej opinii, żeby nie musieć jawnie rzutować w każdym miejscu, gdzie powinno być zrobione, bo właściwą interpretację dla preprocesora stanowią właśnie przyrostki.

Domyślna promocja do int, dla realnie dużych wartości liczb (z dużym prawdopodobieństwem przekroczenia zakresu, jak w tym przypadku), w momencie zaniedbania rzutowań jest niebezpieczna, zatem należałoby wstawiać te przyrostki przy korzystaniu z #define.

Inny sposób, jeśli ktoś jednak chce korzystać z #define to korzystać z konstrukcji:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Powyższe sposoby są równoważne, ale niemniej jednak bardzo istotne.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 11:09 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dziękuję Andrzeju.

Jeszcze nie znalazłem metody na cytowanie, ale poszukam.

" Nadal masz zmienną 64-bitową w Twojej unii, a w zupełności wystarczy 32-bitowa: " Tutaj moja wina, ponieważ zrobiłem kopiuj-wklej na szybko i nie skasowałem LL.

" uint8_t zamiast unsigned char
uint64_t zamiast unsigned long long int
int16_t zamiast int
itd. "

Ja zazwyczaj stosuje metodę uint8_t itd... Tutaj akurat na tą chwilę trzymałem się oryginalnej części kodu i nie zmieniałem. I tak co jakiś etap staram się robić jakąś optymalizację, tak że to na razie.

Dalej, ja się tak szybko nie obrażam :D . Tutaj to ja przepraszam. Może źle napisałem. Ja pisałem ogólnie o całym forum, że to w sumie nie miejsce na naukę od podstaw itd...

Co do opińii o początkujących, to zgadzam się w całej rozciągłości. Wiem sam po sobie. Jeśli coś się udaje, ale nie do końca rozumiem temat, to idę dalej, a to czego nie wiem, to odkładam "na potem". Ja wiem, że robię kardynalny błąd i to się potem mści tak, jak w tym przypadku. Gdybym na spokojnie przeanalizował temat chociażby rzutowania, nauczył się na 99%, to tego tematu by nie było, a ja byłbym dalej z projektem. Nie mniej jednak myślę, że i tak małe bo małe, ale robię postępy, tylko trochę po łepkach i to źle.

Ok. Pisanie i testowanie zacznę od poniedziałku. Teraz inne priorytety (dom). Kończąc dodam, że ktoś inny napisał, że inicjacja i wysłanie freq. do dds-a, to tylko jeden procent projektu i najłatwiejsza część. Pozostałe 99%, to interfejs użytkownika i cala reszta z tym związana. Zobaczę, jak sobie poradzę. Mam czas :) . Pozdrawiam. Robert.


---------------------Dodano-------------------

Tutaj jeszcze pozwolę sobie zacytowć tekst z innego forum. Pisały to osoby, które można by stwierdzić, ze są guru w temacie syntez i ich budowy oraz oprogramowania. Teksty skierowane nie do mnie, tylko dyskusja.

" nie jestem ekspertem od GCC-AVR ale zastanawia mnie jakim cudem podczas mnożenia dwóch liczb 4 bajtowych (long int) chcesz zmieścić wynik na 4 bajtach. "

oraz " FTW jako ciąg bitów wysyłanych do DDS - wynik obliczeń musi być 32 bitowy...

można sobie po drodze liczyć na "dłuższych" liczbach ale na koniec trzeba :

- albo liczbę "obciąć" do 32 bitów
- albo świadomie wysłać 32 młodsze bity
"

Pozdrawiam.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 13:32 
Offline
Tech-support
Avatar użytkownika

Dołączył(a): 26 sty 2016
Posty: 833
Lokalizacja: Kraków
Pomógł: 68

Robert_1967 napisał(a):
Jeszcze nie znalazłem metody na cytowanie, ale poszukam.
Z tym akurat mogę pomóc (bo z postawionym problemem nie bardzo :( )
W prawym dolnym rogu każdego posta masz dwa przyciski - cytuj i cytowanie selektywne. Korzystając z nich możesz cytować.

Albo możesz też "z palca" - tylko to, co piszę, musisz wpisać w nawiasy kwadratowe []. Rozpoczęcie cytowania to quote="nick", a zakończenie to /quote



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 14:19 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dzięki.
Co do tematu, to mi pomogłeś, jak i kolega zealota. Tak czy inaczej w różnych przykładach z różnych projektów, które widziałem (wiele na arduino) to przeważnie
obliczenia były wykonywane na dłuższych liczbach, a do dds-a wysyłane na 32 bitach. Chciałem jeszcze podejrzeć np. na lcd te liczby, ale coś nie wychodziło.
Jeszcze pokombinuje. Pozdrawiam.
Co do szybkości wykonywania tych działań to zależało mi dla tego, że jak będzie inpulsator-enkoder, to żeby nadążył przy szybszych pokręceniach. Ja mam taki chyba 250 kroków i nie chciałbym, a żeby gubiło kroki itp...No oczywiście reszta musi być nie blokująca, to wiem. Może trochę trudny temat, ale mi się nie spieszy
i wiele z tego wyniosę. Pozdrawiam.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 14:45 
Offline
Użytkownik

Dołączył(a): 24 cze 2014
Posty: 85
Pomógł: 1

Robert_1967 napisał(a):
Chciałem jeszcze podejrzeć np. na lcd te liczby, ale coś nie wychodziło.

Trochę zgaduję, ale podejrzyj jakiego typu zmienne obsługuje funkcja do wyświetlania ich na LCD :) Możliwe, że "przekręca" Ci zakres - to taka podpowiedź :)

_________________
.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 15:25 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Dzięki tec_dive
Po niedzieli pokombinuję. Kiedyś napisałem funkcję do wyświetlania długich liczb (z pomocą forum oczywiście) lcd_long(); i wyświetlało prawidłowo długie ciągi liczb,
ale być może trochę inny typ i tu mi coś nie działało. Fakt, że zaraz to zostawiłem, ponieważ bardziej byłem skupiony na tym temacie. Wrócę do tego.
Dzięki za podpowiedź. Pozdrawiam.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 18:51 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 489
Pomógł: 118

Robert_1967 napisał(a):
Co do opińii o początkujących, to zgadzam się w całej rozciągłości. Wiem sam po sobie.

A jak myślisz, skąd ja o tym wiem? Też kiedyś byłem początkujący, choć wcale nie twierdzę, że teraz już wiem wszystko. Może jednak nie będę się już rozpisywał na ten temat, żeby nie zwiększać off-topu.

Chciałbym jednak jeszcze odpowiedzieć koledze Zealota.

Ogólnie zgadzam się z tym, że stosowanie odpowiednich przyrostków określających typ stałej jest ważny. Jak pewnie zauważyłeś, sam pierwszy w tym wątku zacząłem o tym pisać. Chciałbym jednak, żebyś zauważył także fakt, że moja propozycja usunięcia przyrostka nie dotyczyła zasady ogólnej, tylko pewnego konkretnego przypadku przypisania wartości do zmiennej:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Zacznijmy od specyfikacji języka C99. W punkcie 6.4.4 podpunkt 5 na końcu strony 55 znajduje się taki zapis:
    The type of an integer constant is the first of the corresponding list in which its value can be represented.

Na następnej stronie natomiast jest tabela, z której wynika, że typ stałej liczbowej w formacie dziesiętnym bez przyrostka będzie ustalany (dla omawianego przypadku) w sposób następujący
(kolejność sprawdzania to int->long int->long long int):
  • kompilator sprawdzi, czy liczba 25 000 000 mieści się w zakresie typu int - okaże się, że nie,
  • kompilator sprawdzi, czy liczba 25 000 000 mieści się w zakresie typu long int - okaże się że tak, dlatego typ stałej zostanie określony na long int, więc tutaj żadnego zagrożenia zmiany wartości (obcięcia) nie będzie

Teraz kompilator musiałby przypisać wartość typu long int do zmiennej typu unsigned long int, więc musi dokonać niejawnej konwersji typu. Jednak biorąc pod uwagę, że liczba nie jest ujemna i mieści się w zakresie unsigned long int, żadnej utraty informacji czy też zmiany wartości też nie będzie.

Problem może się pojawić w przypadku próby przypisania innej wartości, niż ta z przykładu. Należałoby tu jednak wziąć pod uwagę pewne zależności wynikające z ogólnej koncepcji programu:
  • Wartość zmiennej frequency będzie zawsze dodatnia, bo przecież nikt nie będzie chyba próbował wygenerować częstotliwości ujemnej. Gdyby nawet przez pomyłkę ktoś próbował to zrobić, to przyrostek UL raczej nie uchroni go przed błędem, bo (przynajmniej przy standardowych ustawieniach ostrzeżeń) kompilator, niezależnie od obecności czy braku przyrostka, żadnego ostrzeżenia nie wyświetli, a generowana częstotliwość będzie dość nieoczekiwana (na pewno nie ujemna ;))
  • Jeśli dobrze zrozumiałem dokumentację układu stała CLKIN nie może być większa od 125 000 000. Z kolei zmienna frequency musi być od tej stałej mniejsza, więc nie ma ryzyka, że wykroczy poza zakres typu unsigned long int. Nawet gdyby ktoś omyłkowo próbował przypisać jej wartość większą niż zakres unsigned long int, kompilator powinien wyświetlić ostrzeżenie niezależnie od tego, czy użyjesz prefiksu UL czy też nie.
W każdym razie przypisanie zmiennej frequency wartości spoza zakresu od 0 do CLKIN i tak spowoduje nieprawidłowe działanie programu i użycie przyrostka tutaj nie pomoże. Dobrze byłoby w programie kontrolować, czy wartość zmiennej frequency nie wykracza poza ten zakres.

Moje rozważania dotyczą cały czas przytoczonego wyżej konkretnego przypadku. W innych okolicznościach, kiedy nie jesteśmy pewni, nie pamiętamy lub nie wiemy, w jaki sposób kompilator potraktuje naszą stałą liczbową, zawsze warto jednoznacznie określić jej typ, nie jest to oczywiście błędem. W tym konkretnym przypadku jednak użycie przyrostka, zgodnie ze specyfikacją języka, nie jest niezbędne.

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 19:36 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 15 lut 2017
Posty: 259
Lokalizacja: Gliwice
Pomógł: 21

andrews, dzięki za sprecyzowanie.
Średnio rozgarnięty programista zwykle nie zna takich szczegółów, nawet gdyby pogryzł specyfikację C99 :)
Moja poprzednia odpowiedź była bowiem trochę prowokacyjna, żeby dowiedzieć się więcej.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 kwi 2019, o 20:03 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Ładnie napisane.
Odnośnie off topu, to popieram, ale dodam na koniec, że nieraz są osoby, które uczyły się informatyki, studiują itd. i mają już obeznanie, myślą programistycznie.
Rozumieją te bity, bajty i cały ten "slang". Ponad to mają profesora, nauczyciela, który ma materiał do zrealizowania w odpowiedniej kolejności. Są sprawdziany i tego typu podobne rzeczy, gdzie musimy się dostosować, zaliczyć i to zmusza nas do pełnego opanowania materiału. Musi być dyscyplina, bo inaczej nie zaliczysz.
Ja z kolei nie mam kompletnego przygotowania, jak również wiele podobnych osób i nam jest zdecydowanie trudniej, No i nie ma sprawdzianów, zliczeń i mamy wolna rękę, co skutkuje tym, co widać. No i niektórzy są urodzonymi matematykami, mają predyspozycje itd. Znam osobę, która po roku nauki wyczynia takie rzeczy, że szczena opada. No ale mnie to bardzo fascynuje i będę dalej się uczył i coś tam dłubał z czystej przyjemności. Koniec tematu i nie wracam do tego.

Chciałem jeszcze raz się odnieść do tych typów. Zakładamy, że mamy dwa ciągi liczb. Oba mieszczą się w uint32. Ale kiedy wykonamy mnożenie na tych liczbach, to nagle okazuje się że wynik mieści się dopiero w 64 bitach. Przecież procesor musi gdzieś przechowywać ten wynik i musi mieć dla niego odpowiedni worek gdzieś w ramie, bo jak będzie za mały, to się nie zmieści. Ja tylko piszę w kontekście mojego samo myślenia. To nie jest podważanie Waszej opinii, ponieważ mam o wiele za mało wiedzy. Podobno kompilator sam sobie pomoże i naprawi błąd programisty, ale mi o tym nie powie, a ja będę sądził, ze napisałem poprawnie, bo przecież "działa". Jeszcze inny przypadek. Powiedzmy, że mamy dwie liczby , które mieszczą się w zakresie uint32 i wykonujemy mnożenie. Następnie dzielimy wynik przez kolejną zmienną i wynik mieści się w zakresie uint32, ale "przez chwilę" przed dzieleniem występowała sytuacja gdzie wynik mnożenia nie mieścił się w uint32, a procesor, czy też kompilator musi sobie z tym poradzić. To są momenty, kiedy czegoś do końca nie wiem i wychodzi kaszana. Niby rozumiem mechanizmy działania, ale brak kropki nad i w posiadanej wiedzy i to w różnych innych przypadkach odnośnie C. Pewnie z czasem tych luk będzie coraz mniej :D . Dla tego ktoś napisał, że zawsze należy dążyć do poprawności kodu, nie bacząc na to ,że kompilator zrobi za mnie robotę.
Również czytałem, że jeśli jest potrzeba dodania np. UL, czy ULL, to powinniśmy dopisać do wszystkich zmiennych, które biorą udział w działaniu. Ale również czytałem, że jeśli w jakimś działaniu np. mnożeniu dwóch, czy więcej zmiennych dodamy do jednej z nich UL, czy ULL (bo taka jest potrzeba w tym konkretnym przypadku), to pozostałe zmienne równie przyjmą format UL, czy ULL mimo że nie jest dopisane do tych zmiennych. Różnie piszą i potem trzeba wybrać to co najwłaściwsze, a samemu można się pomylić. Trochę się rozpisałem, ale dobra. Kończę i pozdrawiam wszystkich czytających wątek. Jest bardzo dużo otwarć na stronie, ale żeby się wypowiedzieć, to cisza :lol: .



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 kwi 2019, o 17:35 
Offline
Użytkownik

Dołączył(a): 18 cze 2015
Posty: 268
Pomógł: 0

Jeszcze raz wielkie dzięki andrews za tak dokładne i precyzyjne wytłumaczenie tematu.
Myślę, że rozwiało wszelkie wątpliwości. Trochę się napisaliśmy, ale warto było :) . Pozdrawiam wszystkich.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 22 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 0 gości


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO