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

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2015-04-12T16:01:44+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=4&amp;t=11357&amp;mode</id>
<entry>
<author><name><![CDATA[faber33]]></name></author>
<updated>2015-04-12T16:01:44+01:00</updated>
<published>2015-04-12T16:01:44+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=11357&amp;p=126280#p126280</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=11357&amp;p=126280#p126280"/>
<title type="html"><![CDATA[Re: Regulator PID AVR221 - regulacja temperatury]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=11357&amp;p=126280#p126280"><![CDATA[
Jeden błąd znalazłem. Mianowicie Get_Measurement powinna zwracać wartość ADC_czujnik. Ale to dużo nie zmienia. Nadal wygląda na to że problem jest w tej konwersji Set_Input :/<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=976">faber33</a> — 12 kwi 2015, o 16:01</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[faber33]]></name></author>
<updated>2015-04-12T12:59:48+01:00</updated>
<published>2015-04-12T12:59:48+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=11357&amp;p=126264#p126264</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=11357&amp;p=126264#p126264"/>
<title type="html"><![CDATA[Regulator PID AVR221 - regulacja temperatury]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=11357&amp;p=126264#p126264"><![CDATA[
Witam. Próbuje okiełznać regulator PID ze strony atmela AVR221:<br /><!-- m --><a class="postlink" href="http://www.atmel.com/Images/doc2558.pdf" >http://www.atmel.com/Images/doc2558.pdf</a><!-- m --><br /><br /><br />Testy przeprowadzam obecne na żarówce żeby łatwiej było określić czy działa ten regulator.<br /><br />Niestety mam problem z wartościami inputValue. Wyświetlam sobie wartość temperatury z czujnika, zwartość zadaną oraz właśnie wartość inputValue.<br /><br />Na początku po włączeniu zasilania układu gdy wartość nastawy równa się 0 to inputValue (żarówka jest wyłączona) pokazuje się -30 ( i co ciekawe gdy podgrzewam czujnik wartość inputValue taka sama jak wartość temperatury w Celsjuszach tylko że ze znakiem &quot;-&quot;).<br /><br />I teraz jest dziwna zależność, gdy ustawie wartość zadaną powyżej 30 stopni to wartość inputValue skacze do 255 i nic się nie zmienia wraz ze wzrostem temperatury. A co ciekawe powyżej nastawy 110 stopni wartość InputValue zaczyna maleć (żarówka świeci słabiej) i przy nastawie 175 stopni InputValue przeskakuje na -255 :/ . Przy nastawie 185 stopni żarówka miga na przemian pełną mocą, a przy 190 wartość InputValue powoli spada a następnie rośnie.<br /><br /><br />W czym jest problem źle podaje wartości zwracane przez funkcje <strong>Get_Reference</strong> i <strong>Get_Measurement</strong> ??? <img src="https://forum.atnel.pl/images/smilies/icon_cry.gif" alt=":cry:" title="Płacze" />  <br /><br /><br />Nie mam już pomysłu w czym może być problem poza tym InputValue jest typu int16_t więc powinna się zmieniać w zakresie -32768 do +32767 a zmienia się od -255 do 255  <br /><br /><br /><br />Czujnik temperatury w moim przypadku mierzy od 30 stopni w górę więc ograniczyłem wartość zwracaną przez funkcję <strong>Get_Reference</strong> w taki sposób:<br /><br />[syntax=c]int16_t Get_Reference(void)<br />{<br />  int16_t l;<br />  if(zmienna2&lt;30) l=0;<br />  if(zmienna2&gt;=30)  l=ADCTable&#91;(zmienna2/5)&#93;;<br /><br />  return l;<br /><br />}[/syntax]<br /><br />Natomiast funkcja <strong>Get_Measurement</strong> zwraca temperaturę w stopniach Celsjusza.<br /><br />[syntax=c]int16_t Get_Measurement(void)<br />{<br />  return t;<br />}[/syntax]<br /><br />Funkcja  <strong>Set_Input</strong> sterująca triakiem przeskalowuje wartości z <strong>inputValue</strong> na zakres od <strong>0 do 200</strong> wygląda następująco:<br /><br />[syntax=c]void Set_Input(int16_t inputValue)<br />{<br />  pwm_value = inputValue;   // Skalowanie wyniku -<br />  if(pwm_value &gt;= 200)<br />  pwm_value = 200;<br /><br /><br />  if(pwm_value &lt; 0)<br />  pwm_value = 0;<br /><br />  kanal1=pwm_value;<br /><br />}[/syntax]<br /><br /><br /><br />Cały kod main.c:<br />[syntax=c]//F_CPU 8MHz<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 />#include &quot;LCD/lcd44780.h&quot;<br />#include &quot;PID/pid.h&quot;<br /><br />int ADC_czujnik=0;<br />int ADC_pomiar=0;<br />uint16_t pomiar(uint8_t kanal);<br />uint16_t adc_kx&#91;3&#93; PROGMEM = {245,488,1023};<br /><br />uint8_t keys&#91;3&#93;;<br />int zmienna=0,zmienna1=0,zmienna2=0,zmienna3=0;<br />int16_t pwm_value;<br /><br />#define REF_256 (1&lt;&lt;REFS1)|(1&lt;&lt;REFS0)<br /><br />int16_t t;<br />uint32_t srednia1 = 0;<br /><br />uint8_t k=0;<br />uint8_t sw_on;<br />uint8_t menu_element = 0;<br /><br />int16_t referenceValue, measurementValue, inputValue;<br /><br />#define ADC_RANGE 50 // zakres &quot;skakania&quot; napięcia<br /><br />volatile uint16_t Timer1,Timer2;<br /><br />uint8_t sw_on;<br /><br /><br />//Constants for conversion<br />#define TablePoints   (35)<br />//Conversion to şCelsius<br />#define ToCels      (30)<br />#define dTCels       (5)<br /><br />//Prototipes for public functions<br />int TempNTC(unsigned int adc, int To, int dT);<br /><br />//** NTC Linealization table<br />const unsigned int ADCTable&#91;TablePoints&#93;=<br />{<br />    1017, 998, 977, 952, 924, 894, 860, 824,<br />    786, 746, 705, 663, 621, 579, 538, 498,<br />    460, 423, 388, 355, 325, 297, 271, 247,<br />    225, 205, 187, 170, 155, 141, 129, 118,<br />    108, 99, 90<br />};<br /><br /><br />//***************************************************************************<br />//*  Function TempNTC<br />//*  Returns temperature value converted by means of interpolation<br />//*  ADC is the ADC result<br />//*  To is temperature blealue for index 0 from the table (-30şC)<br />//*  dT is temperature difference between two entries in the tabel (10şC)<br />//***************************************************************************<br />int TempNTC(unsigned int adc, int To, int dT)<br />{<br />  int aux;<br />  unsigned int min, max;<br />  unsigned char i;<br /><br />  //Search the interval where adc value fits<br />  for(i=0;(i&lt;TablePoints)&amp;&amp;(adc&lt;(ADCTable&#91;i&#93;)); i++);<br />  if ((i==0)) //If we don't find it, return error<br />    return ToCels;<br />  max=ADCTable&#91;i-1&#93;; //Took the highest value of the interval<br />  min=ADCTable&#91;i&#93;;   //and the smallest<br />  aux=(max-adc)*dT;  //first step of the interpolation<br />  aux=aux/(max-min); //and second step<br />  aux+=(i-1)*dT+To;  //and we add the offset<br />  return aux;<br />}<br />//************************ The End *******************************************<br /><br /><br />/*********************** D I M M E R  -   U S T A W I E N I A   ***************************/<br />  #define LICZBA_KROKOW 200<br /><br />  // czas trwania szpilki (Detekcja ZERA) wyrażony w milisekundach np: 1,2,... albo np: 0.5<br />  #define SZPILKA_MS 1.6<br />  /*********************** D I M M E R  -   U S T A W I E N I A   ***************************/<br /><br />  #define __OCR_STEP ((F_CPU/8)*((1000-((SZPILKA_MS*100)/2))/LICZBA_KROKOW))/100000<br /><br /><br />  static uint8_t procent(uint8_t pr) {<br />          return (pr * (LICZBA_KROKOW-1))/100;<br />  }<br /><br />  #define TRIAK_ON PORTD |= (1&lt;&lt;PD1)<br />  #define TRIAK_OFF PORTD &amp;= ~(1&lt;&lt;PD1)<br /><br />  #define TIMER2_START TCCR2 |= (1&lt;&lt;CS21) // prescaler=8<br />  #define TIMER2_STOP TCCR2 &amp;= ~(1&lt;&lt;CS21) // prescaler off<br /><br />  volatile uint8_t kroki;<br />  volatile uint8_t kanal1;<br />  volatile uint8_t ika1;<br />  //************************ The End *******************************************<br /><br /><br /><br /><br />  /*********************** REGULATOR PID   ***************************/<br />#define K_P     1.00<br />#define K_I     0.00<br />#define K_D     0.00<br /><br />struct GLOBAL_FLAGS {<br />  //! True when PID control loop should run one time<br />  uint8_t pidTimer:1;<br />  uint8_t dummy:7;<br />} gFlags = {0, 0};<br /><br />//! Parameters for regulator<br />struct PID_DATA pidData;<br /><br />#define TIME_INTERVAL   157<br /><br />void Init(void)<br />{<br />  pid_Init(K_P * SCALING_FACTOR, K_I * SCALING_FACTOR , K_D * SCALING_FACTOR , &amp;pidData);<br /><br />}<br /><br />int16_t Get_Reference(void)<br />{<br />  int16_t l;<br />  if(zmienna2&lt;30) l=0;<br />  if(zmienna2&gt;=30)  l=ADCTable&#91;(zmienna2/5)&#93;;<br /><br />  return l;<br /><br />}<br /><br />int16_t Get_Measurement(void)<br />{<br />  return t;<br />}<br /><br />void Set_Input(int16_t inputValue)<br />{<br />  pwm_value = inputValue;   // Skalowanie wyniku -<br />  if(pwm_value &gt;= 200)<br />  pwm_value = 200;<br /><br /><br />  if(pwm_value &lt; 0)<br />  pwm_value = 0;<br /><br />  kanal1=pwm_value;<br /><br />}<br />//************************ The End *******************************************<br /><br /><br /><br /><br />int main(void)<br />{<br />    uint32_t srednia = 0;<br />    uint8_t dt = 10;<br />    int wzr;<br /><br />  Init(); //inicjalizacja regulatora PID<br /><br />// Ustawienie pinów sterującego triak jako wyjście<br />    DDRD |= (1&lt;&lt;PD1);<br /><br />// Przerwanie INT0 służące do wykrywania przejścia przez Zero sieci<br />MCUCR |= (1&lt;&lt;ISC01)|(1&lt;&lt;ISC00);// zbocze narastające<br />GICR |= (1&lt;&lt;INT0);// odblokowanie INT0<br /><br /><br />// TIMER0 - konfiguracja timera do programowych timerów<br />TCCR0 |= (1&lt;&lt;CS02); //prescaler = 1024<br />TIMSK |= (1&lt;&lt;TOIE0); // zezwolenie na przerwanie OVF<br />TCNT0 = 195; // częstotliwość przerwania 100 Hz<br /><br /><br />//TIMER1 - konfiguracja timera do PID - tryb CTC<br />TCCR1B |= (1&lt;&lt;WGM12)|(1&lt;&lt;CS11) |(1&lt;&lt;CS10);  //Tryb CTC i preskaler 64<br />TIMSK |= (1&lt;&lt;OCIE1A);  // zezwolenie na przerwanie COMPARE MATCH<br />    OCR1A = 124;<br /><br /><br />// TIMER2 - konfiguracja timera do programowych timerów<br />TCCR2 |= (1&lt;&lt;WGM21);// tryb CTC<br />TIMSK |= (1&lt;&lt;OCIE2);// odblokowanie przerwania COMPARE MATCH<br />OCR2 = __OCR_STEP;<br /><br /><br />// inicjalizacja przetwornika ADC<br />ADCSRA |= (1&lt;&lt;ADEN); // włącz ADC<br />ADCSRA |= (1&lt;&lt;ADPS2)|(1&lt;&lt;ADPS1)|(1&lt;&lt;ADPS0); // preskaler<br />ADMUX |= REF_256;// ustawiamy wewn. źr odn. 2,56V<br /><br /><br /> //=====  LCD  ======================<br /> _delay_ms(50);  //opóźnienie wymagane przez niektóre wyświetlacze.<br /> lcd_init(); //inicjalizuj LCD<br /><br /> //Napis startowy<br /> lcd_locate(0,0);<br />          lcd_str(&quot;Sterwonik&quot;);<br /> lcd_locate(1,0);<br />          lcd_str(&quot;v 1.0&quot;);<br /><br /> _delay_ms(2000);<br /><br /> lcd_cls();<br /><br /><br />TRIAK_OFF;<br /><br />sei(); //włącz przerwania globalne<br /><br /> while(1){ //pętla główna<br /><br /> //pomiar ADC klawiatura<br />ADC_pomiar = pomiar(7);<br /><br />//pomiar ADC termistor<br />ADC_czujnik = pomiar(PC1);<br /><br />        srednia = srednia * dt;<br />        srednia = srednia + ADC_czujnik * 10;<br />        srednia = (srednia+dt) / (dt+1);<br />        srednia1=srednia/10;<br /><br /><br /> // Przeliczanie ADC na temperature w stopniach<br /> t = TempNTC(srednia1,ToCels,dTCels);<br /><br />// Run PID calculations once every PID timer timeout<br />    if(gFlags.pidTimer)<br />    {<br />      referenceValue = Get_Reference();<br />      measurementValue = Get_Measurement();<br /><br />      inputValue = pid_Controller(referenceValue, measurementValue, &amp;pidData);<br /><br />      Set_Input(inputValue);<br /><br />      gFlags.pidTimer = FALSE;<br />    }<br /><br /><br />     lcd_locate(0,0);<br />     lcd_str(&quot;Temp:&quot;);<br />     lcd_locate(0,10);<br />     lcd_int(t);<br />     lcd_locate(1,0);<br />     lcd_int(ADC_pomiar);<br />     lcd_str(&quot;  &quot;);<br />    lcd_locate(1,4);<br />lcd_int(zmienna2);<br />lcd_str(&quot;  &quot;);<br />    lcd_locate(1,10);<br />lcd_int(inputValue);<br />lcd_str(&quot;  &quot;);<br /><br /><br /> if( keys&#91;0&#93;==29 &amp;&amp; zmienna2&lt;190) {<br />    zmienna2+=5;<br /> }<br /><br />if( keys&#91;1&#93;==29 &amp;&amp; zmienna2&gt;0) {<br />    zmienna2-=5;<br />}<br /><br /><br /><br />    uint8_t i;<br />    for(i=0;i&lt;3;i++){<br />    wzr = pgm_read_word (&amp;adc_kx&#91;i&#93;);<br />    if((ADC_pomiar &gt; wzr-ADC_RANGE) &amp;&amp; (ADC_pomiar &lt; wzr+ADC_RANGE)){<br />     if( keys&#91;i&#93;&lt;30) keys&#91;i&#93;++;<br />     } else keys&#91;i&#93;=0;<br />    }<br /> }<br />}<br /><br />uint16_t pomiar(uint8_t kanal){<br /><br />ADMUX = (ADMUX &amp; 0b11111000) | kanal;<br /><br />ADCSRA |= (1&lt;&lt;ADSC); //start pomiaru<br /><br />while( ADCSRA &amp; (1&lt;&lt;ADSC) );<br /><br />return ADCW;<br />}<br /><br /><br />ISR(TIMER0_OVF_vect){<br />zmienna++;<br />uint16_t x;<br />x=Timer1;<br />if(x) Timer1 = --x; //częstotliwość 100Hz<br />x=Timer2;<br />if(x) Timer2 = --x; //częstotliwość 100Hz<br /><br />}<br /><br /><br />//Przejście napięcia sieci przez zero<br />ISR(INT0_vect) {<br />        TIMER2_STOP;<br />        TRIAK_OFF;<br /><br />        kroki=LICZBA_KROKOW;<br /><br />        /* podwójne buforowanie, synchronizacja do 50Hz */<br />        ika1=kanal1;<br /><br />        TCNT2 = 0;<br />        TIMER2_START;<br />}<br /><br /><br />ISR(TIMER2_COMP_vect) {<br />        if(ika1 &amp;&amp; kroki == ika1) TRIAK_ON;<br />        kroki--;<br />}<br /><br /><br />ISR(TIMER1_COMPA_vect) {<br />static uint16_t i = 0;<br />if(i &lt; TIME_INTERVAL)<br />  i++;<br />else{<br />  gFlags.pidTimer = TRUE;<br />  i = 0;<br />}<br />}[/syntax]<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=976">faber33</a> — 12 kwi 2015, o 12:59</p><hr />
]]></content>
</entry>
</feed>