Skocz do zawartości

Generowanie 6 faz na Arduino - SPWM


Pomocna odpowiedź

Napisano

Chciałbym zrobić 6 faz (używając 2 piny do każdej fazy) i do tej pory skutecznie zrobiłem takim sposobem 2 fazy na Arduino UNO i teraz napotykam ograniczenie, które nie wiem jak obejść. Najpierw wyjaśnię jak działa kod na 2 fazy oto on:

int i=0;
int j=0;
int x=0;
int y=0;
int OK=0;
int OK1=0;
int OK2=0;
int sinPWM[]={1,2,5,7,10,12,15,17,19,22,24,27,30,32,34,37,39,42,
44,47,49,52,54,57,59,61,64,66,69,71,73,76,78,80,83,85,88,90,92,94,97,99,
101,103,106,108,110,113,115,117,119,121,124,126,128,130,132,134,136,138,140,142,144,146,
148,150,152,154,156,158,160,162,164,166,168,169,171,173,175,177,178,180,182,184,185,187,188,190,192,193,
195,196,198,199,201,202,204,205,207,208,209,211,212,213,215,216,217,219,220,221,222,223,224,225,226,227,
228,229,230,231,232,233,234,235,236,237,237,238,239,240,240,241,242,242,243,243,244,244,245,245,246,246,
247,247,247,248,248,248,248,249,249,249,249,249,255,255,255,255,249,249,249,249,249,248,
248,248,248,247,247,247,246,246,245,245,244,244,243,243,242,242,241,240,240,239,238,237,237,236,235,234,
233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,217,216,215,213,212,211,209,208,207,205,204,
202,201,199,198,196,195,193,192,190,188,187,185,184,182,180,178,177,175,173,171,169,168,166,164,162,160,
158,156,154,152,150,148,146,144,142,140,138,136,134,132,130,128,126,124,121,119,117,115,113,110,108,106,
103,101,99,97,94,92,90,88,85,83,80,78,76,73,71,69,66,64,61,59,57,54,52,49,47,44,42,39,37,34,32,30,
27,24,22,19,17,15,12,10,7,5,2,1};

void setup() {
Serial.begin(9600);

pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
pinMode(3,OUTPUT);
pinMode(11,OUTPUT);

cli();// stop interrupts
TCCR0A=0;//reset the value
TCCR0B=0;//reset the value
TCNT0=0;//reset the value
//0b allow me to write bits in binary
TCCR0A=0b10100001;//phase correct pwm mode
TCCR0B=0b00000001; //no prescaler

TCCR2A=0;//reset the value
TCCR2B=0;//reset the value
TCNT2=0;//reset the value
//0b allow me to write bits in binary
TCCR2A=0b10100001;//phase correct pwm mode
TCCR2B=0b00000001; //no prescaler

TCCR1A=0;//reset the value
TCCR1B=0;//reset the value
TCNT1=0;//reset the value
OCR1A=509;// compare match value
TCCR1B=0b00001001; //WGM12 bit is 1 and no prescaler

TIMSK1 |=(1 << OCIE1A);// enable interrupts

sei();//stop interrupts
}
ISR(TIMER1_COMPA_vect){// interrupt when timer 1 match with OCR1A value
if(i>313 && OK==0){// final value from vector for pin 6
i=0;// go to first value of vector
OK=1;//enable pin 5
}
if(i>313 && OK==1){// final value from vector for pin 5
i=0;//go to first value of vector
OK=0;//enable pin 6
}
x=sinPWM[i];// x take the value from vector corresponding to position i(i is zero indexed)
i=i+1;// go to the next position
if(OK==0){
OCR0B=0;//make pin 5 0
OCR0A=x;//enable pin 6 to corresponding duty cycle
}
if(OK==1){
OCR0A=0;//make pin 6 0
OCR0B=x;//enable pin 5 to corresponding duty cycle
}

if ((i==209) || OK1==1){// the first signal has reached to position 209
//in the lookup table
OK1=1;// to maintain if function valid
if(j>313 && OK2==0){// final value from vector for pin 11
j=0;// go to first value of vector
OK2=1;//enable pin 3
}
if(j>313 && OK2==1){// final value from vector for pin 3
j=0;//go to first value of vector
OK2=0;//enable pin 11
}
y=sinPWM[j];// x take the value from vector corresponding to position j(j is zero indexed)
j=j+1;// go to the next position
if(OK2==0){
OCR2B=0;//make pin 3 0
OCR2A=y;//enable pin 11 to corresponding duty cycle
}
if(OK2==1){
OCR2A=0;//make pin 11 0
OCR2B=y;//enable pin 3 to corresponding duty cycle
}
}

}
void loop() {

}

Program wykorzystuje wszystkie 3 dostępne timery w UNO timer0, timer1 i timer2. W tablicy sinPWM[] zapisane są kolejne wartości dodatniej połówki sinusoidy, odpowiadają one kolejnym wartościom wypełnienia PWM.  Timer0 i Timer2 są ustawione w trybie PWM o konkretnej częstotliwości. Timer1 generuje przerwania o częstotliwości równej częstotliwości pozostałych dwóch timerów. W przerwaniu wartość wypełnienia sygnału np. na pinie 5 jest równa kolejnym wartościom z tablicy sinPWM[]. Po tym jak po kolei zostaną program przeleci te wszystkie wartości dla tego pinu, następuje zmiana na pin 6 i w taki sposób powstaje 1 faza. Analogicznie jest dla drugiej tyle, że ona zaczyna od wartości 209, a nie od 0 jak w przypadku 1 fazy (przesunięcie fazowe).

 

Ja chcę domyślnie zrobić 6 faz (mam swoje powody he he). Od razu widać, że tym sposobem nie osiągnę 6 faz na UNO, ponieważ ono ma tylko 3 timery, a ja potrzebuje po jednym timerze na każdą fazę do generowania PWM  i jeden timer, który będzie ustawiał wypełnienie w przerwaniu. 

Myślałem, że Arduino MEGA rozwiąże mój problem, ale tam jednak jest tylko 6 timer'ów czyli o 1 za mało bo ja potrzebuję ich 6. 

Czy jest może jakiś sposób / trik w jaki mógłbym uzyskać ten 1 dodatkowy timer? Ewentualnie jakieś inne rozwiązania mojego problemu? 

Są oczywiście inne uC, które mają więcej timerów, ale ich nie ogarniam.  Myślałem o Arduino DUE, ale tam też jest inne CPU i nie wiem nawet jak się za  to zabrać.

Z góry dzięki 😃 

(edytowany)

Jeśli ma to być robione sprzętowo to musisz użyć czegoś wydajniejszego np: atmega128 ma w sam raz 6 wyjść PWM https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/2467S.pdf lub szukać czegoś co ma "AT90PWM..." w nazwie, jest sporo tych mikrokontrolerów. Ja pewnie użyłbym do tego któregoś STMa  ale to taka moja opinia poza konkursem 🙂

 

Edytowano przez _LM_
35 minut temu, Januszxd napisał:

ale tam jednak jest tylko 6 timer'ów

właściwie nie interesuje Cię ilość timerów a kanałów PWM jeden timer może obsłużyć wiele kanałów więc to nie jest kryterium

26 minut temu, Januszxd napisał:

Ewentualnie jakieś inne rozwiązania mojego problemu? 

ESP32 posiada coś , co się nazywa MCPWM - sprzętowe rozwiązanie generowania przebiegów do sterowania silnikami. Są dwa moduły po 3 fazy, a więc tyle, ile potrzeba.

Jednak wdrożenie wymagać będzie wiele dociekliwości i pracy, bo opisy tej funkcjonalności są bardzo skąpe. Na początek do poczytania tu.

  • Lubię! 2
12 minut temu, _LM_ napisał:

właściwie nie interesuje Cię ilość timerów a kanałów PWM jeden timer może obsłużyć wiele kanałów więc to nie jest kryterium

Czy sugerujesz, że da radę to zrobić na Arduino MEGA skoro w nim jest 15 kanałów PWM ? Z tego co się rozeznałem to tam niektóre timery mają po 3 rejestry porównawcze i łącznie na wszystkich timer'ach jest ich tyle, że powinno wystarczyć do generowania 6 faz...  jakbym np. w moim kodzie zmienił warunek tej instrukcji przerwania, żeby porównywała wartość z innym rejestrem porównawczym? Albo jakbym na tych dodatkowych kanałach generował kolejne przebiegi?
 

2 godziny temu, Januszxd napisał:

Czy sugerujesz, że da radę to zrobić na Arduino MEGA

Przy takiej ilości tajmerów jak najbardziej jest to możliwe, tyle że rozwiązanie drogie płyta mega to koszt > 200zł to samo osiągniesz na dużo tańszych układach jak wspomniany ESP32, STM32 i RPI2040 Ale to twój wybór.

2 godziny temu, Januszxd napisał:

jakbym np. w moim kodzie zmienił warunek tej instrukcji przerwania, żeby porównywała wartość z innym rejestrem porównawczym? Albo jakbym na tych dodatkowych kanałach generował kolejne przebiegi?

Myślę że przeróbki programu to nie jest prosta podmiana paru linijek kodu. Już samo uruchomienie tylu timerów i powiązanych z nimi kanałami PWM to będzie nieco gimnastyki. Ja tego na tym mikrokontrolerze nie robiłem, z resztą mało co już robię w AVR  

  • Lubię! 1
(edytowany)

To ma być sześć niezależnych kanałów PWM?

Niektóre AVRy np. ATTINY861 miały coś takiego jak tryb "6 kanałów PWM", ale było to pod kątem sterowania silnikami i ich mostkami. W praktyce były to sprzętowe kanały symetryczne, tzn. jeden kanał generował 2 przebiegi PWM, jeden w fazie, drugi w przeciw fazie.

Mając odpowiednio szybki mikrokontroler da się to zrobić pół programowo na 1 timerze.

Sprzętowo można było coś takiego zrobić na jakieś serii mikrokontrolerów PIC od MICROCHIPa, chyba max 4 kanały na jeden Timer, ale nie pamiętam czy PIC16 czy PIC18. Niestety to nie Arduino i nie AVRy. Obecnie rodzina AVR należy do MICROCHIPa, więc może mają jakieś nowe odmiany co potrafią taką sztuczkę zrobić jak PICi, ale trzeba by szukać i wnikać w temat.

Do zrobienia na ATMEGA 64 i Timer 1 oraz 3, bo maja po trzy kanały PWM. Na ATMEGA328 z ARDUINO UNO też niby do zrobienia, ale zużyjesz wszystkie Timery i rozdzielczość 8-bitów na 4 kanałach i 16 na dwóch.

Edytowano przez BlackJack
  • Lubię! 1
16 godzin temu, BlackJack napisał:

To ma być sześć niezależnych kanałów PWM?

 

To ma być 6 faz sinusoidalnych przesuniętych względem siebie o 60 stopni do których potrzebuje po 2 piny na każdą z nich przy obecnym programie, jeżeli o to pytasz. 

Dziękuję wam za wszystkie przedstawione alternatywy. 

Ja osobiście skorzystam z Arduino skoro jest taka możliwość, ponieważ z nim tylko miałem doświadczenie do tej pory i jakoś się w nim odnajdę. Mimo wszystko porównując ceny innych uC to faktycznie prędzej czy później będę musiał przesiąść się na coś innego. W przyszłości spróbuję STM i kurs do niego.

Jeszcze raz dzięki 😁 

  • 2 tygodnie później...

Znalazłem artykuł w którym opisano temat generowania PWM na AVR. Z 16MHz ATMegi udało się wyciągnąć 16 kanałów PWM 300Hz. Wszystko zależy jakie parametry ma mieć twój PWM?

  • Lubię! 1

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...