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

Nieprawidłowe działanie ATMEGA8A - sterowanie silnikiem krokowym i INT0

DawidGwo 01 Lip 2021 15:49 504 4
  • #1 19502689
    DawidGwo
    Poziom 1  
    WItam, mam problem na który nie mam pomysłu. Na ATMEGA8A robie sterowanie silnikiem krokowymw 3 pozycjach lewo, prawo i stop,i dziala zgodnie z oczekiwaniami. Nastepnie dolaczylem do INT0 wlacznik krańcowy zeby generowal przerwanie i cofal silnikiem wrazie wystapienia przerwania. I tu zaczely sie schody bo podciagam VCC pod INT0 zeby przerwanie generowalo sie przy zwarciu wlacznika krancowego z masa, ale po odpaleniu caly czas sie kreci silnikczek a dopeiro w zwarciu z masą zatrzymuje sie i mozna nim sterować. a powinno byc na odwrót....moglby mi ktos kod przeanalizowac i pomoc??
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    #define T1 (1<<PC0)
    #define T2 (1<<PC1)
    #define T3 (1<<PC2)
    #define T4 (1<<PC3)
    
    #define KROK1 PORTC |= T1; PORTC &=~ (T2|T3|T4)
    #define KROK2 PORTC |= T2; PORTC &=~ (T1|T3|T4)
    #define KROK3 PORTC |= T3; PORTC &=~ (T1|T2|T4)
    #define KROK4 PORTC |= T4; PORTC &=~ (T1|T2|T3)
    
    
    
    int main () {
    
    	MCUCR |= (1<<ISC01); //ustawiamy reakcje przerwań ze stanu 1->0
    	GICR |= (1<<INT0);  //aktywujemy przerwania na INT0 i INT1
    
    	DDRC |= T1 | T2 | T3 | T4; //ustawiamy porty C jako wyjscia do silniczka KROKOWEGO
    	DDRB &=~ ((1<<PB1)|(1<<PB2)); // piny B ustawiamy jako wejscia od przelacznika kierunku obrotu
    	DDRD &=~ (1<<PD2); //pin D ustawiamy jako wejscia od przelacznikow krancowych
    	PORTC &=~ (T1|T2|T3|T4);  //wyjsciowo silniczek wylaczony
    	PORTB |= (1<<PB1)|(1<<PB2); //piny B podciagniete pod VCC
    	PORTD |= (1<<PD2); //pin D podciagniete pod VCC
    sei();
    while(1) {
    	if(!(PINB & 0b00000100)) {
    	KROK1;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK4;
    	_delay_ms(10);
    	KROK1;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK4;
    	_delay_ms(10);
    	}
    
    	else if(!(PINB & 0b00000010)) {
    	KROK4;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK1;
    	_delay_ms(10);
    	KROK4;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK1;
    	_delay_ms(10);
    	}
    
    	else {
    	PORTD &=~ (T1|T2|T3|T4);
    	}
    }
    }
    ISR(INT0_vect) {
    	KROK1;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK4;
    	_delay_ms(10);
    	KROK1;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK4;
    	_delay_ms(10);
    }
    
    ISR(INT1_vect) {
    	KROK4;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK1;
    	_delay_ms(10);
    	KROK4;
    	_delay_ms(10);
    	KROK3;
    	_delay_ms(10);
    	KROK2;
    	_delay_ms(10);
    	KROK1;
    	_delay_ms(10);
    }
    
    


    Dodano po 13 [minuty]:

    dodam ze jesli zewre vcc do INT0 przez rezystor to dziala wszytsko tak jak powinno, cos jakby wewnetrzne podciagniecie szwankowalo....
  • #2 19502873
    maciej_333
    Poziom 38  
    Może zacznijmy od całości kodu. Jest on całkowicie pozbawiony sensu. W pętli są zwykłe opóźnienia. Już samo to nie ma sensu. Rozwiązanie takie zajmuje 100% czasu mikrokontrolera, zatem nie ma możliwości zrobienia czegoś innego. Kolejna sprawa to opóźnienie wewnątrz podprogramu obsługi przerwania. Przecież jest to niedopuszczalne! Przerwanie powinno się wykonywać możliwie krótko. Ustawienie poszczególnych rejestrów poprzez operację odczyt-modyfikacja-zapis nie ma sensu.

    Powinno się generować przerwanie jakimś Timerem co 10 ms. Wewnątrz podprogramu obsługi tego przerwania powinno się dokonywać zmian stanu linii sterujących silnikiem. Można stany te zapisać np. w jakiejś tablicy, zaś z każdym przerwaniem inkrementować licznik. Na podstawie licznika można odczytywać wartości z tablicy. Potem kiedy licznik osiągnie wartość maksymalną należy go wyzerować.

    Dopiero po przerobieniu programu na zgodny ze sztuką można dyskutować co dalej. Oczywiście należy go całkowicie napisać od nowa.
  • Pomocny post
    #3 19503896
    dondu
    Moderator na urlopie...
    Pomijając częściowo słuszne uwagi kol. maciej_333, choć w Twoim przypadku możesz zrobić od nich odstępstwo, to sprawdź najpierw poprawność działania rezystora pull-up na PD2. Choć to mało prawdopodobne to teoretycznie jest możliwe, że wewnętrzny rezystor pull-up nie działa prawidłowo.

    Ponieważ wydaje się, że w programie prawidłowo poustawiałeś piny, rezystor pull-up oraz przerwania, a dodatkowo zaobserwowałeś, że:

    DawidGwo napisał:
    dodam ze jesli zewre vcc do INT0 przez rezystor to dziala wszytsko tak jak powinno, cos jakby wewnetrzne podciagniecie szwankowalo....


    to na początek przetestuj rezystor pull-up. Napisz prosty program bez przerwań :
    - włącz rezystor pull-up PD2
    - ustaw pin diody LED na wyjście
    - w pętli głównej sprawdzaj stan bitu PD2 w rejestrze PIND i odpowiednio włączaj lub wyłączaj LED.

    Swoją drogą masz funkcję przerwania INT1, ale nie jest ono włączone.

    Dodano po 5 [minuty]:

    Powyższy test będzie działał prawidłowo, ponieważ błąd jest tutaj ... wyłącza rezystor pull-up. :)
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #4 19504117
    StaryVirus_e_Wiarus
    Poziom 21  
    Cześć
    Wyjaśnijcie mi proszę co zdecyduje preprocesor i kompilator po wykonaniu tej części kodu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
REKLAMA