Czy poszczególne piny różnych portów mikrokontrolera można zmapować do rejestru, a ich wartości można zmienić przy zmianie wartości rejestru?

12

P: Czy poszczególne piny różnych portów mikrokontrolera można zmapować do rejestru i zmienić ich wartości podczas zmiany wartości rejestru?

Scenariusz: Zużyłem niektóre piny z każdego portu (8 bitów) mikrokontrolera. Teraz chcę interfejs urządzenia, które potrzebuje 8-bitowej magistrali (przypuśćmy, że D0 do D7 W SEKWENCJI), to znaczy, że potrzebuję 8 pinów od kontrolera, aby móc połączyć je jeden na jeden

portx0  -> D0 // x is the name of port followed by bit location on that port
portx1  -> D1
...
portx7  -> D7

ale nie mam całego portu 8 pinów, które mogę połączyć z tym urządzeniem, raczej mam kilka pinów z portx, niektóre z porty i niektóre z portz. Nowy scenariusz połączenia wygląda następująco (odpowiednio połączenie mikrokontrolera z urządzeniem)

portx0  -> D0
portx1  -> D1
portx2  -> D2
porty4  -> D3
porty5  -> D4
porty6  -> D5
porty7  -> D6
portz1  -> D7

W tym stanie, jeśli chcę wysłać wartość powiedz

unsigned char dataReg = 0xFA;

do mojego urządzenia z kontrolera muszę wykonać nieco mądre operacje na wartości, która ma zostać wysłana i ustawić każdy pin zgodnie z wartością w rejestrze indywidualnie. Na przykład

portx0 = ((dataReg & 0x01) >> 0 );  // Masking and shifting as bit position
portx1 = ((dataReg & 0x02) >> 1 );
portx2 = ((dataReg & 0x04) >> 2 );
porty4 = ((dataReg & 0x08) >> 3 );
porty5 = ((dataReg & 0x10) >> 4 );
porty6 = ((dataReg & 0x20) >> 5 );
porty7 = ((dataReg & 0x40) >> 6 );
portz1 = ((dataReg & 0x80) >> 7 );

Teraz, przechodząc do głównego pytania, aby uniknąć tych indywidualnych obliczeń dla każdego bitu na różnych portach, czy poszczególne piny różnych portów mikrokontrolera mogą być mapowane na rejestr, a ich wartości można zmieniać przy zmianie wartości rejestru?

Osaid
źródło
1
Jakiś czas temu miałem ten sam pomysł. W przypadku PIC nie jest to możliwe: microchip.com/forums/tm.aspx?high=&m=696277 - Nie sądzę, że jest to możliwe w przypadku każdej mikro, ale umieszczenie urządzenia w liście byłoby pomocne.

Odpowiedzi:

6

Wygląda na to, że twoje pytanie sprowadza się do posiadania 8-bitowej wartości w oprogramowaniu układowym oraz chęci odczytania i zapisania tego z dowolnej kolekcji pinów portu.

Nie ma na to bezpośredniego sposobu sprzętowego. Musisz napisać dwie procedury, jedną, aby odczytać wartość 8-bitową, a drugą, aby ją zapisać. Inni wspominali o stosowaniu związków, ale to zły pomysł. W związkach musisz poradzić sobie z każdym bitem osobno, a kod staje się zależny od kolejności bitów mikroprocesora. To może być i tak droga, jeśli wszystkie 8 bitów jest rozproszonych całkowicie niezależnie. Jeśli tak, niewiele możesz zrobić, ale stworzyć specjalny kod dla każdego bitu.

Lepszym sposobem na zrobienie tego, szczególnie jeśli możesz pogrupować bity w kilku ciągłych porcjach na fizycznych portach, jest użycie maskowania, przesunięcia i ORowania. Na przykład, jeśli trzy niskie bity bajtu wewnętrznego znajdują się na bitach <6-4> portu, przesuń tę wartość portu o 4, a ORAZ o 7, aby ustawić te bity w ich końcowej pozycji. Przesunięcie i maskowanie (lub maskowanie i przesunięcie) bitów z innych portów na miejsce i złożenie ostatniego 8-bitowego bajtu przez ORowanie w nim wyników.

Tego rodzaju kręcenie bitów niskiego poziomu jest łatwiejsze w asemblerze niż C. Prawdopodobnie umieściłbym procedury odczytu i zapisu bajtów w jednym module asemblera i sprawiłbym, że interfejs można wywoływać z C.

Olin Lathrop
źródło
6
Moja odpowiedź byłaby prawie identyczna z twoją, z tym wyjątkiem, że w ogóle nie używałbym zgromadzenia; manipulowanie bitami jest w C. trywialne. Myślę, że bardziej kłopotliwe byłoby (ponowne) nauczenie się konkretnej konwencji wywoływania C dla kompilatora i tego, jak uruchomić konsolidator. Zależy naprawdę od kompilatora i od tego, jak trudne to sprawia. :-)
akohlsmith
@Andrew: Poważnie? Konwencje wywoływania są jasno określone w każdym podręczniku kompilatora, który widziałem, gdzie może zaistnieć potrzeba połączenia z kodem asemblera. Manipulowanie bitami może być „trywialne” do pisania w C, ale jest to obszar, w którym kompilatory mogą wytwarzać przerażający kod. Jeśli szybkość lub przestrzeń kodu nie ma znaczenia, użyj tego, co bardziej ci odpowiada. Czuję się lepiej z asemblerem do kręcenia bitów na niskim poziomie, więc skorzystam z tego. Jeśli jest to rutynowa rutyna niskiego poziomu, powinieneś to zrobić w asemblerze. To naprawdę powinno być łatwe.
Olin Lathrop
1
Mówię tylko, że zmuszanie mnie do robienia czegoś tak trywialnego, jak manipulacja bitami, nie jest czymś, co zrobiłbym, chyba że istniałby bardzo dobry powód. Nie znamy specyfiki jego równoległej magistrali, ale większość magistrali ma sygnały stroboskopowe, które eliminują potrzebę aktualizacji „prawie atomowych” wszystkich pinów magistrali, więc zrzucenie się na montaż jest prawdopodobnie niepotrzebną optymalizacją i niepotrzebną złożonością (nawet jeśli jest to proste).
akohlsmith
@Andrew: To kłopotliwe lub skomplikowane, jeśli nie wiesz, co robisz. Myślę, że prawdziwym problemem jest to, że niektórzy ludzie boją się asemblera i nie znają go dobrze. To pomyłka. To musi być gotowe narzędzie w twoim zestawie narzędzi. Jeśli nie znasz tego dobrze lub czujesz się z tym niekomfortowo, zawsze będziesz uzasadniał, jak to zrobić w inny sposób. Niektóre rzeczy są łatwiejsze w asemblerze, jeśli znasz to i HLL równie dobrze. Większość ludzi tego nie robi, ale to problem z nimi, nie z użyciem asemblera.
Olin Lathrop
2
Jestem dobrze zorientowany w języku asemblera na wielu mikrokontrolerach / mikroprocesorach. Nie zgadzam się, że powinno to być gotowe narzędzie; należy go używać oszczędnie i tylko w razie potrzeby, zwykle do bardzo niskiego poziomu inicjalizacji, kodu krytycznego pod względem czasu lub rozmiaru lub, w bardziej powszechnym przypadku, do optymalizacji obszaru, który został już określony jako wąskie gardło. Uważam, że projekty, w których autorzy przeskakują do asemblera, ponieważ często tam piszą mniej przejrzysty kod lub nie rozpoznają, kiedy algorytm jest źle stosowany. Nie mówię konkretnie, że to ty, ale w bardziej ogólnym przypadku.
akohlsmith,
4

Zasadniczo nie jest to możliwe. O ile mi wiadomo, z PIC nie jest to możliwe.

Znam tylko jeden mikrokontroler, który może to zrobić, Cypress PSoC . Jest to wysoce konfigurowalny system na chipie. Spośród wielu rzeczy, które możesz zrobić, to dosłownie zdefiniować własny rejestr (1-8 bitów) i podłączyć go do dowolnych pinów, które lubisz, a nawet do obwodów wewnętrznych.

Okablowanie PSoC

Na przykład tutaj utworzyłem 6-bitowy rejestr kontrolny. 5 bitów przechodzi prosto na piny, a 6 bit używam do XOR z wejściem z 7 pinu.

Kołki PSoC

Na chipie mogę przypisać te piny do dowolnych dostępnych pinów GPIO. (To szare zdjęcie)

Rocketmagnet
źródło
1
LPC800 również powinien być w stanie to zrobić, ponieważ funkcje można dowolnie przypisywać do pinów.
starblue
-1

Możesz wypróbować następujące. Napisz własną strukturę, która mapuje odpowiednie piny 2 portów (które mają być użyte). Teraz aktualizacja wartości w tym rejestrze spowoduje ustawienie / zresetowanie pinów tych 2 portów. Spróbuj i daj nam znać, czy zadziałało !!

Jestem pewien, że to powinno zadziałać.

Rahul Ranjan
źródło
2
W C możesz zamapować strukturę na lokalizację pamięci i możesz odwzorować bity swojej struktury (pola bitowe) na przesunięcia bitów, ale nie ma sposobu, aby zapobiec kompilatorowi w bałaganie z bitami „pomiędzy”, a teraz jest sposób, aby wyświetlić „ogólną” strukturę pojedynczą wartość całkowitą. To nie zadziała.
Wouter van Ooijen
-1

Jeśli poprawnie zrozumiałem pytanie, w C jest to dość łatwe:

Ogólna deklaracja typu, może być ponownie wykorzystana w dowolnym rejestrze:

typedef union    // Generic 8-bit register Type
{
  uint8 reg; // Whole register
  struct
  {
    unsigned  bit7     : 1;  // Bit 7 
    unsigned  bit6     : 1;  // Bit 6 
    unsigned  bit5     : 1;  // Bit 5 
    unsigned  bit4     : 1;  // Bit 4 
    unsigned  bit3     : 1;  // Bit 3 
    unsigned  bit2     : 1;  // Bit 2 
    unsigned  bit1     : 1;  // Bit 1 
    unsigned  bit0     : 1;  // Bit 0 
  } bit;
} typ_GENERIC_REG8;

Aby zdefiniować port, którym chcemy się zająć:

#define MCU_GPO_PORTx   (*(volatile typ_GENERIC_REG8 *)(0x12345678)) // Number is address

Aby bezpośrednio przekręcić pinezkę na tym porcie:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

W kodzie:

MCU_PORTx_PINn = 1; // Set pin high

Cały rejestr:

MCU_GPO_PORTx.reg = 0xF; // All pins high

Warto przeczytać o strukturach, związkach, typach i enumie - wszystko to sprawia, że ​​życie jest o wiele przyjemniejsze w osadzeniu i ogólnie!

John U
źródło
OP chce połączyć kilka bitów z różnych portów w „jeden bajt”. Nie rozumiem, jak to by to zrobiło? Olin Lathrop wyjaśnia , dlaczego nie jest to możliwe.
To w rzeczywistości nie rozwiązuje problemu, a w zależności od tego, jak „smrt” jest twój kompilator, może wygenerować całkiem nowy zestaw problemów do debugowania.
akohlsmith