ATmega, jak zaprogramować narastanie wartości sygn

Witam,

Używam mikrokontrolera ATmega128. W moim programie użytkownik ustawia wartość prądu (liczba całkowita od 0 do 1000) oraz czas (od 1 do 40 sekund). Prąd ma narosnąć od 0 do wartości ustawionej w ustawionym czasie. Funkcja służąca do obliczania aktualnej wartości prądu podczas jego narastania jest wywoływana z pewną częstotliwością (od 10 do 60Hz, zależnie od ustawienia w parametrach programu). Zatem narastanie prądu odbywa się w liczbie kroków wyrażonej wzorem: K = czas[s] * częstotliwość[Hz]. Żeby uniknąć obliczeń zmiennoprzecinkowych, zastosowałem algorytm Bresenhama do kreślenia odcinków. Zapowiada się, że będzie to działać bardzo szybko, gdy K >= wartość prądu. Gdy K < wartość prądu, to algorytm Bresenhama normalnie kreśli odcinek w pętli "idąc po zmiennej Y". Tymczasem ja działam w osi odciętych, czyli X (u mnie jest to liczba kroków, w których prąd ma narosnąć). Bez większych problemów przerobiłem ten algorytm tak, aby dla K < wartość prądu, "szedł on po zmiennej X". Przy czym po tej przeróbce uzyskałem podpętlę (while), która niekiedy będzie wykonywać się wiele razy (dla pojedynczego kroku w osi X), co spowolni algorytm. Inną metodą, zamiast tej podpętli, byłoby zastosowanie dzielenia, co też nie jest rozwiązaniem, gdyż dzielenie realizowane jest przez kompilator także w pętli. Poniżej przedstawiłem algorytm, który stosuję -- na razie to jest wersja kreśląca grafikę (tak łatwiej mi obserwować działanie tego algorytmu), a nie funkcja wywoływana z pewną częstotliwością i sterująca prądem. Algorytm działa prawidłowo. Przy czym może działać niekiedy wolno (pętla while może wykonywać się wiele razy) dla K < wartość prądu -- no i to jest mój problem. Mam pytanie do Was, jak przyspieszyć ten algorytm? A jeśli się nie da, to byłbym wdzięczny za naprowadzenie na jakiś inny sposób zaprogramowania opisanego problemu (narastania wartości w pewnej liczbie kroków).

Ilustracja graficzna działania poniżej zaprezentowanego algorytmu:

formatting link
K = czas * czestotliwosc;

if (K >= wartoscPradu) { for (t = 0; t <= K; t++) { drawPixel(px, py); y += wartoscPradu + 1; if (y >= K + 1) y -= K + 1, py++; px++; } } else { for (t = 0; t <= K; t++) { while (1) { x += K + 1; if (x >= wartoscPradu + 1) { drawPixel(px, py); x -= wartoscPradu + 1, px++; py++; break; } py++; } } }

Pozdrawiam i z góry dziękuję za pomoc, Robbo

Reply to
Robbo
Loading thread data ...

cyt:

"Algorytm może działać zarówno na liczbach zmiennoprzecinkowych jak i całkowitych, ale ze względów wydajnościowych wykorzystuje się najczęściej realizacje całkowitoliczbowe. Zatem jeżeli początkowa wartość zmiennej decyzyjnej d lub jej przyrosty wychodzą nam ułamkowe, to mnożymy zarówno zmienną decyzyjną d jak i jej przyrosty tak by uzyskać liczby całkowite. Możemy tak zrobić gdyż do decyzji bierzemy pod uwagę jedynie znak zmiennej decyzyjnej d."

źródło:

formatting link

Reply to
Dondu

Albo czegoś nie zrozumiałem, albo to jest zwykła proporcja: I(s)=I(S0)+(I(Se)-I(S0))*((s-S0)/(Se-S0)) I(s)=I(S0)+(I(Se)-I(S0))/(Se-S0) * (s-S0) gdzie s - czas, S0 - czas początkowy, Se - czas końcowy

Przekształcasz to sobie na: I(t)=I(T0)+t*dI I(t)=I(t-1)+dI

Raz wyliczasz iloraz różnicowy dI, potem masz w każdym cyklu jedno dodawanie i jeden shift.

Reply to
Michoo

Użytkownik "Robbo" snipped-for-privacy@gmail.com napisał w wiadomości news:5073652e$0$26682$ snipped-for-privacy@news.neostrada.pl...

Jestem lepszy w EMC niż algorytmach ale zaproponuję to, co mi się nasunęło.

Może w przypadku K<I podzielić I/n (n=2,4,8,...) aż będzie K>I, a potem pętla już jak dla przypadku K>I, tylko py++ zastąpić py+=n. "Schodki" wyjdą większe niż z twojej części else, ale jeśli dzielenie przed pętlą nie byłoby problemem to może być n=2,3,4,5,.... i wtedy to chyba już wyjdzie prawie to samo. P.G.

Reply to
Piotr Gałka

Użytkownik "Piotr Gałka" snipped-for-privacy@CUTTHISmicromade.pl napisał w wiadomości news:5073db09$ snipped-for-privacy@news.home.net.pl...

Poprawka. Jednak nie prawie to samo bo będą stałe przyrosty a czasem brak przyrostu. Przyrosty zmienne są jednak bliższe ideału. P.G.

Reply to
Piotr Gałka

Witam,

Dziękuję za odpowiedź, która mam nadzieję naprowadzi mnie na właściwe tory.

Tak. Prąd ma przyrastać w K krokach o wartość maxPrąd/K w każdym kroku.

Czas będzie zawsze liczony od zera. Prąd początkowy także będzie narastać od zera. Więc jeśli I(S0) = 0, S0 = 0. Zatem powyższe formuły można uprościć do: I(s) = I(Se) * (s/Se) I(s) = I(Se)/Se*s

Tu bym prosił o wyjaśnienie. Mało spałem i chyba nie do końca myślę, dlatego proszę o wybaczenie.

Czy dI będzie wartością zmiennoprzecinkową? W jaki sposób będzie użyty shift?

Czy chodzi o to, że przy wyliczaniu dI robimy shift w lewo, aby nie tracić precyzji, a działać na liczbach całkowitych. Potem działamy na dużych wartościach dI, a tuż przed użyciem wartości I robimy shift w prawo?

Robbo

Reply to
Robbo

Dokładnie. Ale tak długo jak zmiany są liniowe to wystarcza raz policzyć iloraz różnicowy.

Stałoprzecinkową, np. o 16 bitach części całkowitej i 16 po przecinku:

uint16_t I=0; uint32_t I_accu=0; uint32_t dI; time_t last_time=0;

void new_setting(/**/){ dI=(I_target<<16)/time_slices; } void calc(time_t t){ I_accu+=dI*(t-last_time); I=I_accu>>16; last_time=t; }

Reply to
Michoo

Serdeczne Bóg zapłać. Wszystko ładnie działa.

Robbo

Reply to
Robbo

Użytkownik Robbo napisał:

Jakie bóg zapłać? Chłopaki piwa by się napili ;)

Reply to
AlexY

Nie ma problemu. Chętnie wyślę pocztą dobre piwo z małego browaru, a nie sikacz z koncernu.

R.

Reply to
Robbo

Łączę zainteresowanie elektroniką i piwem:

formatting link

Reply to
Michoo

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.