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

Jak ustawić konkretny bit portu zgodnie ze stanem innego bit

hessuss 06 Paź 2009 14:47 2681 6
  • #1 7096565
    hessuss
    Poziom 13  
    Witajcie.
    To moje poczatki w mikrokontrolerami. Piszę w C.
    Mam taką procedurkę która zapala mi diodki podłaczone do rejestru przesównego w zależności od stanu jakiegoś tam Bajtu ( buduje zegarek z wyświetlaczem na matrycy LED, wiem że sa gotowce ale chcę wszystko samemu od podstaw zrobić żeby się czegoś nauczyć) , wszystko ładnie działa tylko algorytm jest bardzo nieelegancki:

    
    if (wers & 0b00000001)
    {
       PORTC |=_BV(4);
    } else{
       PORTC &=~_BV(4);
    }
    if (wers & 0b00000010)
    {
       PORTC |=_BV(4);
    } else{
       PORTC &=~_BV(4);
    }
    if (wers & 0b00000100)
    {
       PORTC |=_BV(4);
    } else{
       PORTC &=~_BV(4);
    }
    

    i tak do końca bajtu

    Jak to zrobić bardziej elegancko? tzn żeby nie było tych durnych if-elsów tylko jednym zapisem zobić:
    
    ustaw czwarty bit portu C tak jak jest ustawiony pierwszy bit bajtu "wers"
    

    w następnej linijce miał bym:
    
    ustaw czwarty bit portu C tak jak jest ustawiony drógi bit bajtu "wers"
    i tak aż do końca tegoż bajtu, oczywiście nie wpływając na stan pozostałych bitów portu C

    Przyznam, że czytałem kurs ale niestety nie rozumiem jeszcze dokładnie tych zawiłych skądinąd operatorów przypisania.
    Pozdrawiam.
  • #3 7096643
    skynet_2
    Poziom 26  
    Czyli jeżeli wers != 0 to PORTC.4 = 1
    if (wers != 0)
       PORTC |= (1<<4);
    else
       PORTC &= ~(1<<4);
    

    chyba że tu będzie jeszcze jakiś kod wtedy prościej dać pętlę
    for (uint8_t i=1; i ; i<<=1)
    {
       if (wers & i)
          PORTC |= (1<<4);
       else
          PORTC &= ~(1<<4);
    }


    Pozdrawiam
  • #4 7096795
    hessuss
    Poziom 13  
    niestety, nie o to chodzi a pozatym dalej mamy ify a optymalny kod by ich nie miał, no chyba żę tego się nie da zrobic w C ale znając życie to po prostu trzeba znaleźć kogoś kto nie wie o tym "że się nie da" przyjdzie i to zrobi.

    Więc jeszcze raz:

    Mamy 8 diód podłączonych do rejestru przesównego.
    W zmiennej 'wers' przechowujemy stan tych ośmiu diód.

    I teraz chodzi o to żeby zaświecić te diody zgodnie ze stanem zapisanym w zmiennej wers:

    Algorytm:
    
    sprawdź jaki stan ma pierwszy bit w zmiennej 'wers'
    jeśli to jedynka to ustaw wyjście PC4 w atmedze na '1'
    jeśli to zero to ustaw wyjście PC4 w atmedze na '0'
    puść impuls przesówający rejestr przesówny
    
    sprawdź jaki stan ma drugi bit w zmiennej 'wers'
    jeśli to jedynka to ustaw wyjście PC4 w atmedze na '1'
    jeśli to zero to ustaw wyjście PC4 w atmedze na '0'
    puść impuls przesówający rejestr
     
    ...
    
    sprawdź jaki stan ma ósmy bit w zmiennej 'wers'
    jeśli to jedynka to ustaw wyjście PC4 w atmedze na '1'
    jeśli to zero to ustaw wyjście PC4 w atmedze na '0'
    puść impuls przesówający rejestr przesówny
    
    hura, ciesz się że diody świecą się tak jak są zapisane jedynki i zera w zmiennej 'wers'
    


    no i ten mój algorytm dokłądnie to robi ( w pierwszym poście podałem skrócony zapis bez impulsów przesówających )

    Chodzi mi o ty by zoptymalizować kod czyli pozbyć się tych amatorskich ifów i elsów a zastąpić to przepisaniem stanu konkretnego bajtu w zmiennej 'wers' na czwartą końcówe portu C do krórej mam podłączone SDI od rejestru.

    zrobić coś w stylu :
    
    PORTC4 = wers & 0x01
    impuls przesówający
    PORTC4 = wers & 0x02
    impuls przesówający
    PORTC4 = wers & 0x04
    impuls przesówający
    PORTC4 = wers & 0x08
    impuls przesówający
    PORTC4 = wers & 0x0f
    ...
    impuls przesówający
    PORTC4 = wers & 0xf0
    

    tylko nie mam za cholere pojęcia jak to poprawnie zapisać :/
    próbowałem tak:
    PORTC & 0x08 = wers & 0x01;
    przesun;
    PORTC & 0x08 = wers & 0x02;
    itd
    ale dupa, mam błędy przy kompilacji :/
  • Pomocny post
    #5 7096884
    skynet_2
    Poziom 26  
    W kodzie który umieściłeś w pierwszym poście nie podałeś że pomiędzy if'ami ma być to "przesuń".

    if'y wcale nie są amatorskie, poza tym działają bardzo szybko, czasem prościej dać if'a niż skomplikowany wzór arytmetyczny.

    Nawet w algorytmie użyłeś jeśli[ang. if];

    kod który będzie działał tak jak chcesz:
    for (uint8_t i=1; i ; i<<=1) 
    { 
       if ((wers & i) != 0) 
          PORTC |= (1<<4); 
       else 
          PORTC &= ~(1<<4); 
       przesun();
    }


    szybsza wersja:

    for (uint8_t i=1; i ; i<<=1)
    {
      PORTC &= ~(1 << 4);
      if ((wers & i) != 0)
    	PORTC |= (1 << 4);
      przesun();
    }


    Ale jak nie chcesz if'ów:

    PORTC = ( PORTC & (~(1<<4)) ) | (((wers >> nr_bitu) & 1) << 4 );// nr_bitu 0-7, liczba 4 to pin portu liczony od zera


    Kod na if'ie będzie działać dużo szybciej.

    hessuss napisał:
    próbowałem tak:
    PORTC & 0x08 = wers & 0x01;
    przesun;
    PORTC & 0x08 = wers & 0x02;
    itd
    ale dupa, mam błędy przy kompilacji :/

    To jest bzdura ;) tutaj masz jak stosować operatory http://pl.wikibooks.org/wiki/C/Operatory

    Tutaj masz porównanie 3 fragmentów:
    		if ((wers & i) != 0)
    0x00000000004008f5 <main+23>:  movzbl -0xb(%rbp),%eax
    0x00000000004008f9 <main+27>:  movzbl -0x9(%rbp),%edx
    0x00000000004008fd <main+31>:  and    %edx,%eax
    0x00000000004008ff <main+33>:  test   %eax,%eax
    0x0000000000400901 <main+35>:  je     0x400909 <main+43>
    			PORTC |= (1 << 4);
    0x0000000000400903 <main+37>:  orb    $0x10,-0xa(%rbp)
    0x0000000000400907 <main+41>:  jmp    0x40090d <main+47>
    			PORTC &= ~(1 << 4);
    0x0000000000400909 <main+43>:  andb   $0xef,-0xa(%rbp)
    
    
    
    		PORTC &= ~(1 << 4);
    0x00000000004008f5 <main+23>:  andb   $0xef,-0xa(%rbp)
    		if ((wers & i) != 0)
    0x00000000004008f9 <main+27>:  movzbl -0xb(%rbp),%eax
    0x00000000004008fd <main+31>:  movzbl -0x9(%rbp),%edx
    0x0000000000400901 <main+35>:  and    %edx,%eax
    0x0000000000400903 <main+37>:  test   %eax,%eax
    0x0000000000400905 <main+39>:  je     0x40090b <main+45>
    			PORTC |= (1 << 4);
    0x0000000000400907 <main+41>:  orb    $0x10,-0xa(%rbp)
    
    
    
    		PORTC = (PORTC & (~(1 << 4))) | (((wers >> nr_bitu) & 1) << 4);
    0x00000000004008f5 <main+23>:  movzbl -0xa(%rbp),%eax
    0x00000000004008f9 <main+27>:  mov    %eax,%edx
    0x00000000004008fb <main+29>:  and    $0xffffffffffffffef,%edx
    0x00000000004008fe <main+32>:  movzbl -0xb(%rbp),%eax
    0x0000000000400902 <main+36>:  movzbl -0x9(%rbp),%ecx
    0x0000000000400906 <main+40>:  sar    %cl,%eax
    0x0000000000400908 <main+42>:  and    $0x1,%eax
    0x000000000040090b <main+45>:  shl    $0x4,%eax
    0x000000000040090e <main+48>:  or     %edx,%eax
    0x0000000000400910 <main+50>:  mov    %al,-0xa(%rbp)
  • #6 7096995
    hessuss
    Poziom 13  
    Dzieki za poradę, nie miałem pojęcia że ify są szybsze, kiedyś koleżka uczył mnie pisać jakeiś tam softy lata temu i zawsze powtarzał żę ify są dla amatorów, tylko switch - Casy i odwołania bezpośrednie. No cóż widać inna szkoła. Pozdrawiam.
  • Pomocny post
    #7 7097015
    skynet_2
    Poziom 26  
    switch to jest to samo co kilka if'ów tylko ładniej wygląda, if'y nie są szybsze, tylko szybsze są fragmenty kodu na nich oparte w niektórych sytuacjach, ale czasem łatwiej dać if'a niż męczyć się z arytmetyką, mimo że będzie ciut wolniej.

    Najlepiej włączyć debugger i zobaczyć co zajmuje mniej cykli zegarowych i instrukcji.
REKLAMA