<?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=13864&amp;mode" />

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2015-12-16T20:03:47+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=23&amp;t=13864&amp;mode</id>
<entry>
<author><name><![CDATA[danielos]]></name></author>
<updated>2015-12-16T20:03:47+01:00</updated>
<published>2015-12-16T20:03:47+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148249#p148249</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148249#p148249"/>
<title type="html"><![CDATA[Re: Obsługa Enkodera - moja koncepcja]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148249#p148249"><![CDATA[
Dokładnie tak jak piszesz. Jeżeli byś mógł czekać ponad 40s na pełny obrót to byś mógł zastosować, ale piszesz że chcesz mieć dość dużą prędkość więc nie ma co próbować.<br /><br />Dzięki za chęci.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=898">danielos</a> — 16 gru 2015, o 20:03</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[maniocek]]></name></author>
<updated>2015-12-15T15:44:00+01:00</updated>
<published>2015-12-15T15:44:00+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148104#p148104</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148104#p148104"/>
<title type="html"><![CDATA[Re: Obsługa Enkodera - moja koncepcja]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148104#p148104"><![CDATA[
Ten silnik+enkoder który mam generuje 8246 impulsów na jeden obrót wału na wyjściu przekładni.<br />Mam rolkę fi 31 mm, więc maksymalną prędkość jaką uzyskam to ~54 mm/s , oczywiście planuję ją regulować poprzez PWM, więc będzie również sporo niższa.<br /><br />Zakładając prędkość maksymalną, rolka w ciągu sekundy obróci się o jakieś 1 i 2/3 raza.<br />8246 impulsów na pełny obrót * 5ms =  41230 ms = 41,230 s<br />Czas jednego pełnego obrotu rolki jest krótszy niż odczyt, więc Twój warunek jest nie spełniony.<br /><br />W takim wypadku chyba Twoja biblioteka nie zadziała poprawnie? Czy się mylę?<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=8503">maniocek</a> — 15 gru 2015, o 15:44</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[danielos]]></name></author>
<updated>2015-12-14T21:49:53+01:00</updated>
<published>2015-12-14T21:49:53+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148014#p148014</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148014#p148014"/>
<title type="html"><![CDATA[Re: Obsługa Enkodera - moja koncepcja]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148014#p148014"><![CDATA[
<div class="quotetitle">maniocek napisał(a):</div><div class="quotecontent"><br />Licznik obrotów zrealizowałeś, więc można na tej podstawie mierzyć np. drogę jaką rolka napędowa przebyła,a czy można na podstawie Twojej biblioteki mierzyć rzeczywistą prędkość obrotową silnika/rolki napędowej?<br /></div><br /><br />Można, ale jeżeli będzie zależało ci na dokładności pomiaru drogi i prędkości to przy względnie dużych prędkościach może być dość duże przekłamanie. Zauważ, że &quot;próbkowanie&quot; stanu kanałów odbywa się co 1ms. Poprawny stan jest wykrywany dopiero po 5ms, przy 20 krokach masz 100 ms - więc pełny obrót rolki musiałby wykonać się w czasie nie mniejszym jak 100ms. Pamiętaj też o liczniku (takim moim watchdogu) - domyślnie jest ustawiony na 150 ms więc problemu z resetowaniem zmiennych pomocniczych nie będzie - więc go nie zmieniaj na mniejsze wartości.<br /><br />A co do obliczania prędkości możesz zrobić tak jak to jest w licznikach rowerowych - znając obwód rolki mierzysz tylko czas pełnego obrotu tej rolki i już masz wszystko co jest potrzebne - drogę i czas do obliczenia prędkości rolki (nie wiem jak to jest w przypadku silników z przekładniami).<br /><br />Jak już będziesz po testach to daj znać jak się moja biblioteka spisała (nie przewidywałem zastosowania jej do silników, ale zawsze może okazać się przydatna) - pewnie będziesz testował również inne biblioteki więc jestem ciekaw jak wypadnie w porównaniu z nimi.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=898">danielos</a> — 14 gru 2015, o 21:49</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[maniocek]]></name></author>
<updated>2015-12-14T21:34:11+01:00</updated>
<published>2015-12-14T21:34:11+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148009#p148009</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148009#p148009"/>
<title type="html"><![CDATA[Re: Obsługa Enkodera - moja koncepcja]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=148009#p148009"><![CDATA[
Dziękuję za podzielenie się biblioteką <img src="https://forum.atnel.pl/images/smilies/icon_e_smile.gif" alt=":)" title="Szczęśliwy" /><br /><br />Chciałbym ją po testować ze swoim  silniczkiem:<br /><!-- m --><a class="postlink" href="https://www.pololu.com/product/2288" >https://www.pololu.com/product/2288</a><!-- m --><br /><br />Licznik obrotów zrealizowałeś, więc można na tej podstawie mierzyć np. drogę jaką rolka napędowa przebyła,a czy można na podstawie Twojej biblioteki mierzyć rzeczywistą prędkość obrotową silnika/rolki napędowej?<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=8503">maniocek</a> — 14 gru 2015, o 21:34</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[danielos]]></name></author>
<updated>2015-12-13T15:07:21+01:00</updated>
<published>2015-12-13T15:07:21+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=147856#p147856</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=147856#p147856"/>
<title type="html"><![CDATA[Obsługa Enkodera - moja koncepcja]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=13864&amp;p=147856#p147856"><![CDATA[
Witam.<br /><br />Chciałbym wam przedstawić moją bibliotekę do obsługi enkodera.<br /><br /> <img src="https://forum.atnel.pl/images/smilies/icon_exclaim.gif" alt=":!:" title="Wykrzyknik" /> Na początku chce jednak zaznaczyć, że została ona utworzona w celu przypomnienia sobie pewnych zagadnień, zrozumienia działania enkodera, a także sprawdzeniu swoich umiejętności. Pewnie nie jest ona optymalna pod względem szybkości i objętości, jak biblioteka zaprezentowana przez mirka w <!-- m --><a class="postlink" href="http://mirekk36.blogspot.com/2013/04/encoder-avr-callbackow-ciag-dalszy-cz2.html" >http://mirekk36.blogspot.com/2013/04/en ... y-cz2.html</a><!-- m --> , ale najważniejsze że działa i spełniła swoją rolę. <img src="https://forum.atnel.pl/images/smilies/icon_exclaim.gif" alt=":!:" title="Wykrzyknik" /> <br /><br />Warunki pracy biblioteki:<br />- kwarc co najmniej 8MHz;<br />- przerwanie od dowolnego timera, wykonywane co 1ms (biblioteka nie konfiguruje przerwania) - do ustawienia przez użytkownika;<br />- podłączenie kanałów A i B do dowolnego pina mikrokontrolera - niekoniecznie do tego samego portu.<br /><br />Zasada działania enkodera obrotowego (wyglądem przypomina potencjometr) jest oparta na odpowiednim przełączaniu kanałów A i B. W zależności w jakiej kolejności te kanały po sobie są załączane i wyłączane można określić w którą stronę kręcimy.<br /><br />Do interpretacji kierunku obrotu, oraz w celu usunięcia pomyłek w odczycie do życia powołałem zmienną <em>stan</em>, w której przechowywane są informacje dot. kierunku obrotu, oraz na którym etapie przełączania znajduje się enkoder. Poniżej przedstawiam graficzną interpretację zmiennej <em>stan</em>:<br /><a href="https://obrazkiforum.atnel.pl/898/2c80e33b14f9e930c43193d12e96f5a8.png"  class="postlink"><img src="https://obrazkiforum.atnel.pl/thumb/898/2c80e33b14f9e930c43193d12e96f5a8.png" alt="Obrazek" /></a><br /><br />Cztery najmniej znaczące bity określają kierunek obrotów zgodny z ruchem wskazówek zegara (CW), natomiast 4 najbardziej znaczące kierunek przeciwny do ruchu wskazówek zegara (CCW). Poniżej w dwóch kolumnach znajduje się reprezentacja stanu kanałów A i B podczas obrotu w danym kierunku. Należy zaznaczyć, że poziom logiczny 0 oznacza, że kanał jest aktywny (tak jak to ma miejsce podczas obsługi przycisków). Podczas każdej zmiany stanu kanału w odpowiedniej 4-ce bitów zmiennej <em>stan</em> ustawiane są w 1 bitowe (odpowiednim miejscu) w zależności który etap został wykryty (etapy zmiany stanów określone są jako A B C D). <br />Jeżeli został wykryty etap A dla kierunku zgodnego z ruchem wskazówek zegara, kolejne etapy będą wykrywane tylko dla tego obrotu - dzięki czemu podczas zakończenia ruchu zmienna <em>stan</em> osiągnie wartość 0xF0 (dla CCW) bądź 0x0F (dla CW). Po wykonanym obrocie można sprawdzić wartość tej zmiennej i określić czy obrót został dobrze zinterpretowany przez program czy nie.<br /><br />Poniżej przedstawiam algorytm działania programu, które może rozwiać większość wątpliwości:<br /><a href="https://obrazkiforum.atnel.pl/898/10c3bcccf4cbf48e4a972f409b41bb15.png"  class="postlink"><img src="https://obrazkiforum.atnel.pl/thumb/898/10c3bcccf4cbf48e4a972f409b41bb15.png" alt="Obrazek" /></a><br /><br />Dodatkowo podczas rozpoczęcia ruchu &quot;uruchamiany&quot; jest licznik, który odmierza czas w którym obrót powinien się zakończyć. W przypadku prawidłowego obrotu, licznik jest zatrzymywany. Natomiast, gdy ruch się zakończył a zmienna <em>stan </em>nie osiągnęła wartości 0x0F lub 0xF0 (poprzez wykonanie pół kroku, lub jakieś inne zakłócenia) licznik zakończy swoje odliczanie, czego skutkiem będzie zresetowanie wszystkich zmiennych do wartości początkowych. Dzięki temu zabiegowi uniknąłem przekłamań i błędów podczas odczytu stanów z enkodera.<br /><br />Działanie biblioteki oparte jest na zdarzeniach. Użytkownik ma do dyspozycji rejestrację dwóch zdarzeń - od obrotu w dowolną stronę, oraz od przycisku:<br /><br />[syntax=c]void ENCODER_EVENT(void);<br />void register_encoder_event( void(*encoder_callback)(void) );//rejestracja funkcji obsługi dowolnego obrotu, użytkownik ma do dyspozycji całą strukturę<br />void register_encoder_switch_event( void(*encoder_callback)(void) );//rejestracja funkcji obsługi przycisku[/syntax]<br /><br />Konfiguracja biblioteki dostępna jest w osobnym pliku. Użytkownik może ustawić odpowiednie porty oraz piny do których jest podłączony enkoder (biblioteka nie korzysta z przerwań zewnętrznych - enkodera podłączamy do dwóch dowolnych pinów uC). Może również ustawić czas dla licznika (taki mój watchdog - pisałem o nim wcześniej),  ilość impulsów przypadających na pełny obrót dla danego enkodera, oraz czy enkoder posiada przycisk (parametr ten włącza do kompilacji zdarzenie, oraz funkcje dla obsługi przycisku).<br /><br />Zawartość pliku ds_enc_conf.h:<br />[syntax=c]/*<br /> * ds_enc_conf.h<br /> *<br /> *  Created on: 04-12-2015<br /> *      Author: Daniel<br /> *<br /> *      Plik konfiguracyjny dla użytkownika.<br /> *<br /> *      Użytkownik biblioteki może dokonywać zmian parametrów.<br /> *<br /> */<br /><br />#ifndef DS_ENC_CONF_H_<br />#define DS_ENC_CONF_H_<br /><br /><br />//ustalenie portu do którego podłączone są kanały A,B enkodera oraz przycisk E<br />#define ENC_PORT_AB<br />#define ENC_PORT_BB<br />#define ENC_PORT_EB<br /><br />//ustalenie pinu do którego podłączone są kanały A,B enkodera oraz przycisk E<br />#define ENC_PIN_A0<br />#define ENC_PIN_B1<br />#define ENC_PIN_E2<br /><br />//ustalenie wartosci licznik czuwającego nad poprawną pracą enkodera (*1ms) -maks 255<br />#define ENC_TIME_COUNTER 150<br /><br />//ustalenie ile impulsów posiada enkoder na pełny obrót<br />#define ENC_MAX_IMP20<br /><br />//*****wybór właciwosci bilioteki<br />#define ENC_SWITCH_ENABLE1//czy jest dostępny przycisk w enkoderze- jeżeli tak to jest także dostępne zdarzenie od przycisku<br /><br />#endif /* DS_ENC_CONF_H_ */[/syntax]<br /><br />Wszystkie informacje dot. enkodera zapisane są w strukturze, do której użytkownik ma dostęp poprze zmienną <em>enkoder_status</em>. Struktura ta ma następującą budowę:<br /><br />[syntax=c]typedef struct{<br />uint8_t switch_active;//czy przycisk aktywny<br />uint8_t switch_toggle;//zmienna toggle dla przycisku<br />uint16_t rotation_clockwise;//ilosc impulsów zgodnie z ruchem wskazówek<br />uint16_t rotation_counter_clockwise;//ilosc impulsów przeciwnie do ruchu wskazówek<br />uint8_t full_rotation_cw;//liczba pełnych obrotów zgodnych do ruchu wskazówek zegara (clockwise)<br />uint8_t full_rotation_ccw;//liczba pełnych obrotów przeciwnych do ruchu wskazówek zegara(counter clockwise)<br />}DS_ENCODER;[/syntax]<br /><br />Do dyspozycji użytkownika oddane są również następujące funkcje: <br /><br />[syntax=c]void encoder_init(void);//inicjalizacja enkodera<br />void encoder_proccedure(void);//procedura pracy enkodera - musi znaleźć się w przerwania wykonywanym co 1ms<br />void encoder_clear_value(void);//wyzerowanie wszystkich wartosci w zmiennej enkoder_status[/syntax]<br /><br />Pierwsza funkcja powinna znaleźć się przed pętlą główną - odpowiada ona za poprawną inicjalizację enkodera ( <img src="https://forum.atnel.pl/images/smilies/icon_exclaim.gif" alt=":!:" title="Wykrzyknik" /> Inicjalizacja ta nie obejmuje konfiguracji przerwania <img src="https://forum.atnel.pl/images/smilies/icon_exclaim.gif" alt=":!:" title="Wykrzyknik" /> ). <br />Całe dekodowanie enkodera znajduje się w kolejnej funkcji - encoder_proccedure. Funkcję tą NALEŻY umieścić w przerwania od dowolnego timera, które jest wykonywane co 1ms.<br />Ostatnia funkcja zeruje wszystkie wartości które są przechowywane w strukturze enkoder_status.<br /><br />Zawartość pliku ds_enc.h<br />[syntax=c]/*<br /> * ds_enc.h<br /> *<br /> *  Created on: 04-12-2015<br /> *      Author: Daniel<br /> *<br /> *<br /> *UWAGA!!!<br /> *<br /> *W tym pliku nie należy niczego zmieniać<br /> *<br /> */<br /><br />#ifndef DS_ENC_H_<br />#define DS_ENC_H_<br /><br />#include &quot;ds_enc_conf.h&quot;<br /><br />//definicje<br /><br />// Makra upraszczające dostęp do portów<br />// *** PORT<br />#define PORT(x) SPORT(x)<br />#define SPORT(x) (PORT##x)<br />// *** PIN<br />#define PIN(x) SPIN(x)<br />#define SPIN(x) (PIN##x)<br />// *** DDR<br />#define DDR(x) SDDR(x)<br />#define SDDR(x) (DDR##x)<br /><br />#define ENC_SW_A!(PIN(ENC_PORT_A) &amp; (1&lt;&lt;ENC_PIN_A))<br />#define ENC_SW_B!(PIN(ENC_PORT_B) &amp; (1&lt;&lt;ENC_PIN_B))<br /><br />#if ENC_SWITCH_ENABLE<br />#define SW_E!(PIN(ENC_PORT_E) &amp; (1&lt;&lt;ENC_PIN_E))<br />#endif<br /><br />typedef struct{<br />uint8_t switch_active;//czy przycisk aktywny<br />uint8_t switch_toggle;//zmienna toggle dla przycisku<br />uint16_t rotation_clockwise;//ilosc impulsów zgodnie z ruchem wskazówek<br />uint16_t rotation_counter_clockwise;//ilosc impulsów przeciwnie do ruchu wskazówek<br />uint8_t full_rotation_cw;//liczba pełnych obrotów zgodnych do ruchu wskazówek zegara (clockwise)<br />uint8_t full_rotation_ccw;//liczba pełnych obrotów przeciwnych do ruchu wskazówek zegara(counter clockwise)<br />}DS_ENCODER;<br /><br />extern volatile DS_ENCODER enkoder_status;<br /><br />//**********funkcje<br />//********zewnętrzne<br /><br />void encoder_init(void);//inicjalizacja enkodera<br />void encoder_proccedure(void);//procedura pracy enkodera - musi znaleźć się w przerwania wykonywanym co 1ms<br />void encoder_clear_value(void);//wyzerowanie wszystkich wartosci w zmiennej enkoder_status<br /><br />//*****zdarzenia<br />void ENCODER_EVENT(void);<br /><br />void register_encoder_event( void(*encoder_callback)(void) );//rejestracja funkcji obsługi dowolnego obrotu, użytkownik ma do dyspozycji całą strukturę<br /><br />#if ENC_SWITCH_ENABLE<br />void register_encoder_switch_event( void(*encoder_callback)(void) );//rejestracja funkcji obsługi przycisku<br />#endif<br /><br />#endif /* DS_ENC_H_ */[/syntax]<br /><br />Zawartość pliku ds_enc.c:<br />[syntax=c]/*<br /> * ds_enc.c<br /> *<br /> *  Created on: 04-12-2015<br /> * Edited on: 11-12-2015<br /> *      Author: Daniel<br /> *<br /> *All rights reserved.<br /> *<br /> *Przy pomocy książki:<br /> *Mikrokontrolery AVR<br /> *Język C - podstawy programowania<br /> *<br /> *Autor:<br /> *Mirosław Kardaś<br /> *Język C.<br /> *Pasja programowania mikrokontrolerów 8-bitowych<br /> *<br /> *Autor:<br /> *Mirosław Kardaś<br /> *<br /> *Do użytkownika dostępne są następujące elementy:<br /> *<br /> *-struktura DS_ENCODER, oraz zmienna enkoder_status, która przechowuje wszystkie aktualne stany dotyczące enkkodera.Użytkownika może dowolnie je zmieniać<br /> *- funkcjia do inicjalizacji enkodera encoder_init<br /> *- funkcja obsługi enkodera encoder_proccedure, która powinna znaleźć się w przerwania od timera który wykonuje się co 1ms (jest to warunek konieczny do prawidłowego działania biblioteki)<br /> *-funkcja zerujące wszystkie zmienna w strukturze enkoder_status: encoder_clear_value<br /> *- zdarzenie od enkodera ENCODER_EVENT, które należy umiescic w pętli głównej programu<br /> *-rejestrację funkcji obsługi enkodera<br /> *-rejestrację funkcji obsługi przycisku z enkodera<br /> *<br /> *Konfigurację biblioteki należy dokonać w pliku ds_enc_conf.h<br /> *<br /> *<br /> *W strukturze dostępnej dla użytkownika znajduje się następujące dane:<br /> * - switch_active-czy przycisk aktywny<br /> * - switch_toggle;-zmienna toggle dla przycisku<br /> * - rotation_clockwise;-ilosc impulsów zgodnie z ruchem wskazówek<br /> * - rotation_counter_clockwise;-ilosc impulsów przeciwnie do ruchu wskazówek<br /> *  - full_rotation_cw;-liczba pełnych obrotów zgodnych do ruchu wskazówek zegara (clockwise)<br /> * - full_rotation_ccw;-liczba pełnych obrotów przeciwnych do ruchu wskazówek zegara(counter clockwise)<br /> *<br /> *<br /> *UWAGA!!!<br /> *<br /> *W tym pliku nie należy niczego zmieniać<br /> *Do prawidłowego działania biblioteki, konieczne jest umieszczenie funkci encoder_proccedure w przerwaniu od timera, które wykonuje się do 1ms<br /> *<br /> *<br /> *<br /> */<br /><br /><br />#include &lt;avr/io.h&gt;<br />#include &lt;avr/interrupt.h&gt;<br />#include &lt;avr/pgmspace.h&gt;<br />#include &lt;util/delay.h&gt;<br /><br />#include &quot;ds_enc.h&quot;<br />#include &quot;ds_enc_conf.h&quot;<br /><br /><br /><br />//**********zmienne<br /><br />volatile DS_ENCODER enkoder_status;<br /><br />//**********funkcje<br /><br />//przerwanie<br /><br />void encoder_proccedure(void){<br /><br />static volatile uint8_t licznik;//odmierza czas do wyzerowania zmiennych pomocniczych w przypadku złego odczytu z enkodera<br />static volatile uint8_t stan=0x00;//przechowuje informację o tym, w jakim położeniu jest enkoder (podczas przełączania)<br />static volatile uint8_t enkoder=0;//stan kanału A i B<br />static volatile uint8_t tmp_enkoder=0x03;//pamięta ostatnio stan kanału A i B<br /><br />if(licznik){<br />//odmierza czas do wyzerowania zmiennych pomocniczych<br />--licznik;<br />}<br /><br /><br />enkoder = (!ENC_SW_A&lt;&lt;1) | !ENC_SW_B;//odczytuje obecny stan kanału A i B<br /><br />//reakcja dla licznika gdy odliczy swoj czas<br />if(!licznik &amp;&amp; (stan != 0x00) &amp;&amp; (enkoder == 0x03) ){<br />stan = 0x00;//wyzeruje dany stan położenia enkodera<br />tmp_enkoder = 0x03;//przywróc początkowe wartosci odczytanych wczesniej kanałów<br />}<br /><br />if( (stan==0x00)){<br />//gdy jest stan początkowy<br /><br />if(enkoder == 0x01){<br />//Kanał A czyli zgodnie z ruchem wskazówek<br /><br />stan = 0x01;//4 najmniej znaczące bity odnoszą się do obrotu zgodnie z ruchem wskazówek - pierwsza zmiana<br />licznik=ENC_TIME_COUNTER;<br /><br />}else if(enkoder == 0x02){<br />//Kanał B czyli przeciwnie z ruchem wskazówek<br /><br />stan = 0x10;//4 najbardzej znaczące bity odnoszą się do obrotu przeciwnie z ruchem wskazówek - pierwsza zmiana<br />licznik=ENC_TIME_COUNTER;<br /><br />}<br />tmp_enkoder = enkoder;<br /><br />//0x00<br />}else if(stan &amp; 0x01){<br />//obroty zgodnie z ruchem wskazówek zegara<br /><br />if( (enkoder == 0x00) &amp;&amp; (tmp_enkoder == 0x01) ){<br /><br />stan |= 0x02;//druga zmiana<br />tmp_enkoder = enkoder;//zapamiętanie stanu kanału A i B<br /><br />}else if( (enkoder == 0x02) &amp;&amp; (tmp_enkoder == 0x00) ){<br /><br />stan |= 0x04;//trzecia zmiana<br />tmp_enkoder = enkoder;//zapamiętanie stanu kanału A i B<br /><br />}else if( (enkoder==0x03) &amp;&amp; (tmp_enkoder==0x02) ){<br /><br />stan |= 0x08;//czwarta zmiana<br />tmp_enkoder = enkoder;//zapamiętanie stanu kanału A i B<br /><br />if(stan == 0x0F){<br />stan = 0x00;//wyzerowanie<br />enkoder_status.rotation_clockwise++;<br />licznik = 0;<br />}<br /><br />}<br />//0x01<br />}else if(stan &amp; 0x10){<br />//obroty przeciwne z ruchem wskazówek zegara<br /><br />if( (enkoder == 0x00) &amp;&amp; (tmp_enkoder == 0x02) ){<br />stan |= 0x20;//druga zmiana<br />tmp_enkoder = enkoder;//zapamiętanie stanu kanału A i B<br /><br />}else if( (enkoder == 0x01) &amp;&amp; (tmp_enkoder == 0x00) ){<br />stan |= 0x40;//trzecia zmiana<br />tmp_enkoder = enkoder;//zapamiętanie stanu kanału A i B<br /><br />}else if( (enkoder==0x03) &amp;&amp; (tmp_enkoder==0x01) ){<br />stan |= 0x80;//czwarta zmiana<br />tmp_enkoder = enkoder;//zapamiętanie stanu kanału A i B<br /><br />if(stan == 0xF0){<br />stan = 0x00;<br />enkoder_status.rotation_counter_clockwise++;<br />licznik = 0;<br />}<br /><br />}<br />}//0x10<br /><br />//odczyt stanu przycisku w enkoderze<br />#if ENC_SWITCH_ENABLE<br />if(SW_E &amp;&amp; !enkoder_status.switch_active){<br />enkoder_status.switch_active = 1;<br />enkoder_status.switch_toggle ^= 1;<br /><br />}else if(!SW_E &amp;&amp; enkoder_status.switch_active){<br />enkoder_status.switch_active = 0;<br />}<br />#endif<br /><br />}//encoder_procedure<br /><br />//********wewnętrzne<br />void encoder_full_rotation(void){<br /><br />static uint16_t tmp_cw;<br />static uint16_t tmp_ccw;<br /><br />if( enkoder_status.rotation_clockwise &amp;&amp; !(enkoder_status.rotation_clockwise % ENC_MAX_IMP) &amp;&amp; (enkoder_status.rotation_clockwise != tmp_cw) ){<br /><br />enkoder_status.full_rotation_cw++;//zwiększ licznik pełnych obrotów<br />tmp_cw = enkoder_status.rotation_clockwise;//zapamiętanie obecnej wartosci impulsów<br />}<br /><br />if( enkoder_status.rotation_counter_clockwise &amp;&amp; !(enkoder_status.rotation_counter_clockwise % ENC_MAX_IMP) &amp;&amp; (enkoder_status.rotation_counter_clockwise != tmp_ccw) ){<br /><br />enkoder_status.full_rotation_ccw++;//zwiększ licznik pełnych obrotów<br />tmp_ccw = enkoder_status.rotation_counter_clockwise;//zapamiętanie obecnej wartosci impulsów<br />}<br />}<br /><br />//******** zewnętrzne<br /><br />void encoder_init(void){<br />//inicjalizacja portów<br /><br />//kierunek - wejście<br />DDR(ENC_PORT_A) &amp;= ~(1&lt;&lt;ENC_PIN_A);//A<br />DDR(ENC_PORT_B) &amp;= ~(1&lt;&lt;ENC_PIN_B);//B<br /><br />#if ENC_SWITCH_ENABLE<br />DDR(ENC_PORT_E) &amp;= ~(1&lt;&lt;ENC_PIN_E);//switch<br />#endif<br /><br />//podciągnięcie do VCC<br />PORT(ENC_PORT_A) |= (1&lt;&lt;ENC_PIN_A);//A<br />PORT(ENC_PORT_B) |= (1&lt;&lt;ENC_PIN_B);//B<br /><br />#if ENC_SWITCH_ENABLE<br />PORT(ENC_PORT_E) |= (1&lt;&lt;ENC_PIN_E);//switch<br />#endif<br /><br />}<br /><br />void encoder_clear_value(void){<br />//wyzerowanie wszystkich liczników enkodera<br />enkoder_status.full_rotation_ccw=0;<br />enkoder_status.full_rotation_ccw=0;<br />enkoder_status.rotation_clockwise=0;<br />enkoder_status.rotation_counter_clockwise=0;<br />enkoder_status.switch_active=0;<br />enkoder_status.switch_toggle=0;<br />}<br /><br /><br />//*****zdarzenia<br />static void (*encoder_event_callback)(void);//zmienna przechowująca wskaźnik do funkcji<br /><br />#if ENC_SWITCH_ENABLE<br />static void (*encoder_switch_event_callback)(void);<br />#endif<br /><br />void ENCODER_EVENT(void){<br /><br />encoder_full_rotation();//sprawdzenie czy odbył się pełny obrót<br /><br />if( encoder_event_callback )<br />if ( enkoder_status.rotation_clockwise || enkoder_status.rotation_counter_clockwise ) //sprawdź czy funkcja została zarejestrowana<br />(*encoder_event_callback)();//jeżeli tak to ją wywołaj<br /><br />#if ENC_SWITCH_ENABLE<br />if( encoder_switch_event_callback )<br />if( enkoder_status.switch_active )<br />(*encoder_switch_event_callback)();<br />#endif<br /><br />}<br /><br />void register_encoder_event( void(*encoder_callback)(void) ){//rejestracja funkcji obsługi przycisków<br /><br />encoder_event_callback = encoder_callback;<br />}<br /><br />#if ENC_SWITCH_ENABLE<br />void register_encoder_switch_event( void(*encoder_callback)(void) ){<br />//rejestracja funkcji obsługi przycisku<br /><br />encoder_switch_event_callback = encoder_callback;<br />}<br /><br />#endif[/syntax]<br /><br />Poniżej przedstawiam przykład zastosowania bilioteki:<br />[syntax=c]#include &lt;avr/io.h&gt;<br />#include &lt;avr/interrupt.h&gt;<br /><br />#include &quot;DS_ENC/ds_enc.h&quot;<br />#include &quot;DS_ENC/ds_enc_conf.h&quot;<br /><br /><br />//zmienne pomocnicze<br />uint8_t time_ls=0;<br />volatile uint8_t time_10ms = 0;<br />volatile uint8_t time_1ms = 0;<br />volatile uint8_t time_1s = 0;<br /><br />ISR(TIMER0_COMP_vect){<br /><br />if(++time_1ms&gt;9){<br />time_1ms=0;<br /><br />if(++time_10ms&gt;99){<br />time_10ms=0;<br /><br />if(++time_1s&gt;59) time_1s=0;<br />}<br />}<br /><br />encoder_proccedure();<br /><br />}// /isr<br /><br />void obsluga_enkodera(void){<br />//kod obsługi dla enkodera<br /><br />//wyzerowanie zmiennych w enkoder_status<br />enkoder_status.rotation_clockwise = 0;<br />enkoder_status.rotation_counter_clockwise = 0;<br />};<br /><br />void obsluga_przycisk(void){<br />//kod obsługi dla przycisku<br />};<br /><br />int main(void){<br /><br />//inicjalizacja I/O<br />DDRC |= (1&lt;&lt;PC0);//debuger kontrolny miga co 1 s<br /><br />//*******************************inicjalizacja I/O enkodera<br />encoder_init();<br />//*******************************<br /><br />//inicjalizacja przerwań<br />//timer0 w trybie ctc<br />TCCR0 |= (1&lt;&lt;WGM01);//tryb CTC<br />TCCR0 |= (1&lt;&lt;CS01) | (1&lt;&lt;CS00);//preskaler 64<br />OCR0 = 249;//co 1ms dla preskalera 64 bity i kwarcu 16MHz<br />TIMSK |= (1&lt;&lt;OCIE0);//aktywacja przerwania<br /><br />//aktywacja przerwań<br />sei();<br /><br />//*******************************inicjalizacja zdarzeń enkodera<br /><br />register_encoder_event(obsluga_enkodera);<br />register_encoder_switch_event(obsluga_przycisk);<br /><br />//*******************************<br /><br />while(1){<br /><br />//wywołanie zdarzenia od enkodera<br />ENCODER_EVENT();<br /><br />//puls programu;)<br />if( time_1s != time_ls ){<br />time_ls = time_1s;<br />PORTC ^= (1&lt;&lt;PC0);<br />}<br /><br />//..reszta kodu<br /><br />}<br /><br />}[/syntax]<br /><br />Reasumując - biblioteka ta umożliwia poprawny odczyt obrotów z enkodera, niwelując przy tym wystąpienie zatrzymanie enkodera w &quot;połowie kroku&quot;. Nie jest również wrażliwa na drgania styków, które również występują w enkoderze. Użytkownika ma do dyspozycji dość obszerną strukturę, w której znajduję się wszystkie informacje dot. enkodera. Obsługa oparta jest na zdarzeniach - zdarzenie od enkodera aktywowane jest w przypadku wykrycie obrotu w dowolnym kierunku (użytkownik musi zadbać o wyzerowanie tych zmiennych). Natomiast zdarzenie dla przycisku aktywowane jest tylko gdy przycisk jest wciśnięty podczas przejścia do obsługi tego zdarzenia. <br /><br />Mam nadzieję, że wszystko opisałem w dość zrozumiały sposób. <br />Jestem ciekaw czy w jakiś sposób zainteresowałem kogoś moim sposobem obsługi enkodera.<br /><br />Jak są jakieś pytania to pisać - postaram się na nie odpowiedzieć.<br />Jeżeli jest jakaś fala krytyki - pisać. Może uda mi się wybronić;)<br /><br /><br />Dodano po chwili namyślenia;) :<br />Ach teraz zauważyłem dopiero, że w złym miejscu umieściłem ten post. Proszę więc o przeniesienie go do Projekty programistyczne w DIY. Dzięki<br /><br />Zapomniałem też napisać, że chociaż biblioteka ma kilka dni to jest używana w urządzeniu. Jak na razie działa bezproblemowo.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=898">danielos</a> — 13 gru 2015, o 15:07</p><hr />
]]></content>
</entry>
</feed>