Skocz do zawartości

Manipulowanie bitami w rejestrach portów - pierwsze próby


Pomocna odpowiedź

Napisano

Witam, jak zmodyfikować ten kod, żeby ustawiał wyjście i jedynkę na pinie D13 a nie D2?

void setup()
{DDRD = B00000100;
PORTD = B00000100;}
void loop()
{}

Próbowałem przez analogię:

  
void setup()
 {
 DDRB = B00100000; 
 }
 void loop()
{
PORTB = B00100000; 
delay(1000);
PORTB = B00100000; 
delay(1000);  
}
{}

ale nie działa.

Może nie działa, bo Atmega328 nie ma pinu D13.

Zobacz np tutaj: https://www.theengineeringprojects.com/2017/08/introduction-to-atmega328.html - punkt 11

Inna sprawa, że ta "analogia" i tak nie zadziała, nawet jak wybierzesz istniejący pin.

Zasugerowałem się: https://www.arduino.cc/en/Reference/PortManipulation

Port Registers

Port registers allow for lower-level and faster manipulation of the i/o pins of the microcontroller on an Arduino board. The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:

B (digital pin 8 to 13)

C (analog input pins)

D (digital pins 0 to 7)

Each port is controlled by three registers, which are also defined variables in the arduino language. The DDR register, determines whether the pin is an INPUT or OUTPUT. The PORT register controls whether the pin is HIGH or LOW, and the PIN register reads the state of INPUT pins set to input with pinMode(). The maps of the ATmega8 and ATmega168 chips show the ports. The newer Atmega328p chip follows the pinout of the Atmega168 exactly.

Ok, jeśli z D13 chodziło o pin Arduino 13 to faktycznie odpowiada mu PB5 i kod wygląda poprawnie.

[ Dodano: 25-02-2018, 18:05 ]

Edit: inna sprawa, że masz dwa razy do samo:

PORTB = B00100000;

Ano fakt 🙂 Oczywiście powinno być:

void setup() 
 { 
 DDRB = B00100000; 
 } 
 void loop() 
{ 
PORTB = B00100000; 
delay(1000); 
PORTB = B00000000; 
delay(1000);  
} 
Właściwie to wypadałoby zmieniać tylko jeden bit, a nie zerować przy okazji wszystkie...

No fakt, a jak w takim poleceniu "bitowym" wskazać na konkretny bit bez dotykania pozostałych?

I jeśli można od razu drugie pytanie - gdybym chciał podpiąć zegar do któregoś timera, to muszę ustawić bit CS10 np w TCCR1B. Idąc za słuszną radą kolegi sprawdziłem w dokumentacji Atmegi 328P, że to jest pierwszy bit w rejestrze. Czyli znów chciałem na zasadzie analogii zrobić tak : TCCR1B = B00000001; No ale wtedy bym znów wyzerował pozostałe bity więc przydałoby się znów wiedzieć jak wskazać tylko ten konkretny bit...

Typowe rozwiązanie to użycie operacji OR i AND, czyli aby ustawić bit piszesz:

PORTB |= B00100000

natomiast do zerowania:

PORTB &= ~B00100000

Tak, chociaż jest w tym pewna pułapka związana z przerwaniami - na szczęście na AVR kompilator powinien wygenerować odpowiedni kod i wszystko zadziała zawsze prawidłowo.

  • Lubię! 1

Przypominam też, że do odwrócenie bitu na porcie nie trzeba robić operacji AND/OR. W AVR wystarczy wpisać jedynkę do rejestru PINx na bicie, który chcemy odwrócić:

PINB = 0b00100000;

Powyższe odwraca linię PB5. Oczywiście można mrugać na raz wieloma bitami:

PINB = 0b1011;

A do rejestrów timera nie pisz zer i jedynek bo jutro zapomnisz co to miało być, tylko używaj nazw tych bitów. Ktoś już odwalił robotę w podefiniowanie tego wszystkiego więc żeby odpalić zegar timera możesz zrobić tak:

TCCR2B = _BV(CS20);

albo tak, jeśli potrzebujesz więcej bitów na raz (i wolniejszy zegar):

TCCR2B = _BV(CS20) | _BV(CS21);

_BV() zamienia liczbę na zapalony bit na tej pozycji i jest liczone przez kompilator więc nie "zużywa" procesora.

Nie jestem na 100% pewien, ale w przypadku AVR kompilator chyba zamienia operację OR/AND wykonywaną na jednym bicie na pojedynczą instrukcję asemblera - SBI/CBI czy jakoś tak. W każdym razie jest to operacja atomowa i nie ma problemów np. z przerwaniami. Inna sprawa, że niewielka zmiana w kodzie i ustawienie 2 bitów daje zupełnie inny kod i przestaje być atomową operacją. Inne mikrokontrolery mają często dodatkowe rejestry do ustawiania oraz kasowania bitów, albo jeszcze bardziej skomplikowane mechanizmy dostępu do pojedynczych bitów.

Przypominam też, że do odwrócenie bitu na porcie nie trzeba robić operacji AND/OR. W AVR wystarczy wpisać jedynkę do rejestru PINx na bicie, który chcemy odwrócić:

PINB = 0b00100000;

Powyższe odwraca linię PB5. Oczywiście można mrugać na raz wieloma bitami:

PINB = 0b1011;

A do rejestrów timera nie pisz zer i jedynek bo jutro zapomnisz co to miało być, tylko używaj nazw tych bitów. Ktoś już odwalił robotę w podefiniowanie tego wszystkiego więc żeby odpalić zegar timera możesz zrobić tak:

TCCR2B = _BV(CS20);

albo tak, jeśli potrzebujesz więcej bitów na raz (i wolniejszy zegar):

TCCR2B = _BV(CS20) | _BV(CS21);

_BV() zamienia liczbę na zapalony bit na tej pozycji i jest liczone przez kompilator więc nie "zużywa" procesora.

Dzięki marek1707!

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...