Skocz do zawartości

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


sidek92

Pomocna odpowiedź

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:

#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

Link do komentarza
Share on other sites

"oczekiwanie na zakonczenie pomiaru" masz źle napisane

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.

Link do komentarza
Share on other sites

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

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:

ADCSRA |= _BV(ADEN);
ADMUX |= _BV(ADLAR); 
DDRC   |= (0<<PC0) | (0<<PC1) | (0<<PC2) | (0<<PC3) | (0<<PC4) | (0<<PC5);
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

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:

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ą?

Link do komentarza
Share on other sites

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

while (ADCSRA & _BV(ADSC)) {};

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

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:

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ń:

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • 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.