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

Atmega16 sterowanie diodami

Dziekan 15 Lut 2009 20:07 2660 21
  • #1 6155105
    Dziekan
    Poziom 13  
    Witam wiecie może dlaczego jeśli mam podpięte 2 diody do portów PD4 i PD5 procka nie mogę zapalić ich jednocześnie tylko zapala się jedna po naciśnięciu przycisku a druga się nie pali tylko pali się w chwili kiedy trzymam switch. Zamieszczam swój program czy ktoś może to skomentować?

    pozdrawiam
  • #2 6155285
    rrata
    Poziom 19  
    #define LED_ON_1 DDRD=0x10;PORTD=0x6F;
    #define LED_ON_2 DDRD=0x20;PORTD=0x5F;

    a później masz:
    LED_ON_1; 
    LED_ON_2;

    Najpierw ustawiasz PD4 jako wyjście, a wszystkie inne piny jako wejścia i zapalasz diodę gasząc tą drugą (tą na PD5).
    Drugim poleceniem gasisz poprzednią (PD4) ustawiając ten pin jako wejście i w stan wysoki (wewnętrzny pullup), ponadto pin PD5 jest wyjściem (reszta pinów wejściami) więc dioda świeci (ta na PD5). Przy włączonym stale przycisku obydwie diody będą migotać, a ty odnosisz wrażenie, że świecą światłem ciągłym.
    Ogólnie cały program napisany niepoprawnie.
  • #3 6155351
    Dziekan
    Poziom 13  
    to jak go poprawić żeby było wszystko ok bo kombinuje i jak narazie nie ma efektów, zależy mi na zapaleniu dwóch na raz.
  • #4 6155445
    rrata
    Poziom 19  
    Obydwie diody powinny zaświecić się, gdy trzymasz przycisk, jak puścisz mają zgasnąć. Napisałem teraz ten kod sprawdź czy jest dobry.
    #include <avr/io.h>
    
    #define klawiszD DDRD
    #define klawiszP PORTD
    #define klawiszI PIND
    #define sw1 PD3
    //zapalanie diod
    #define LED_1	PD4
    #define LED_2	PD5
    
    int main (void)
    
    {
    	DDRD |= (1<<LED_1) | (1<<LED_2);
    	PORTD = 0xFF;
    	
    	klawiszD &= ~_BV(sw1);
    	
    	klawiszP |= _BV(sw1); 
    
    	for (;;)
    	{
    	
    		if(bit_is_clear(klawiszI ,sw1))
    		{
    			PORTD &= ~(1<<LED_1);
    			PORTD &= ~(1<<LED_2);
    		}
    		else
    		{
    			PORTD |= (1<<LED_1);
    			PORTD |= (1<<LED_2);
    		}
    	}
    }
    
  • #5 6155517
    Dziekan
    Poziom 13  
    Dzięki zaraz zobaczę czy działa, bo ogólnie to robię sobie takie menu na 2 diodach 4 opcje: 00, 01, 10, 11. i po każdym naciśnięciu przycisku przechodzę dalej a później od początku itd. i jak narazie to widać jakie są postępy ale to dopiero początki więc sorry jak są straszne błędy.

    Dodano po 43 [minuty]:

    programik działa fajnie a powiedz mi jeszcze co sprawdza funkcja bit_is_clear czy jest 0 czy jest 1 bo nie wiem jak to jest.
  • #6 6155919
    rrata
    Poziom 19  
    if (bit_is_clear(PIND, PD3)) //Taki warunek jest spełniony, gdy bit 3 w rejestrze PIND jest równy 0

    if (bit_is_set(PIND, PD3)) //Taki warunek jest spełniony, gdy bit 3 w rejestrze PIND jest równy 1
  • #7 6156048
    Dziekan
    Poziom 13  
    Podpowiedz mi jeszcze jak te warunki sprawdzać żeby te diody zapalać bo jak robię pętle if i inkrementuje zmienną i to nie przechodzi mi do kolejnych linijek aby diody zapalały się po kolejnych naciśnięciach switcha: 1 raz 1 dioda, 2- raz druga dioda itd aż się obie zapalą to muszę jakiś timer użyć, bo jak switch wcisnę raz to jak mam ograniczyć wciskanie go do 3 razy i wrócić do początku. Za trudne to chyba zadanie dla mnie:)

    pozdrawiam
  • #8 6156131
    rrata
    Poziom 19  
    Dziekan napisał:
    bo jak robię pętle if
    If to nie pętla, tylko instrukcja warunkowa. Sprawdzi warunek, zrobi co trzeba i program leci dalej. W związku z tym, że instrukcję if masz w nieskończonej pętli for, to ten warunek jest sprawdzany wielokrotnie.

    Musisz użyć dodatkowej zmiennej, która będzie zapamiętywać poprzedni stan przycisku (taki który był, kiedy warunek if był przed chwilą sprawdzany, a sprawdzany jest wielokrotnie). Wyglądałoby to tak:
    Jeżeli poprzednim razem przycisk nie był wciśnięty i żadna dioda się nie świeciła, a teraz jest wciśnięty to zapal diodę 1.
    Jeżeli poprzednim razem przycisk był wciśnięty i teraz też jest wciśnięty to nic nie rób (cały czas trzymasz przycisk).
    Jeżeli poprzednim razem przycisk był wciśnięty, a teraz nie jest wciśnięty to nic nie rób (wcisnąłeś, zapaliłeś diodę i puściłeś).
    Jeżeli poprzednim razem przycisk nie był wciśnięty i teraz też nie jest to nic nie rób (przycisku nikt nie naciska).
    Jeżeli poprzednim razem przycisk nie był wciśnięty i dioda 1 świeciła się, a teraz jest wciśnięty to zgaś diodę 1 i zapal diodę 2.

    I tak dalej.
  • #9 6156164
    Dziekan
    Poziom 13  
    zaraz zobaczę czy jestem w stanie to zrobić i jak coś to jutro albo jeszcze dzisiaj ale późno napiszę co wyszło bo to kupa roboty.

    Dodano po 2 [godziny] 2 [minuty]:

    Napisałem już kawałek tego programu jak możesz to zobacz czy dobrze zrozumiałem to co pisałeś, jak to zrobić jak teraz nacisnę raz przycisk i puszcze to pali się jedna dioda ale nie chce zgasnąć i zapalić się druga kiedy nacisnę i puszcze drugi raz.
  • #10 6157121
    rrata
    Poziom 19  
    Zasadniczym błędem jaki robisz to porównywanie wyniku działania makra bit_is_clear albo bit_is_set do wartości stałej (skąd wpadłeś na taki pomysł?).
    if(i==1 && bit_is_clear(klawiszI ,sw1)==0)

    W tym momencie warunek będzie spełniony (ten drugi), gdy przycisk będzie puszczony, a nie wciśnięty. A tutaj to już wogóle nie wiadomo kiedy warunek będzie prawdziwy:
    if(bit_is_set(klawiszI, sw1)==1)

    makro zwróci wartość różną od zera, gdy puścisz przycisk. Skąd wiesz że będzie to wartość 1? W języku C wystarczy, że wartość będzie różna od zera, żeby była prawdziwa, np. takie zapisy:
    if (4)
    while (1)
    if (123)

    powodują, że powyższe instrukcje zawsze sie wykonają. Nie wykonałyby się, gdyby tam było 0.

    Dioda nie gaśnie z racji tego, że w ostatnim warunku robisz to co wyżej opisałem.

    Może lepiej dla zrozumienia napisać program obsługujący jedną diodę. Jedno naciśnięcie zapala, drugie naciśnięcie - dioda gaśnie.

    Poniżej zamieszczam program, który robi tak dla jednej diody. Wykorzystywana jest tylko jedna zmienna, bo więcej nie potrzeba.

    Podpowiem, że jak chcesz po kolei załączać diody to musisz utworzyć nową zmienną, która będzie przechowywać informacje o tym która dioda się świeci. W tym programie masz tylko pojedyncze instrukcje zapalające lub gaszące diodę, zamiast nich wstaw instrukcję która, będzie zmieniać wartość zmiennej przechowującej dane o zapalonych diodach (tą dodatkową którą utworzysz) np. inkrementując jej wartość. Następnie musisz utworzyć dodatkową instrukcje której jedynym zadaniem będzie sprawdzanie wartości tej zmiennej i odpowiednio zapalać i gasić diody.
  • #11 6157367
    Dziekan
    Poziom 13  
    Dzięki za pomoc, ta Twoja druga wersja działa dobrze dla jednej diody tylko nie wiem dlaczego jak nieraz nacisnę to dioda się zapali jak puszcze gaśnie a powinna świecić cały czas do czasu aż nacisnę i zgaśnie, to mam switch popsuty? czy może te drgania styków trzeba wyeliminować programowo bo czytałem o czymś takim w programowaniu przycisków.

    pozdr.
  • #12 6157424
    rrata
    Poziom 19  
    Dziekan napisał:
    jak nieraz nacisnę to dioda się zapali jak puszcze gaśnie
    Rozumiem, że nie dzieje się to zawsze? Skoro nie zawsze to właśnie problem jest z drganiami styków. Trzeba zrobić to tak: Sprawdzić, czy przycisk wciśnięty, jeżeli tak to odczekać jakiś czas np. kilka ms i jeszcze raz sprawdzić czy jest wciśnięty. Jak za drugim razem nie będzie wciśnięty tzn., że styk drgał, jak będzie tzn., że ktoś wcisnął.

    Co do tego drugiego programu to trochę za bardzo nakombinowałem, bo można to było prościej napisać. Czyli zrobić to tak:
  • #13 6157594
    Dziekan
    Poziom 13  
    dokładnie tak nie jest za każdym razem, w sumie to nawet nie jest tak często. Napisałem tą funkcję, tzn. przepisałem prawie z książki której się uczę ale nie wiem czy dobrze to będzie, bo nie wiem jaki ten czas ma być to zależy od kwarcu jaki mam czy to sobie sam ustalam. Program teraz wygląda tak, nie wiem jak ten czas tam ustawić, ale diody palą się już tak jak powinny.
  • #14 6157762
    rrata
    Poziom 19  
    Pisanie funkcji opóźniających to wyważanie otwartych drzwi. Są do tego już zrobione funkcje, musisz tylko dołączyć do programu plik util/delay.h
    i możesz ich używać.
    _delay_ms(milisekundy);
    _delay_us(mikrosekundy);

    Czyli w funkcji klawisz zamiast
    czekaj(30*tau);
    wpisz np.
    _delay_ms(5);
    program będzie czekał 5ms.

    Później musiałbyś wywoływać funkcję klawisz w pętli głównej programu w ten sposób:
    klawisz(0b00001000);
    //Trzeba podać tej funkcji gotową liczbę, a nie numer bitu, patrz na pętle w niej zawarte


    To rozwiązanie ma taką wadę, że będzie zatrzymywać program w tych pętlach dopóki ktoś nie wciśnie klawisza. Teraz to nie robi różnicy, ale gdybyś takie rozwiązanie zastosował w większym programie to może być problem.

    Ja osobiście zrobiłbym tak, że dodałbym tylko, czy klawisz jest wciśnięty, i jeżeli tak to odczekał chwilę. Np dołożyć do mojego programu taka instrukcję:
    if ( bit_is_clear(klawiszI ,sw1) ) _delay_ms(5);
    i tyle.
    Myślę że coś to da. Oczywiście i w jednym i w drugim przypadku musisz wpisać na początku programu
    #include <util/delay.h>


    Opóźnienie jest obliczane przez kompilator na podst. parametrów funkcji _delay_ms() i częstotliwości zegara systemowego, którą definiujesz w MakeFile (sekcja F_CPU). Albo dopisz sobie na początku programu
    #define F_CPU częstotliwość w hercach
  • #16 6157927
    rrata
    Poziom 19  
    Ostatnio mam dużo czasu.
  • #17 6157933
    Freddie Chopin
    Specjalista - Mikrokontrolery
    luz, twoj wybor. pytanie tylko jest takie - czy gdy nastepnym razem osoba ktora wyreczyles bedzie miala problem - tez bedziesz mial duzo czasu? nie sadzisz chyba, ze kogokolwiek nauczysz czegos wyreczaniem go w praktycznie 100%...

    4\/3!!
  • #18 6157953
    rrata
    Poziom 19  
    Freddie Chopin napisał:
    nie sadzisz chyba, ze kogokolwiek nauczysz czegos wyreczaniem go w praktycznie 100%...
    hmm chyba masz rację. Chciałem dobrze i troche przesadziłem :|
  • #19 6157958
    Dziekan
    Poziom 13  
    już ustawiłem to opóźnienie i działa w sumie bez jakiegoś skomplikowanego kodu już prawie napisałem cały program z Twoją pomocą jeszcze mi została końcówka co będzie najgorsze jak dla mnie bo mam masę błędów bo teraz ten programik na diodach ma być połączony z innym programem do wysyłania czegoś po uarcie program który wysyła działa bez problemu ale nie mogę go teraz połączyć z tym z diodami, chcę żeby każde kombinacja diod odpowiadała innej częstotliwości wysyłania przykładowo nie pali się żadna:

    00 - 10 razy na sekunde
    01 - 100 razy na sek
    10 - 1000 razy
    11 - 10000 razy

    bo jak narazie to tylko wysyła z jedną częstotliwościa tą ustawioną
    #define TIME_SECONDS 1

    i muszę zmieniać w programie i kompilować, programować procesor a tak to będę sobie przyciskiem zmieniał i wiedział co się dzieje.
    Masz czas to zobacz jak byś to połączył żeby tą zmienną zmienić bo mój najlepszy wynik to 8 błędów ale pracuje nad tym.
    Programy 2 wrzucę oddzielnie bo w moim się będzie ciężko połapać.
  • #20 6158076
    rrata
    Poziom 19  
    Tamten program z diodami trochę za bardzo pokręciłeś. Trzeba było (w moim programie) zamiast instrukcji zmieniającej stan diody, dać instrukcję inkrementującą zmienną licznik, a poźniej umieścić instrukcję sprawdzającą wartość zmiennej licznik i zależnie od jej wartości gasić czy zapalać diody. To możesz załatwić jedną instrukcją switch. W dodatku opóźnienie po wciśnięciu klawisza dałeś przed pętlą główną, więc nic ono nie daje. W programie z uartem TIME_SECONDS powinno być zmienną typu unsigned int i powinieneś zmieniać jej wartość tak samo jak gasiłeś diody.
  • #21 6158178
    Dziekan
    Poziom 13  
    Wstawiłem jedno w drugie i nadal 8 błędów jest ale to opóźnienie to chyba działa bo nie mam już takich sytuacji że puszcze to gaśnie. ustawiłem tą zmienną na unsigned int i zmieniam ją w każdym przypadku tak mi się przynajmniej wydaje.
  • #22 6158369
    rrata
    Poziom 19  
    Coś mi sie zdaje, że zrobiłeś to na szybko i byle jak, bo teraz masz taką sytuację, że masz dwie pętle nieskończone. Jak program wejdzie ci w jedną NIESKOŃCZONĄ to to co jest za nią NIGDY nie wykona się.
    Czemu dwa razy dołączasz plik avr/io.h a nie dołączasz pliku util/delay.h?
    Czemu do zmiennej przypisujesz wartość, której nigdy ta zmienna nie osiągnie, ponieważ wykracza poza zakres? (chodzi mi tu o TIME_SECONDS, ponadto nazwy zmiennych przyjęło się pisać z małych liter) poczytaj o typach danych.

    Zauważyłem jeszcze, że warunek if( (i==1) && (bit_is_set(klawiszI ,sw1)) ) skopiowałeś kilka razy dopisując tylko
    && licznik == jakas liczba
    Ten pierwszy warunek załatwia wszystkie. Zawsze kiedy tamte ze zmienną licznik będą prawdziwe to i pierwszy będzie prawdziwy. Mam nadzieję, że zrozumiałeś o co chodzi i co trzeba z tym zrobić.
    Zrób to powoli, przemyśl wszystko kilka razy nie ma się co spieszyć.
REKLAMA