logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Framework AVR GCC do tablicowego sterowania pinami Atmegi jak w Arduino

fizyk_xyz 23 Sty 2024 22:44 1164 71
Najlepsze odpowiedzi LABEL_AI_GENERATED

Jak w AVR GCC zrobić tablicowy dostęp do pinów Atmegi w stylu Arduino HAL, tak aby jeden zapis kodował DDR, PORT i PIN oraz numer bitu?

Najpraktyczniej zrobić to jako lekki framework makr, w którym pin jest zakodowany jedną stałą, np. `W2B(port,pin)`, a potem przez `B2P()` i `B2B()` wyliczasz dostęp do `DDR`, `PORT` i `PIN`; dzięki temu można trzymać tablice typu `uint8_t diody[] = { W2B(PA,0), ... }` bez rozbijania pinu na trzy osobne definicje [#20925587] Zamiast struktur i większego zużycia RAM lepiej zostać przy `#define` i stałych rozwijanych przez preprocesor, bo to jest „prawie darmowe” pamięciowo, szczególnie na ATtiny [#20925721] Dla czytelności warto nadać makrom bardziej opisowe nazwy, np. `MAKE_PIN`, `GET_PORT`, `GET_PIN`, `PIN_OUTPUT`, `PIN_HIGH`, `PIN_READ`, zamiast mieszać logikę w jednej funkcji lub strukturze [#20925721] Jeśli chcesz automatycznie tworzyć nazwy typu `A0`, `B2` itd., da się to próbować zrobić preprocesorem, ale trzeba pamiętać, że różne AVR mają różną liczbę portów i nie zawsze pełne 8 bitów na port, więc zwykle trzeba dopasować zestaw definicji do konkretnego MCU [#20925553][#20925561] Jeden z uczestników zwrócił też uwagę, że taki „framework” w czystym C jest słabszym pomysłem niż w C++, jeśli chcesz iść w stronę HAL podobnego do Arduino [#20925868]
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
  • #1 20925518
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Zaproponuj framework dla avr gcc tablicowego dostępu do poszczególnych pinów portu w atmegach, podobnie, jak robi to HAL w arduino. Chodzi o to, aby definicje pinów obejmowały adresy rejestrów DDR, PORT i PIN łącznie z bitami danych pinów sprzętowych. Chodzi o to by nie musieć definiować np. pinu kontroli LED czy przycisku jako trzech rejestrów, lecz jednej wartości (niekoniecznie liczbowej jak w Arduino), może być np #define LED A3, gdzie A3 jest odpowiednikiem zarówno DDRA |= (1 << PA3), PORTA |= (1<<PA3) jak i PINA & (1<<PA3). Umożliwi to definiowanie tablic pinów (np. do sterowania wieloma ledami) jako:
    const uint8_t pinLED[] = {A1, B2, D3, C5}; // Ledy na PA1, PB2,PD3 i PC5
  • #2 20925521
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) no), może być np #define LED A3, gdzie A3 jest odpowiednikiem zarówno DDRA |= (1 << PA3), PORTA |= (1<<PA3) jak i PINA & (1<<PA3). Umożliwi to definiowanie tablic pinów (np. do sterowania wieloma ledami) jako:
    const uint8_t pinLED[] = {A1, B2, D3, C5}; // Ledy na PA1, PB2,PD3 i PC5
    Tworzenie takiego frameworku dla AVR GCC, który pozwalałby na wygodny dostęp do poszczególnych pinów w stylu HAL z Arduino, wymaga zastosowania preprocesora C oraz, ewentualnie, niektórych technik z zakresu metaprogramowania w języku C. Poniżej przedstawiam przykładowe rozwiązanie, które może spełniać Twoje wymagania.

    Na początek zdefiniujemy makra, które będą reprezentować piny. Aby to zrobić w sposób umożliwiający późniejszy dostęp do odpowiednich rejestrów za pomocą jednej wartości, zastosujemy struktury i trochę magii preprocesora.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To podejście pozwala na zdefiniowanie pinu jako jednej wartości, która zawiera wszystkie niezbędne informacje do jego sterowania. Możesz teraz używać zdefiniowanych makr do operowania na pinach, np.:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Powyższy kod jest tylko przykładem. Przy tworzeniu takiego frameworku warto rozważyć dodatkowe aspekty, jak obsługa przerwań, konfiguracja pull-upów czy obsługa różnych konfiguracji sprzętowych w zależności od modelu mikrokontrolera. Koniecznie sprawdź kompatybilność z używanym mikrokontrolerem.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #3 20925553
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Bardzo podoba mi się ten sposób (jeśli zadziała), natomiast chciałbym, aby ten framework sam definiował oznaczenia definicji pinów (czyli, żeby nie trzeba było pisać DEFINE_PIN(A0, A, 0); wiadomo, informatycy to leniwi ludzie;). Ustalmy, że Ax to piny poru A, Bx portu B i tak dalej, np C7 to zawsze pin 7 portu C. Czy jesteś w stanie zdefiniować to poprzez preprocesor? I tu nasuwa się jeszcze jedno pytanie: poszczególne AVR mają inne ilości portów jak i pinów na nich (nie wszyskie porty mają po 8 pinów), jak zautomatyzować definicje preprocesora w oparciu o pliki io.h ? Pomożesz, chodzi o wygodą używania frameworku.
  • #4 20925561
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) y jesteś w stanie zdefiniować to poprzez preprocesor? I tu nasuwa się jeszcze jedno pytanie: poszczególne AVR mają inne ilości portów jak i pinów na nich (nie wszyskie porty mają po 8 pinów), jak zautomatyzować definicje preprocesora w oparciu o pliki io.h ? Pomożesz, chodzi o wygodą używania frameworku.
    Oczywiście, mogę pomóc w automatyzacji procesu definiowania pinów. Aby osiągnąć to, co opisałeś, możemy skorzystać z dodatkowej warstwy automatyzacji z wykorzystaniem preprocesora C. Możemy stworzyć zestaw makr, które pozwolą na generowanie definicji pinów na podstawie liter i numerów bez konieczności ręcznego pisania każdego DEFINE_PIN.

    Jednakże, zanim przejdziemy do tworzenia makr, musimy zająć się kwestią różnych ilości portów i pinów w różnych mikrokontrolerach AVR. To wymaga od nas znajomości szczegółów konkretnego modelu mikrokontrolera, z którym pracujemy. Pliki nagłówkowe io.h dla różnych mikrokontrolerów AVR zawierają definicje portów, więc możemy użyć tych informacji do stwierdzenia, jakie porty są dostępne. Jednakże, problem z różną ilością pinów w portach może być trudniejszy do ogólnego rozwiązania, ponieważ preprocesor nie ma możliwości wykonywania pętli lub dynamicznie generowania kodu w zależności od wartości w plikach nagłówkowych.

    Natomiast możemy stworzyć zestaw makr dla najczęściej spotykanych konfiguracji portów (np. 8-pinowych), które będą wymagały niewielkich modyfikacji w przypadku mikrokontrolerów o innych konfiguracjach portów. Poniżej przedstawiam przykład takiego systemu makr dla pełnych 8-bitowych portów:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Używając powyższego systemu, możesz teraz odwołać się do konkretnego pinu przy pomocy `A0`, `B1`, itp., bez konieczności ręcznego definiowania każdego z nich. Jednakże, pamiętaj, że dla mikrokontrolerów z niestandardowymi konfiguracjami portów będziesz musiał dostosować ten system do ich specyfiki.

    Powyższy przykład nie pokrywa wszystkich możliwych przypadków i jest uproszczeniem. W praktyce, może być konieczne stworzenie bardziej złożonych makr, które będą w stanie obsłużyć różne konfiguracje portów i ich dostępność. Implementacja takiego rozwiązania może wymagać głębszej znajomości preprocesora C i specyfik mikrokontrolerów AVR, a także może być konieczna modyfikacja kodu źródłowego w zależności od konkretnego projektu.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #5 20925587
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Ja kiedyś podszedłem do sprawy podobnie, ale nie mając doświadczenia - bardzo zakręcony był mój pomysł. Mógłbyś go ocenić i ewentualnie poprawić na podstawie poniższego kodu:

    /*
    * 01_ARRAY_PINS main.c
    *
    * Autor: Dąbrowski Tomasz
    * Stworzono: 2016-08-01
    * Edycja: 08:28:46
    */



    #include <avr/io.h>
    #include <util/delay.h>



    // *********************** PRZYGOTOWANIE TABLICOWEGO DOSTĘPU DO PINÓW *********************

    //definicje portów umożliwiające działanie w formie numerycznej np.PORT(0)=PORT(PD)=PORTD
    #define PORTS 4
    #define PA 0
    #define PB 1
    #define PC 2
    #define PD 3

    volatile uint8_t *myports[] = { &PORTA, &PORTB, &PORTC, &PORTD };


    #define _DDR(x) _SFR_IO8(_SFR_IO_ADDR(*(myports[x]))-1) // adr. r. kier. DDRx
    #define _PORT(x) _SFR_IO8(_SFR_IO_ADDR(*(myports[x]))) // adr. r. wyj. PORTx
    #define _PIN(x) _SFR_IO8(_SFR_IO_ADDR(*(myports[x]))-2) // adr. r. wej. PINx
    #define DDR(p) _DDR(p)
    #define PORT(p) _PORT(p)
    #define PIN(p) _PIN(p)


    //makro zmiany opisu Px,y np PD,5 na BAJT w formacie xxxxxyyy czyli port 0-31, pin 0-7 i vice-versa
    #define W2B(port,pin) (((port)<<3)|((pin)&0x07))
    #define B2P(bajt) ((bajt)>>3) //bajt to port
    #define B2B(bajt) ((bajt)&(0x07)) //bajt to bity

    //makra obsługi pinów w formacie LOW_A(W2B(PA,3))
    #define OUTPUT_A(pin) (DDR(B2P(pin)) |= (1 << (B2B(pin))))
    #define INPUT_A(pin) (DDR(B2P(pin)) &= ~ (1 << (B2B(pin))))
    #define HIGH_A(pin) (PORT(B2P(pin)) |= (1 << (B2B(pin))))
    #define LOW_A(pin) (PORT(B2P(pin)) &= ~ (1 << (B2B(pin))))
    #define TOGGLE_A(pin) (PORT(B2P(pin)) ^= (1 << (B2B(pin))))
    #define READ_A(pin) ((PIN(B2P(pin)) >> (B2B(pin))) & 1)

    //*************************** MOŻNA WYODRĘBNIĆ DO PLIKU NAGŁÓWKOWEGO ************


    //************************** PROGRAM WŁAŚCIWY - WYKORZYSTANIE ******************

    //definicja przez tablicę
    uint8_t diody[] = { W2B(PA,0), W2B(PA,1), W2B(PA,2), W2B(PA,3), W2B(PA,4), W2B(PA,5), W2B(PA,6), W2B(PA,7),
    W2B(PB,0), W2B(PB,1), W2B(PB,2), W2B(PB,3), W2B(PB,4), W2B(PB,5), W2B(PB,6), W2B(PB,7),
    W2B(PC,0), W2B(PC,1), W2B(PC,2), W2B(PC,3), W2B(PC,4), W2B(PC,5), W2B(PC,6), W2B(PC,7),
    W2B(PD,0), W2B(PD,1), W2B(PD,2), W2B(PD,3), W2B(PD,4), W2B(PD,5), W2B(PD,6), W2B(PD,7)};


    uint8_t nrLed;
    #define T_LEDON 200
    #define T_LEDOFF 5
    //zwykła definicja pinu
    #define blinkLed W2B(PD,7)


    int main(void) //rozpoczynamy
    {

    for(nrLed=0;nrLed<sizeof(diody);nrLed++) //ustawiamy nóżnki AVR na wyjścia
    {
    OUTPUT_A(diody[nrLed]);
    }

    while(1) //pętla nieskończona
    {

    for(nrLed=0;nrLed<sizeof(diody);nrLed++) //zapalamy i gasimy kolejne diody od w tablicy
    {
    HIGH_A(diody[nrLed]);
    _delay_ms(T_LEDON);
    LOW_A(diody[nrLed]);
    _delay_ms(T_LEDOFF);
    TOGGLE_A(blinkLed); //migająca podstawa litery L
    }


    }
    }
  • #6 20925589
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) diody[nrLed]);
    _delay_ms(T_LEDON);
    LOW_A(diody[nrLed]);
    _delay_ms(T_LEDOFF);
    TOGGLE_A(blinkLed); //migająca podstawa litery L
    }


    }
    }
    Twój kod wykorzystuje kreatywne podejście do mapowania pinów mikrokontrolera na struktury, które można łatwo używać w programie. Chociaż metoda, którą zaproponowałeś, jest funkcjonalna, to istnieje kilka obszarów, które można ulepszyć, aby kod był bardziej zwięzły i czytelny. Oto kilka sugestii:

    1. Uproszczenie makr: Twoje makra wykorzystują zamianę wartości między formatami (port i pin na bajt i odwrotnie), co wprowadza dodatkową warstwę abstrakcji, ale może być mylące dla innych użytkowników kodu. Można to uprościć, używając bezpośrednio struktur, jak w poprzednim przykładzie.

    2. Zautomatyzowanie generacji definicji pinów: Zamiast ręcznie definiować każdy pin, możemy zastosować system makr, aby zautomatyzować proces na podstawie dostępnych portów.

    3. Zarządzanie dostępnością portów: Twoje makra zakładają, że wszystkie porty są dostępne, co w praktyce może nie być prawdą dla każdego mikrokontrolera AVR. Możesz użyć warunków preprocesora, aby sprawdzić, czy porty są dostępne, zanim zdefiniujesz do nich dostęp.

    Oto przykład ulepszonego kodu, który zawiera te zmiany:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ten kod jest bardziej zwięzły i czytelny. Automatyzuje definicję pinów na podstawie dostępnych portów, eliminując konieczność ręcznej ich definicji za pomocą makra `W2B`. Ponadto, upraszcza interakcję z pinami, korzystając bezpośrednio ze struktur `Pin`, zamiast konwertować wartości między różnymi formatami.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #7 20925720
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Przypomniałam sobie, że moje podejście zajmuje mniej cennej pamięci RAM, zwłaszcza w serii ATiny. Jednak struktury do każdego pinu zajmą 4 bajty wg Twojego pomysłu, natomiast wykorzystanie stałych dosłownych przetworzonych przez preprocesor są prawie "darmowe". Czy mógłbyś tak zmodyfikować moje podejście oparte o #define, aby było bardziej czytelne ?
  • #8 20925721
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    Przypomniałam sobie, że moje podejście zajmuje mniej cennej pamięci RAM, zwłaszcza w serii ATiny. Jednak struktury do każdego pinu zajmą 4 bajty wg Twojego pomysłu, natomiast wykorzystanie stałych dosłownych przetworzonych przez preprocesor są prawie "darmowe". Czy mógłbyś tak zmodyfikować moje podejście oparte o #define, aby było bardziej czytelne ?
    Rozumiem Twoje obawy dotyczące zużycia pamięci RAM, zwłaszcza w mikrokontrolerach z serii ATtiny, które mają ograniczone zasoby. W takim przypadku, wykorzystanie makr preprocesora, które przetwarzane są w czasie kompilacji i nie zajmują miejsca w RAM, jest rozsądnym podejściem.

    Twoje makra są już dość efektywne, ale mogę zaproponować kilka ulepszeń, które mogą uczynić kod bardziej czytelnym i elastycznym. Poniżej prezentuję zmodyfikowaną wersję Twoich makr z dodatkowymi komentarzami i lepszą strukturą:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Powyższy kod skupia się na poprawie czytelności poprzez bardziej deskryptywne nazewnictwo makr i użycie stałych zamiast magicznych liczb. Makra `MAKE_PIN`, `GET_PORT` i `GET_PIN` pozwalają na intuicyjne tworzenie i dekodowanie "wartości pinu", podczas gdy makra takie jak `PIN_OUTPUT`, `PIN_INPUT`, `PIN_HIGH`, `PIN_LOW`, `PIN_TOGGLE`, `PIN_READ` zapewniają proste interfejsy do manipulacji stanem pinów.

    Pamiętaj, aby dostosować tablicę `port_registers`, dodając lub usuwając wskaźniki do rejestrów portów, w zależności od mikrokontrolera, którego używasz. Nie wszystkie mikrokontrolery AVR będą miały porty A, B, C, i D, więc musisz to sprawdzić w dokumentacji swojego układu.

    Dzięki tym zmianom kod powinien być teraz bardziej czytelny, a jednocześnie nadal efektywny pod względem wykorzystania pamięci RAM.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #9 20925868
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1464
    Szukanie ratunku, wręcz konstrukcji "frameworku" w C to jeden ze słabszych pomysłów, zwłaszcza że

    fizyk_xyz napisał:
    jak robi to HAL w arduino


    Arduino to C++


    Wbrew opowieściom nie czają się tam diabły ... (a wręcz za samą zmianę typu projektu na C++ zaoszczędziłem 2B danych i ok 6 bajtów kodu - Atmega 8)
  • #10 20926586
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5

    @ElektrodaBot Czy można w jakiś sposób skryptem Python/AutoIt3 wprowadzić schemat do aplikacji Proteus firmy Labcenter? Jeśli znasz API lub inne metody, chętnie poznam te możliwości skryptowania. Możesz przytoczyć przykład, który wybiera z Part Managera Atmegę 8 i podłącza LED z rezystorem anodą do pinu PB3?
  • #11 20926592
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    Czy można w jakiś sposób skryptem python/Autoit3 wprowadzić schemat do aplikacji Proteus firmy Labcenter? Jeśli znasz API lub inne metody z chęcią poznam te mozliwości skryptowania. Możesz przytoczyć przykład, który wybiera z Part managera Atmegę 8 i podłącza LED z rezystorem anodą do pinu PB3 ?
    Proteus firmy Labcenter to popularne oprogramowanie do projektowania i symulacji układów elektronicznych. Niestety, Proteus nie posiada oficjalnego API do skryptowania, które umożliwiałoby bezpośrednie manipulowanie schematem za pomocą zewnętrznych skryptów, takich jak Python czy AutoIt. Funkcjonalność skryptowania w Proteusie jest bardzo ograniczona i głównie pozwala na tworzenie własnych modeli urządzeń (np. w języku VHDL lub w postaci działających modeli DLL).

    Jednakże, istnieją nieoficjalne metody, które mogą być użyte do automatyzacji niektórych zadań w Proteusie, chociaż mogą one wymagać zaawansowanej wiedzy i bycia kreatywnym w znajdowaniu obejść:

    1. Automatyzacja GUI: Możesz użyć narzędzi do automatyzacji interfejsu użytkownika, takich jak AutoIt lub inne narzędzia do symulacji kliknięć myszy i nacisków klawiatury, aby programowo sterować Proteusem. Jednakże, takie podejście jest podatne na błędy i może nie być stabilne.

    2. Modyfikacja plików projektu: Proteus przechowuje projekty w plikach z rozszerzeniem .DSN i .LYT, które są w formacie tekstowym. Możliwe jest napisanie skryptu, który modyfikuje te pliki bezpośrednio, dodając lub zmieniając komponenty i ich połączenia. Skrypt musiałby być jednak precyzyjnie dopasowany do struktury plików projektu Proteusa.

    3. Wykorzystanie makr: Proteus ma wbudowaną funkcję makr, gdzie można zapisać serię akcji i później je odtworzyć, ale jej możliwości są raczej ograniczone do prostych operacji.

    Jeśli interesuje Cię opcja automatyzacji interfejsu użytkownika, mogę przedstawić przykładowy pseudokod, jak można by to zrobić w AutoIt:

    Kod: Text
    Zaloguj się, aby zobaczyć kod


    Należy podkreślić, że powyższy pseudokod jest jedynie ilustracją i wymagałby dostosowania do konkretnych koordynatów i procedur działania Proteusa.

    Bez oficjalnego API, każda próba automatyki będzie nieoficjalnym obejściem i nie może być gwarantowana jako niezawodna ani polecana do poważnego zastosowania inżynieryjnego. W związku z tym, najlepszą praktyką jest ręczne tworzenie schematów w środowisku Proteusa.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #12 20926633
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Od niedawna Wokwi wspiera tworzenie własnych układów (custom chip), pomożesz stworzyć układ 74HC245 w języku c. Poniżej masz szablon programu, uzupełnij o działający kod bramek 74hc245 oraz stwórz plik json opisujący układ od strony pinout:

    // Wokwi Custom Chip - For docs and examples see:
    // https://docs.wokwi.com/chips-api/getting-started
    //
    // SPDX-License-Identifier: MIT

    #include "wokwi-api.h"
    #include <stdio.h>
    #include <stdlib.h>

    typedef struct {
    // TODO: Put your chip variables here
    } chip_state_t;

    void chip_init() {
    chip_state_t *chip = malloc(sizeof(chip_state_t));

    // TODO: Initialize the chip, set up IO pins, create timers, etc.

    printf("Hello from custom chip!\n");
    }
  • #13 20926643
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) io.h>
    #include <stdlib.h>

    typedef struct {
    // TODO: Put your chip variables here
    } chip_state_t;

    void chip_init() {
    chip_state_t *chip = malloc(sizeof(chip_state_t));

    // TODO: Initialize the chip, set up IO pins, create timers, etc.

    printf("Hello from custom chip!\n");
    }
    Aby stworzyć własny układ 74HC245 w Wokwi, musimy zrozumieć jego funkcjonalność. Układ 74HC245 to ośmiokanałowy, dwukierunkowy bufor/sterownik linii z trójstanowymi wyjściami, który zazwyczaj jest używany do przesyłania danych między dwoma magistralami. Posiada wejście kierunku (DIR), wejście zezwalające na wyjście (OE), osiem wejść/wyjść danych (A1-A8 i B1-B8) oraz zasilanie (VCC) i masę (GND).

    Przedstawię kod w C, który będzie symulował zachowanie układu 74HC245, a także plik JSON, który opisuje jego pinout. Zacznijmy od uzupełnienia kodu C:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Teraz, aby zdefiniować pinout układu w formacie JSON dla Wokwi, załóżmy, że piny są numerowane od 1 do 20 i tworzymy plik JSON:

    Kod: JSON
    Zaloguj się, aby zobaczyć kod


    Powyższy kod i definicja JSON są przykładowe i należy je dostosować do rzeczywistych wymagań symulacji w Wokwi. Przykład zakłada, że piny A1 do A8 są na pinach 1 do 8, piny B1 do B8 na pinach 9 do 16, pin DIR to pin 18, OE to pin 19, a VCC i GND to piny 20 i 10 odpowiednio. Rzeczywiste koordynaty x i y powinny zostać dostosowane, aby odpowiadały graficznemu przedstawieniu Twojego komponentu w edytorze Wokwi.

    Nie zapomnij przetestować swojego układu w symulatorze, aby upewnić się, że zachowuje się on zgodnie z oczekiwaniami.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #14 20927314
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Do programatora TL866II plus jest projekt oprogramowania alternatywnego https://gitlab.com/DavidGriffith/minipro, pomożesz mi go skompilować w cygwin na windows 10? Podaj kolejne kroki do kompilacji źródła, lub zaproponuj jakiś kompilator online, który sobie z tym poradzi pod (plik wykonywalny pod Windows).
  • #15 20927317
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    Do programatora TL866II plus jest projekt oprogramowania alternatywnego https://gitlab.com/DavidGriffith/minipro, pomożesz mi go skompilować w cygwin na windows 10? Podaj kolejne kroki do kompilacji źródła, lub zaproponuj jakiś kompilator online, który sobie z tym poradzi pod (plik wykonywalny pod Windows).
    Kompilacja oprogramowania `minipro` w środowisku Cygwin na Windows 10 wymaga zainstalowania odpowiednich pakietów i bibliotek. Oto kroki, które można podjąć, aby skompilować ten projekt:

    1. Instalacja Cygwina:
    - Pobierz instalator Cygwin z oficjalnej strony: [https://www.cygwin.com/](https://www.cygwin.com/).
    - Uruchom instalator i postępuj zgodnie z instrukcjami, wybierz pakiet deweloperski (np. `gcc`, `make`, `git`) oraz dodatkowe biblioteki niezbędne do kompilacji (np. `libusb1.0`).

    2. Pobranie kodu źródłowego `minipro`:
    - Uruchom Cygwin Terminal.
    - Zainstaluj `git` (jeśli jeszcze tego nie zrobiłeś) wpisując: `apt-cyg install git`.
    - Sklonuj repozytorium `minipro` wpisując: `git clone https://gitlab.com/DavidGriffith/minipro.git`.

    3. Instalacja zależności:
    - Zainstaluj potrzebne pakiety kompilatora i bibliotek: `apt-cyg install make gcc-core gcc-g++ libusb1.0-devel`.

    4. Kompilacja:
    - Przejdź do katalogu `minipro` za pomocą `cd minipro`.
    - Uruchom `make` aby skompilować projekt. Powinno to stworzyć plik wykonywalny `minipro` w katalogu.

    Alternatywnie, jeśli napotkasz problemy z kompilacją w Cygwin lub wolisz nie instalować dodatkowego oprogramowania, możesz skorzystać z gotowego pliku wykonywalnego dla Windows dostępnego w sekcji "Releases" na stronie projektu `minipro` w GitLab, o ile taki istnieje.

    Aktualnie nie istnieją popularne usługi kompilacji online, które obsługują tworzenie plików wykonywalnych dla Windows z kodu źródłowego, głównie ze względu na potrzebę specyficznych zależności i konfiguracji środowiska kompilacji. W takim przypadku zalecałbym użycie lokalnego środowiska kompilacji, takiego jak Cygwin lub WSL (Windows Subsystem for Linux).

    Jeśli natomiast `minipro` nie zapewniałby gotowego pliku wykonywalnego i kompilacja w Cygwin by nie powiodła się, alternatywną opcją jest użycie WSL, które oferuje bardziej natywne środowisko typu Linux na Windowsie i może lepiej radzić sobie z kompilacją projektów przewidzianych dla systemów typu Unix.

    WSL (Windows Subsystem for Linux):
    - Włącz funkcję WSL w funkcjach systemu Windows.
    - Zainstaluj dystrybucję Linux z Microsoft Store (np. Ubuntu).
    - Otwórz terminal Linux i zainstaluj potrzebne pakiety (`build-essential`, `libusb-1.0-0-dev`, `pkg-config`, `git`).
    - Sklonuj i skompiluj `minipro` tak jak opisano powyżej.

    Mam nadzieję, że te instrukcje pomogą Ci skompilować projekt `minipro` w systemie Windows. Jeśli napotkasz jakiekolwiek problemy, daj mi znać, a postaram się dalej pomóc.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #16 20930973
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Wytłumacz, jak działa algorytm Zellera do znalezienia dnia tygodnia na podstawie roku, miesiąca i dnia miesiąca.
  • #17 20930974
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    Wytłumacz jak działa algorytm Zellera do znalezienia dnia tygodnia na podstawie roku, miesiąca i dnia miesiąca.
    Algorytm Zellera to metoda obliczeniowa, która pozwala na znalezienie dnia tygodnia dla dowolnej daty. Został on opracowany przez niemieckiego matematyka Christiana Zellera. Algorytm jest dość prosty w implementacji i może być zastosowany zarówno do dat gregoriańskich (po roku 1582), jak i juliańskich (przed rokiem 1582). Istnieją dwie wersje algorytmu Zellera: jedna dla kalendarza gregoriańskiego i druga dla kalendarza juliańskiego. Tutaj skupimy się na wersji gregoriańskiej.

    ### Jak działa algorytm Zellera?

    Algorytm opiera się na kilku krokach matematycznych, które ostatecznie prowadzą do obliczenia dnia tygodnia. Najpierw jednak potrzebujemy wstępnie dostosować dane wejściowe:

    1. Dostosowanie miesiąca i roku: Jeśli miesiąc to styczeń lub luty, traktujemy je jako 13. i 14. miesiąc poprzedniego roku. Na przykład 14 lutego 2021 będzie traktowane jako 14. dzień 14. miesiąca 2020. Dzięki temu unikamy problemów z datami wokół początku roku.

    2. Obliczenia: Następnie wykonujemy obliczenia według wzoru:
    $$ h = (q + \left\lfloor\frac{13(m+1)}{5}\right\rfloor + K + \left\lfloor\frac{K}{4}\right\rfloor + \left\lfloor\frac{J}{4}\right\rfloor - 2J) \mod 7 $$
    gdzie:
    - $$q$$ to dzień miesiąca,
    - $$m$$ to miesiąc (3=marzec, 4=kwiecień, ..., 12=grudzień, styczeń=13, luty=14),
    - $$K$$ to rok w stuleciu ($$rok \mod 100$$),
    - $$J$$ to zero-based liczba stuleci ($$\left\lfloor\frac{rok}{100}\right\rfloor$$).

    3. Interpretacja wyniku: Wartość $$h$$ to dzień tygodnia, gdzie 0 = sobota, 1 = niedziela, 2 = poniedziałek, ..., 6 = piątek.

    ### Przykład

    Znajdź dzień tygodnia dla 4 lipca 2021 roku:

    1. Miesiąc lipiec to miesiąc 7, więc nie musimy dostosowywać daty.
    2. Rok 2021, więc $$K=21$$ i $$J=20$$.
    3. Podstawiając do wzoru:
    $$ h = (4 + \left\lfloor\frac{13(7+1)}{5}\right\rfloor + 21 + \left\lfloor\frac{21}{4}\right\rfloor + \left\lfloor\frac{20}{4}\right\rfloor - 2 \cdot 20) \mod 7 = 0 $$
    Oznacza to, że 4 lipca 2021 roku był sobotą.

    Algorytm Zellera jest przydatnym narzędziem, szczególnie w sytuacjach, gdy potrzebujemy szybkiego sposobu obliczenia dnia tygodnia w głowie lub przy użyciu prostego kodu programistycznego. Może również posłużyć jako ciekawe ćwiczenie z programowania.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #18 20930978
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot, skąd się wzięła liczba 13 we wzorze?
  • #19 20930979
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    skąd się wzięła liczba 13 we wzorze?
    Liczba 13 we wzorze algorytmu Zellera odgrywa kluczową rolę w obliczaniu dnia tygodnia i pochodzi z metody rozłożenia miesięcy na równomiernie rozłożone okresy w ciągu roku.

    W algorytmie Zellera, miesiące są traktowane w niestandardowy sposób, gdzie styczeń i luty są liczonymi jako 13 i 14 miesiąc poprzedniego roku. Dzieje się tak, aby umożliwić skuteczne obliczenia dla dat wokół nowego roku oraz uwzględnić sposób, w jaki rok przestępny wpływa na dni tygodnia w styczniu i lutym.

    Część wzoru $$\left\lfloor\frac{13(m+1)}{5}\right\rfloor$$, gdzie $$m$$ to miesiąc (z tą szczególną obsługą stycznia i lutego), jest wykorzystywana do uwzględnienia wpływu, jaki miesiąc ma na dzień tygodnia. Liczba 13 pojawia się tutaj, ponieważ:

    - Kiedy analizujemy rok pod kątem miesięcy i dni tygodnia, zauważamy, że miesiące nie są równomiernie rozłożone. Niektóre miesiące mają 30 dni, inne 31, a luty ma 28 lub 29 dni. Jednak przez większość roku, każdy miesiąc przesuwa dzień tygodnia o pewną liczbę dni (np. jeśli 1 marca to poniedziałek, to 1 kwietnia nie będzie poniedziałkiem).
    - Liczba 13 pomaga rozłożyć te różnice równomiernie przez rok, tworząc rodzaj "sztucznego" miesiąca, który ułatwia obliczenia.
    - Efektywnie, każdy miesiąc „przesuwa” dzień tygodnia o pewną liczbę dni. Wzór wykorzystuje 13, aby zapewnić, że te przesunięcia są rozłożone równomiernie i matematycznie dokładne dla celów obliczeń.
    - Ponadto, mnożąc miesiąc (z odpowiednim przesunięciem dla stycznia i lutego) przez 13 i dodając 1 przed podzieleniem przez 5, algorytm „symuluje” naturalny przepływ czasu i wpływ miesięcy na przesunięcie dni tygodnia.

    W praktyce, użycie liczby 13 w tym wzorze jest wynikiem matematycznego uogólnienia, które pozwala algorytmowi Zellera skutecznie przewidywać dzień tygodnia dla dowolnej daty w kalendarzu gregoriańskim, uwzględniając nieregularne długości miesięcy oraz specjalne traktowanie stycznia i lutego.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #20 20931022
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot Mam napisany moduł operacji na czasie, ale brakuje mi w nim funkcji obliczenia nr tygodnia w standardzie ISO. Zaproponował być kod w c dla AVR GCC z uwzględnieniem małych ilości RAM na uC Atiny, ATmega oraz oparty na arytmetyce liczb całkowitych (zmienno przecinkowe liczby są nie efektywne na AVR i większości uC) ?
  • #21 20931028
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    Mam napisany moduł operacji na czasie, ale brakuje mi w nim funkcji obliczenia nr tygodnia w standardzie ISO. Zaproponował być kod w c dla AVR GCC z uwzględnieniem małych ilości RAM na uC Atiny, ATmega oraz oparty na arytmetyce liczb całkowitych (zmienno przecinkowe liczby są nie efektywne na AVR i większości uC) ?
    Obliczenie numeru tygodnia w standardzie ISO 8601 na mikrokontrolerach AVR, takich jak ATtiny lub ATmega, wymaga uwzględnienia kilku istotnych ograniczeń, takich jak ograniczona ilość pamięci RAM i konieczność unikania operacji na liczbach zmiennoprzecinkowych. Standard ISO 8601 określa pierwszy tydzień roku jako ten, który zawiera pierwszy czwartek roku. Co więcej, numer tygodnia zaczynamy liczyć od 1.

    Poniżej znajdziesz propozycję implementacji funkcji obliczającej numer tygodnia w standardzie ISO 8601, opartej wyłącznie na arytmetyce liczb całkowitych:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Warto zwrócić uwagę, że powyższa implementacja opiera się na kilku założeniach i uproszczeniach:

    - Funkcja `dayOfWeek` służy do obliczenia dnia tygodnia danej daty i jest oparta na zmodyfikowanym algorytmie Zellera, dostosowanym do standardu ISO (tj. tydzień zaczyna się od poniedziałka).
    - Funkcja `weekNumberISO` oblicza numer tygodnia w standardzie ISO 8601. Obejmuje ona obliczenie numeru dnia roku, a następnie wykorzystuje tę informację oraz dzień tygodnia 1 stycznia, aby określić numer tygodnia.
    - Funkcja uwzględnia specjalne przypadki, takie jak początek i koniec roku, oraz przestępność roku w przypadku lutego.

    Taka implementacja powinna być efektywna na mikrokontrolerach AVR, nie wymaga operacji na liczbach zmiennoprzecinkowych i minimalizuje użycie pamięci RAM.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #22 20931038
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5

    @ElektrodaBot Hej, mam jeszcze problem z obsługą 1Wire, chodzi o termometry DS18B20, gdzie po zadaniu pomiaru trzeba czekać do 750 ms do konwersji i odczytu temperatury. Jaki zaproponowałbyś kod (AVR GCC), aby nie trzeba było używać delay'a (może pooling lub maszynę stanu)? Przy okazji przedstaw optymalną (bez zmiennoprzecinkowych liczb) konwersję danych ze scratchpad'a na stopnie (może być złożeniem liczb całkowitych jako stopnie i części ułamkowe).
  • #23 20931040
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) odczytu temperatury. Jaki zaproponowałbyś kod (AVR GCC), aby nie trzeba było używać delay'a (może pooling lub maszynę stanu) ? Przy okazji przedstaw optymalną (bez zmiennoprzecinkowych liczb) konwersję danych ze scratpad'a na stopnie (może być złożeniem liczb całkowitych jako stopnie i części ułamkowe).
    Do obsługi termometrów DS18B20 bez blokowania wykonywania programu (czyli bez użycia funkcji `delay`), możemy zastosować technikę opartą na maszynie stanów oraz polling (odpytywanie) z wykorzystaniem timera. Wykorzystanie timera pozwoli na asynchroniczne czekanie na zakończenie konwersji temperatury, dzięki czemu mikrokontroler może wykonywać inne zadania w tym czasie. Poniżej znajdziesz przykładową implementację w C dla AVR GCC.

    Zakładam, że masz już funkcję do inicjacji pomiaru oraz odczytu wyniku z DS18B20 oraz obsługę 1Wire. Skupimy się na strukturze programu umożliwiającej asynchroniczny odczyt.

    ### Kroki do implementacji maszyny stanów z wykorzystaniem timera

    1. Inicjacja timera - Skonfiguruj timer tak, aby generował przerwania z odpowiednią częstotliwością. Na przykład, jeśli chcesz odpytywać stan DS18B20 co 100 ms, ustaw timer odpowiednio do tego celu.

    2. Definicja maszyny stanów - Zdefiniuj stany, w jakich może znajdować się Twój program podczas odczytu temperatury, np. `IDLE` (bezczynność), `INIT_CONVERSION` (inicjacja konwersji), `WAIT_FOR_CONVERSION` (oczekiwanie na konwersję), `READ_TEMPERATURE` (odczyt temperatury).

    3. Obsługa przerwania timera - W funkcji obsługi przerwania timera zmieniaj stany maszyny w zależności od upływu czasu i wykonuj odpowiednie akcje dla każdego stanu.

    4. Konwersja odczytanych danych - Do konwersji danych ze scratchpad'a na stopnie Celsjusza użyj arytmetyki liczb całkowitych, pamiętając o rozdzielczości DS18B20 i ewentualnej konieczności obsługi wartości ujemnych.

    ### Przykładowa implementacja

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Warto zaznaczyć, że powyższy kod to uproszczony przykład mający na celu ilustrację koncepcji. W rzeczywistości, należy dostosować konfigurację timera, obsługę 1Wire i DS18B20 do swojego środowiska i konkretnych wymagań sprzętowych. Funkcje `ds18b20_start_conversion` i `ds18b20_read_temperature` należy zaimplementować zgodnie z protokołem 1Wire i specyfikacją DS18B20, co może wymagać dodatkowej obsługi błędów i szczegółów komunikacji.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #24 20931048
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5

    @ElektrodaBot Jak w czystym C (AVR GCC) wyglądałaby funkcja millis() ?, a może pokaż też 2 podejścia (listing), gdzie milisekundy to zmienna globalna np. millis. Wykorzystaj timer do przerwania dostępnego na każdym AVR.
  • #25 20931050
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    Jak w czystym C (AVR GCC) wyglądała by funkcja millis() ?, a może pokaż też 2 podejście (listing), gdzie milisekundy to zmienna globalna np millis. Wykorzystaj timer do przerwać dostępny na każdym AVR.
    W AVR GCC, funkcja podobna do `millis()` z Arduino, która zwraca liczbę milisekund od startu programu, może być zaimplementowana z wykorzystaniem timera i przerwań. W systemach mikrokontrolerów AVR, takich jak ATmega328P, często wykorzystuje się Timer1 lub inny dostępny timer do generowania przerwań co określony czas. Poniżej przedstawię dwa podejścia do realizacji funkcji `millis()`.

    ### Podejście 1: Funkcja `millis()` zwracająca liczbę milisekund

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    ### Podejście 2: Zmienna globalna `millis`

    W drugim podejściu, zamiast funkcji `millis()`, bezpośrednio korzystamy z zmiennej globalnej `timer_millis`, dbając o to, aby podczas odczytu tymczasowo blokować przerwania (aby uniknąć problemów związanych z równoczesnym dostępem do zmiennej z różnych kontekstów wykonania).

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    ### Uwagi

    - Wartość `TCNT0`, preskaler oraz co ile przerwanie timer ma być generowane, należy dostosować do konkretnej częstotliwości zegara mikrokontrolera, aby móc precyzyjnie zliczać milisekundy. W przykładach przyjęto, że przerwanie generowane jest co około 1 ms, ale w rzeczywistości może być potrzebna kalibracja, zależnie od konfiguracji sprzętowej.

    - Funkcja `cli()` i `sei()` służą do blokowania i odblokowywania przerwań. Jest to kluczowe podczas odczytywania lub zapisywania wartości `timer_millis`, by uniknąć problemów związanych z równoczesnym dostępem do tej zmiennej z różnych kontekstów (np. główna pętla programu i obsługa przerwania).

    - Pamiętaj, że używanie przerwań i dostępu do zmiennych w nich zwiększa zużycie zasobów mikrokontrolera. Projektując system czasu rzeczywistego, zawsze bierz pod uwagę ograniczenia swojego mikrokontrolera.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #26 20931070
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5

    @ElektrodaBot Nasunęły mi się jeszcze dwie kwestie podczas naszej rozmowy:

    1) W listingu ISO week użyłeś linii dayOfYear += 28 + (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
    zabiegu, który ja od dawna stosuję eliminując, gdzie możliwe instrukcje warunkowe. Jestem przekonany, że procesorom i uC łatwiej się liczy niż skacze po adresach pamięci odkładając je na stos. Dlatego często używam metody porównania dającej 1 lub 0 (true/false) i wklejam do równania. Na przykład liczbę dni miesiąca roku nie przestępnego obliczam tak #define MONTHSIZE1(month) (30+((month)+((month)>7))%2-((month)==2)*2). Oczywistym jest, że jest to mniej czytelne, ale bardziej wydajne. Czy możesz to zweryfikować w asemblerze na uC ATmega?

    2) Jak formatować liczby z zerami wiodącymi (najlepiej bez sprintf zajmującego dużo FLASH), zwłaszcza w wypadkach jakie podałeś przy DS18B20 int16_t fraction = (temperature & 0xF) * 625; // Część ułamkowa, 625 = 0.0625 * 10000, przecież gdybyśmy wyświetlili samą liczbę po przecinku mielibyśmy 0.625 zamiast 0.0625 ?
  • #27 20931076
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) matować liczby z zerami wiodącymi (najlepiej bez sprintf zajmującego dużo FLASH), zwłaszcza w wypadkach jaki podałeś przy DS18B20 int16_t fraction = (temperature & 0xF) * 625; // Część ułamkowa, 625 = 0.0625 * 10000, przecież gdybyśmy wyświetlili samą liczbę po przecinku mielibyśmy 0.625 zamiast 0.0625 ?
    ### 1) Weryfikacja w asemblerze na uC ATmega

    Aby zweryfikować efektywność twojego podejścia w asemblerze na mikrokontrolerach ATmega, zróbmy krótkie porównanie. Mikrokontrolery AVR, jak ATmega, faktycznie pracują efektywniej wykonując operacje arytmetyczne i logiczne bezpośrednio na rejestrach niż wykonując skoki warunkowe, które mogą wprowadzać opóźnienia związane z przewidywaniem skoków i zarządzaniem stosami.

    Instrukcje warunkowe, jak `if()` w C, przekształcane są przez kompilator do skoków warunkowych w asemblerze, co może wprowadzać opóźnienia, zwłaszcza gdy przewidywanie skoku nie działa efektywnie. Z kolei operacje arytmetyczne i logiczne, które wprost zwracają wartość 0 lub 1, są kompilowane do prostych i szybkich instrukcji, które nie wymagają skoków i są bezpośrednio wykonywane na rejestrach.

    Porównując oba podejścia na poziomie asemblera, operacje matematyczne i logiczne na ogół będą zajmować mniej cykli zegara niż sekwencje instrukcji związane ze skokami warunkowymi. Dlatego twoje podejście, pomimo mniejszej czytelności, może być bardziej wydajne na mikrokontrolerach z rodziny AVR. Aby uzyskać dokładne porównanie, najlepiej jest skompilować oba fragmenty kodu i przeanalizować wygenerowany kod maszynowy za pomocą narzędzia takiego jak `avr-objdump`.

    ### 2) Formatowanie liczb z zerami wiodącymi bez `sprintf()`

    Aby sformatować liczby z zerami wiodącymi bez użycia funkcji `sprintf()`, która faktycznie może zajmować znaczny obszar pamięci FLASH, można użyć prostych operacji arytmetycznych i logicznych w połączeniu z pętlami lub rekurencją. Oto przykład funkcji formatującej część ułamkową temperatury z DS18B20 jako ciąg znaków, z uwzględnieniem zer wiodących:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    W powyższym przykładzie, funkcja `formatFraction` przyjmuje liczbę reprezentującą część ułamkową temperatury i bufor, do którego zapisywany jest sformatowany ciąg znaków. Ta metoda pozwala na zachowanie zer wiodących bez konieczności użycia ciężkich funkcji formatujących. Należy jednak pamiętać o dostosowaniu rozmiaru bufora do maksymalnej możliwej długości sformatowanej wartości.

    Takie podejście jest znacznie bardziej efektywne pod względem wykorzystania pamięci FLASH i czasu wykonania, zwłaszcza w systemach wbudowanych, gdzie zasoby są ograniczone.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #28 20931089
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5

    @ElektrodaBot Wracając do DS18b20, pokazało się wiele podróbek, w tym takie, które przy standardowej obsłudze 1Wire blokują magistrale. Czy jeżeli elektronicznie podłączenie jest sprawne, zaproponujesz listing (AVR GCC) testujący taką "obciążoną" magistralę wyświetlający adresy odczytanych termometrów, ich parametry i temperatury oraz szacunek, który z nich to fake. Program ma możliwie najwięcej nieprawidłowości wychwycić (obsługa błędów).
  • #29 20931094
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8880
    Pomógł: 364
    Ocena: 954
    LABEL_AI_GENERATED
    fizyk_xyz napisał:
    (...) y jeżeli elektronicznie podłączenie jest sprawne, zaproponujesz listing (AVR GCC) testujący taka "obciążoną" magistralę wyświetlający adresy odczytanych termometrów, ich parametry i temperatury oraz szacunek, który z nich to fake. Program ma możliwie najwięcej nieprawidłowości wychwycić (obsługa błędów).
    Rozpoznanie podróbek DS18B20 wymaga zaimplementowania kilku kluczowych funkcji: inicjalizacji magistrali 1-Wire, wykrywania urządzeń na magistrali, odczytu ich adresów, konfiguracji, odczytu temperatury oraz analizy otrzymanych danych pod kątem zgodności ze specyfikacją oryginalnych komponentów. Poniżej znajdziesz przykładowy kod, który implementuje podstawową obsługę magistrali 1-Wire z użyciem mikrokontrolera AVR (np. ATmega328P) oraz przedstawia podstawową obsługę błędów. Proszę jednak zauważyć, że detekcja podróbek nie jest prosta i wymaga analizy zachowania urządzeń na magistrali, które mogą różnić się w zależności od konkretnego egzemplarza podróbki.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ten kod jest uproszczony i zakłada, że funkcje takie jak `onewire_reset`, `ds18b20_read_rom`, `ds18b20_start_conversion_by_address` oraz `ds18b20_read_temperature_by_address` są już zaimplementowane i prawidłowo obsługują magistralę 1-Wire oraz komunikację z termometrami DS18B20. Należy również zaimplementować funkcje do obsługi UART, aby możliwe było wyświetlanie wyników.

    ### Analiza podróbek

    - Sprawdź CRC: Oryginalne DS18B20 mają wbudowany mechanizm sprawdzania CRC adresu ROM, co może być pierwszym krokiem do weryfikacji autentyczności urządzenia. Funkcje biblioteczne często już zawierają mechanizmy do weryfikacji CRC.
    - Analiza czasu konwersji: Niektóre podróbki mogą mieć inny czas konwersji niż oryginalne urządzenia. Można zmierzyć czas od momentu rozpoczęcia konwersji do momentu, gdy linia danych staje się ponownie wolna, i porównać z oczekiwanym czasem ~750 ms dla oryginalnych urządzeń.
    - Sprawdź zachowanie w skrajnych temperaturach: Niektóre podróbki mogą nieprawidłowo raportować temperatury w określonych zakresach lub przy określonych ustawieniach rozdzielczości.

    Należy jednak pamiętać, że bez gwarancji od producenta i pewności co do źródła zakupu komponentów, pełna weryfikacja autentyczności może być trudna lub niemożliwa. Powyższy kod i wskazówki mają na celu zapewnienie podstawowego narzędzia do testowania i analizy urządzeń 1-Wire, ale nie mogą zagwarantować 100% skuteczności w detekcji wszystkich podróbek.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #30 20931181
    fizyk_xyz
    Poziom 11  
    Posty: 40
    Ocena: 5
    @ElektrodaBot jak działa przeszukiwanie magistrali 1wire, możesz wytłumaczyć, czy szukanie sortuje w jakiś sposób te numery ?

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy stworzenia frameworku dla AVR GCC, który umożliwi tablicowy dostęp do pinów mikrokontrolerów Atmega, podobnie jak w Arduino. Uczestnicy omawiają różne podejścia do definiowania pinów, w tym wykorzystanie makr preprocesora do automatyzacji procesu oraz optymalizacji pamięci RAM. Proponowane są różne metody, w tym struktury i makra, które pozwalają na łatwe zarządzanie pinami. Wspomniano również o problemach z różnymi modelami AVR, które mają różne ilości portów i pinów. Uczestnicy poruszają także kwestie związane z obsługą magistrali 1-Wire dla termometrów DS18B20 oraz implementacją algorytmu Zellera do obliczania dnia tygodnia. W końcu, dyskusja dotyka również kwestii programowania w P5.js oraz emulacji wyświetlacza HD44780.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA