Witam zrobiłem generator PWM z zmiennym wypełnieniem jego wyjście to PB3 czy istnieje jakiś sposób na zamianę na inne wyjście ?
Czy wolisz polską wersję strony elektroda?
Nie, dziękuję Przekieruj mnie tamPiotr Kania napisał:Witam zrobiłem generator PWM z zmiennym wypełnieniem jego wyjście to PB3 czy istnieje jakiś sposób na zamianę na inne wyjście ?
Piotr Kania napisał:Jest jeśli w przerwaniu będziemy zmieniać stan jakiegoś wyjścia
Piotr Kania napisał:Na razie zrobiłem to na TOGGLE i działa ale w wartościach skrajnych pwm przyjmuje 50%.
Piotr Kania napisał:
w przerwaniu będziemy zmieniać stan jakiegoś wyjścia
#include <avr/io.h>
#include <avr/interrupt.h>
#define DOWOLNY_DDR DDRD
#define DOWOLNY_PORT PORTD
#define DOWOLNY_PIN 7
volatile uint8_t pwm=0;
int main(void)
{
DOWOLNY_DDR |= 1<< DOWOLNY_PIN; // ustaw jako wyjscie
DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); // zero
TCCR2 = 1<<CS22 | 1<<CS20; // Normalny tryb, preskaler /128
TIMSK |= 1<<OCIE2 | 1<<TOIE2; // wlacz przerwania od przepelnienia i prownania
OCR2 = pwm; // ustaw wypelnienie
sei();
while(1)
{
}
return 0;
}
ISR(TIMER2_OVF_vect)
{
if(pwm) // tylko jesli wypelnienie jest rozne od 0
DOWOLNY_PORT |= 1<<DOWOLNY_PIN;
OCR2 = pwm;
}
ISR(TIMER2_COMP_vect)
{
if(pwm!=255)
{ // ustaw '0', tylko gdy wypelnienie jest rozne od 255
DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN);
}
}
ISR(TIMER2_COMP_vect)
{
static uint8_t cnt=0;
if(cnt<my_pwm1) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN);
if(cnt<my_pwm2) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN);
cnt++;
} zerpo napisał:Czy rzeczywiście więc moje rozwiązanie jest tak mało optymalne?
mirekk36 napisał:zerpo ---> aż dwa przerwania ??????? do takiego czegoś ?? czy to nie przesada ?to znaczy nie przesada ale to można spokojnie zrobić w jednym przerwaniu.
ISR(TIMER2_COMP_vect) { static uint8_t cnt=0; if(cnt<my_pwm1) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN); if(cnt<my_pwm2) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN); cnt++; }
PO. napisał:
Pozwolę sobie czepnąć się tego kodu, przynajmniej estetycznie: przekroczenie zakresu zmiennych w c to zdaje się zachowanie niezefiniowane? W związku z tym może się dla cnt bezboleśnie przekręcić licznik (tak jak chcemy tutaj) a może zacząć nadpisywać sąsiedni bajt - zależnie od kompilatora. Czy się mylę?
PO. napisał:Przy okazji offtopnę zapytaniem? Jaka jest różnica w deklaracji globalnej a lokalnej static? Przecież i tak musi być cały czas przechowywana wartość, więc ta sama zajętość pamięci cały czas?
zerpo napisał:Static powoduje, że zmienna umieszczana jest w RAMie i sobie tam siedzi i nie ma do niej dostępu z innego miejsca programu, poza tą funkcją.
zerpo napisał:Mnie też się nie podoba ten sposób na PWMa.
cnt będzie się "przekręcał" co 256, jeśli więc chcemy rozdzielczość inną niż 8-bitów, to trzeba wprowadzić dodatkowe IF-y.
if( ++cnt > 64 ) cnt=0;ISR(TIMER2_COMP_vect)
{
static uint8_t cnt=0;
// rozdzielczość 7bit
if( (cnt & 0b01111111 ) < my_pwm1) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN);
// rozdzielczość 6bit
if( (cnt & 0b00111111) < my_pwm2) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN);
// rozdzielczość 8bit
if( cnt < my_pwm3) DOWOLNY_PORT &= ~(1<<DOWOLNY_PIN); else DOWOLNY_PORT |= (1<<DOWOLNY_PIN);
cnt++;
} zerpo napisał:Poza tym taki kod generuje pewne problemy.
Brak buforowania wart. zadanej pwma "my_pwmx" powoduje, że jeśli gdzieś w programie zmniejszymy wartość żądanego wypełnienia do 0, a akurat będzie stan wysoki, to taki stan zostanie załączony aż do zmiany wypełnienia na != 0.
Podobnie z ustawianiem my_pwmx na 255 podczas trwania niskiego stanu PWMa.
Oprócz tego przy zmianie wart my_pwmx mogą pojawiać się dziwne impulsy np. stan wysoki/niski trwający jeden okres.
Procedura ta wymaga dodania paru if-ów i dodatkowej zmiennej buforującej. Co spowoduje, że obsługa przerwania stanie się dosyć długa, a co za tym idzie spadnie znacznie maksymalna częstotliwość PWMa.
if ( cnt < my_pwm )mirekk36 napisał:PO. napisał:
Pozwolę sobie czepnąć się tego kodu, przynajmniej estetycznie: przekroczenie zakresu zmiennych w c to zdaje się zachowanie niezefiniowane? W związku z tym może się dla cnt bezboleśnie przekręcić licznik (tak jak chcemy tutaj) a może zacząć nadpisywać sąsiedni bajt - zależnie od kompilatora. Czy się mylę?
No mylisz się. Jaki sąsiedni bajt? w zależności od jakiego kompilatora? to jest zapis i działanie tylko na jednym bajcie, więc nie ma co tutaj wymyślać.
PO. napisał:Przy okazji offtopnę zapytaniem? Jaka jest różnica w deklaracji globalnej a lokalnej static? Przecież i tak musi być cały czas przechowywana wartość, więc ta sama zajętość pamięci cały czas?zerpo napisał:Static powoduje, że zmienna umieszczana jest w RAMie i sobie tam siedzi i nie ma do niej dostępu z innego miejsca programu, poza tą funkcją.
Dla rozjaśnienia tego co napisał zepro dodam, że zarówno zmienna lokalna (automatyczna) jak i globalna są deklarowane w RAMie. Tyle, że słówko static powoduje, że jest ona umieszczona w tej sekcji gdzie znajdują się wszystkie inne zmienne globalne i żyje przez cały czas trwania programu, natomiast bez słówka static zmienna jest tworzona w pamięci RAM ale na stosie w związku z tym, żyje ona tylko tyle czasu ile funkcja w której została zdefiniowana ta zmienna. Po zakończeniu funkcji czyszczony jest stos i ślad po niej nie zostaje.
PO. napisał:
- pytałem czy z punktu widzenia optymalizacji kodu jest różnica w obciążeniu w stosunku do globalnej deklaracji, w sumie retorycznie chyba. Różnice są tylko od strony programisty w ochronie wartości poza blokiem i zwolnieniem nazwy do innych bloków. Coś pominąłem?
mirekk36 napisał:PO. napisał:
Pozwolę sobie czepnąć się tego kodu, przynajmniej estetycznie: przekroczenie zakresu zmiennych w c to zdaje się zachowanie niezefiniowane? W związku z tym może się dla cnt bezboleśnie przekręcić licznik (tak jak chcemy tutaj) a może zacząć nadpisywać sąsiedni bajt - zależnie od kompilatora. Czy się mylę?
No mylisz się. Jaki sąsiedni bajt? w zależności od jakiego kompilatora? to jest zapis i działanie tylko na jednym bajcie, więc nie ma co tutaj wymyślać.
Cytat:
Niezdefiniowane zachowania [edytuj]
Wiele operacji w C mających niezdefiniowane zachowanie nie jest sprawdzanych w czasie kompilacji. W przypadku C, „niezdefiniowane zachowanie” oznacza, że zachowanie nie jest opisane w standardzie i co dokładnie się stanie nie musi być opisane w dokumentacji danej implementacji C. W praktyce czasami poleganie na niezdefiniowanych zachowaniach może prowadzić do trudnych w rozpoznaniu błędów. Zachowania te mogą różnić się między kompilatorami C. Głównym celem pozostawienia niektórych zachowań jako niezdefiniowane jest pozwolenie kompilatorowi na generowanie bardziej wydajnego kodu dla zdefiniowanych zachowań, co jest ważne dla głównej roli języka C jako języka implementacji systemów; unikanie niezdefiniowanych zachowań jest odpowiedzialnością programisty. Przykłady niezdefiniowanych zachowań:
Odczyt i zapis poza zasięgiem tablicy.
Przekroczenie zakresu liczb całkowitych.
Dotarcie do końca funkcji zwracającej wartość, bez napotkania na wyrażenie return.
Odczytanie zmiennej przed zapisaniem do niej wartości.
Kolejność wykonywania wyrażeń przekazanych jako argumenty do funkcji.
Wszystkie te operacje to błędy programistyczne, które mogą się zdarzyć w wielu językach programowania; C przyciąga krytykę ponieważ jego standard wyraźnie wylicza wiele przypadków niezdefiniowanego zachowania, także tam, gdzie mogłoby ono zostać dobrze zdefiniowane i nie zawiera żadnego mechanizmu obsługi błędów w czasie wykonywania programu.
Cytat:Rezultat operacji arytmetycznej może wykroczyć poza dostępny zakres użytego w obliczeniach typu danych. W takiej sytuacji, zwykle dochodzi do utraty najstarszych bitów wyniku (efekt slangowo określany jako przekręcenie się licznika), i ustawienia odpowiedniej flagi (carry flag), która informuje programistę o nieprawidłowości wyniku.
Niektóre języki nie przewidują automatycznego sprawdzania wspomnianej flagi: w standardzie ISO C99, wynik operacji, dla której zachodzi błąd przekroczenia zakresu liczb całkowitych, jest po prostu niezdefiniowany (a w praktyce, zgodny z wyżej opisanym zachowaniem).