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

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2018-03-18T21:51:42+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=4&amp;t=20427&amp;mode</id>
<entry>
<author><name><![CDATA[abel11]]></name></author>
<updated>2018-03-18T21:51:42+01:00</updated>
<published>2018-03-18T21:51:42+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205719#p205719</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205719#p205719"/>
<title type="html"><![CDATA[Re: PRZEPŁYWOMIERZ PROPORCIONALNY]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205719#p205719"><![CDATA[
Całkowanie w dyskretnej dziedzinie czasu sprowadza się do sumowania - upraszczając jeśli masz całkę od 0 do T w ciągłej dziedzinie czasu to w dyskretnej będzie to suma od 0 do T.<br />Zasadniczo ALU potrafi tylko dodawać (8 bitowe uC), odejmowanie to sumowanie liczb z przeciwnym znakiem, mnożenie to sukcesywne sumowanie. Czyli w wielkim uproszczeniu nie mającym przełożenia na asemblera 3*3 to będą 2 operacje sumowania 3+3+3. W układach 16 bitowych i wyżej sprzętowe mnożenie i dzielenie jest już standardem.<br /><br />Czas wykonania programu można przyspieszyć poprzez dobranie właściwych długości zmiennych do żądanej operacji (nie dłuższych niż jest to niezbędnie konieczne), o ile się da nie stosowanie operacji zmiennoprzecinkowych (pochłaniają dużo mocy obliczeniowej), porządnie napisany kod -  bez bezsensownych delay() itp.<br /><br />Z resztą jeśli dopiero rozpoczynasz naukę to myślę, że bardzo pomoże Ci lektura <a href="http://atnel.pl/mikrokontrolery-avr-jezyk-c.html"  class="postlink">http://atnel.pl/mikrokontrolery-avr-jezyk-c.html</a>. Książka naprawdę jest dobrze napisana, część zagadnień opisana wręcz &quot;łopatologicznie&quot; - ciężko ich nie zrozumieć. Sam nabyłem tą pozycję jak już przebrnąłem przez większość mniej przystępnych zagadnień i do dziś żałuje, że nie kupiłem jej wcześniej.<br /><br />Tu masz przykładowy PID, tyle że ten kod nie jest w żadnym razie przenośny (wyliczony metodą kompensacji dynamiki obiektu regulacji), wymaga też operacji zmiennoprzecinkowych (był połączony z filtrem cyfrowym).<br />[syntax=c]/*Współczynniki regulatora*/<br />#define Kp 0.935000<br />#define Ki 235.000000<br />#define Kd 1.201325<br />#define Tp 0.000100<br />#define T 0.005<br /><br />float PID(float uchyb){<br /><br />static struct io{<br />    float we&#91;2&#93;;<br />    float wy&#91;2&#93;;<br />}tmp;<br />/* zamiast zmiennej n możesz wpisać stałe wartości */<br />    n=2;<br />    tmp.we&#91;n&#93; = uchyb;<br />      <br />    tmp.wy&#91;n&#93; = tmp.wy&#91;n-2&#93; + ((4.0*(Kp*T+Kd)<br />        - 2.0*(Ki*T*Tp - Kp*Tp)+Ki+Tp)/<br />        (4.0*T - 2.0*Tp))*tmp.we&#91;n-2&#93;<br />            <br />    -((4.0*T)/(2.0*T-Tp))*tmp.wy&#91;n-1&#93; - <br />        ((4.0*Kp*T+4.0*Kd+Ki*Tp*Tp)/<br />        (2.0*T - Tp))*tmp.we&#91;n-1&#93;<br />            <br />    +((4.0*(Kp*T+Kd)<br />        + 2.0*(Ki*T*Tp + Kp*Tp)+Ki+Tp)/<br />        (4.0*T - 2.0*Tp))*tmp.we&#91;n&#93;;<br /><br />    return tmp.wy&#91;n&#93;;  <br />}[/syntax]<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=17861">abel11</a> — 18 mar 2018, o 21:51</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[ire]]></name></author>
<updated>2018-03-18T20:06:07+01:00</updated>
<published>2018-03-18T20:06:07+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205709#p205709</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205709#p205709"/>
<title type="html"><![CDATA[Re: PRZEPŁYWOMIERZ PROPORCIONALNY]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205709#p205709"><![CDATA[
DZIĘKUJĘ ZA ODPOWIEDŻ  <br />Regulator pid byłby dobry do sterowania prędkością  silnika proporcjonalną do zadawanej temperatury ,nawet jeśli bym próbował  przerobić <br />kod to na całkowaniu z timerami i przerwaniami nie dałbym sobie rady.<br />Ale te całkowanie to z dziesięć operacji i to ma przyśpieszyć, czytałem że operacje +-*/ opcjążają  procesor .<br />Zliczanie impulsów  z INTO i obliczanie litrów na minutę idzie dobrze .<br /> Zliczanie impulsów z ICP  i obliczanie kilometrów na godzinę też dobrze .<br />wolno oblicza litry na kilometr <br />i po tym zamyka lub otwiera zawór z wodą ,po ustawieniu dawki litrów np 250L/5KM/H<br />Morze jakięś przykłady by mi pomogły.<br />Uczę się programowani od 3 miesięcy z internetu dla swoich potrzeb i interesuje mnie to<br />Edukacje zakończyłem w latach 90 w innym kierunku <br />morze coś uda się zrobić<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=18660">ire</a> — 18 mar 2018, o 20:06</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[abel11]]></name></author>
<updated>2018-03-18T01:38:45+01:00</updated>
<published>2018-03-18T01:38:45+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205661#p205661</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205661#p205661"/>
<title type="html"><![CDATA[Re: PRZEPŁYWOMIERZ PROPORCIONALNY]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205661#p205661"><![CDATA[
Regulacja proporcjonalna nigdy nie będzie szybsza niż wynika to z współczynnika proporcjonalności...<br />Jeśli oczekujesz szybszej reakcji na wymuszenie rozważ regulator PI, część całkująca znacznie przyśpiesza proces regulacji, jednak nastawę musiał byś albo wyliczyć albo dobrać doświadczalnie. Podyktowane jest to możliwym zmniejszeniem stabilności lub nawet niestabilnością wynikającą z stopnia całkującego.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=17861">abel11</a> — 18 mar 2018, o 01:38</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[ire]]></name></author>
<updated>2018-03-17T22:44:57+01:00</updated>
<published>2018-03-17T22:44:57+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205658#p205658</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205658#p205658"/>
<title type="html"><![CDATA[PRZEPŁYWOMIERZ PROPORCIONALNY]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=20427&amp;p=205658#p205658"><![CDATA[
Witam.<br />Złożyłem jeden projekt z dwóch obrotomierzy ,z 1 czujnika są podawane impulsy zliczające przepływ wody a z 2   czujnika są <br />podawane impulsy zliczające prędkość  w k/h  ,program mi oblicza ile mi przepływa  wody w litrach na kilometr i wtedy reguluje mi<br />zadaną dawkę za pomocą zaworu, problem jest szybkością reagowania na zmianę prędkości jazdy i czy ten kod jest dobry ,czy <br />coś trzeba zmienić , procesor atmega328p taktowany 8mhz ,jestem początkującym i chciałbym żeby mi ktoś pomógł .<br />[syntax=c]#include &lt;avr/io.h&gt;<br />#include &lt;avr/interrupt.h&gt;<br />#include &lt;util/delay.h&gt;<br />#include &quot;hd/HD_44780.h&quot;<br /><br />#define F_CPU 8000000UL<br />#define BUTTON_DIRDDRD<br />#define BUTTON_PORTPORTD<br />#define BUTTON_PINPIND<br />#define BUTTON4(1 &lt;&lt; PD0)<br />#define BUTTON5(1 &lt;&lt; PD1)<br />#define BUTTON1(1 &lt;&lt; PD5)<br />#define BUTTON2(1 &lt;&lt; PD6)<br />#define BUTTON3(1 &lt;&lt; PD7)<br />#define SENSOR_DIRDDRD<br />#define SENSOR_PORTPORTD<br />#define SENSOR_PINPIND<br />#define SENSOR1(1 &lt;&lt; PD2)<br /><br />uint16_t ostatni_pomiar=0; //ostatni pomiar<br /> double licznik=0;<br /><br /><br />uint8_t odliczania_1_sekundy=0; //pomocnicza do odliczania 1 sekundy<br />uint8_t flaga_1_sekundy=0; //flaga 1 sekundy<br /><br />uint16_t ilosc_przerwan_int0=0; //ilosc przerwan int0<br />//uint16_t jaki_enkoder=1; //konfiguracja enkodera<br />uint8_t blokada=0; //blokowanie naciskania klawiszy<br />uint16_t dawka_LI=1;<br />//uint16_t dawka_LI=0;<br />volatileuint16_t dawka_H=0;<br /><br />volatile uint16_t dawka_L=0;<br /><br /><br /><br />//tutaj ustaw własne zasady pomiaru<br />#define POMIAR_ILOSC_IMPULSOW_NA_OBROT4//ilość inpulsów na jeden obrót<br />#define POMIAR_ILOSC_OBROTOW2//ile obrotów ma trwać pomiar<br /><br />volatile unsigned long int pomiar_ilosc_cykli;<br />volatile unsigned int ilosc_przepelnien;<br />volatile unsigned char pomiar_zbocze_nr;<br />volatile unsigned char pomiar_gotowy;<br /><br />volatile unsigned int ICR1_moment_A;<br />volatile unsigned int ICR1_moment_B;<br />char wynik&#91;16&#93;; //bufor wyświetlacza<br /><br />ISR(TIMER1_CAPT_vect){<br /><br />//Obsługa zdarzenia na ICP1<br /><br />static unsigned int ICR1_aktualny;//wartość ICR1 złapana w aktualnie<br />//złapanym zboczu<br /><br />ICR1_aktualny = ICR1;//odczytaj złapany stan licznika<br /><br /><br />if(pomiar_zbocze_nr == 1){        //czy to pierwsze złapane zbocze?<br /><br />//tak, pierwsze zbocze pomiarowe,<br /><br />//uruchamiamy zliczanie przepełnień Timer1<br /><br />//zgaś flagę przerwania od przepełnienia<br />TIFR1 |= (1&lt;&lt;TOV1);<br /><br />//włącz przerwania od przepełnienia Timer1<br />TIMSK1|=(1&lt;&lt;TOIE1);<br /><br />//zeruj licznik przepełnień Timera1<br />ilosc_przepelnien = 0;<br /><br />//zapamiętujemy stan licznika początku obrotu (moment A)<br />ICR1_moment_A=ICR1_aktualny;<br />}<br />else{<br /><br />//każde następne zbocza pomiarowe<br /><br />//czy to ostatnie zbocze (koniec pełnego obrotu silnika)?<br />if(pomiar_zbocze_nr == POMIAR_ILOSC_IMPULSOW_NA_OBROT<br />* POMIAR_ILOSC_OBROTOW){<br /><br />//tak, wykryto ostatnie zbocze pomiarowe,<br />//czyli wykonał się pełny ostatni obrót tarczy<br /><br />//wyłączamy przerwania z Input Capture Unit<br />//oraz przepełnienia Timer1<br />TIMSK1&amp;=~( (1&lt;&lt;ICIE1) | (1&lt;&lt;TOIE1) );<br /><br />//zapamiętujemy zmienne dla main()<br />ICR1_moment_B=ICR1_aktualny;<br />pomiar_gotowy=1;<br /><br />}<br /><br />//w pozostałych przypadkach nic nie robimy i czekamy na zliczanie<br />//dalszych zboczy<br /><br />}<br /><br />//zwiększ licznik wykrytych zboczy<br />pomiar_zbocze_nr++;<br />}<br /><br />ISR(TIMER1_OVF_vect)<br />{<br />//powiększ licznik przepełnień Timera1<br />ilosc_przepelnien++;<br /><br />}<br />void wykonaj_pomiar(void){<br /><br />//Funkcja włącza pomiar<br /><br />//zerujemy licznik przepełnień Timer0<br />ilosc_przepelnien = 0;<br /><br />//ustawiamy nr pierwszego zbocza<br />pomiar_zbocze_nr = 1;<br /><br />//zerujemy flagę gotowości pomiaru<br />pomiar_gotowy = 0;<br /><br />//włącz przerwania z ICP1 Timer1<br />TIMSK1|=(1&lt;&lt;ICIE1);<br />}<br /><br />ISR(TIMER0_OVF_vect)<br />{<br />if (odliczania_1_sekundy==60) //1 sekunda<br />{<br />    flaga_1_sekundy++;<br />odliczania_1_sekundy=0;<br />}<br /><br />odliczania_1_sekundy++;<br />}<br /><br />ISR(INT0_vect)<br />{<br />    ilosc_przerwan_int0++;<br />    if(ilosc_przerwan_int0)<br />{<br />licznik=licznik+0.01;<br />}<br />}<br /><br />void Device_Initalize()<br />{<br />BUTTON_DIR &amp;= ~BUTTON1;<br />    BUTTON_DIR &amp;= ~BUTTON2;<br />    BUTTON_DIR &amp;= ~BUTTON3;<br />    BUTTON_DIR &amp;= ~BUTTON4;<br />    BUTTON_DIR &amp;= ~BUTTON5;<br /><br />    BUTTON_PORT |= BUTTON1;<br />BUTTON_PORT |= BUTTON2;<br />BUTTON_PORT |= BUTTON3;<br />BUTTON_PORT |= BUTTON4;<br />BUTTON_PORT |= BUTTON5;<br /><br />SENSOR_DIR &amp;= ~SENSOR1;<br /><br />SENSOR_PORT |= SENSOR1;<br /><br />EICRA |= (1&lt;&lt;ISC00);//przerwanie na kazde zbocze<br /><br />EIMSK |= (1&lt;&lt;INT0); //zezwolenie na przerwanie INT0<br />TCCR0B |= (1&lt;&lt;CS00)|(1&lt;&lt;CS01);//preskaler 64<br />TIMSK0 |= (1&lt;&lt;TOIE0); //zezwolenie na przerwanie od przepełnienia<br /><br /><br />return;<br />}<br />uint8_t Parse_Input() //interpretacja klawiszy, dla wygody<br />{<br />unsigned char ret=0;<br />if (!(BUTTON_PIN&amp;BUTTON1)) ret|=0x08;<br />if (!(BUTTON_PIN&amp;BUTTON2)) ret|=0x04;<br />if (!(BUTTON_PIN&amp;BUTTON3)) ret|=0x02;<br />if (!(BUTTON_PIN&amp;BUTTON4)) ret|=0x01;<br />if (!(BUTTON_PIN&amp;BUTTON5)) ret|=0x10;<br />return ret;<br />}<br />void dawkowanie() //podmenu wyswietlajace konfig enkodera<br />{<br />uint8_t klawisz,done=0;<br /><br /><br />//_delay_ms(1000);<br /><br />while (!done)<br />{<br />    klawisz=Parse_Input();<br />     if (klawisz&amp;0b00010000)<br />{<br /> if (!blokada &amp;&amp; dawka_LI&gt;100)<br />    {<br />         dawka_LI= dawka_LI-100;<br />    blokada=1;<br />    }<br />}<br /><br />    else if (klawisz&amp;0x08)<br />{<br />if (!blokada &amp;&amp; dawka_LI&gt;1)<br />{<br /><br />     dawka_LI= dawka_LI-10;<br />     dawka_L= dawka_LI-5;<br />     dawka_H= dawka_LI+5;<br />blokada=1;<br />}<br />}<br />else if (klawisz&amp;0x04)<br />{<br />if (!blokada)<br />{<br />done=1;<br />blokada=1;<br />}<br />}<br />else if (klawisz&amp;0x02)<br />{<br />if (!blokada &amp;&amp;  dawka_LI&lt;400)<br />{<br /><br />    dawka_LI= dawka_LI+10;<br />    dawka_L= dawka_LI-5;<br />    dawka_H= dawka_LI+5;<br />blokada=1;<br />}<br />}<br /> if (klawisz&amp;0x01)<br />{<br />if (!blokada &amp;&amp; dawka_LI&lt;400)<br />{<br />     dawka_LI= dawka_LI+100;<br />blokada=1;<br />}<br />//}<br /><br />}<br /> else blokada=0;<br /><br />LCD_Clear();<br />LCD_WriteText(&quot;dawka: &quot;);<br />LCD_UInt(dawka_LI);<br />LCD_WriteText(&quot; litry&quot;);<br /><br />LCD_GoTo(0,1);<br />LCD_WriteData(( dawka_LI&gt;1)?0x7F:0xFE);<br />LCD_GoTo(5,1);<br />LCD_WriteText(&quot;ustaw&quot;);<br />LCD_GoTo(15,1);<br />LCD_WriteData(( dawka_LI&lt;255)?0x7E:0xFE);<br /><br />_delay_ms(30);<br />}<br />}<br /><br />int main(void)<br />{<br />    uint8_t klawisz;<br />//uint8_t keys;<br />    //zmienne do obliczeń<br />    double czas_jednego_obrotu;<br />    double metry_na_minute;<br />    double kilometry_na_godzine;<br /><br />    uint8_t litry_na_min=0;<br />    uint16_t dawka_LI_HA;<br /><br />    uint16_t dawka_K;<br />    uint16_t dawka_LITROW;<br />    //double ilosc_ha;<br /><br />     PORTB|= (1&lt;&lt;PB0);//włącz pullup transoptora<br />                      DDRB = 0b000110;<br /><br />                  //Ustawienie Timer1<br />                  TCCR1A=0;<br />                  TCCR1B=(1&lt;&lt;CS10);//preskaler 1,<br /><br />Device_Initalize(); //zainicjuj urzadzenie<br />LCD_Initalize(); //zainicjuj wyswietlacz<br /><br />sei(); //pozwalaj na przerwania<br /><br />wykonaj_pomiar();//włącz pierwszy pomiar<br /><br />while (1)<br />{<br />LCD_Home();<br /><br />if (flaga_1_sekundy) //jesli minela 1 sekunda to pobierz zliczenia int0<br />{<br /><br />    ostatni_pomiar=ilosc_przerwan_int0;<br />    litry_na_min = (30*ostatni_pomiar)/50;//<br />    ilosc_przerwan_int0=0;<br />    flaga_1_sekundy=0;<br />}<br /><br />LCD_GoTo(14,0);<br />LCD_UInt( litry_na_min); //wypisz wynik na lcd<br /><br />//LCD_WriteText(&quot;obr/min&quot;);<br />LCD_GoTo(13, 1);<br />LCD_UInt((licznik)); //wypisz wynik na lcd<br /><br /><br />//_delay_ms(20);<br /><br />if(pomiar_gotowy)<br />{<br />// gdy pomiar został wykonany<br /><br />//obliczenia<br /><br />pomiar_ilosc_cykli =  65500 * ilosc_przepelnien - ICR1_moment_A<br />+ ICR1_moment_B;<br /><br />czas_jednego_obrotu=(double) pomiar_ilosc_cykli<br />/ POMIAR_ILOSC_OBROTOW / F_CPU ;<br /><br />metry_na_minute=1.0 / czas_jednego_obrotu;<br /><br /><br /> kilometry_na_godzine=  2.0*metry_na_minute;<br /><br /> //kilometry na godzine<br />    sprintf(wynik,&quot;%2.1f &quot;, kilometry_na_godzine);<br />    LCD_GoTo(0, 0);<br />    LCD_WriteText(wynik);<br /><br />dawka_LITROW= 600* litry_na_min;//dawka litrów na minute * 600 sekund<br />     dawka_K=15 *kilometry_na_godzine;//kilometry na h *15metrów<br /><br />    dawka_LI_HA=dawka_LITROW /dawka_K;<br /><br />   sprintf(wynik,&quot;%3.u&quot;,dawka_LI_HA );<br />    LCD_GoTo(0,1);<br />    LCD_WriteText(wynik);<br /><br />    wykonaj_pomiar();<br /><br />    }<br />klawisz=Parse_Input();<br />if (klawisz&amp;0b00010000) //lewy<br />{<br />if (!blokada)<br />{<br />    blokada=1;<br />}<br />}<br /><br />if (klawisz&amp;0x08) //lewy<br />{<br />if (!blokada)<br />{<br />    blokada=1;<br />}<br />}<br />else if (klawisz&amp;0x04) //srodkowy<br />{<br />if (!blokada)<br />{<br />    blokada=1;<br />    dawkowanie();<br />LCD_Clear();<br />}<br />}<br />else if (klawisz&amp;0x02) //prawy<br />{<br />if (!blokada)<br />{<br />    blokada=1;<br />}<br /><br />    else if (klawisz&amp;0x01) //lewy<br />    {<br />    if (!blokada)<br />    {<br />blokada=1;<br />    }<br />    }<br />}<br />else blokada=0;<br />if(dawka_LI_HA&lt;dawka_L )    //jerzeli dawka jest mniejsza od 240<br />     {<br />     PORTB=0x02;    //otwieraj zawór<br />     }<br />     else if (dawka_LI_HA&gt;dawka_L)  //jerzeli dowka jest większa<br />     {<br />      PORTB&amp;=~0x02;    //zatrzymaj zawór<br />      PORTB&amp;=~0x04;  //zatrzymaj zawór<br />     }<br /><br />      if  (dawka_LI_HA&gt;dawka_H)  //jerzeli dawka jest większa od 250<br />     {<br />     PORTB=0x04;  //zamykaj zawór<br />     }<br />LCD_GoTo(9,1);<br />LCD_UInt( dawka_L);<br />      LCD_GoTo(10,0);<br />LCD_UInt( dawka_H);<br />}<br /><br />return 0;<br />}[/syntax]<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=18660">ire</a> — 17 mar 2018, o 22:44</p><hr />
]]></content>
</entry>
</feed>