Ta strona używa ciasteczek (plików cookies), dzięki którym może działać lepiej. Dowiedz się więcejRozumiem i akceptuję

[C] Wysterowanie silników według odczytów z ADC

Autor Wiadomość
sidek92 



Posty: 10
Skąd: KZ
Wysłany: 06-11-2017, 10:08   [C] Wysterowanie silników według odczytów z ADC

Witam, stworzyłem swojego pierwszego LF'a i jestem w trakcie pisania kodu. Początkowo będzie on sterowany w prostych pętlach "if", a w miarę rozwoju będę chciał dojść do napisania regulatora PD.
Aktualnie mam problem z odpowiednim wysterowaniem silników, w kodzie który napisałem nie dostaje oczekiwanych efektów.
Silniki zachowują się w następujący sposób:
1. Gdy czujniki nie wykrywają lini silniki dostają maksymalne obroty
2. Gdy wykryta jest linia na którymkolwiek czujniku obroty są identyczne, chociaż w kodzie wypełnienie się różni dla kolejnych par lub pojedynczych czujników.

Niestety nie mogę znaleźć gdzie leży błąd, dlatego też poprosił bym o pomoc z waszej strony.
Kod wygląda następująco:
Kod programu: Zaznacz cały
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define MOTOR_LEWY_PRZOD PORTD   // |= (1<<PD2)
#define MOTOR_PRAWY_PRZOD PORTD  // |= (1<<PD7)
#define MOTOR_LEWY_TYL PORTD     // |= (1<<PD3)
#define MOTOR_PRAWY_TYL PORTB    // |= (1<<PB0)
#define MOTOR_LEWY_PWM OCR1B    //PB2
#define MOTOR_PRAWY_PWM OCR1A    //PB1

void PWM(int LEWY, int PRAWY)
{
    if(LEWY>=0)
    {
        if (LEWY>255)
        LEWY=255;
        MOTOR_LEWY_PRZOD |= (1<<PD2);
        MOTOR_LEWY_TYL  |= (0<<PD3);
    }
    if (PRAWY>=0)                            //PRZÓD
    {
        if (PRAWY>255)
        PRAWY=255;
        MOTOR_PRAWY_PRZOD |= (1<<PD7);
        MOTOR_PRAWY_TYL |= (0<<PB0);
    }
   
    if(LEWY<0)
    {
        if (LEWY<-255)
        LEWY=-255;
        MOTOR_LEWY_PRZOD |= (0<<PD2);
        MOTOR_LEWY_TYL  |= (1<<PD3);
    }
    if (PRAWY<0)                                    //TYŁ
    {
        if (PRAWY<-255)
        PRAWY=-255;
        MOTOR_PRAWY_PRZOD |= (0<<PD7);
        MOTOR_PRAWY_TYL |= (1<<PB0);
    }
    MOTOR_LEWY_PWM = abs(LEWY);
    MOTOR_PRAWY_PWM = abs(PRAWY);
}

int czujniki[6]={0,0,0,0,0,0};
void odczyt_adc()
{
    for(int i=0; i<6; i++)
    {
       
        ADMUX &= 0b11100000;        //zerowanie bitów mux
        ADMUX |= i;                //tab_czujnikow[i];        //wybór kanału przetwornika
        ADCSRA |= (1<<ADSC);        //uruchomienie pomiaru
        while (ADCSRA & (ADSC==1)) {};    //oczekiwanie na zakonczenie pomiaru
       
        if(ADCH>200)                //porownanie wyniku
        {czujniki[i]=1;}            //wpisanie wyniku do tablicy
        else
        {czujniki[i]=0;}           
    }
}

int main(void)
{
    //------------------------------------- ADC oraz kierunki pinów dla ADC ---------------------------------------
    ADMUX  |= (0<<REFS0) | (0<<REFS1);    //AREF, Internal Vref turned off
    ADMUX  |= (1<<ADLAR);                //wyrównanie do lewej, 8 bitowy wynik konwersji
    ADCSRA |= (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2); //uruchomienie adc, prescaler 128 = 128khz
    PORTC  |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5);
    DDRC   |= (0<<PC0) | (0<<PC1) | (0<<PC2) | (0<<PC3) | (0<<PC4) | (0<<PC5);
    PINC   |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5);

    //--------------------- TIMER1 DLA PWM LEWY/PRAWY oraz kierunki pinów sterowania silnikami --------------------
    TCCR1A |= (1<<COM1A1) | (1<<COM1B1) | (1<<WGM10);        //Set OC0A on Compare Match, clear OC0A at BOTTOM (inverting mode),  fast pwm 8-bit counter
    TCCR1B |= (1<<WGM12) | (1<<CS11);                                    //fast pwm 8 bit counter, prescaler = 8
    DDRB   |= (1<<PB0) | (1<<PB1) | (1<<PB2);        //USTAWIENIE PB0/1/2 JAKO WYJSCIA (kierynek prawy/pwm lewy/pwm prawy)
    DDRD   |= (1<<PD2) | (1<<PD3) | (1<<PD7);        //USTAWIENIE PD2/3/7 JAKO WYJSCIA (kierunek lewy/kierunek lewy/kierunek prawy)

    while (1)
    {
        odczyt_adc();
        if (czujniki[0]==1 && czujniki[1]==0)        //tylko 0
        {
            PWM(100,0);
        }
        if (czujniki[0]==1 && czujniki[1]==1)        //0 i 1
        {
            PWM(150,0);
        }
        if (czujniki[0]==0 && czujniki[1]==1 && czujniki[2]==0)    //tylko 1
        {
            PWM(175,0);
        }
        if (czujniki[1]==1 && czujniki[2]==1)        //1 i 2
        {
            PWM(200,0);
        }
        if (czujniki[1]==0 && czujniki[2]==1 && czujniki[3]==0)    //tylko 2
        {
            PWM(225,0);
        }
        if (czujniki[2]==1 && czujniki[3]==1)    //2 i 3
        {
            PWM(250,250);
        }
        if (czujniki[2]==0 && czujniki[3]==1 && czujniki[4]==0)    //tylko 3
        {
            PWM(0,225);
        }
        if (czujniki[3]==1 && czujniki[4]==1)    //3 i 4
        {
            PWM(0,200);
        }
        if (czujniki[3]==0 && czujniki[4]==1 && czujniki[5]==0)    //tylko 4
        {
            PWM(0,175);
        }
        if (czujniki[4]==1 && czujniki[5]==1)    //4 i 5
        {
            PWM(0,150);
        }
        if (czujniki[5]==1 && czujniki[4]==0)    //tylko 5
        {
            PWM(0,100);
        }
       
    }

}



Z góry dziękuję za udzieloną pomoc.

EDIT: Do odmierzania czasu używam zewnętrznego kwarcu 16mhz.
Ustawienie fuse bitów:
-U lfuse:w:0xf7:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m
Czyli:
Full swing crystal, 16K CK, 14CK +65 ms [CKSEL = 0111, SUT = 111]

EDIT2: w symulatorze zauważyłem, że nie zmieniają mi się kanały na ADC

Polecany artykuł » Wstęp do świata dronów - recenzja Parrot AR.Drone 2.0


Ostatnio zmieniony przez sidek92 06-11-2017, 12:06, w całości zmieniany 2 razy  
Postaw piwo autorowi tego posta
 
 
Wojciech 



Posty: 115
Pomógł: 14 razy
Otrzymał 12 piw(a)
Programuję w:
C/C++
Wysłany: 14-11-2017, 16:22   

"oczekiwanie na zakonczenie pomiaru" masz źle napisane
Kod programu: Zaznacz cały
while (ADCSRA & (ADSC==1)) {};

jest wogóle pomijane bo ADSC = 6, więc (6==1) daje 0, dalej x & 0 zawsze da 0 - brak oczekiwania.

Postaw piwo autorowi tego posta
 
 
sidek92 



Posty: 10
Skąd: KZ
Wysłany: 25-11-2017, 15:27   

Trochę nie miałem czasu ostatnio, ale przerzuciłem się z "if'ów" na regulator PD, co na pewno będzie lepszym rozwiązaniem.
Mam problem z odczytem wyniku ADC, po wyjściu z pętli oczekiwania wynik się restartuje i nie nadążam go odczytywać.

Kod programu: Zaznacz cały
ADMUX &= 0b00100000;        //zerowanie bitów mux

    for(i=0; i<6; i++)
    {
       
        ADMUX = i+32; //kanały adc i left adjust
        ADCSRA |= (1<<ADSC);    //uruchomienie pomiaru
        while (ADCSRA & _BV(ADSC)) {};    //oczekiwanie na zakonczenie pomiaru
       
        wynik=ADCH;
        if(wynik>200)                //porownanie wyniku
        czujniki[i]=1;    //wpisanie wyniku do tablicy
        else
        czujniki[i]=0;
    }


Ustawienia:

Kod programu: Zaznacz cały
ADCSRA |= _BV(ADEN);
    ADMUX |= _BV(ADLAR);
    DDRC   |= (0<<PC0) | (0<<PC1) | (0<<PC2) | (0<<PC3) | (0<<PC4) | (0<<PC5);
   

Postaw piwo autorowi tego posta
 
 
sidek92 



Posty: 10
Skąd: KZ
Wysłany: 05-12-2017, 20:06   

Forum umarło?

Popularny artykuł » Kurs Arduino - #3 - UART (komunikacja z PC), zmienne


Postaw piwo autorowi tego posta
 
 
marek1707 



Posty: 4387
Pomógł: 471 razy
Otrzymał 613 piw(a)
Skąd: WAW
Programuję w:
C, asm
Wysłany: 05-12-2017, 20:27   

Forum nie ma zwyczaju komentować czyjejś walki z programem i nie odpowiada na niezadane pytania. Uruchamiania i testowania własnych programów każdy uczy się bólu własnego zacisza domowego.

EDIT: A wyłamując się z tej konwencji, zapis:
Kod programu: Zaznacz cały
DDRC   |= (0<<PC0) | (0<<PC1) | (0<<PC2) | (0<<PC3) | (0<<PC4) | (0<<PC5);
powoduje, że jeśli w DDRC była już gdzieś jedynka i pin jest wyjściem, ta linijka tego nie zmieni. Czy powszechne nadużywanie operatora |= w stosunku do rejestrów można już nazwać plagą czy na razie tylko bezmyślnością?

Ostatnio zmieniony przez marek1707 06-12-2017, 09:57, w całości zmieniany 1 raz  
Postaw piwo autorowi tego posta
 
 
sidek92 



Posty: 10
Skąd: KZ
Wysłany: 06-12-2017, 13:21   

Cytat:
Forum nie ma zwyczaju komentować czyjejś walki z programem i nie odpowiada na niezadane pytania.


Może nie było tam znaku zapytanie, ale pytałem dlaczego po wyjściu z pętli
Kod programu: Zaznacz cały
while (ADCSRA & _BV(ADSC)) {};

wynik jest kasowany, a ja nie nadążam w kolejnej linijce kodu go oczytać podczas sprawdzania progu.

Cytat:
powoduje, że jeśli w DDRC była już gdzieś jedynka i pin jest wyjściem, ta linijka tego nie zmieni


zmieniłem linijkę na:

Kod programu: Zaznacz cały
DDRC   &= ~(1<<PC0) | ~(1<<PC1) | ~(1<<PC2) | ~(1<<PC3) | ~(1<<PC4) | ~(1<<PC5);


W DDRC jedynymi ustawionymi bitami są właśnie te powyżej.

Czy podczas używania ADC trzeba ustawiać bity w rejestrach I/O? EDIT: już wiem, że się ich nie ustawia

Zastanawiam się, czy mój rezonator kwarcowy 16MHz - HC49
KWARC
jest odpowiednio ustawiony w fuse bitach. Użyłem ustawień:

Ostatnio zmieniony przez sidek92 06-12-2017, 19:47, w całości zmieniany 3 razy  
Postaw piwo autorowi tego posta
 
 
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Wersja do druku

Skocz do:  

Nie rozwiązałeś swojego problemu? Zobacz podobne tematy: Generowanie przebieg... Jaki język programow... Kombinowanie z przer... Czym programujecie u...
lub przeszukaj forum po wybranych tagach: adc, odczytow, silnikow, wedlug, wysterowanie


Powered by phpBB modified by Przemo © 2003 phpBB Group
Popularne kursy: Arduinopodstawy elektroniki