AVR g++ - Wysokopoziomowe odwołanie do pinów

AVR g++ - Wysokopoziomowe odwołanie do pinów
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Witam,

Ostatnio musiałem zrobić coś na Avr, ale po kilkumiesięcznych zmaganiach z c# zapisy typu `PORTA |= (1<<x);` nie były mi przyjemne dla oka.

Pomyślałem - jak dużo tego i parametryzować trzeba to templaty. G++ nie chciał przyjąć jako parametru szablonu adresów portów. Dałem spokój z nimi po chwili szukania na necie.

Potem pomyślałem - dużo tego, w zależności od procka są inne porty itp. Napiszę szybko generator kodu. Wyszło takie coś http://www.github.com/pixellos/CodeGenerator.

Niby ładnie działa, wywalone do innego pliku nagłówkowego.
Tylko czy takie rozwiązanie nie jest mało eleganckie?

Przykładowy output dla A i 2 pin

Kopiuj
class PortA{
        public:
	    void static Set(uint8_t uCharValue)
       {
            PORTA |= uCharValue;
       }

        void static Clear(uint8_t uCharValue)
       {
            PORTA &= ~(uCharValue);
       }

        void static Toggle(uint8_t uCharValue)
       {
            PORTA ^= uCharValue;
       }

        uint8_t static Check()
       {
            return PINA;
       }

        void static AsOutput(uint8_t uCharValue)
       {
            DDRA &= ~(uCharValue);
       }

        void static AsInput(uint8_t uCharValue)
       {
            DDRA |= uCharValue;
       }
       };class Pin_A0{
public:
	    void static Set()
	    {
		    PORTA |= 1 << 0;
	    }

	    void static Clear()
	    {
		    PORTA &= ~(1<<0);
	    }

	    void static Toggle()
	    {
		    PORTA ^= (1<<0);
	    }

	    bool Check()
	    {
		    return ((PINA >> 0) & 1);
	    }

	    void static AsOutput()
	    {
		    DDRA &= ~(1<<0);
	    }

	    void static AsInput()
	    {
		    DDRA |= 1<<0;
	    }
        };class Pin_A1{
public:
	    void static Set()
	    {
		    PORTA |= 1 << 1;
	    }

	    void static Clear()
	    {
		    PORTA &= ~(1<<1);
	    }

	    void static Toggle()
	    {
		    PORTA ^= (1<<1);
	    }

	    bool Check()
	    {
		    return ((PINA >> 1) & 1);
	    }

	    void static AsOutput()
	    {
		    DDRA &= ~(1<<1);
	    }

	    void static AsInput()
	    {
		    DDRA |= 1<<1;
	    }
        };
edytowany 4x, ostatnio: Pixello
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 21 godzin
  • Lokalizacja:Szczecin
1

Klikalne linki się daje ;)

Trochę nie chce mi się wierzyć, że nie mogłeś adresów portów użyć jako parametrów szablonu, ale w sumie nie wiem jak one są zadeklarowane.

Jeśli inaczej się nie da to ok, ale:

  1. \n lub \n\n przed nową klasą, tragicznie teraz to wygląda
  2. dlaczego Clear przyjmuje parametr? Z nazwy funkcji nie wynika, że działa tylko na części pinów.
  3. dlaczego Toggle przyjmuje parametr? Z nazwy funkcji nie wynika, że działa tylko na części pinów.
  4. jak wszystko jest public, to nie wygodniej użyć struct?

edytowany 1x, ostatnio: kq
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Zaraz poprawię formatowanie wygenerowanego kodu, Z tym Set i Clear to sobie pomyślałem, żeby furtkę na jakieś 0b10101001 dać, ale jak o tym wspominasz to masz rację z tą nazwą, troszkę nietrafiona. Ale czy przeciążona funkcja, która może przyjmować parametr lub nie będzie ok, czy dać nazwę typu BitSet?

Co do struct vs class jak wspomniałem - przyzwyczajony jestem do klas z c#, nawet nie pomyślałem o structach.

Co do templatów - w c++ jestem bardzo słaby - tak naprawdę mój kontakt z c++ ograniczał się do std::cout i cin :D, ale dostałem Errora przy kompilacji

Kopiuj
 
Severity	Code	Description	Project	File	Line
Error		'*' cannot appear in a constant-expression	MotorServoController	C:\Users\rogoz\Documents\Atmel Studio\7.0\MotorServoController\MotorServoController\main.cpp	39
edytowany 1x, ostatnio: Pixello
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 21 godzin
  • Lokalizacja:Szczecin
1

Ja bym dał ClearBits i ToggleBits lub podobnie nazwane jako osobne funkcje.

Set jest ok, bo domyślnie nadpisuje wszystkie obecne wartości. Edit: widzę, żeSet zmienia wartości na 1 bitom które są zaznaczone. W takim razie to samo co wyżej.

Ewentualnie dodałbym domyślną wartość parametru funkcji, jakieś Bits::All i enum Bits : uint8_t { All = 255 };


edytowany 1x, ostatnio: kq
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
1

Za późno na enuma, dałem Set() które ustawia na 0xff i Clear() ustawia na 0;

Output teraz

Kopiuj

    class PortA{
        public:
	    void static SetBits(uint8_t uCharValue)
       {
            PORTA |= uCharValue;
       }
        
        void static Set()
       {
            PORTA = 0xff;
       }

        void static ClearBits(uint8_t uCharValue)
       {
            PORTA &= ~(uCharValue);
       }

         void static Clear()
       {
            PORTA = 0;
       }

        void static ToggleBits(uint8_t uCharValue)
       {
            PORTA ^= uCharValue;
       }
        void static Toggle()
       {
            PORTA ^= 0xff;
       }

        uint8_t static Check()
       {
            return PINA;
       }
        void static AsOutput()
       {
            DDRA &= ~(0xff);
       }

        void static AsInputBits()
       {
            DDRA |= 0xff;
       }
        void static AsOutputBits(uint8_t uCharValue)
       {
            DDRA &= ~(uCharValue);
       }

        void static AsInputBits(uint8_t uCharValue)
       {
            DDRA |= uCharValue;
       }
       };

    class Pin_A0{
public:
	    void static Set()
	    {
		    PORTA |= 1 << 0;
	    }

	    void static Clear()
	    {
		    PORTA &= ~(1<<0);
	    }

	    void static Toggle()
	    {
		    PORTA ^= (1<<0);
	    }

	    bool Check()
	    {
		    return ((PINA >> 0) & 1);
	    }

	    void static AsOutput()
	    {
		    DDRA &= ~(1<<0);
	    }

	    void static AsInput()
	    {
		    DDRA |= 1<<0;
	    }
        };

    class Pin_A1{
public:
	    void static Set()
	    {
		    PORTA |= 1 << 1;
	    }

	    void static Clear()
	    {
		    PORTA &= ~(1<<1);
	    }

	    void static Toggle()
	    {
		    PORTA ^= (1<<1);
	    }

	    bool Check()
	    {
		    return ((PINA >> 1) & 1);
	    }

	    void static AsOutput()
	    {
		    DDRA &= ~(1<<1);
	    }

	    void static AsInput()
	    {
		    DDRA |= 1<<1;
	    }
        }; 
Pixello
Hah, teraz pomyślałem o tym, że niektóre porty mogą być 16 bitowe, pomyślę jeszcze na jakimś ifdef.
PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
0

Ah, miałem kiedyś podobny problem, sterownik do UARTa pisałem przenośny pomiędzy różnymi atmegami. Kod ów drivera zaginął w czasie i przestrzeni ale pamiętam że rozwiązałem to w taki sposób. Pod _port podstawiasz PORTB i tak dalej.

Kopiuj
#include <stdint.h>
#include <avr/io.h>

class PortX {
public:
    PortX(volatile uint8_t *_port) 
        : _pv(_port) {
    
    }
private:
   volatile uint8_t* const _pv;
};


int main() {
    PortX port(&PORTB);
}

edytowany 1x, ostatnio: Proxima
Pixello
A czy w ten sposób nie musi objekt port być w pamięci? Ja chciałem zrobic na statycznych metodach, by kompilator to sobie do 1 instrukcji zwinął. Ale zaraz sprawdzę Twój sposób :).
PR
No musi, ja deklarowałem go static PortX w pliku nagłówkowym.
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
1

A czemu nie użyć referencji, budowa nagłówków AVRowych aż się o to prosi:

Kopiuj
  4 struct portOut
  5 { 
  6     private:  
  7     volatile uint8_t& io;
  8     const uint8_t port_no;
  9 
 10     public:    
 11     
 12     portOut(volatile uint8_t& io_, const uint8_t no) : 
 13         io(io_),  
 14         port_no(no) 
 15         {}
 16 
 17     void set() {      
 18         io |= (uint8_t) ((uint8_t) 1 << port_no);
 19     }
 20 
 21     void toggle() {
 22         io ^= (uint8_t) ((uint8_t) 1 << port_no);
 23     }
 24 
 25     void clear() {
 26         uint8_t tmp = (uint8_t) ((uint8_t) 1 << port_no);
 27         tmp = (uint8_t) ~tmp;
 28         io &= (uint8_t) (1 << port_no);      
 29     }
 30 };
PR
Prawda, referencji też można.
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Tylko te rozwiązania co podajecie zużywają więcej Pamięci programu i danych - Chciałem, by kompilator zajął się tym.

PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
0

Fakt, odrobine wiecej, ale nie jest to znowu taka tragedia. Spójrz na źródła arduino, tam właściwie w pełni wykorzystują możliwości c++ i atmegi się nie wieszają xP
No zależy też pod jaką atmegę piszesz, bo pod ATtiny to wiadomo - troche lipa może być.

edytowany 2x, ostatnio: Proxima
Pixello
Pod 16, też lipa, mam dużo ich a kupiłem trochę złomu z niedziałającą elektroniką i chcę sobie zrobić sterownik servo - enkoder + pc, więc każdy bit jest na wagę złota.
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Dlatego nie używam andruino - na medze16 pamięci brakuje mi strasznie, a mam ich trochę :D. Libka od wyświetlacza sh1103 też swoje waży ;)

Dla Portx.set, clear,toogle dla porówniania
Program memory - 1.2% Data 0%,
1.9% 0.8%

Z podmianą wskaźnika 1.9%, 0.2%

edytowany 3x, ostatnio: Pixello
PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
0

Hmm, pamięci w sensie RAMu czy FLASHa? Bo wstawianie po n definicji tej samej klasy tylko ze zmienionym portem zmarnuje pewnie więcej FLASHa niż (jedna) klasa z podstawionymi referencjami/wskaźnikami.

edytowany 1x, ostatnio: Proxima
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
0

Zmierzyłeś ile zajmują w realnej aplikacji? Jeśli nie, to nie zakładaj nic a priori.
EDIT: widzę, że tak. @Proxima pisze dobrze, template'y dodatkowo zwiększą Ci zajętość flasha

edytowany 1x, ostatnio: alagner
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

@alagner kompilator na o3 sobie to wszystko ściąga do podstawowych instrukcji. Testy robiłem na o3.

PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
0

No tak, mówisz o tej klasie z początkowych twoich postów?
Wstaw tyle szablonów tej klasy ile chcesz mieć portów w obiekcie, i wtedy zmierz.
Potem stwórz tyle samo instancji klas z referencją i też zmierz. Wszystko będzie wtedy jasne.

edytowany 1x, ostatnio: Proxima
Pixello
Ale właśnie szablony nie działają, więc napisałem generator kodu
PR
Jako szablon mówie o tym outpucie z generatora. Bo niejako jest to szablon :P (I zakładam że potrzeba ci więcej niż 1 port opakowany w klasę). Dopiero wtedy będzie jasne co zajmuje więcej.
Pixello
Racja :D Dołączyłem go jako plik nagłówkowy. Zaraz dam porównanie jakieś lepsze.
kq
Jak nie pobiera adresów funkcji to kompilator powinien to zoptymalizować do zera.
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

A jeszcze pomyślmy o klasie, która spełaniała by funkcje pinu - w swojej klasie musiałaby mieć zapisany publiczy portx, pinx, ddrx. I albo takich obiektów 40, albo co użycie podmieniać zmienne.

user imageuser imageuser image

Jak coś źle zrozumiałem w stosunku do waszych implementacji to sorry, tak naprawdę w c++ piszę od dzisiaj :P

edytowany 2x, ostatnio: Pixello
Zobacz pozostałe 4 komentarze
AL
Polecam zrobić to po mojemu lub @Proxima -owemu i nie bawić się w takie cuda. Ile Ci tej pamięci brakuje?
Pixello
Na razie nic bo nie zacząłem pisać, a jak mi się program rozrośnie to będzie 100% wszystkiego łącznie z eepromem.
Pixello
@alagner a dlaczego cuda - kompilator by mi sam takie cuś wygenerował, jakby szablony chodziły chyba :D
AL
patrz niżej. Toć od początku mówię, że szablony to imho zły pomysł...
Pixello
@alagner dlaczego zły pomysł - rozwiń proszę
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
2

To jeszcze raz:
możesz zrobić dwojako: odnosić się do każdego PINU osobno i traktować go jak obiekt lub też odnosić się do całego PORTU jako obiektu i przekazywać numer pinu do metody.
Pytanie kolejne: gdzie mają znajdować się obiekty sterujące IO, jaki ma być ich scope?

BTW - masz świadomość, że optymalizacja O3 jest na czas wykonania, a Os na rozmiar?

Pixello
Tak, dlatego sprawdzam na optymalizacji która mnie interesuje - na os u mnie zostaje dalej 1.5, a w pozostałych przypadkach 3.0
PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
1

Ad tych szablonów @Pixello, to spójrzmy na to jak opakowany w makra jest PORTB.
#define PORTB _SFR_IO8(0x05)
link0
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define __SFR_OFFSET 0x20
link1
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
link2
I oto cała tajemnica dlaczego 'szablony nie działają'. Wszystko działa tylko raczej takiej masy makr tam nie idzie wcisnąć (wychodzi lvalue).
Ale jest lekarstwo, jeśli zależy ci na szablonach! Odzoruj budowę tych makr w klasie szablonowej, a jako parametr szablonu przekazuj po prostu sprzętowy numer portu.

edytowany 2x, ostatnio: Proxima
Zobacz pozostały 1 komentarz
PR
No z początku mówił że nie działają szablony jak próbuje PORTB dać jako parametr, ja tylko wskazuje jak 'naprawic szablony' xD A że to pewnie gorszy sposób, to.. no cóż.
Pixello
Patrzę, te wszystkie rejestry są poukładane bez sensu - nie ma żadnej kolejności,wychodzi, że muszę jeszcze jakiegoś enuma wsadzić żeby offsety wyznaczyć
AL
@Pixello otwarłem headera od M32, co bajt idą PIN DDR i PORT także brednie jakieś wypisujesz...
PR
@Pixello, @alagner ma racje, paczaj tu -> http://www.atmel.com/images/2466s.pdf i paczaj od strony 8, każdy adres ma ten offset 0x20 nie wiem czemu, no po prostu ma, pewnie adresy niższe są zarezerwowane. Cały myk opiera się na wpisaniu adresu z datasheeta twojej megi do makra.
Pixello
Sorka, coś źle popaczyłem, Mea Culpa.
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

@Proxima, @alagner ciągle piszecie, że szablony to zły sposób, ale ciągle nie powiedzieliście dlaczego. Ja na prawdę chcę wiedzieć - mam wkuć sobie taką regułkę na pamięć?

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
2

Bo nagenerujesz od cholery kodu. Dla każdej osobnej konkretyzacji szablonu.

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 21 godzin
  • Lokalizacja:Szczecin
2

Ale przecież kompilator/linker to wywali, więc w czym problem?

http://goo.gl/XfMSmK jak widać jak nie jest pobierany adres to nie jest generowany żaden zbędny kod. Dla -Os, -O2, -O3. Dla -O1 clang wygnerował, gcc nie.

Pisząc pod konkretne środowisko łatwo jest sprawdzić czy kompilator zachowuje się rozsądnie czy nie i na tej podstawie zadecydować.

edit: compiler explorer ma też AVR gcc, co powinno rozwiać wszelkie wątpliwości: http://goo.gl/18NQ44


edytowany 3x, ostatnio: kq
Pixello
Dla o3 kompilator robi z tego po prostu taki Syntax Sugar - jest po prostu czytelniej, a bez dodatkowego narzutu ;)
AL
dobre narzędzie, dzięki :)
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
1

@kq io (w bibliotece) jest zdefiniowane tak #define (*(volatile uint8_t*) 0x2f) IO. Chyba prościej napisać port portA(IO) aniżeli męczyć się z szablonami, żeby tylko zmienić nawiasy na ostre, nie sądzę żeby GCC zrobiło różnicę czy napiszesz IO |= (1<<4); i to IO będzie szablonowe czy nie skoro i tak adres jest stały...

W ARM szablony to mają jeszcze jakiś sens bo rejestry są popakowane w formie typedefowanych struktur, ale tutaj imho to jest dokładanie sobie roboty.

Pixello
Generator to 5 minut. Ale ja nie muszę tworzyć obiektów i mam dostęp do metod każdego z pinu - Pin_A3::Set(), czy też Pin_A1::Check(); - kompilator z tego sobie i tak zrobi co trzeba, a ja się nie martwię PINX PORTX DDRX.
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 21 godzin
  • Lokalizacja:Szczecin
1

Jeśli IO będzie miało dodatkową dereferencję wskaźnika (this), co jest trudniejsze do zoptymalizowania dla kompilatora w przypadku zmiennych innych niż lokalne to może to mieć narzut wydajnościowy. A co do męczenia się z szablonami to nie widzę za bardzo gdzie tu "męka", std::addressof powinno wystarczyć.

Tak czy inaczej, napisałem jedynie, że Twój argument przeciw - "bo nagenerujesz od cholery kodu" - nie ma racji bytu. Za mało doświadczenia mam w AVR, żeby coś innego jednoznacznie stwierdzać


PR
Tylko na AVR właściwie nie ma stla, a co dopiero &lt;memory&gt; albo traitsy jakieś.
AL
Ajjjj, na AVR pisałem jak jeszcze C++11 nie było, zapomniałem o addressof. :) To faktycznie ma prawo się udać :)
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Było pytanie o scope - zamierzam wrzucić to do jakiegoś namespace Avr::Atmega16a a wszystkie metody uczynić public static - bo przecież są one środowiskiem.

Napisałem troszkę kodu z tym rozwiązaniem i dla mnie jest bardzo "programmer-friendly". Myślałem o rozszerzenie tego generatora o pliki xml definiujące uC i generować statyczne metody do ustawiania Liczników, Przerwań itp według nich. Przy okazji ukrywa to implementację. Według Was ma to sens czy to dodatkowa, nie potrzebna robota?

Bardzo proszę o opinie, krytykę, bo jedynie przez to mogę się rozwinąć, a że na razie nie mam żadnej okazji do jakiejkolwiek rozmowy na żywo z programistą/code review (uczę się w domu, technikum 3 klasa), to mogę swoimi pomysłami zmierzać w "króliczą norę", więc feedback jest mi bardzo potrzebny ;).

Pozdrawiam

edytowany 2x, ostatnio: Pixello
PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
0

A zmierzyłeś ile zajmują przykładowo 10 portów wygenerowanych w ten sposób? Bo to by była chyba sprawa decydująca.

Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Nic nie zajmują - są statyczne, kompilator je ściąga do 0.

PR
  • Rejestracja:około 11 lat
  • Ostatnio:9 dni
  • Lokalizacja:Pomorskie (Stare Kabaty)
1

Skoro tak.. To czemu nie? Poczekaj aż ktoś bardziej doświadczony się wypowie bo ja tyle samo lat co ty mam ; P Jak na moje to użyłbym metody mojej lub @alagner , ale głównie dlatego że używam większych atmeg i lekki overhead nie przeszkadza mi. (Ewentualnie bym optymalizował jakby brakło miejsca, nie wcześniej)

edytowany 1x, ostatnio: Proxima
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

1f9a3bafae.png

Endrju
  • Rejestracja:około 22 lata
  • Ostatnio:prawie 2 lata
3

O, ja właśnie coś takie napisałem/piszę. Ostatecznie kod wygląda np. tak:

Kopiuj
Avr::Io::Gpio<0>::setDirection(Avr::Io::Direction::OUTPUT);
Avr::Io::Gpio<0>::setValue(true);
Avr::Timer::BusyDelayMs(1.0);
Avr::Io::Gpio<0>::setValue(false);

To bardzo ułatwia robienie czegokolwiek, a kodu wynikowego jest tyle samo jak gdyby pisać to ręcznie. Kompilatory są wystarczająco sprytne.

Zrezygnowałem z jakiegoś generowania zewnętrznymi narzędziami kodu. To co można generować generuje makrami, przynajmniej nie potrzeba do tego nic z zewnątrz. Wymyślnie rozwiązania "generujące" są bez sensu IMO, bo i tak trzeba napisać opis co generować - ostatecznie opisu (czy to dla generatora, czy to makr, czy wprost w kodzie) jest podobna ilość. No chyba, że to coś bardzo skomplikowanego, ale to przecież tylko AVR...

Biblioteki C++ niestety nie ma, ale to co potrzeba można napisać samemu. Dodatkowo warto używać/opakować co się da z avrlibc.

Ogólnie polecam, fajna zabawa.


"(...) otherwise, the behavior is undefined".
Pixello
@Endrju to może byśmy połączyli siły ;)?
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
1

@Pixello sprawdziłem jak to wygląda, generalnie faktycznie Twoja metoda daje najmniejszy kod, przynajmniej na O3. Pytanie jeszcze co chcesz zrobić bo np. nie przekażesz sobie np. obiektu typu IO do funkcji czy nie umieścisz go w klasie. Ale oczywiście wedle woli, zależy co Ci potrzebne.

Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Generalnie, zgodnie z zasadą SRP, chciałem oddzielić abstrakcję (algorytmy działania) od implementacji, a implementacje uczynić zrozumiałą dla "czytacza", bo PortA |= 0xab; nie mówi dużo.
Po poznaniu dobroci debugerów i przejrzystego kodu postanowiłem uprościć sobie życie.
Jak jakieś pół roku temu w c pisałem większość moich błędów polegała na odwołaniu się do nie tego portu, pinu lub wpisania 0b0101110 zamiast 0b01011110.

Na kartce mam napisane kilka rzeczy które tak chcę zaimplementować i przetestować przed pisaniem kodu właściwego - min przerwania , 2 timery, i2c, uart. Mam nadzieję, że uchroni mnie to przed głupimi błędami, a błędy będą łatwiej lokalizowalne. Co do zmieniania pinów w implementacji na razie będę robił to przez #define LedRed Pin_A1.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.