Oskar_Zaremba 0 Napisano Wrzesień 11, 2020 Udostępnij Napisano Wrzesień 11, 2020 Dzień Dobry, Mam pytanie odnośnie programowania mikro kontrolerów. Zajmuję się akurat ATTINY2313A. Mam ustawiony wewnętrzny oscylator na częstotliwość 4 MHz bez wewnętrznego podziału zegara przez 8. Poniżej mój krótki kod w #include <avr/io.h> int main(void) { DDRB = _BV(DDB0); // ustawienie pinu PB0 w stan wyjścia TCCR0A = _BV(WGM01); // ustawienie generatora w tryb CTC TCCR0B = _BV(CS00); // wybór zegara z skalowaniem przez 1 OCR0A = 1; // ustawienie górnej wartości licznika while (1) { if (TIFR & _BV(OCF0A)) { // sprawdzenie czy w rejestrze TIFR ustawiona została flaga OCF0A po przepełnieniu licznika OCR0A TIFR |= _BV(OCF0A); // wyzerowanie flagi OCF0A poprzez ustawienie logicznej jedynki PORTB ^= _BV(DDB0); // przełączenie bitu na pinie PB0 } } } W moim przypadku według dokumentacji czyli wzoru poniżej: fOC0A=fclk_I/O/(2·N·(1+OCR0A)) fOC0A=4000000/(2·1·(1+1)) fOC0A=1000000=1MHz A teraz do meritum:) Co robię nie tak? Częstotliwość którą uzyskuję to --> 207.4KHz. W załączniku przesyłam zdjęcie z oscyloskopu z widocznym przebiegiem na pinie PB0. Pozdrawiam, Oskar Zaremba Cytuj Link to post Share on other sites
deshipu 1122 Wrzesień 11, 2020 Udostępnij Wrzesień 11, 2020 Twoja pętla działa wolniej niż twój licznik. Co z tego, że licznik się przepełnia z prędkością 1MHz, skoro jeden obrót pętli i dojście do sprawdzenia flagi zajmuje dłużej. Cytuj Link to post Share on other sites
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 Próbowałem to też zrobić na przerwaniach, ale bez skutecznie. Czy jest jakiś inny sposób, aby uzyskać potrzebną mi częstotliwość? A tak przy okazji jaka jest szybkość działania tej pętli while i gdzie można znaleźć tą informację?? Cytuj Link to post Share on other sites
deshipu 1122 Wrzesień 11, 2020 Udostępnij Wrzesień 11, 2020 (edytowany) Nie ma określonej szybkości działania pętli while. Mikrokontroler wykonuje instrukcje maszynowe tak, jak kompilator je wygenerował. Prędkość wykonania każdej instrukcji możesz znaleźć w nocie katalogowej mikrokontrolera, ale w przypadku AVR jest dość prosto, bo większość instrukcji zajmuje jeden takt procesora. Uzyskana szybkość będzie zależeć od tego jaki kod się w w tej pętli wykonuje. Aby uzyskać wyższe prędkości, należy użyć trybu PWM timera — wówczas nóżka jest przełączana bezpośrednio przez układ timera, bez udziału reszty mikrokontrolera, więc prędkość nie zależy od szybkości wykonywania kodu. O trybach timera możesz przeczytać w nocie katalogowej w dziale o timerach. W szczególności przeczytaj sekcje 12.8.2 i 12.8.3 noty katalogowej. Edytowano Wrzesień 11, 2020 przez deshipu 1 Cytuj Link to post Share on other sites
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Szukasz producenta PCB? Sprawdź firmę JLCPCB. Dlaczego warto? • Prototypy PCB 2-warstwowe za 2$ (gotowe w 24 godziny) • Prototypy PCB 4-warstwowe za 5$ • Montaż SMT od 7$ • Produkcja w profesjonalnej fabryce (zobacz film) Sprawdź też » Jak powstaje PCB? Wycieczka po fabryce
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 PWM to dobry pomysł, ale z tego co pamiętam to można sterować w nim tylko współczynnikiem wypełnienia a ja potrzebuję wysterować konkretną wartość częstotliwości Rozumiem, że częstotliwość taktowania licznika jest wyrażona przez wzór, który podałem natomiast wykonanie instrukcji warunkowej plus czyszczenie flagi i przełączenie bitu portu zajmuje dodatkowe takty licznika. Te dodatkowe takty sprawiają, że przegapiam kilka przepełnień licznika, a więc przełączam port kilkukrotnie wolniej aniżeli częstotliwość zegara dobrze to rozumiem? Czy jest zatem jakiś sposób, żeby uzyskać na pinie PB0 częstotliwości wynikające z wzoru, który podałem? Chciałbym sterować wartością prescalera i wartością OCR0A tak żeby uzyskiwać wynikające z wzoru częstotliwości. W dalszym ciągu czytam datasheet tego mikrokontrolera i widzę, że w przypadku licznika 16bit tryb fast PWM można najprawdopodobniej sterować częstotliwością PWM. Za chwilkę spróbuję to wytestować Cytuj Link to post Share on other sites
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 Widzę, że jedynym sposobem sterowania częstotliwością PWM jest używanie prescalera (1, 8, 64, 256, 1024) co w moim przypadku jest niewystarczające, ponieważ potrzebuję większej precyzji. W mojej głowie rodzi się teraz pytanie… Po co w trybie CTC jest możliwość tak dokładnego sterowania częstotliwością, skoro nie ma możliwości realnego tego wykorzystania?? Za każdym razem, kiedy sprawdzę którąś z flag i wykonam instrukcję tracę takty zegara więc czynności wykonywane przez program nie będą zgodne z częstotliwością (powyżej pewnej granicznej wartości) z podanego wzoru…:/ Cytuj Link to post Share on other sites
marek1707 2843 Wrzesień 11, 2020 Udostępnij Wrzesień 11, 2020 Nie doczytałeś. PWM to nie jedyny tryb pracy pinów sprzęgniętych z modułem generacji sygnałów (Waveform Generation Mode). Popatrz na bity WGMxx. Jeśli odpowiednio je ustawisz, stan pinu będzie odwracany w chwili przeładowania timera. To idealnie pasuje do Twoich potrzeb: rejestrem OCRxx ustawiasz okres, timer puszczasz w CTC a WGM ustawiasz na odwracanie. Wydaje mi się, że dla 4MHz, właśnie 1MHz będzie maksem jaki możesz z tego wyciągnąć. Cytuj Link to post Share on other sites
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 To rozwiązało mój problem:) #include <avr/io.h> int main(void) { DDRB = _BV(DDB2); // ustawienie pinu PB0 w stan wyjścia TCCR0A = _BV(COM0A0) | _BV(WGM01); // ustawienie generatora w tryb CTC TCCR0B = _BV(CS00); // wybór zegara z skalowaniem przez 1 OCR0A = 1; // ustawienie górnej wartości licznika } Dziękuje za odpowiedzi. Cytuj Link to post Share on other sites
marek1707 2843 Wrzesień 11, 2020 Udostępnij Wrzesień 11, 2020 1 godzinę temu, Oskar_Zaremba napisał: jedynym sposobem sterowania częstotliwością PWM jest używanie prescalera (1, 8, 64, 256, 1024) To też nie jest prawdą. Nawet tiny ma timery wyposażone w tryb PWM, gdzie okres ustawiasz jednym z rejestrów OCRxx. Tracisz w ten sposób jeden kanał sprzętowego wyjścia, ale za to w drugim masz ustawialny zarówno okres jak i wypełnienie. Poza tym bardziej rozbudowany, 16-bitowy timer1 ma tryby PWM z predefiniowanymi okresami 256, 512 i 1024, co daje rozdzielczości odpowiednio 8, 9 i 10 bitów a także można mu ustawiać okres w rejestrze ICR, nie tracąc kanału PWM. No i masz wreszcie pin CKOUT, na którym możesz poprzez odpowiednie zaprogramowanie fuse-bitów dostać zegar CPU wprost z generatora, bez marnowania jakiegokolwiek timera. Dla 4MHz to będzie oczywiście 4MHz, ale może wystarczy prędkość 1MHz? Cytuj Link to post Share on other sites
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 4 godziny temu, marek1707 napisał: Nie doczytałeś. PWM to nie jedyny tryb pracy pinów sprzęgniętych z modułem generacji sygnałów (Waveform Generation Mode). Popatrz na bity WGMxx. Jeśli odpowiednio je ustawisz, stan pinu będzie odwracany w chwili przeładowania timera. To idealnie pasuje do Twoich potrzeb: rejestrem OCRxx ustawiasz okres, timer puszczasz w CTC a WGM ustawiasz na odwracanie. Wydaje mi się, że dla 4MHz, właśnie 1MHz będzie maksem jaki możesz z tego wyciągnąć. Nie twierdziłem, że PWM to jedyny tryb pracy pinów. Pisałem tylko że częstotliwością sygnału PWM można sterować tylko przy użyciu prescalera. Teraz widzę, że rzeczywiście, jeśli ustawię WGM00 i WGM01 to mam np. generator ustawiony na fast PWN, a jeśli dodam do tego WGM02 i COM0A0 to będę miał fastPWM z przełączaniem przy przepełnieniu licznika po uzyskaniu wartości OCRnx tyle tylko że wtedy nie mam już możliwości sterowania wypełnieniem sygnału a skoro steruje i tak tylko samą częstotliwością to po co mi wtedy PWM z stałym wypełnieniem 50%. Przy ustawieniach, które podałem, czyli wykorzystaniu CTC mam mniej kodu. Tak jak pisałeś timer w trybie CTC, czyli WGM01 ustawiony a do przełączania wystarczy COM0A0 zamiast dodatkowych WGMów. Cytuj Link to post Share on other sites
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 4 godziny temu, marek1707 napisał: To też nie jest prawdą. Nawet tiny ma timery wyposażone w tryb PWM, gdzie okres ustawiasz jednym z rejestrów OCRxx. Tracisz w ten sposób jeden kanał sprzętowego wyjścia, ale za to w drugim masz ustawialny zarówno okres jak i wypełnienie. Poza tym bardziej rozbudowany, 16-bitowy timer1 ma tryby PWM z predefiniowanymi okresami 256, 512 i 1024, co daje rozdzielczości odpowiednio 8, 9 i 10 bitów a także można mu ustawiać okres w rejestrze ICR, nie tracąc kanału PWM. No i masz wreszcie pin CKOUT, na którym możesz poprzez odpowiednie zaprogramowanie fuse-bitów dostać zegar CPU wprost z generatora, bez marnowania jakiegokolwiek timera. Dla 4MHz to będzie oczywiście 4MHz, ale może wystarczy prędkość 1MHz? Eh:/ Tutaj przyznam się, że nie do końca wszystko rozumiem:/ Pisząc szczerze to jeszcze 3 tygodnie temu zaczynałem od 0 czytając o elementach biernych typu rezystor i widzę, że jeszcze ogrom wiedzy do zdobycia mnie czeka…☹Wracając do tematu. Tracę jeden kanał sprzętowego wyjścia tzn. pin przełączany przy przepełnieniu licznika zapewne, ale o co chodzi z tym drugim, gdzie mam okres i wypełnienie?? Widzę, że timer 16 bitowy ma różne rozdzielczości, ale czy można mu ustawić i okres, i wypełnienie jednocześnie? Widzę w tabeli generatora fali dla np. PWM, Phase and Freq Correct, że jako TOP jest podane albo ICR1 albo OCR1A, ale czy można ustawić oba tak żeby jeden rejestr trzymał wartość ustalająca częstotliwość a drugi wypełnienie? Trochę to wszystko zagmatwane:/ Czy mógłby Pan podpowiedzieć w jaki sposób mogę ustawić zarówno okres jak i wypełnienie PWM?? Z góry uprzejmie dziękuje Cytuj Link to post Share on other sites
Oskar_Zaremba 0 Wrzesień 11, 2020 Autor tematu Udostępnij Wrzesień 11, 2020 Okay:/ Już wiem jak zrobić i okres i wypełnienie:) #include <avr/io.h> int main(void) { DDRB = _BV(DDB2); // ustawienie pinu PB0 w stan wyjścia TCCR0A = _BV(COM0A0) | _BV(WGM01); // ustawienie generatora w tryb CTC TCCR0B = _BV(CS00); // wybór zegara z skalowaniem przez 1 OCR0A = 5; // ustawienie górnej wartości licznika DDRB |= _BV(DDB3) | _BV(DDB4); TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(COM1B0); TCCR1B = _BV(WGM13) | _BV(CS10); OCR1A = 5; OCR1B = 8; ICR1 = 10; } Przepraszam za przedwczesne pytania...Dopiero się uczę:/ Cytuj Link to post Share on other sites
deshipu 1122 Wrzesień 11, 2020 Udostępnij Wrzesień 11, 2020 5 godzin temu, Oskar_Zaremba napisał: Nie twierdziłem, że PWM to jedyny tryb pracy pinów. To moja wina, jak tak zasugerowałem (zresztą niezamierzenie). Cytuj Link to post Share on other sites
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. 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
Pomocna odpowiedź
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!