Skocz do zawartości

Keadwen

Użytkownicy
  • Zawartość

    31
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    1

Wszystko napisane przez Keadwen

  1. Hmmm no dobra ten reset poprawię. Przetnę ścieżkę i poprawię. AREF to zrobię przy nowej płytce. EDIT: Reset poprawiony. Wyrzuciłem przycisk i podstawiłem rezystor 10k i kabelkiem do Vcc prosto z stabilizatora. Jednak mam pytanie, czy źle podłączony AREF dyskwalifikuje od razu możliwość używania ADC? Czy można wybrać inny punkt odniesienia (2,56V nie wchodzi w grę)
  2. Rzeczywiście, nie zwróciłem na to uwagi wcześniej. W przyszłości nie zbyt odległej i tak planuję nową płytkę więc wtedy to uwzględnię. Nie wiem czemu, ale no nie zauważyłem braku schematu z czujnikami.
  3. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P_PIN (1<<PA7) #define czujnik3P_PIN (1<<PA6) #define czujnik2P_PIN (1<<PA5) #define czujnik1P_PIN (1<<PA4) #define czujnik1L_PIN (1<<PA3) #define czujnik2L_PIN (1<<PA2) #define czujnik3L_PIN (1<<PA1) #define czujnik4L_PIN (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Deklaracje zmiennych volatile uint8_t adc_flag; volatile int16_t pomiar[8]; volatile uint8_t kanal = 0; // Zmienne do regulacji algorytmu P uint16_t docelowa_pozycja = 0; uint16_t wart_graniczna = 700; uint16_t predkosc_silnikow = 150; uint8_t wart_regulacji_pwm = 35; // Zmienne pomocne w algorytmie int16_t aktualna_pozycja; int16_t error; int16_t zmiana_pwm; uint8_t ilosc_czujnikow = 1; // Zabezpieczenie przed dzieleniem przez 0 int8_t czujnik4L, czujnik3L, czujnik2L, czujnik1L, czujnik1P, czujnik2P, czujnik3P, czujnik4P; int16_t v_ocr1a, v_ocr1b; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L_PIN | czujnik3L_PIN | czujnik2L_PIN | czujnik1L_PIN | czujnik1P_PIN | czujnik2P_PIN | czujnik3P_PIN | czujnik4P_PIN); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; OCR1A = 150; OCR1B = 150; // *** ADC ADMUX |= (1<<REFS0); // 1. Włączenie ADC + napięcie odniesienia ADCSRA |= (1<<ADEN) | (1<<ADIE); // 2. Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // 3. Częstotliwość pracy (preskaler = 128, fp=125kHz) moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // 4. Włączenie globalnego zezwolenia na przerwanie ADMUX |= (ADMUX * 0xF8); ADCSRA |= (1<<ADSC); // 5. Ustawienie flagi dla pierwszego pomiaru while(1) { if(adc_flag)// 10. Pętla for - "wylicza sobie coś tam" { if(pomiar[0] > wart_graniczna) { czujnik4L = -4; ilosc_czujnikow++; } else czujnik4L = 0; if(pomiar[1] > wart_graniczna) { czujnik3L = -3; ilosc_czujnikow++; } else czujnik3L = 0; if(pomiar[2] > wart_graniczna) { czujnik2L = -2; ilosc_czujnikow++; } else czujnik2L = 0; if(pomiar[3] > wart_graniczna) { czujnik1L = -1; ilosc_czujnikow++; } else czujnik1L = 0; if(pomiar[4] > wart_graniczna) { czujnik1P = 1; ilosc_czujnikow++; } else czujnik1P = 0; if(pomiar[5] > wart_graniczna) { czujnik2P = 2; ilosc_czujnikow++; } else czujnik2P = 0; if(pomiar[6] > wart_graniczna) { czujnik3P = 3; ilosc_czujnikow++; } else czujnik3P = 0; if(pomiar[7] > wart_graniczna) { czujnik4P = 4; ilosc_czujnikow++; } else czujnik4P = 0; aktualna_pozycja = (((czujnik4L + czujnik3L + czujnik2L + czujnik1L + czujnik1P + czujnik2P + czujnik3P + czujnik4P)* 10)/ilosc_czujnikow); // Dodałem wszystkie czujniki gdzie występuje linia i pomnożyłem x10 by nie robić zmiennej // typu float. Podkoniec podzieliłem przez ilośc czujników w który wystąpiła linia. error = docelowa_pozycja - aktualna_pozycja; // Wyliczam w którym miejscu "mniej więcej" znajduje się linia zmiana_pwm = ((wart_regulacji_pwm * error)/10); // Wyliczam wartość która będzie zmieniać OCR1A/B. Dzielę też przez 10, bo wcześniej mnoż. v_ocr1a = predkosc_silnikow + zmiana_pwm; if(v_ocr1a > 255) v_ocr1a = 255; v_ocr1b = predkosc_silnikow - zmiana_pwm; if(v_ocr1b > 255) v_ocr1b = 255; OCR1A = v_ocr1a; OCR1B = v_ocr1b; // Resety wartości ilosc_czujnikow = 1; error = 0; zmiana_pwm = 0; aktualna_pozycja = 0; // Reset flagi adc_flag = 0; ADMUX |= (ADMUX * 0xF8); // Zerowanie kanalu i jego start poniżej ADCSRA |= (1<<ADSC); // 11. Po wyliczeniach ponownie ustawiamy ADSC by wykonać pomiar // 12. Patrz pkt.6 } } } // ***** OBSŁUGA PRZERWANIA ADC ***** ISR(ADC_vect) // 6. Zakończenie pomiaru (set ADIF, clear ADSC) { pomiar[kanal] = ADCW; // 7. Reset ADIF, rozpoczęcie przerwania kanal++; // 8. Odczytanie wartości z bajtów ADCW ADMUX |= (ADMUX * 0xF8) | kanal; // 8.1. Zmiana kanału pomiarowego ADC if(kanal < 8) ADCSRA |= (1<<ADSC); // 8.2. Zainicjowania nowego pomiaru else { kanal = 0; adc_flag = 1; // 9. Ustawienie flagi dla programu głównego } // -> ale dopiero po wykonaniu 8 pomiarów! }
  4. Jedzie przed siebie, czujniki nie reagują na linię. Sądzę, że to może być wina tych żałosnych kabelków dlatego je dzisiaj wymieniam na porządne, estetyczne wielożyłowe drucisze
  5. Poprawiłem kod, na bardziej czytelny w sposób przez Ciebie Mog podrzucony. Wyrzuciłem wszystko co nie było związane z ADC i rozrysowałem blokowy schemat działania ogólnego. Niestety jakoś nadal nie działa i niezbyt wiem dlaczego. Zasada działania mojego programu wygląda tak: 1. Wykonuję odczyt z 8 czujników (10bit rozdzielczość) i zapisuje wartości do tabeli pomiar[] // opis odczytu kilka postów u góry 2. Za pomocą pętli if sprawdzam czy pomiar dla poszczególnych czujników przekroczył wartość graniczną np. 700. 2.a. Jeżeli tak, to zmienna czujnikXX przyjmuje wartość zależną od położenia czujnika (czujnik po lewej ma wart -4, potem -3, -2, -1. Natomiast czujniki od prawej 1, 2, 3, 4) Inkrementuję również zmienną "ilość czujników" którą wykorzystam w późniejszych obliczeniach. 2.b Jeżeli nie przekroczyła wart_granicznej, wartość czujnika = 0 3. Po wykonaniu wszystkich odczytów sumuję wartości ich wszystkich i dzielę przez ilość gdzię wystąpiła linia. (mnożę też x10 by uniknąć wartości po przecinku) 4. Wyliczam rozrzut (error) względem docelowej pozycji 5. Wyliczam wartość którą będę regulował OCR1A i OCR1B 6. Wyznaczam nowe wartości OCR1A/B #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P_PIN (1<<PA7) #define czujnik3P_PIN (1<<PA6) #define czujnik2P_PIN (1<<PA5) #define czujnik1P_PIN (1<<PA4) #define czujnik1L_PIN (1<<PA3) #define czujnik2L_PIN (1<<PA2) #define czujnik3L_PIN (1<<PA1) #define czujnik4L_PIN (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Deklaracje zmiennych volatile uint8_t adc_flag; volatile int16_t pomiar[8]; volatile uint8_t kanal = 0; // Zmienne do regulacji algorytmu P uint16_t docelowa_pozycja = 0; uint16_t wart_graniczna = 700; uint16_t predkosc_silnikow = 150; uint8_t wart_regulacji_pwm = 35; // Zmienne pomocne w algorytmie int16_t aktualna_pozycja; int16_t error; int16_t zmiana_pwm; uint8_t ilosc_czujnikow = 1; // Zabezpieczenie przed dzieleniem przez 0 int8_t czujnik4L, czujnik3L, czujnik2L, czujnik1L, czujnik1P, czujnik2P, czujnik3P, czujnik4P; int16_t v_ocr1a, v_ocr1b; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L_PIN | czujnik3L_PIN | czujnik2L_PIN | czujnik1L_PIN | czujnik1P_PIN | czujnik2P_PIN | czujnik3P_PIN | czujnik4P_PIN); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; OCR1A = 150; OCR1B = 150; // *** ADC ADMUX |= (1<<REFS0); // 1. Włączenie ADC + napięcie odniesienia ADCSRA |= (1<<ADEN) | (1<<ADIE); // 2. Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // 3. Częstotliwość pracy (preskaler = 128, fp=125kHz) moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // 4. Włączenie globalnego zezwolenia na przerwanie ADCSRA |= (1<<ADSC); // 5. Ustawienie flagi dla pierwszego pomiaru ADMUX |= (ADMUX * 0xF8); while(1) { if(adc_flag)// 10. Pętla for - "wylicza sobie coś tam" { if(pomiar[0] > wart_graniczna) { czujnik4L = -4; ilosc_czujnikow++; } else czujnik4L = 0; if(pomiar[1] > wart_graniczna) { czujnik3L = -3; ilosc_czujnikow++; } else czujnik3L = 0; if(pomiar[2] > wart_graniczna) { czujnik2L = -2; ilosc_czujnikow++; } else czujnik2L = 0; if(pomiar[3] > wart_graniczna) { czujnik1L = -1; ilosc_czujnikow++; } else czujnik1L = 0; if(pomiar[4] > wart_graniczna) { czujnik1P = 1; ilosc_czujnikow++; } else czujnik1P = 0; if(pomiar[5] > wart_graniczna) { czujnik2P = 2; ilosc_czujnikow++; } else czujnik2P = 0; if(pomiar[6] > wart_graniczna) { czujnik3P = 3; ilosc_czujnikow++; } else czujnik3P = 0; if(pomiar[7] > wart_graniczna) { czujnik4P = 4; ilosc_czujnikow++; } else czujnik4P = 0; aktualna_pozycja = (((czujnik4L + czujnik3L + czujnik2L + czujnik1L + czujnik1P + czujnik2P + czujnik3P + czujnik4P)* 10)/ilosc_czujnikow); // Dodałem wszystkie czujniki gdzie występuje linia i pomnożyłem x10 by nie robić zmiennej // typu float. Podkoniec podzieliłem przez ilośc czujników w który wystąpiła linia. error = docelowa_pozycja - aktualna_pozycja; // Wyliczam w którym miejscu "mniej więcej" znajduje się linia zmiana_pwm = ((wart_regulacji_pwm * error)/10); // Wyliczam wartość która będzie zmieniać OCR1A/B. Dzielę też przez 10, bo wcześniej mnoż. v_ocr1a = predkosc_silnikow + zmiana_pwm; if(v_ocr1a > 255) v_ocr1a = 255; v_ocr1b = predkosc_silnikow - zmiana_pwm; if(v_ocr1b > 255) v_ocr1b = 255; OCR1A = v_ocr1a; OCR1B = v_ocr1b; // Resety wartości ilosc_czujnikow = 1; error = 0; zmiana_pwm = 0; aktualna_pozycja = 0; // Reset flagi adc_flag = 0; ADCSRA |= (1<<ADSC); // 11. Po wyliczeniach ponownie ustawiamy ADSC by wykonać pomiar // 12. Patrz pkt.6 } } } // ***** OBSŁUGA PRZERWANIA ADC ***** ISR(ADC_vect) // 6. Zakończenie pomiaru (set ADIF, clear ADSC) { pomiar[kanal] = ADCW; // 7. Reset ADIF, rozpoczęcie przerwania kanal++; // 8. Odczytanie wartości z bajtów ADCW // 8.1. Zmiana kanału pomiarowego ADC if(kanal < 8) ADCSRA |= (1<<ADSC); // 8.2. Zainicjowania nowego pomiaru else { kanal = 0; // adc_flag = 1; // 9. Ustawienie flagi dla programu głównego } // -> ale dopiero po wykonaniu 8 pomiarów! ADMUX |= (ADMUX * 0xF8) | kanal; } Podsumowując, chciałbym powiedzieć, że wzoruje się na ostatnim artykul i jego kodzie Kp = 10 //Współczynnik Kp Docelowa = 0 //Pozycja docelowa Tp = 50 //Docelowa prędkość robota Do //Pętla nieskończona Odczytaj pod, którymi czujnikami jest linia Policz aktualną pozycję Błąd = Docelowa + Aktualna pozycja Zmiana = Kp * błąd //Liczymy wartość zmiany PWM Silnik_L = Tp + Zmiana // Przekazujemy do silnika lewego nową prędkość Silnik_p = Tp - Zmiana // Przekazujemy do silnika prawego nową prędkość Loop //Koniec pętli
  6. Działa, jeździ ale ma jedną wadę Dość ostro przestrzeliwuje zakręty, wręcz w 90% jedzie prosto, a w 10% jak już skręci to i tak ucieka potem prosto. Sądzę, że to może być wina zbyt długiego przerwania i podczas wykonywania go, następne się już dobija. Zamieszczam poniżej aktualny kod. Dzisiaj jeszcze dużo będę ekperymentował bo mam wolnego czasu nadmiar EDIT: Poprawiony kod. Póki co nie działa. Wszelkie zmiany będę tutaj wprowadzał, bez tworzenia nowego postu. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 670 #define predkosc_srodkowa 100 #define wart_regulacji_pwm 35 // *** Deklaracje zmiennych uint8_t czujnik; volatile uint8_t adc_flag; volatile uint16_t pomiar[8]; volatile uint8_t kanal; int8_t cz1L, cz2L, cz3L, cz4L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm, licznik; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; OCR1A = 150; OCR1B = 150; // *** ADC ADMUX |= (1<<REFS0); // 1. Włączenie ADC + napięcie odniesienia ADCSRA |= (1<<ADEN) | (1<<ADIE); // 2. Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // 3. Częstotliwość pracy (preskaler = 128, fp=125kHz) moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // 4. Włączenie globalnego zezwolenia na przerwanie ADCSRA |= (1<<ADSC); // 5. Ustawienie flagi dla pierwszego pomiaru while(1) { if(adc_flag)// 10. Pętla for - "wylicza sobie coś tam" { if(pomiar[0] > wart_graniczna) { cz4L = -30; licznik++; } else cz4L = 0; if(pomiar[1] > wart_graniczna) { cz3L = -20; licznik++; } else cz3L = 0; if(pomiar[2] > wart_graniczna) { cz2L = -10; licznik++; } else cz2L = 0; if(pomiar[3] > wart_graniczna) { cz1L = 0; licznik++; } else cz1L = 0; if(pomiar[4] > wart_graniczna) { cz1P = 0; licznik++; } else cz1P = 0; if(pomiar[5] > wart_graniczna) { cz2P = 10; licznik++; } else cz2P = 0; if(pomiar[6] > wart_graniczna) { cz3P = 20; licznik++; } else cz3P = 0; if(pomiar[7] > wart_graniczna) { cz4P = 30; licznik++; } else cz4P = 0; // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / licznik; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = (wart_regulacji_pwm * error)/10; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa + regulacja_pwm; OCR1B = predkosc_srodkowa - regulacja_pwm; // Reset erroru i wartosci czujników error = 0; licznik = 0; adc_flag = 0; ADCSRA |= (1<<ADSC); // 11. Po wyliczeniach ponownie ustawiamy ADSC by wykonać pomiar // 12. Patrz pkt.6 } } } // ***** OBSŁUGA PRZERWANIA ADC ***** ISR(ADC_vect) // 6. Zakończenie pomiaru (set ADIF, clear ADSC) { pomiar[kanal] = ADCW; // 7. Reset ADIF, rozpoczęcie przerwania kanal++; // 8. Odczytanie wartości z bajtów ADCW // 8.1. Zmiana kanału pomiarowego ADC if(kanal < 8) ADCSRA |= (1<<ADSC); // 8.2. Zainicjowania nowego pomiaru else { kanal = 0; adc_flag = 1; // 9. Ustawienie flagi dla programu głównego } // -> ale dopiero po wykonaniu 8 pomiarów! ADMUX |= (ADMUX * 0xF8) | kanal; }
  7. Wydaje mi się, że najbardziej optymalne z punktu widzenia line followera jest to by najpierw odczytał 8 kanałów i dopiero potem obliczył error i OCR1A/B.
  8. Napisałem na kartce pseudokod. 1. Włączam ADC 2. Włączam zezwolenie na przerwanie ADC 3. Ustawiam częstotliwość pracy ADC 4. Włączam globalne zezwolenie na przerwanie 5. Ustawiami (1< 6. Zakończenie pomiaru (czyli automatyczny clear ADSC i set ADIF) 7. Rozpoczęcie przerwania ADC_vect 8. Odczyt wartości z zmierzonego kanału (bajty ADCW) 8.1. Zmiana kanału pomiarowego ADC 8.2 Zainicjowania nowego pomiaru 9. Ustawienie flagi dla pętli głównej o nowych odczytach 10. Pętla while wylicza sobie coś tam 11. Ustawiamy ADSC i tak w kółko od pkt 6 Idę walczyć z kodem, mam nadzieje, że ten pseudokod pomoże. Co do cierpliwości, to wróciła ;D Książkę mam autora Mirekk36. EDIT: #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 750 #define predkosc_srodkowa 130 #define wart_regulacji_pwm 30 // *** Deklaracje zmiennych volatile uint8_t adc_flag; volatile uint16_t pomiar[8]; volatile uint8_t kanal; int8_t cz1L, cz2L, cz3L, cz4L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm, liczba_czujnikow; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; OCR1A = 150; OCR1B = 150; // *** ADC ADMUX |= (1<<REFS0); // 1. Włączenie ADC + napięcie odniesienia ADCSRA |= (1<<ADEN) | (1<<ADIE); // 2. Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // 3. Częstotliwość pracy (preskaler = 128, fp=125kHz) moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // 4. Włączenie globalnego zezwolenia na przerwanie ADCSRA |= (1<<ADSC); // 5. Ustawienie flagi dla pierwszego pomiaru while(1) { for(adc_flag = 1; adc_flag; adc_flag--) // 10. Pętla for - "wylicza sobie coś tam" { } // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / liczba_czujnikow; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = wart_regulacji_pwm * error; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa - regulacja_pwm; OCR1B = predkosc_srodkowa + regulacja_pwm; // Reset erroru i wartosci czujników error = 0; liczba_czujnikow = 0; ADCSRA |= (1<<ADSC); // 11. Po wyliczeniach ponownie ustawiamy ADSC by wykonać pomiar // 12. Patrz pkt.6 } } // ***** OBSŁUGA PRZERWANIA ADC ***** ISR(ADC_vect) // 6. Zakończenie pomiaru (set ADIF, clear ADSC) { // 7. Reset ADIF, rozpoczęcie przerwania pomiar[kanal] = ADCW; // 8. Odczytanie wartości z bajtów ADCW kanal++; // 8.1. Zmiana kanału pomiarowego ADC if(kanal < 8) ADCSRA |= (1<<ADSC); // 8.2. Zainicjowania nowego pomiaru else { kanal = 0; adc_flag = 1; // 9. Ustawienie flagi dla programu głównego } // -> ale dopiero po wykonaniu 8 pomiarów! }
  9. Teraz widzę jak ten brak doświadczenia z programowaniem. Mam wielką nadzieję, że jesteś bardziej cierpliwy i spokojny niż ja Dondu. Powoli zaczyna mnie denerwować to, że rozumiem ale nie umiem napisać Ale mam kolejną wersję. Przerwanie ADC zrobiłem z opisami punktowymi i pasuje do twojego algorytmu działania. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 750 #define predkosc_srodkowa 130 #define wart_regulacji_pwm 30 // *** Deklaracje zmiennych uint8_t czujnik; volatile uint8_t adc_flag; volatile uint16_t pomiar[]; volatile uint8_t kanal; int8_t cz1L, cz2L, cz3L, cz4L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm, liczba_czujnikow; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; OCR1A = 150; OCR1B = 150; // *** TIMER0 - dla ADC TCCR0 |= (1<<WGM01) | (1<<COM01); // CTC, Clear OC0 on compare match TCCR0 |= (1<<CS00); // preskaler = 1 OCR0 = 160; // Compare Match (zbocze opadające) na wart. 160 TIMSK |= (1<<OCIE0); // *** ADC ADMUX |= (1<<REFS0); // AVCC with external capacitor at AREF pin ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // Włączenie ADC, Auto Trigger Enable, Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // preskaler = 128, fp=125kHz SFIOR |= (1<<ADTS1) | (1<<ADTS0); // Przerwanie - Compare Match Timer0 moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // Globalne zezwolenie na przerwanie while(1) { if(adc_flag) { czujnik = kanal; // // switch (czujnik) // Przypisanie wyniku cyfrowego z dokonanego { // pomiaru do zmiennej odpowiadającej za case 0: // swój czujnik cz4L = pomiar[czujnik]; break; case 1: cz3L = pomiar[czujnik]; break; case 2: cz2L = pomiar[czujnik]; break; case 3: cz1L = pomiar[czujnik]; break; case 4: cz1P = pomiar[czujnik]; break; case 5: cz2P = pomiar[czujnik]; break; case 6: cz3P = pomiar[czujnik]; break; case 7: cz4P = pomiar[czujnik]; break; } adc_flag = 0; } // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / liczba_czujnikow; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = wart_regulacji_pwm * error; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa - regulacja_pwm; OCR1B = predkosc_srodkowa + regulacja_pwm; // Reset erroru i wartosci czujników error = 0; liczba_czujnikow = 0; } } // ***** OBSŁUGA PRZERWANIA ADC ***** ISR(ADC_vect) { for(kanal = 0; kanal < 8; kanal++) // 2.2 Zmiana kanału + 2.3 Inicjacja kolejnego pomiaru { ADMUX |= (ADMUX & 0xF8) | kanal; // 2.1 Odczyt ADC ADCSRA |= (1<<ADSC); // Zabronione czekanie, ale jak mam to inaczej while (ADCSRA & (1<<ADSC)) // poczekać na wynik?! pomiar[kanal] = ADCW; // 2.1 Zapisanie do zmiennej if(pomiar[kanal] > wart_graniczna) // pomiar[kanal] = 1; else pomiar[kanal] = 0; } if(kanal>7) kanal=0; // Reset - przygotowanie do następnego przerwania adc_flag = 1; // 2.4 Ustawienie flagi dla programu głównego } Odpowiedz mi proszę na poniższe pytania: 1. Czy mam usunąć Timer0 czy nie? Jeżeli go usunę to co ma być wyzwalaczem przerwania? 2. Czy Timer0 nie wywołuje przerwania zbyt często? 3. Jeżeli nie mogę używać _delay_ ani pętli oczekujących to w jaki sposób mam mieć pewność, że ADC wykonało odpowiednią ilość cykli i odczytana wartość jest poprawna? (przeczytałem twoją stronę. Tam jest napisane jak nie robić, a brak informacji jak to zastąpić) Znalazłem polską wersję karty katalogowej Atmegi16 i doczytałem, że z tym ADIF to rzeczywiście ulega wyczyszczeniu po rozpoczęciu przerwania.
  10. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 750 #define predkosc_srodkowa 130 #define wart_regulacji_pwm 30 // *** Deklaracje zmiennych uint8_t czujnik; volatile uint8_t adc_flag; volatile uint16_t pomiar[]; volatile uint8_t kanal; int8_t cz1L, cz2L, cz3L, cz4L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm, liczba_czujnikow; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; OCR1A = 150; OCR1B = 150; // *** TIMER0 - dla ADC TCCR0 |= (1<<WGM01) | (1<<COM01); // CTC, Clear OC0 on compare match TCCR0 |= (1<<CS00); // preskaler = 1 OCR0 = 160; // Compare Match (zbocze opadające) na wart. 160 TIMSK |= (1<<OCIE0); // *** ADC ADMUX |= (1<<REFS0); // AVCC with external capacitor at AREF pin ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // Włączenie ADC, Auto Trigger Enable, Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // preskaler = 128, fp=125kHz SFIOR |= (1<<ADTS1) | (1<<ADTS0); // Przerwanie - Compare Match Timer0 moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // Globalne zezwolenie na przerwanie while(1) { if(adc_flag) { czujnik = kanal; // // switch (czujnik) // Przypisanie wyniku cyfrowego z dokonanego { // pomiaru do zmiennej odpowiadającej za case 0: // swój czujnik cz4L = pomiar[czujnik]; break; case 1: cz3L = pomiar[czujnik]; break; case 2: cz2L = pomiar[czujnik]; break; case 3: cz1L = pomiar[czujnik]; break; case 4: cz1P = pomiar[czujnik]; break; case 5: cz2P = pomiar[czujnik]; break; case 6: cz3P = pomiar[czujnik]; break; case 7: cz4P = pomiar[czujnik]; break; } adc_flag = 0; } // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / liczba_czujnikow; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = wart_regulacji_pwm * error; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa + regulacja_pwm; OCR1B = predkosc_srodkowa - regulacja_pwm; // Reset erroru i wartosci czujników error = 0; liczba_czujnikow = 0; } } // ***** OBSŁUGA PRZERWANIA ADC ***** ISR(ADC_vect) { ADMUX |= (ADMUX & 0xF8) | kanal; // wybór kanału while(!ADIF) // oczekiwanie na koniec pomiaru (automatycznie ADIF = 1) ADCSRA |= (0<<ADIF); // ręczny reset ADIF po zakończonym pomiarze if(kanal<7) kanal=0; // sprawdzenie mierzonego kanału pomiar[kanal] = ADCW; // przepisanie ADCW do zmiennej pomiar if(pomiar[kanal] > wart_graniczna) // porównanie z wartością graniczną pomiar[kanal] = 1; // kanal++; // przygotowanie zmiennej do następnego pomiaru adc_flag = 1; // ustawienie flagi sygnalizującej pobranie danych } To jest nowy kod, napisany dzisiaj rano. Mam nadal kilka pytań: 1. Dlaczego mam usuwać Timer0? Przecież jakiś sygnał musi zboczem narastającym wyzwolić przerwanie. W bajcie SFIOR ustawiłem Timer/Counter 0 CTC. 2. Cytuję "ADIF - tak, ale Ciebie nie interesuje, ponieważ od razu wywoła się przerwanie, które go zgasi. " - niestety wykorzystałem ADIF, gdyż nie widzę jeszcze innego sposobu przeczekania w pętli na zakońcenie pomiaru, skoro nie wykorzystuję bitu ADSC. Program się kompiluje, jednak są warning przy deklaracji tablicy, mówiący "array 'pomiar' assumed to have one element" EDIT: Po przerwie i ponownym spojrzeniu na kod widzę, że nie potrzebnie dodałem zmienną czujnik oraz zastanawiam się czy na początku przerwania ustawić adc_flag = 0, żeby nie wykonywała się pętla if(adc_flag) w pętli głównej programu.
  11. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 750 #define predkosc_srodkowa 130 #define wart_regulacji_pwm 30 // *** Deklaracje zmiennych volatile uint8_t wart_pomiaru; int8_t cz1L, cz2L, cz3L, cz4L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm, liczba_czujnikow; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; // *** TIMER0 - dla ADC TCCR0 |= (1<<WGM01) | (1<<COM01); // CTC, Clear OC0 on compare match TCCR0 |= (1<<CS00); // preskaler = 1 OCR0 = 160; // Compare Match (zbocze opadające) na wart. 160 TIMSK |= (1<<OCIE0); // *** ADC ADMUX |= (1<<REFS0); // AVCC with external capacitor at AREF pin ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // Włączenie ADC, Auto Trigger Enable, Interrupt Enable ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // preskaler = 128, fp=125kHz SFIOR |= (1<<ADTS1) | (1<<ADTS0); // Przerwanie - Compare Match Timer0 moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY sei(); // Globalne zezwolenie na przerwanie while(1) { // *** PRZETWARZANIE WART. ANALOGOWYCH NA CYFROWE. NAPIECIE WYJ > 3,4V if( cz4L ) { cz4L = -30; // Wartości x10 - ucieczka od zmiennej float liczba_czujnikow++; } if( cz3L ) { cz3L = -20; liczba_czujnikow++; } if( cz2L ) { cz2L = -10; liczba_czujnikow++; } if( cz1L ) { cz1L = 0; liczba_czujnikow++; } if( cz1P ) { cz1P = 0; liczba_czujnikow++; } if( cz2P ) { cz2P = 10; liczba_czujnikow++; } if( cz3P ) { cz3P = 20; liczba_czujnikow++; } if( cz4P ) { cz4P = 30; liczba_czujnikow++; } // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / liczba_czujnikow; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = wart_regulacji_pwm * error; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa + regulacja_pwm; OCR1B = predkosc_srodkowa - regulacja_pwm; // Reset erroru i wartosci czujników error = 0; liczba_czujnikow = 0; } } // ***** OBSŁUGA PRZERWANIA TIMER/COUNTER0 CTC ***** ISR(ADC_vect) { static uint8_t kanal; // zmienna dla bitów MUX4:0 ADMUX |= (ADMUX & 0xF8) | kanal; // Maskowanie bitów + ustawienie kanału _delay_us(13); // Przerwa na odczyt wart_pomiaru = ADCW; // Przepisanie wartosci ADCW do zmiennej if(wart_pomiaru > wart_graniczna) // Przyrownanie pomiaru do wart_granicznej = 750 { wart_pomiaru = 1; // Przekszałcenie wyniku na wartość binarną if(kanal==0) cz4L=wart_pomiaru; // Wybór zmiennej w zależności od mierzonego kanału if(kanal==1) cz3L=wart_pomiaru; if(kanal==2) cz2L=wart_pomiaru; if(kanal==3) cz1L=wart_pomiaru; if(kanal==4) cz1P=wart_pomiaru; if(kanal==5) cz2P=wart_pomiaru; if(kanal==6) cz3P=wart_pomiaru; if(kanal==7) cz4P=wart_pomiaru; } if(kanal<7) kanal=0; // Reset kanalu po przekroczeniu ADC7 } Nie mam pomysłu jak wprowadzić flagę. To jest ostatnia wersja na dzisiaj, gdyż mój umysł odmawia posłuszeństwa :-> Mam wrażenie, że utknąłem w szablonie myślowym i ciągle piszę to samo. Postęp minimalny, ale zawsze jakiś. P.S. Piwko za pomoc, mam nadzieje, że jutro też łykniesz
  12. Rozumiem działanie twojej rozpiski, jednak mam problem z przekształceniem tego w kod. Powalczę jeszcze kilka godzin. Na tą chwilę doszedłem do tego, że bit ADIF ustawia się na 1, gdy zakończy się pomiar. Czyli "gdy ADC zakończy pomiar zgłasza przerwanie" to wykorzystuje ISR(ADC_vect)?
  13. Poniżej znajduje się aktualna wersja zmajstrowanego kodu. Kompiluje się, ale nie działa. Niestety z przerwaniami nie mam dużego doświadczenia. Prawdę mówiąc, z większych projektów C to mój pierwszy, więc ciężko mówić tutaj o jakimkolwiek doświadczeniu bojowym. Kwarc 16MHz, taktowanie ADC 125kHz. Dlaczego 125kHz, otóż na str. 207 jest zdanie "By default, the successive approximation circuitry requires an input clock frequency between 50kHz and 200 kHz to get maximum resolution." Zmniejszenie częstotliwości, wiąże się ze zmianą częstotliwości kwarca, gdyż preskaler jest na max = 128. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 750 #define predkosc_srodkowa 130 #define wart_regulacji_pwm 30 // *** Deklaracje zmiennych volatile uint16_t pomiar(volatile uint8_t czujnik); uint16_t wynik(uint8_t kanal); volatile uint8_t wart_pomiaru; int8_t cz1L, cz2L, cz3L, cz4L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm, liczba_czujnikow; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY // *** TIMER0 - dla ADC TCCR0 |= (1<<WGM01) | (1<<COM01); // CTC, Clear OC0 on compare match TCCR0 |= (1<<CS00); // preskaler = 1 OCR0 = 160; // Compare Match (zbocze opadające) na wart. 160 TIMSK |= (1<<OCIE0); // *** ADC ADMUX |= (1<<REFS0); // AVCC with external capacitor at AREF pin ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // Włączenie ADC, Auto Trigger Enable, Interrupt Enable ADCSRA |= (1<<ADIF); // ADC Interrupt Flag // ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // preskaler = 128, fp=125kHz SFIOR |= (1<<ADTS1) | (1<<ADTS0); // Przerwanie - Compare Match Timer0 sei(); // Globalne zezwolenie na przerwanie while(1) { // *** PRZETWARZANIE WART. ANALOGOWYCH NA CYFROWE. NAPIECIE WYJ > 3,4V if( cz4L ) { cz4L = -30; // Wartości x10 - ucieczka od zmiennej float liczba_czujnikow++; } if( cz3L ) { cz3L = -20; liczba_czujnikow++; } if( cz2L ) { cz2L = -10; liczba_czujnikow++; } if( cz1L ) { cz1L = 0; liczba_czujnikow++; } if( cz1P ) { cz1P = 0; liczba_czujnikow++; } if( cz2P ) { cz2P = 10; liczba_czujnikow++; } if( cz3P ) { cz3P = 20; liczba_czujnikow++; } if( cz4P ) { cz4P = 30; liczba_czujnikow++; } // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / liczba_czujnikow; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = wart_regulacji_pwm * error; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa + regulacja_pwm; OCR1B = predkosc_srodkowa - regulacja_pwm; // Reset erroru i wartosci czujników error = 0; liczba_czujnikow = 0; } } //uint16_t pomiar(uint8_t czujnik) //{ // ADMUX |= (ADMUX & 0xF8) | czujnik; // maskowanie + ustawienie bitów MUX4:0 // ADCSRA |= (1<<ADSC); // ustawienie flagi startu pomiaru // while(ADCSRA & ADSC) // oczekiwanie na zakończenie pomiaru // return ADCW; // przepisz wynik do uint16_t pomiar //} // ***** OBSŁUGA PRZERWANIA TIMER/COUNTER0 CTC ***** ISR(TIMER0_COMP_vect) { static int cnt; cnt = 0; for(cnt=0; cnt<8 ; cnt++) { ADMUX |= (ADMUX & 0xF8) | cnt; // maskowanie + ustawienie bitów MUX4:0 ADCSRA |= (1<<ADSC); // ustawienie flagi startu pomiaru while(ADCSRA & ADSC) // oczekiwanie na zakończenie pomiaru wart_pomiaru = ADCW; if(wart_pomiaru > wart_graniczna) { wart_pomiaru = 1; if(cnt==0) cz4L=wart_pomiaru; if(cnt==1) cz3L=wart_pomiaru; if(cnt==2) cz2L=wart_pomiaru; if(cnt==3) cz1L=wart_pomiaru; if(cnt==4) cz1P=wart_pomiaru; if(cnt==5) cz2P=wart_pomiaru; if(cnt==6) cz3P=wart_pomiaru; if(cnt==7) cz4P=wart_pomiaru; } } }
  14. Witam ponownie, przesiedziałem troszkę już nad kartą katalogową i wydaje mi się, że dobrze rozumiem "co autor miał na myśli". Do kodu wprowadziłem kilka linijek: // *** TIMER0 - COMPARE MATCH dla ADC TCCR0 |= (1<<WGM01) | (1<<COM01); // CTC, Clear OC0 on compare match TCCR0 |= (1<<CS00); // preskaler = 1 OCR0 = 160; // Compare Match (zbocze opadające) na wart. 160 TIMSK |= (1<<OCIE0); // *** ADC ADMUX |= (1<<REFS0); // AVCC with external capacitor at AREF pin ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // Włączenie ADC, Auto Trigger Enable, Interrupt Enable ADCSRA |= (1<<ADIF); // ADC Interrupt Flag // ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // preskaler = 128, fp=125kHz SFIOR |= (1<<ADTS1) | (1<<ADTS0); // Przerwanie - Compare Match Timer0 sei(); // Globalne zezwolenie na przerwanie Mam kilka pytań teraz: 1. Wrzuciłem w komentarz linijkę z ustawieniami preskalera. Wydaje mi się, że w przypadku pomiaru na żądanie jest to zbędne. Czy dobrze wynioskowałem? 2. Wybrałem opcję przerwania Timer0 CTC, jednak w kodzie mam wykorzystać TIMER0_COMP_vect czy ADC_vect? 3. Dondu czy na twojej stronie jest to może opisane?
  15. Haha no dobra. Dondu podstawy logiki znam, ale wpadłem teraz w taką śmiechawę, że mnie szczęka boli. Widzę teraz ten błąd, ale dopiero jak sobie to na kartce rozpisałem. Ale ważne, że mamy progress Jutro z rana, na świeżo biorę się za data sheeta z przerwaniem ADC. Dobrej nocki życzę.
  16. Patrząc w notę katalogową Atmega16 str. 218 Tabla 84 widzę konfigurację bitów MUX4:0 bajtu ADMUX. Jeżeli wykorzystam zapis: ADMUX |= czujnik; Uzyskam na czterech (w moim wypadku trzech) bitach odpowiednie ustawienie, powodujące odczytanie wartości z danego kanału i przypisanie tego do uint16_t pomiar. Wydaje mi się, że ta linia źródła jest poprawna, a błąd siedzi gdzieś indziej. Zastanawiam się nad wykorzystaniem przerwania, niestety nie miałem z pomiarem na żądanie styczności, ale sądzę, że podołam zadaniu.
  17. Witam, w wolnej chwili stworzyłem program oparty na algorytmie P. Kod jest stworzony na wzór ostatniego poradnika o PID. Po wgraniu softu robot kompletnie nie klei się linii. W 99% jestem pewny, że błąd leży po stronie odczytu wartości z ADC. Na dole znajduje się kod. #include <avr/io.h> #include <util/delay.h> // ***** CZUJNIKI CNY70 ***** #define czujnik4P (1<<PA7) #define czujnik3P (1<<PA6) #define czujnik2P (1<<PA5) #define czujnik1P (1<<PA4) #define czujnik1L (1<<PA3) #define czujnik2L (1<<PA2) #define czujnik3L (1<<PA1) #define czujnik4L (1<<PA0) // *** SILNIK 1 (LEWY) #define moto1_A (1<<PC0) #define moto1_B (1<<PC1) #define moto1_EN (1<<PD4) #define moto1_jazda PORTC |= moto1_A; PORTC &= ~(moto1_B) #define moto1_cofka PORTC &= ~(moto1_A); PORTC |= moto1_B #define moto1_stop PORTC &= ~(moto1_A | moto1_B) // *** SILNIK 2 (PRAWY) #define moto2_A (1<<PC2) #define moto2_B (1<<PC3) #define moto2_EN (1<<PD5) #define moto2_cofka PORTC |= moto2_A; PORTC &= ~(moto2_B) #define moto2_jazda PORTC &= ~(moto2_A); PORTC |= moto2_B #define moto2_stop PORTC &= ~(moto2_A | moto2_B) // *** Wartości dodatkowe #define wart_graniczna 750 #define predkosc_srodkowa 130 #define wart_regulacji_pwm 30 // *** Deklaracje zmiennych uint16_t pomiar(uint8_t czujnik); uint16_t wynik(uint8_t kanal); uint8_t wart_pomiaru, liczba_czujnikow; int8_t cz4L, cz3L, cz2L, cz1L, cz1P, cz2P, cz3P, cz4P; int8_t error, regulacja_pwm; int main(void) { // *** DATA DIRECTION REGISTER DDRA &= ~(czujnik4L | czujnik3L | czujnik2L | czujnik1L | czujnik1P | czujnik2P | czujnik3P | czujnik4P); DDRC |= (moto1_A | moto1_B | moto2_A | moto2_B); DDRD |= (moto1_EN | moto2_EN); // *** TIMER1 TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; // Compare Output Mode, Fast PWM TCCR1A |= (1<<WGM10) | (1<<WGM11); // Fast PWM 10bit TCCR1B |= (1<<WGM12); TCCR1B |= (1<<CS10) | (1<<CS11); // Preksaler = 64 //fpwm = 980Hz TCNT1 = 1024; moto1_jazda; // ROZRUCH - SILNIK LEWY moto2_jazda; // ROZRUCH - SILNIK PRAWY // *** ADC ADMUX |= (1<<REFS0); // AVCC with external capacitor at AREF pin ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Włączenie ADC, preskaler = 128, fp=125kHz while(1) { // *** PRZETWARZANIE WART. ANALOGOWYCH NA CYFROWE. NAPIECIE WYJ > 3,4V if( pomiar(0) > wart_graniczna ) { cz4L = -30; // Wartości x10 - ucieczka od zmiennej float liczba_czujnikow++; } if( pomiar(1) > wart_graniczna ) { cz3L = -20; liczba_czujnikow++; } if( pomiar(2) > wart_graniczna ) { cz2L = -10; liczba_czujnikow++; } if( pomiar(3) > wart_graniczna ) { cz1L = 0; liczba_czujnikow++; } if( pomiar(4) > wart_graniczna ) { cz1P = 0; liczba_czujnikow++; } if( pomiar(5) > wart_graniczna ) { cz2P = 10; liczba_czujnikow++; } if( pomiar(6) > wart_graniczna ) { cz3P = 20; liczba_czujnikow++; } if( pomiar(7) > wart_graniczna ) { cz4P = 30; liczba_czujnikow++; } // Suma wartości z odczytanych czujników przekraczających wart_graniczna = 7 error = cz4L + cz3L + cz2L + cz1L + cz1P + cz2P + cz3P + cz4P; // Error podzielony przez ilosc czujników error = error / liczba_czujnikow; // Wyliczanie wartości regulującej OCR1A/B regulacja_pwm = wart_regulacji_pwm * error; // Przypisanie nowych wartosci bajtom OCR1A/B OCR1A = predkosc_srodkowa + regulacja_pwm; OCR1B = predkosc_srodkowa - regulacja_pwm; // Reset erroru i wartosci czujników error = 0; liczba_czujnikow = 0; } } uint16_t pomiar(uint8_t czujnik) { ADMUX |= czujnik; ADCSRA |= (1<<ADSC); while(ADCSRA & ADSC) return ADCW; } Moje pytanie: 1. Czy w line followerze wykorzystać pomiar ADC typu free-run, czy wykorzystać przerwania w celach pomiaru. Nie posiadam jeszcze doświadczenia w tej materii, więc liczę na pomoc. Pozdrawiam Keadwen
  18. Troszkę odkopuję, jednak zastanawiam się nad doborem tych wartości do wzoru. Mógłby mi ktoś powiedzieć mniej więcej jakie wartości powinno mieć wzmocnienie oraz jeżeli program np. wykonuje się w 0,1ms to wartość ta wynosi 0,0001? Interesuje mnie również, w jaki sposób uwzględnić pomiar z większej ilości czujników we wzorze?
  19. Dzisiaj, że akurat miałem chwilę wolnego szybko napisałem program wykorzystujący tylko cztery czujniki z ośmiu dostępnych. Nie ukrywam, że chciałbym napisać program wykorzystujący algorytm pokroju PID i analogowy odczyt wartości wyjściowej z czujnika. Jedynym problemem, który tutaj występuje to brak doświadczenia jeśli chodzi o pisanie programów. Miejmy nadzieje, że sobie poradzę ;D Na filmiku słychać straszny pisk, spowodowane jest to niskim wypełnieniem impulsu w PWM. W tym filmiku jest to 150/1024. Irytujące jest też słabo manewrujące koło podporowe.
  20. 1. Co do mocowań silników to zdaję sobie sprawę, lecz będę to dopiero zmieniał jak napiszę program i wytrawię nową płytkę (nieco chudszą). 2. Haha te czujniki to przyznam, że była ostra jazda. Jest to mój pierwszy błąd w projektowaniu pcb, niestety akurat tą płytę zamówiłem i trzeba było kombinować, by zamienić element THT na SMD 3. Film wrzucę jak tylko dokończę program. Aktualnie wykonuje proste testy dotyczące PWM. Postaram się to zrobić jak najszybciej, ale w te wakacje ciężko z czasem. 4. Kulka z linku Carpe Diem to chyba ta, moja ma 3/4 cala jeśli dobrze pamiętam. Wychodzi, że podczas postoju robot ma 3mm do podłoża względem CNY70.
  21. Witam wszystkich! Wstęp No szczerze mówiąc, to ten post powinien powstać już minimum miesiąc temu, lecz brak wolnego czasu kompletnie mnie zablokował. W wolnym czasie zamiast uczyć się C i czytać forum, układam kostkę granitową wokół domu i pracuję na full etat. Jednakże, udało mi się wreszcie ukończyć mojego pierwszego robota. Mechanika Jako napęd zastosowałem dwa silniczki Pololu 30:1 i koła 32mm. Wszystko zostało kupione w jednym sklepie internetowym (mocowanie, ballcaster itp. itd.). Rozmiar kół dobrałem do napięcia z Li-Pol 7,4V. Na przodzie konstrukcji jest plastikowy ballcaster. Elektronika Schemat i płytka były moją konstrukcją i nie ukrywam, że przesiedziałem tutaj kilka godzin. Czujniki CNY70 (8szt.) podłączyłem pod wewnętrzny komparator, lecz póki co w programie wykorzystuje 0/1. Zastosowałem L298 co uważam, za średnio trafioną decyzję. Zaletą jest odpowiednia wytrzymałość prądowa, ale te diody na wyjściu to kompletna porażka. Procesor odpowiadający za poprawną pracę to Atmega16 taktowana z zewnętrznego kwarca 16MHz. Wyprowadziłem również cztery piny, które w przyszłości chcę zastosować do komunikacji radiowej lub innych dupereli. Podsumowanie Jako główny mój cel, było stworzenie "jeżdżącej platformy naukowej". Przyznaję się, że brzmi to przesadnie, lecz dzięki Auxis'owi widzę postęp w mojej nauce języka C. Program jest podczas finalizowania i postaram się w najbliższym czasie wrzucić film (pod koniec sierpnia). Na koniec, chciałbym podziękować paru osobom, które przyczyniły się do stworzenia tego Line Followera: - mirek36 - super książka, która pokazała, że programowanie nie boli. - prof. Suchanek (ZSŁ Poznań) - człowiek, który wciągnął mnie w robotykę amatorską Najbliższe cele: - ukończyć program dla Auxis'a - stworzyć MiniSumo FotoBlog Trawiarka: Auxis: Autor: Jakub Młynarczyk PS. Na pytania "Dlaczego tyle kabli!!!???", odpowiadam "bo to wersja v1 + zamienię je na jednolitą taśmę" Pozdrawiam
  22. No pomysł z tym bajtem jest o niebo lepszy, że wczoraj na to nie wpadłem. Dzięki wielkie za pomoc.
  23. No ja chciałbym osiągnąć własnie PWM do sterowania wejściami EN dla L298. Wszystko będę sterował kwarcem 16MHz. Dzięki za pomoc, jednak godzinka spędzona przy karcie katalogowej dala konkretny wynik. Pozdrawiam [ Dodano: 07-07-2011, 20:42 ] Chciałbym dorzucić jeszcze jedno pytanie, bez zakładania nowego tematu. Otóż jaki sposób jest najbardziej optymalny do zapisu danych (cyfrowych 0/1) z CNY70. Mam ich 8 i zastanawiam się czy zastosować tablicę wielowymiarową czy są jakieś inne sposoby? Nie chciałbym bawić się w if/else bo to spowolni robota maksymalnie. W przypadku tablicy jak mialo by to wyglądać? uint8_t aktualny_stan[2][2][2][2][2][2][2][2] Czy coś w tym stylu jak u góry, jeśli tak to w jaki sposób zapisać dane do poszczególnych komórek?
  24. Witam, dzisiaj po prostu się zawiesiłem. Pierwszy raz wykorzystuje Timer1 w Atmega16 i chciałbym podzielić go na dwa nie zależne 8bitowe kanały z trybem FAST PWM lub PWM (z korekcją fazy). Zamieszczam poniżej fragment kodu dotyczącego ustawień sprzętowego PWM'u TCCR1A |= (0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(1<<COM1B1); TCCR1A |= (1<<WGM10); TCCR1B |= (1<<WGM13); TCCR1B |= (1<<CS10); // Preksaler = 1 Widziałem post dondu (link), siedziałem też troszkę z kartą katalogową, ale jednak postanowiłem poprosić o sprawdzenie, ponieważ nie mam pewności czy dobrze zrozumiałem.
  25. Chodzi Harnasiowi o rezystor 10k do resetu, o którym Sabre pisał u góry. Przy okazji już prawie ukończyłem płytki, ale ogółem masakra, te piny ADC są tak rozrzucone po prawie każdej stronie układu.
×
×
  • Utwórz nowe...