<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl-pl">
<link rel="self" type="application/atom+xml" href="https://forum.atnel.pl/feed.php?f=23&amp;t=11570&amp;mode" />

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2015-05-20T21:45:15+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=23&amp;t=11570&amp;mode</id>
<entry>
<author><name><![CDATA[Anonymous]]></name></author>
<updated>2015-05-12T23:59:55+01:00</updated>
<published>2015-05-12T23:59:55+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129020#p129020</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129020#p129020"/>
<title type="html"><![CDATA[Re: Enkoder obrotowy - kolejna biblioteka.]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129020#p129020"><![CDATA[
Dzieki za odpowiedz . co do Bascoma to owszem właśnie w nim od w sumie bedzie już od wersji na 51 pisze , z 16 lat ? <img src="https://forum.atnel.pl/images/smilies/icon_e_smile.gif" alt=":)" title="Szczęśliwy" /> tak jakoś , daje rade pod warunkiem że z daleka obchodzi sie właśnie wiele pułapek w postaci &quot;złych&quot; gotowych procedur . Kiedyś próbowałem gotowizny właśnie dla takiego &quot;ręcznego nastawnika&quot; w postaci enkodera ,masakra , napisałem swoje  i nie było z tym problemów .Zawsze oscyloskop pod ręką i optymalizacja czasowa kodu <img src="https://forum.atnel.pl/images/smilies/icon_e_smile.gif" alt=":)" title="Szczęśliwy" /> .<br />Ale chce wejść w nowe procesory i tu jest język C . <br />OKI . Dziękuje ci za wyjaśnienia .<p>Statystyki: Napisane przez Gość — 12 maja 2015, o 23:59</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[ryba84]]></name></author>
<updated>2015-05-12T23:07:39+01:00</updated>
<published>2015-05-12T23:07:39+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129018#p129018</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129018#p129018"/>
<title type="html"><![CDATA[Re: Enkoder obrotowy - kolejna biblioteka.]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129018#p129018"><![CDATA[
Tak to jest biblioteka do obsługi enkoderów &quot;ręcznych&quot;, na wyjściu których pojawia się dwu bitowy kod Graya. W przykładzie próbkowanie stanu wynosi 1kHz i jeśli zbyt szybko zakręcimy gałką to program się &quot;gubi&quot;, tzn. będą chwilowe problemy z odczytem kierunku kręcenia (najczęściej jeden impuls nie w tą stronę, bo nie próbowałem zakładać gałki enkodera do wkrętarki). Można próbkować z większą częstotliwością (wydaje mi się, że przynajmniej 2, jak nie 4 razy większą niż częstotliwość impulsów) i kod powinien działać dla enkoderów dających na wyjściu taki sam przebieg. Problemem może być zapewnienie wywołania przerwania ze stałą częstotliwością i zmieszczenie się w cyklach procesora między przerwaniami (przy próbkowaniu 1MHz i zegarze 16MHz masz tylko 16 cykli co będzie stanowczo za mało dla biblioteki w tej formie - oczywiście można nanieść zmiany w tym kodzie w celu zwiększenia wydajności tracąc na uniwersalności, ale raczej nie zmieścisz się w 16 cyklach - kod wynikowy funkcji encPool ma 188 bajtów i 74 linie w assemblerze, nie licząc wywoływanych callbacków i kodu samego przerwania - cykli nie próbowałem liczyć).<br />Ilość kodu - pojęcie względne. Tu jest pełno komentarzy, system callbacków co pozwala na bardziej uniwersalną obsługę niezależną od platformy bez grzebania w kodzie biblioteki (można to zamienić na makra co zmniejszy nieznacznie kod wynikowy, ale nadal użytkownik musi definiować obsługę od strony sprzętowej - stany wejść, przerwania timera), no i starałem się by kod był czytelny. Jeśli porównujesz do BASIC (BASCOM) to tam masz gotowe biblioteki i korzystasz z tego co dostarcza, a jak czegoś nie ma to musisz pisać na piechotę i dochodzisz do tego co w C. Jak w C masz gotowe biblioteki to tego kodu wcale nie jest dużo.<br />Co do notki na dole po prostu jeśli skorzystasz z biblioteki w swoim projekcie hobbystycznym i będziesz chciał go opublikować to daj linka to tego tematu z kodem i sprawa załatwiona.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=3170">ryba84</a> — 12 maja 2015, o 23:07</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[Anonymous]]></name></author>
<updated>2015-05-12T21:12:40+01:00</updated>
<published>2015-05-12T21:12:40+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129012#p129012</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129012#p129012"/>
<title type="html"><![CDATA[Re: Enkoder obrotowy - kolejna biblioteka.]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=129012#p129012"><![CDATA[
Przyznam że to jest to co odpycha mnie w jezyku C ,,, ta ilość kodu . No ale chce osobiście to sprawdzić , tzn. jezyk C a że często korzystam z enkoderów to fajnie że ktoś prezentuje biblioteke , być może za jakiś <br />czas skorzystam z niej ,przetestuje . <br />Małe pytanko do autora , ważne bo nie wyjaśnił tego .<br />Otóż klasyczny enkoder wiadomo jak działa , dwie fale impulsów przesuniete wzajemnie w fazie .<br />Sa inne typy enkoderów ale zakładam że tu mowa o takim &quot;klasycznym&quot; .<br />Pytanie brzmi : czy jest to biblioteka do obsługi typowego &quot;cyfrowego potencjometru&quot; ręcznie pokręcanego przez użytkownika ?<br />Czy też jest to biblioteka która &quot;umie&quot; bez błędów obsłużyć dość szybki enkoder przemysłowy dający <br />zmienne impulsy (szybkość oraz kierunek) z czestotliwościami na jednej fazie powiedzmy na przykład <br />250 kHz . Wiem ... mam świadomość że to jest zależne od Platwormy (mikroprocesora) ale chodzi mi o samo założenie autora oraz pewnie jakieś testy które musiał przeprowadzić przed prezentacją kodu na forum .<br />//<br />Jeśli to nie jest  jakiś problem to prosiłbym o odpowiedż.<br /><br />PS &quot;Proszę o niekopiowanie kodu w innych miejscach bez mojej zgody. Kod udostępniam do użytku niekomercyjnego.<br />Jak ktoś ma uwagi z chęcią się zastosuję do nich.&quot;<br /><br />Prosze sie nie obawiać uszanuje taką wole ,zaprezentowany kod będzie dla mnie jedynie przykładem .<br />Z innej strony to chyba ,tak mi sie wydaje . warto sie dobrze zastanowić przed publikacją czy oddajemy swoją myśl innym czy też zachowujemy dla siebie . Pośrednie rozwiązania słabo sie sprawdzają w praktyce .<p>Statystyki: Napisane przez Gość — 12 maja 2015, o 21:12</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[ryba84]]></name></author>
<updated>2015-05-20T21:45:15+01:00</updated>
<published>2015-05-01T21:37:23+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=128024#p128024</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=128024#p128024"/>
<title type="html"><![CDATA[Enkoder obrotowy - kolejna biblioteka.]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=11570&amp;p=128024#p128024"><![CDATA[
Witam.<br /><br />Dziś biblioteka do obsługi enkodera obrotowego. Znów uniwersalna (inicjalizacja i odczyt sprzętu po stronie użytkownika). Możliwości biblioteki:<ul><li>Nieblokująca.</li><li>Reakcja na zdarzenia z enkodera (użytkownik musi zdefiniować).</li><li>Obsługa przycisku enkodera z rozróżnieniem długości wciśnięcia - 3 poziomy.</li></ul>Poniżej kod.<br />encoder.h:[syntax=c]/*<br /> * encoder.c<br /> *<br /> *  Created on: 1 maj 2015<br /> *      Author: Piotr Rudzki ryba.lodz@gmail.com<br /> *      Version: 1.0<br /> *  Changelog:<br /> *  1.0 - small code optimizations, and cleanups<br /> *  0.9 - split encPool function code for better code readable<br /> *      - added encoder pulse divisor macro for encoders with many pulses between steady states<br /> *      - added macro to disable encoder button routines<br /> *  0.8 - initial release<br /> */<br /><br />#ifndef ENKODER_H_<br />#define ENKODER_H_<br /><br />#include &lt;stdint.h&gt;<br /><br />#define ENC_BUTTON// Należy zakomentować jeśli nie obsługujemy przycisku enkodera. Zmniejszy kod wynikowy usuwając zbędne funkcje.<br />#define ENC_DIVISOR4// Ile impulsów generuje enkoder pomiędzy stanami stabilnymi.<br />#define SHORT_TIME250 // Krótkie wciśnięcie czas wyrażony w zależności od tempa wywoływania funkcji encPool.<br />#define LONG_TIME1000// Dłuższe j.w.<br />#define VERY_LONG_TIME3000// Bardzo długie j.w.<br /><br />// Struktura opisująca stan enkodera.<br />typedef struct{<br />uint8_t A;<br />uint8_t B;<br />uint8_t SW;<br />} encState_t;<br /><br />enum encRotate {STOP, CW, CCW}; // Zdarzenia obracania enkoderem.<br />#ifdef ENC_BUTTON<br />enum encButton {NONE, SHORT, LONG, VERY_LONG}; // Zdarzenia przycisku enkodera.<br />#endif<br />// Struktura opisująca zdarzenia enkodera.<br />typedef struct{<br />enum encRotate rotate;<br />#ifdef ENC_BUTTON<br />enum encButton button;<br />#endif<br />} encEvent_t;<br /><br />void regEncState(encState_t (*callback)(void)); // Rejestracja funkcji odczytującej stan enkodera.<br />void regEncAction(void (*callback)(encEvent_t const event)); // Rejestracja funkcji obsługującej zdarzenia enkodera.<br />void encPool(void); // Wywołujemy w przerwaniu timera.<br /><br />#endif /* ENKODER_H_ */[/syntax]<br />encoder.c:[syntax=c]/*<br /> * encoder.c<br /> *<br /> *  Created on: 1 maj 2015<br /> *      Author: Piotr Rudzki ryba.lodz@gmail.com<br /> *      Version: 1.0<br /> *  Changelog:<br /> *  1.0 - small code optimizations, and cleanups<br /> *      - small changes in button code it only reacts for release<br /> *  0.9 - split encPool function code for better code readable<br /> *      - added encoder pulse divisor macro for encoders with many pulses between steady states<br /> *      - added macro to disable encoder button routines<br /> *  0.8 - initial release<br /> */<br /><br />#include &quot;encoder.h&quot;<br /><br />// Odczyt kierunku obrotu enkodera.<br />// Jeśli przypiszemy jednemu pinowi wagę 1 a drugiemu 2 to sekwencja<br />// w kierunku wskazówek zegara wygląda tak:<br />// w kodzie Gray-a:0, 1, 3, 2, 0 ...<br />// w binarnym:0, 1, 2, 3, 0 ...<br />static inline enum encRotate readEncRotate(encState_t const * const state) {<br />static uint8_t encLast = 0; // Ostatnia pozycja enkodera.<br />static uint8_t encDivisor = 0; // Licznik impulsów enkodera.<br />uint8_t last = 0, actual = 0; // Zmienne pomocnicze.<br />// Zmiana kodu Gray-a na binarny.<br />if (!state-&gt;A) {<br />actual++; // 1<br />}<br />if (!state-&gt;B) {<br />actual ^= 3; // XOR 3<br />}<br />last = encLast;<br />encLast = actual; // Zapisujemy aktualną pozycję.<br />// Ustalamy czy nastąpiła zmiana pozycji. Wynik odejmowania wskazuje czy nastąpił ruch,<br />// oraz kierunek tego ruchu. Bit 0 wskazuje czy nastąpił ruch, a bit 1 jego kierunek.<br />// Kierunek wskazówek: 2 - 3 = 255 (0b11111111) (ponieważ posługujemy się zmiennymi typu unsigned)<br />// Przeciwnie:   0 - 3 = 253 (0b11111101) (j.w.)<br />actual -= last;<br />if (actual &amp; 1) {<br />if (actual &amp; 2) {<br />if (++encDivisor == ENC_DIVISOR) { // Bierzemy pod uwagę licznik impulsów.<br />encDivisor = 0;<br />return CW; // Kierunek wskazówek zegara.<br />}<br />} else {<br />if (--encDivisor == (uint8_t) (0 - ENC_DIVISOR)) { // J.w.<br />encDivisor = 0;<br />return CCW; // Kierunek przeciwny do wskazówek zegara.<br />}<br />}<br />}<br />return STOP;<br />}<br />#ifdef ENC_BUTTON<br />// Obsługa przycisku enkodera.<br />static inline enum encButton readEncButton(encState_t const * const state) {<br />static uint16_t pushTime = 0; // Czas trzymania przycisku.<br />enum encButton tmp;<br />if (pushTime &amp;&amp; state-&gt;SW) { // Zwolnienie przycisku.<br />if ((SHORT_TIME &lt; pushTime) &amp;&amp; (pushTime &lt; LONG_TIME)) {<br />tmp = SHORT;<br />}<br />if ((LONG_TIME &lt; pushTime) &amp;&amp; (pushTime &lt; VERY_LONG_TIME)) {<br />tmp = LONG;<br />}<br />if (VERY_LONG_TIME &lt; pushTime) {<br />tmp = VERY_LONG;<br />}<br />pushTime = 0;<br />} else {<br />tmp = NONE;<br />}<br />if (!state-&gt;SW) { // Trzymanie przycisku.<br />++pushTime;<br />}<br />return tmp;<br />}<br />#endif<br />// Callback do odczytu stanu enkodera.<br />encState_t (*_encState)(void);<br />// Rejestracja powyższej funkcji.<br />void regEncState(encState_t (*callback)(void)) {<br />_encState = callback;<br />}<br />// Callback wywoływany w przypadku wystąpienia zdarzenia enkodera.<br />void (*_encEvent)(encEvent_t const event);<br />// Rejestracja powyższej funkcji.<br />void regEncAction(void (*callback)(encEvent_t const event)) {<br />_encEvent = callback;<br />}<br />// Funkcja obsługi enkodera wywoływana w przerwaniu timera.<br />void encPool(void) {<br />encState_t state; // Odczytany stan enkodera.<br />encEvent_t event; // Zdarzenie enkodera.<br />if (_encState) {<br />state = (*_encState)(); // Pobierz aktualny status enkodera.<br />}<br />// Sprawdzenie czy enkoder nie został obrócony.<br />event.rotate = readEncRotate(&amp;state);<br />#ifdef ENC_BUTTON<br />// Sprawdzenie stanu przycisku.<br />event.button = readEncButton(&amp;state);<br />#endif<br />// Wywołujemy callback tylko przy jakimś zdarzeniu.<br />if (<br />#ifdef ENC_BUTTON<br />(event.button != NONE) ||<br />#endif<br />(event.rotate != STOP)) {<br />if (_encEvent) {<br />(*_encEvent)(event);<br />}<br />}<br />}[/syntax]<br />Przykład znów dla Atmega2560.<br />main.h:<br />[syntax=c]/*<br /> * main.h<br /> *<br /> *  Created on: 1 maj 2015<br /> *      Author: Piotr Rudzki ryba.lodz@gmail.com<br /> */<br /><br />#ifndef MAIN_H_<br />#define MAIN_H_<br /><br />#include &lt;avr/io.h&gt;<br />#include &lt;avr/interrupt.h&gt;<br />#include &quot;encoder.h&quot;<br /><br />#define ENKODER_DDR DDRB<br />#define ENKODER_PIN PINB<br />#define ENKODER_PORT PORTB<br />#define ENKODER_A (1 &lt;&lt; PB4)<br />#define ENKODER_B (1 &lt;&lt; PB5)<br />#define ENKODER_SW (1 &lt;&lt; PB6)<br /><br />#endif /* MAIN_H_ */[/syntax]<br />main.c:[syntax=c]/*<br /> * main.c<br /> *<br /> *  Created on: 1 maj 2015<br /> *      Author: Piotr Rudzki ryba.lodz@gmail.com<br /> */<br /><br />#include &quot;main.h&quot;<br /><br />// Inicjalizacja enkodera.<br />static inline void encoderInit() {<br />ENKODER_DDR &amp;= ~(ENKODER_A | ENKODER_B | ENKODER_SW); // Piny enkodera jako wejście.<br />ENKODER_PORT |= ENKODER_A | ENKODER_B | ENKODER_SW; // Wewnętrzne pullupy.<br />}<br />// Inicjalizacja timera dla Atmegi2560.<br />static inline void timerInit() {<br />// Timer1 tryb CTC przerwanie COMPA co 1ms do obsługi enkodera.<br />TCCR1A = 0;<br />OCR1A = 249;<br />TCCR1B = (1 &lt;&lt; WGM12) | (1 &lt;&lt; CS11) | (1 &lt;&lt; CS10);<br />TCCR1C = 0;<br />TIMSK1 = (1 &lt;&lt; OCIE1A);<br />// Timer0 dla wizualizacji pracy enkodera. Dioda na pinie PB7;<br />DDRB |= (1 &lt;&lt; PB7);<br />TCCR0A = (1 &lt;&lt; COM0A1) | (1 &lt;&lt; WGM00);<br />TCCR0B = (1 &lt;&lt; CS02) | (1 &lt;&lt; CS00);<br />OCR0A = 0;<br />}<br />// Odczyt stanu enkodera.<br />encState_t readEncoder() {<br />encState_t tmp;<br />if (ENKODER_PIN &amp; ENKODER_A) { // Stan na pinie A<br />tmp.A = 1;<br />} else {<br />tmp.A = 0;<br />}<br />if (ENKODER_PIN &amp; ENKODER_B) { // Stan na pinie B<br />tmp.B = 1;<br />} else {<br />tmp.B = 0;<br />}<br />if (ENKODER_PIN &amp; ENKODER_SW) { // Jeśli przycisk nie wciśnięty stan wysoki.<br />tmp.SW = 1; // Przycisk nie wciśnięty.<br />} else {<br />tmp.SW = 0; // Przycisk wciśnięty.<br />}<br />return tmp;<br />}<br />// Obsługa zdarzeń z enkodera. Jako argument ma przyjmować zmienną typu encEvent_t.<br />void encoderEvent(encEvent_t const event) {<br />char liczba&#91;4&#93;;<br />switch (event.rotate) {<br />case CW: // Ruch w kierunku wskazówek zegara.<br />OCR0A++;<br />break;<br />case CCW: // Ruch w przeciwnym kierunku do wskazówek zegara.<br />OCR0A--;<br />break;<br />default:<br />break;<br />}<br />switch (event.button) {<br />case SHORT: // Krótkie wciśnięcie przycisku.<br />OCR0A = 0;<br />break;<br />case LONG: // Dłuższe wciśnięcie przycisku.<br />OCR0A = 127;<br />break;<br />case VERY_LONG: // Bardzo długie wciśnięcie przycisku.<br />OCR0A = 255;<br />break;<br />default:<br />break;<br />}<br />}<br />// Główny program.<br />int main(void) {<br />// Rejestracja używanych callbacków.<br />regEncState(readEncoder); // Rejestracja funkcji odczytujące stan enkodera.<br />regEncAction(encoderEvent); // Rejestracja funkcji wywoływanej podczas jakiegoś zdarzenia enkodera.<br /><br />// Inicjalizacja peryferii.<br />encoderInit(); // Inicjalizacja pinów enkodera.<br />timerInit(); // Inicjalizacja timerów.<br /><br />sei(); // Start przerwań.<br /><br />while (1) {<br />// Hmmm. Pętla główna pusta, a program działa ;)<br />}<br />}<br />// Przerwanie timera wywoływane co 1ms nieblokujące innych przerwań. Wywołujemy w nim odczyt stanu enkodera.<br />ISR(TIMER1_COMPA_vect, ISR_NOBLOCK) {<br />encPool();<br />}[/syntax]<br />Timer wywołuje przerwanie co 1 ms dla F_CPU 16000000UL. Dla innego zegara MCU trzeba policzyć na nowo.<br />Proszę o niekopiowanie kodu w innych miejscach bez mojej zgody. Kod udostępniam do użytku niekomercyjnego.<br />Jak ktoś ma uwagi z chęcią się zastosuję do nich.<br /><br />EDYTA1:<br />Zmiany w kodzie:<ul><li>Dodałem możliwość wyłączenia obsługi przycisku przez bibliotekę.</li><li>Dodałem obsługę podzielnika impulsów enkodera. Moje wszystkie enkodery pomiędzy stabilnymi pozycjami dają po 4 impulsy.</li><li>Podzieliłem funkcję encPool na kilka aby poprawić czytelność kodu.</li></ul>EDYTA2:<br />Kolejne zmiany w kodzie:<ul><li>Poprawiłem funkcje odczytu kierunku obrotu enkodera (działała odwrotnie, bo miałem odwrotnie podłączony enkoder).</li><li>Dodano więcej komentarzy w kodzie.</li><li>Trochę optymalizacji w celu zmniejszenia kodu wynikowego - każdy bajt w AVR się liczy <img src="https://forum.atnel.pl/images/smilies/icon_e_wink.gif" alt=";)" title="Puszcza oko" /></li><li>Zmiana działania bardzo długiego wciśnięcia przycisku - teraz reaguje dopiero po puszczeniu.</li><li>Bardziej restrykcyjne przekazywanie zmiennych do funkcji (również callback). Dodałem const wszędzie gdzie funkcja nie powinna zmieniać wartości ani wskaźnika.</li><li>Małe zmiany w kodzie w main.c.</li></ul><p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=3170">ryba84</a> — 1 maja 2015, o 21:37</p><hr />
]]></content>
</entry>
</feed>