Skocz do zawartości

Pomocna odpowiedź

Napisano

Witam, dziś ruszyłem temat pwm. Udało mi się uruchomić na 2 kanałach tryb fast pwm 8 bit.  Doczytałem, że za wartość wypełnienia odpowiadają rejestry porównawcze OCR1A i OCR1B, do nich należy wprowadzić wartość. Myślałem, że jak wybieram pwm 8 bitowy to maksymalna wartość to będzie 255.(od 0 do 255). Jednak w te rejestry mogę wpisać o wiele większą liczbę,.. przy 1023 świeci maksymalnie, przy 1024 baardzo słabo.. napisałem prosty program, rozjasniajaco-ściemniający 2 diody i wszystko OK, działa... 

#include <avr/io.h>
#include <util/delay.h>
#include<avr/interrupt.h>

int main (){
	DDRB |= 0b00000110; // Ustawienie portów wyjscia PB1 i PB2
// =INICJALIZACJA PWM= //
	TCCR1A |= (1<<WGM10)|(1<<WGM11)|(1<<COM1B1)|(1<<COM1A1); // tryb 8 bit i wlaczone 2 kanaly
	TCCR1B |= (1<<WGM12); // tryb 8bit fast PWM
	TCCR1B |= (1<<CS11); // prescaler 8

while(1) {
	for (int16_t i=0; i<1024; i++){ // pętla zwiekszająca wypelnienie
	OCR1A = i;
	OCR1B = i;
	_delay_ms(1);
}
	for (int16_t i=1023; i>=0; i--) { // pętla zmniejszająca wypełnienie
	OCR1A = i;
	OCR1B = i;
	_delay_ms(1);
}

}
}

Chciałbym jednak zrozumieć, gdzie mój błąd w rozumowaniu, że do OCRxx mozna wprowadzać takie a nie inne wartości... 

(edytowany)

Napisze tylko "xD". Do zamknięcia, dzięki 😄

Albo dopytam jeszcze o jedną rzecz... Pamiętam z kursu arduino, że do sterowania servo potrzebujemy wygenerować sygnal o okresie 20ms.. czyli o częstotliwości 50Hz. Próbuje to podzielić jednak się nie udaje tak dokladnie 😛  Moj cpu taktuje 1MHz, więc najblizsza wartość 

1 000 000/prescaler 64/256(8bitowy pwm) i otrzymam ok 61Hz. czyli ok 16ms... Jak to dokladnie skalibrować.. ? 

Edytowano przez Krawi92

W której nocie? W powstającym właśnie robocie mam cztery rodzaje różnych (tanich) serw i wszystkie ładnie pracują zarówno na 50, jak i 60 Hz. 

Na arduinowym pwm (okolo 490 Hz) servo dziala normalnie...no ale tu sie akurat zakres mniej wiecej miesci w specyfikacji serva jak @ethanak wspomnial...czyli max okres "wlaczenia" to 2ms...gdzie serwo ma miec miedzy 1-2ms...i pozostaly czas do 20ms to przerwa...na tym trybie pwm nie zrobisz tego...musisz inaczej kombinowac..ja to zrobilem tak ze do 1ms dodawalem cos z zakresu 1-2ms i pozniej od 20ms odjalem ten czas wlaczenia i ustawialem pin na wylaczenie i tak w kolko...

@farmaceuta a z ciekawości - co by było, gdybyś ustawił czas pauzy sztywno na 16 msec i nie bawił się w odejmowanie? Czyli: impuls o określonej zmiennej długości plus stała pauza?

Ja jestem leniem i po prostu podpinam sterownik na I2C, nie bardzo mi się chce bawić w generowanie przebiegów na esp32 czy rpi pico (pomijając fakt, że jak masz dziesięć serw i jeszcze parę led to się piny kończą). Ale tam też mogę ustawić częstotliwość...

Yyyy czekajcie bo troche się pogubiłem. Ja napisze jakbym chciał to zrobić a Wy mi powiecie czy Ok 😄 Powiedzmy, że sobię ustawie 1Mhz/64 presc/ wybiore 8bitowy fast pwm... .. I pozycją serva sterujemy poprzez zmiane wartosci OCRxx ? Oj bo chyba coś źle mysle 😛

Nie no nic sie nie stanie, zaraz zaczne to skladac. Na arduino to bylo prostackie, nie martwilem sie takimi rzeczami, byla gotowa biblioteka servo.h podlaczalem i działało. Teraz jak to zaczynam poznawać od srodka to jednak trzeba sie nad tym duzo glebiej pochylic. 

(edytowany)

No to poczytaj sobie kod biblioteki servo dla Arduino.  Naprawdę ciekawe!

A zauważ, że biblioteka nie korzysta w ogóle ze sprzętowego pwm, a jakoś jest w stanie w czasie rzeczywistym machać dwunastoma serwami...

Edytowano przez ethanak
(edytowany)
47 minut temu, ethanak napisał:

@farmaceuta a z ciekawości - co by było, gdybyś ustawił czas pauzy sztywno na 16 msec i nie bawił się w odejmowanie? Czyli: impuls o określonej zmiennej długości plus stała pauza?

Bedzie dzialac z roznymi "pauzami"... ja to tak sobie zrobilem jako cwiczenie.. (troszke sie zakrecilem..ja nie odejmuje tylko licze sobie i w odpowiednim momencie robie co mam robic...)

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>



volatile uint16_t x = 0;   //uint16 = 50Hz / uint8 = prawie 8 razy wieksza czestotliwosc (x sam sie "przekreci" po 256 przerwaniach
volatile uint8_t pw = 0;


void setup() {
 Serial.begin(115200);
  
 DDRD |= (1 << PD2);        //pin 2 jako wyjscie
 
 TCCR2B &= 0x00;
 TCCR2A &= 0x00;
  TCCR2A |= (1<<WGM21);     //CTC tryb                           
 
  TCCR2B |= (1<<CS21);      //preskaler na 8
 // TCCR2B |= (1<<CS20);    //preskaler na 0
   
   TIMSK2 |= (1<<OCIE2A);    //wlaczenie przerwania od porownania
   OCR2A = 20;  //255 max    //przypisanie wartosci startowej do licznika
  sei();                    // przerwania globalne wlacz
}

void loop() {

 //pw = map(analogRead(A0), 0, 1023, 0, 100);
 pw++;
 if(pw == 100) {
  pw = 0;
 }
 delay(50);
 
}

ISR (TIMER2_COMPA_vect)
{   x++;
      
    if (x < (100 + pw)) {       //1ms + wartosc wypelnienia 0-100 (1ms)
        PORTD |= (1 << PD2);  //stan wysoki
  } else {
     if (x < 2000) {     //20ms cykl
        PORTD &= ~(1 << PD2);         //stan niski
      }  else {
      x = 0;       // jesli minelo 20ms zacznij od nowa liczyc 
    }
  }
}

z tym ze u mnie rozdzielczosc to 0-100...przerwanie nastepuje co 10us, a jak juz wiadomo zakres dla serwa to 1-2ms...ten sam kod lekko zmieniony tak zeby "pauza" byla sztywna tez dziala bez zarzutu, przerwy co 10ms/20ms/50ms a nawet 100ms tez dziala z tym ze przy tych dluzszych przerwach juz widac/slychac wyraznie "kroki"...

Edytowano przez farmaceuta

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