Skocz do zawartości

Keadwen

Users
  • Zawartość

    31
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    1

Keadwen zajął 1. miejsce w rankingu.
Data osiągnięcia: 14 sierpnia 2011.

Treści użytkownika Keadwen zdobyły tego dnia najwięcej polubień!

O Keadwen

  • Urodziny 13.01.1993

Informacje

  • Płeć
    Mężczyzna
  • Lokalizacja
    Dachowa k.P-ń
  • Zawód
    Teleinformatyk
  • Moje zainteresowania:
    ICT, elektronika

Osiągnięcia użytkownika Keadwen

Wynalazca

Wynalazca (6/19)

  • Za 5 postów
  • Za 25 postów
  • Młodszy Juror
  • Młodszy roboty
  • To już rok!

Odznaki

7

Reputacja

  1. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    #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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    #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. Keadwen

    [C] ADC + algorytm P

    #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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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. Keadwen

    [C] ADC + algorytm P

    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ę.
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.