• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Oświetlenie Led PWM
#1
Witam po dłuższej przerwie. Smile

Jestem w trakcie budowy belki oświetleniowej nad akwarium, sterowanej PWM i mam pewien problem. Znalazłem sketch na jednej ze stron i działa. Ale ja mam takie pytanie do Was, mianowicie, jak najprościej zrobić, by wszystkie kroki od 0 do 255 przechodziły płynnie w określonym przez nas czasie? Innymi słowy chce sterować pełnym rozjaśnieniem i ściemnieniem diod regulując czas w jakim ma się całe zdarzenie odbyć. Ewentualnie zmienić krok rozjaśniania z jednej minuty na jedną sekundę, bo teraz długość trwania jednego kroku to minuta.
Poniżej sketch.

Kod:
   #include <DS1307.h>    //użyte biblioteki
   #include <Wire.h>    //użyte biblioteki
   #define DS1307_ADDRESS 0x68    //zegar
   byte zero = 0x00;    //zegar

   //***********************opis wyjść*************************

   int LED1 = 11;    //diody 1
   int GODZ;    //Godzina
   int MIN;    //Minuta
   int SEC;    //Sekundy
   int dzienG = 10;    //początek dnia - godziny
   int dzienM = 00;    //początek dnia - minuty
   int nocG = 21;    //początek nocy - godziny
   int nocM = 00;    //początek nocy - minuty
   int maxD1 = 60;    //maksymalna moc kanału LED1
   int ZMIANA = 60;    //długość trwania rozjaśniania
   int STEP = 1;    //długość trwania jednego kroku

   void setup()
     {
       Wire.begin();
       pinMode(LED1, OUTPUT);    //diody
       Serial.begin(9600);    //serial port
     }

   void loop()
     {
       int CZAS = (GODZ*60+MIN);    //aktualna godzina
       int czas1 = (dzienG*60+dzienM);    //początek dnia
       int czas2 = (nocG*60+nocM);    //początek nocy

       GODZ = (RTC.get(DS1307_HR,true));    //godzina pobierana z RTC
       MIN = (RTC.get(DS1307_MIN,true));    //minuta pobierana z RTC
       SEC = (RTC.get(DS1307_SEC,true));    //sekundy pobierana z RTC

       static int D1;    //stopień rozjaśniania LED1

       int mocD1[61] =    //stopień rozjaśniania LED1
         {
           255,230,220,210,200,195,190,185,180,175,
           170,165,160,155,150,145,140,135,130,125,
           120,115,110,105,100,95,90,85,80,75,
           70,65,60,55,50,45,40,35,30,25,
           20,19,18,17,16,15,14,13,12,11,
           10,9,8,7,6,5,4,3,2,1,0
         };

       if (CZAS<czas1)    //noc
         {
           D1=0; //digitalWrite(LED1, LOW);
           Serial.print("noc ");
         }
       if ((czas1<=CZAS)&&(CZAS<(czas1+ZMIANA)))    //poranek
         {
           D1=((CZAS-czas1)/STEP);
           Serial.print("swit ");
         }
           if (((czas1+ZMIANA)<=CZAS)&&(CZAS<(czas2-ZMIANA)))    //dzień
         {
           D1=maxD1;
           Serial.print("dzien ");
         }
       if(((czas2-ZMIANA)<=CZAS)&&(CZAS<czas2))    //zmrok
         {
           D1=((czas2-CZAS)/STEP);
           Serial.print("zmrok ");
         }
       if(czas2<=CZAS)    //noc
         {
           D1=0; //digitalWrite(LED1, LOW);
           Serial.print("noc ");
         }

      analogWrite(LED1, mocD1[D1]);

   /*************************** serial monitor **************/
       Serial.print("LED:");
       Serial.print((D1*100)/maxD1);
       Serial.print(" ");
       Serial.print(GODZ);
       Serial.print(":");
       Serial.print(MIN);
       Serial.print(":");
       Serial.print(SEC);
       Serial.println(" MN-Tech.pl _1pwm ");
       delay (1000);
     }


Pozdrawiam
 
Odpowiedź
#2
(04-05-2019, 08:28)Lobaf napisał(a): jak najprościej zrobić, by wszystkie kroki od 0 do 255 przechodziły płynnie w określonym przez nas czasie?
Na przerwaniach od timera.
 
Odpowiedź
#3
Ja używam wbudowanej w Arduino funkcji millis() -  tiku systemowego co 1ms, jest na bazie liczby 32bity, więc raz w loop zamieniam sobie na różne flagi oznaczające upływ części sekundy, sekundy, minuty itp. Używając timerów pamiętaj, że powinieneś wiedzieć, które są już użyte, by nie rozwalić tego co już działa. Zabawa z millis() i micros() jest łatwiejsza:
Kod:
uint32_t czasTeraz,czasPoprzedni,tik=10; //tik musi byc mniejszy niz 1000 i dzilic 1000ms na rowne czesci
uint8_t nTik,sekundy,minuty,godziny,dni; //liczniki tikow, sekund, itd.
bool fnTik,fsekundy,fminuty,fgodziny,fdni; //flagi zdarzen nowy tik, nowa sekunda,minuta, godzina, dzien
char napis[10];
void setup() {
 // put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_BUILTIN,OUTPUT);

}

void loop() {
 // put your main code here, to run repeatedly:
czas();


if(fsekundy) {
sprintf(napis,"%03d:%02d:%02d",godziny,minuty,sekundy);
Serial.println(napis);


}

if(fnTik&&! (nTik%20)) digitalWrite(LED_BUILTIN,! digitalRead(LED_BUILTIN));//gdy nowy tik i co 20 tikow
}


void czas()
{
 czasTeraz=millis();
fnTik=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik) //tan napisany warunek jest odporny na "klątwe 50 dni millis()"
{
 czasPoprzedni=czasTeraz;
 fnTik=1;
 nTik++;
 if(nTik>=(1000/tik))
 {
   nTik=0;
   sekundy++;
   fsekundy=1;
    if (sekundy>=60)
   {
     sekundy=0;
     minuty++;
     fminuty=1;
     if (minuty>=60)
     {
       minuty=0;
       godziny++;
       fgodziny=1;
       if (godziny>=24)
       {
         godziny=0;
         fdni=1;
         dni++;
   
       }
     }
   }
 }
}
}
Jeśli wystarcza zmieniać ściemnianie z krokiem 1s można użyć if(fsekundy)...., jeśli co 100ms if (fnTik && (nTik%10==0))... , ostatnie można zapisać też !(nTik%10) - gdy od poprzedniego tyknięcie upłyneło 10ms, to jest nowe i jednocześnie licznik tych tyknięć podzielony przez 10 nie ma reszty (==0). Tak, wiem, że liczba jest max 255 i często będzie coś gubić w tym wypadku, ale oko tego nie zauważy. Do sterowania szwajcarskim zegarkiem w aptece można to zrobić inaczej. Trzeba też pamiętać, że jak są zakamarki w programie, gzie program znacząco dłużej niż nTik znika z loop błąd pomiaru wszystkich liczników będzie mocno odjeżdżał od normalnych sekund i minut. Z drugiej strony funkcję czas() czy każdą inną opartą o millis() uruchomisz na Arduino z AVR, STM, ESP i co tam kiedyś wymyślą i uczynią zgodnym z Arduino IDE.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#4
(04-05-2019, 15:16)kaczakat napisał(a): Używając timerów pamiętaj, że powinieneś wiedzieć, które są już użyte, by nie rozwalić tego co już działa.
Nie spotkałem bibliotek korzystających z przerwań OCR0x wywoływanych co ok (podkreślam ok) 1ms. T0 jest skonfigurowany więc wystarczy zezwolić na przerwania OCR0x, ewentualnie ustawić rejestr OCR0x i obsłużyć wektor tegoż przerwania.
 
Odpowiedź
#5
Panowie, odbiegając od waszej jakże ciekawej dyskusji, pozwolę sobie wrócić do sedna tematu i zapytam inaczej. Który fragment programu odpowiada za to, że kroki są co minutę?
 
Odpowiedź
#6
(05-05-2019, 18:43)Lobaf napisał(a): Panowie, odbiegając od waszej jakże ciekawej dyskusji, pozwolę sobie wrócić do sedna tematu i zapytam inaczej. Który fragment programu odpowiada za to, że kroki są co minutę?
Pisz do mnie na es2@ep.com.pl. Z pomocy na forach wyliczyłem się.
 
Odpowiedź
#7
Lobaf, jeśli pytasz o mój przykładowy szkic to if(fminuty). Wystąpienie zdarzenia obwieszczają flagi:
bool fnTik,fsekundy,fminuty,fgodziny,fdni; //flagi zdarzen nowy tik, nowa sekunda,minuta, godzina, dzień.
Funkcja czas() ustawia na początku wszędzie w nich zera, a potem 1 tam gdy zdarzenie wystąpi. Potem do końca pętli loop możesz zrobić if(fminuty) i w tym obiegu pętli gdy wybije nowa minuta ten warunek się spełni.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości