logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Atmega88][Bascom] Sekwencja impulsów na 4 pinach równolegle

Marcinkowski125 02 Cze 2009 00:17 2022 12
REKLAMA
  • #1 6605508
    Marcinkowski125
    Poziom 2  
    Witam się miło z całym gronem...

    Szukałem odpowiedzi tu na forum, ale nie potrafiłem znaleźć potrzebnych mi informacji. Więc pozwolę sobie zadać znawcą pytań kilka. Ale zacznę od pierwszego i najważniejszego.

    Mianowicie mam do zrealizowania następujące zadanie...
    Potrzebuję wygenerować na czterech końcówkach portu tego procesora sekwencję impulsów o stałym czasie trwania poziomu wysokiego i zmiennej przerwie między nimi i to w dość szerokim zakresie.
    Impuls mam trwać 2ms. Natomiast przerwy między impulsami to od 10ms do 3sek. Oczywiście sekwencja ma być wcześniej zdefiniowana i odtwarzana w pętli przez ustalony czas.
    Oczywiście dla każdego wyprowadzenia mam mieć różną sekwencję i ma się to odbywać równolegle.

    Z tego co wymyśliłem to program będzie wyglądał w ten sposób:
    W pętli będzie się zwiększał licznik co 1ms (komenda waitms 1 na końcu pętli wystarczy tu w zupełności, gdyż większa stabilność i dokładność nie jest wymagana) dla każdego kanału i gdy osiągnie określoną wartość włączy daną końcówkę na 2ms, czyli tu znowu zliczy do 2 (2x1ms) i ponownie wyłączy daną końcówkę licząc czas.

    ...i to mam napisane i działa bez problemu. Owa komenda na końcu pętli waitms1 daje mi 1ms dokładność, a zarazem nie wpływa mi znacząco na opóźnienie działaniu programu.

    Teraz jest pytanie zasadnicze...
    Jak przechować i odczytać sekwencję owych przerw dla impulsów?
    W przypadku przerwy 3sek muszę zliczyć aż 3.000ms, więc muszę tu użyć zmiennej Integer. A dla przerw rzędu 10ms znowu tych wartości muszę mieć dość znaczną ilość dla całej sekwencji trwającej kilkanaście sekund.
    Nie za bardzo wiem jak zapisać i przechowywać taką sekwencję danych i tu proszę kolegów o pomoc.
    Jakąś ideę i podpowiedź. A może jakieś konkretne rozwiązanie?
    Choć oczywiście z samego naprowadzenia na rozwiązanie będę bardzo kontent :)

    A może źle podchodzę do całej idei i ktoś ma inna koncepcję umieszczenia sekwencji równoległych impulsów na 4 wyprowadzeniach o zmiennej przerwie i stałym czasie trwania (w zadanych granicach impuls 2ms przerwy od 10ms do 3sek)?

    Pozdrawiam
    Marcin
  • REKLAMA
  • #2 6605554
    dawid512
    Poziom 32  
    Możesz użyć timera aby odliczyć sobie konkretny odcinek czasu.
  • #3 6605564
    rpal
    Poziom 27  
    Jeśli chcesz kolego miec super dokładnoś bo tej niestety komenda wait tobie nie zagwarantuje to może użyj baterii układów np. 74193 są to programowalne liczniki binarne. Połączone w szereg mogą dać tobie zadowalającą wartość np. 32 albo 64 bitową. Taktowane impulsem np. o szerokość 1us po zaprogramowaniu wygenerują impuls przeniesienia albo pożyczki (zależy w którą strone będzie liczyć) i w ten sposób zasygnalizują odliczenie czasu. Niestety wewnętrzny licznik ma najwięcej 16 bitów wię nie zapewni tak szerokich wartośći do zliczania co byłoby najproszym rozwiązaniem.
  • REKLAMA
  • #4 6605638
    Marcinkowski125
    Poziom 2  
    Witam :)

    Dzięki za kolejne koncepcje.
    Ale nie uśmiecha mi się dokładać kolejne kostki liczników, tym bardziej jak ma ich być "bateria". Zależy mi raczej na małych gabarytach układu.
    Liczniki też wolał bym zarezerwować dla innych celów - choć by odliczania czasu całej sekwencji i PWM,u


    Jak pisałem powyżej komenda Waitms wystarcza tu w zupełności gdyż na super dokładności czasu impulsu mi nie zależy, zresztą czas przerw też może mieć dokładność jaką owa komenda dostarcza.
    Sam algorytm mojej koncepcji odmierzania czasu impulsu, jak i odmierzana czasu przerw działa.
    obrazowo tak to wygląda:
    <zwiększ licznik>
    <porównaj z wartością danego kanału>
    <leżeli się równa, to na 2ms ustaw stan wysoki na danej koncówce - 2x1ms>
    <z zeruj licznik danego kanału>
    <na końcu całej pętli odczekaj 1ms>

    Głównie chodzi mi o sposób zapisu, przechowywania i późniejszego odczytu wartości zmiennych przerw między tymi 2ms impulsami dla 4 kanałów.

    Sekwencja to coś w rodzaju: _I_I______I___I_______I_I___I______I___

    "I" to impuls 2ms,
    "_" to wielokrotność 1ms (od 10 do 3000) dla przerwy między impulsami
    i o zapis sekwencji "_" mi chodzi.
    Jak te dane przechowywać??

    Nie mniej dziękuję za zainteresowanie i przedstawienie swoich pomysłów.

    Na tych programowych zależy mi najbardziej...

    Pozdrawiam
    ...
  • #5 6606171
    danthe
    Poziom 30  
    Jak długa ma być ta sekwencja? Mam na myśli ilość tych elementów "_____" czyli przerw.

    Osobiście proponował bym użycie przerwania z licznika timer0,

    CONFIG TIMER0 = TIMER , PRESCALE = 64

    LOAD TIMER0, 125 (także przed wyjściem zobsługi przerwania)

    To da przepełnienie licznika timer0 co 1ms przy zegarze 8Mhz.

    Do zapamiętania sekwencji można użyć zmiennej tablicowej:

    DIM Sekwencja1 (10) AS ERAM Word

    Spowoduje że będziesz mógł używać zmiennej "sekwencja1" z parametrem od 1 do 10, zapamiętanej w pamięci eeprom.
  • REKLAMA
  • #6 6606529
    Marcinkowski125
    Poziom 2  
    Witam.

    Sekwencja to kilkanaście sekund, odtwarzana w kilkuminutowej pętli.

    Proponowane wykorzystanie timera daje jedynie odmierzanie owych 1ms impulsów dla liczników i zapewni jedynie większą dokładność pomiaru niż waitms. Z tym nie ma problemu. Komenda ta zapewnia mi to czego potrzebuję i z tym nie mam problemu.

    Wykorzystanie tablicy to pomysł wart uwagi.
    Musiał bym stworzyć X-elementową tablicę ze zdefiniowanymi wartościami przerw, sekwencyjnie odczytywać jej wartości i porównywać z wartością licznika danego kanału (takich elementów tablicy musi być dość sporo aby zapewniała spory zakres przerw od 10 do 3000ms).
    Ale dalej pozostaje pytanie jak zapisać sekwencję odczytu takiej tablicy?
    Raz trzeba będzie oczytać X pozycję z tablicy z wartością przerwy 10ms, raz 120ms, raz znowu 2000ms...
    To niestety niesie za sobą pytanie czy jest sens robić tablicę ze zdefiniowanymi wartościami i jakoś (jak?) zapisać sekwencję odczytu wartości z tej tablicy. Czy od razu robić zapis sekwencji przerw...

    Muszę mieć zdefiniowane coś, gdzieś w stylu 100 20 20 2000 10 10 10 10 1000ms.... itd. itd. I odczytywać po kolei te wartości... - i nie wiem jak można zrealizować taki sekwencyjny zapis i odczyt sporej ilości danych...

    - odczytam pierwszą wartość,
    - odczekam tyle ms ile wynosi odczytana wartość (czyli tyle pętli 1ms),
    - ustawię 2ms impuls na danej końcówce portu (czyli kolejne 2 1ms pętle)...
    - ponownie muszę odczytać kolejną wartość z szeregu itd...

    Pozdrawiam
    ...
  • #7 6608329
    janbernat
    Poziom 38  
    "Liczniki też wolał bym zarezerwować dla innych celów - choć by odliczania czasu całej sekwencji i PWM,u"
    To może zrobić to tak:
    Jedna pętla do...loop-a w niej cztery+1(dla 1ms) liczniki programowe-
    nie jest to eleganckie bo trzeba cierpliwie obliczać czas pętli i kłopotliwa modyfikacja-ale realizowalne.
    Zwłaszcza jak chcesz zachować liczniki dla PWM.
  • #8 6608524
    piotr5000
    Poziom 21  
    Jeśli bez timerów to
    zadeklaruj 4 zmienne typu long ( dla odliczania dużych wartości - to będą czasy przerw )
    i 4 zmienne typu byte (czas impulsu)
    zerujesz zmienne przed pętlą .

    W pętli incrementujesz kolejno te cztery zmienne.
    sprawdzasz komendą if czy kazda z nich osiągneła założoną wartośc (czas przerwy) .
    Jeżeli tak to : zerujesz zmienną , incrementujesz zmiennna (czas impulsu) dla tej zmiennej , po odliczeniu 2 impulsów , zerujesz (czas przerwy i zazwalasz na zwiększanie ( czasu przerwy ) dla tej zmiennej .

    musisz wprowadzić dodatkowe warunki którą zmienną liczy i kiedy .

    dajesz waitms 1

    koniec pętli .

    dla poprawienia dokładności możesz zastosować zmienną waittus ( czas w mikrosekundach ) i np 980 co pozwoli zwiększyć dokładnośc ( 20 mikrosekund na wykonanie pętli i sprawdzenie warunków - musisz ustalić doświadczalnie

    jest to tylko ogólny zarys programu bez timerów
  • REKLAMA
  • #9 6608672
    Marcinkowski125
    Poziom 2  
    piotr5000 - Mniej więcej w tej sposób mam zrealizowane pętle w swoim programie. I to działa jak trzeba.
    Z tym nie mam problemu.
    Jedyne czego nie mam i pytanie od początku tego dotyczy to jak zapisać wartości dal tych przerw??
    Tego nie wiem jak taśmowo je zapisać i odczytywać po kolei.
    Dla kilku wartości nie mam problemu. Deklaruję tablicę z 10, czy 20 wartościami i odczytuję je po kolei.
    Ale jak impulsy wypadają co 10ms i tak przez sekundę dwie, lub więcej, to już muszę mieć ich 100 na każdą sekundę...
    Tej części programu nie potrafię zrealizować.
    Sam algorytm odmierzania impulsu i przerw mam, nie mam tylko zapisu i odczyty wartości tych przerw...

    Algorytm wygląda tak:
    
    Do
    If Zezwolenie = 1 Then    ' jezeli jeden 1 to impuls
       PortC.1 = 1    ' wlacz koncowke
       If X = 2 Then    ' odlicz dwie petle
          X = 0    ' zeruj licznik 1ms odczinkow czasu
          Zezwolenie = 0    ' przelacz zezwolenie na przerwe
          PortC.1 = 0    ' wylacz koncowke
       End If
    End If
    
    If Zezwolenie = 0 Then   ' jezeli 0 to licz czas przerwy
          If X = Y Then    ' pomijaj petle dopuki licznik nie zrowna sie z zapisanym czasem przerwy
          X = 0    ' zeruj licznik 1ms sekund
          Zezwolenie = 1    ' przelacz zezwolenie na impuls
       End If
    End If
    
    Waitms 1    ' odczekaj na koncu 1ms
    Incr X1    ' zwieksz licznik (ile w liczniku tyle msekund)
    
    Loop
    


    Teraz brak mi jedynie sekwencyjnego podstawiania wartości Y
    Oczywiście tu tylko jedna pętla. Mam ich cztery. Czyli muszę mieć zapis: Y1, Y2, Y3, Y4....

    Pozdrawiam
  • #10 6608773
    janbernat
    Poziom 38  
    piotr5000:
    jak: "dajesz waitms 1"-czy jakikolwiek inny wait- to program wchodzi w "pustą" pętlę.
  • #11 6609401
    danthe
    Poziom 30  
    Jeżeli przerwy mają wynosić max 3 sek. to zmienna typu word jest wystarczająca. Zmienna tablicowa jest chyba najbardziej odpowiednia, np. tak:


    t 1 = t1 - 1 lub decr t1
    t2 = ....
    .
    t4 = t4-1
    .
    .
    .
    .
    if t 1 = 0 then portx.x = 1
    waitms 2
    port x.x = 0
    index1 = index1 + 1
    t = sekwencja1 (index1)
    endif

    if t 2 = 0 then portx.x = 1
    waitms 2
    port x.x = 0
    index2 = index2 + 1
    t = sekwencja2 (index2)
    endif

    ....

    loop

    Oczywiście trzeba dodać instrukcje sprawdzające czy zmienne "index" nie wychodzą poza zadeklarowane wymiary tablic.
    Jedynym mankamentem będzie wydłużanie się pozostałych przerw o 2 ms co każdy generowany impuls. Ale jak kolega zaznaczył duża dokładność nie jest konieczna ?

    Oczywiście można też zamiast waitms 2 użyć zmiennych "zezwolenie" tak jak na przykładzie powyżej, no i uważam że jednak na przerwaniu było by bardziej "elegancko"
  • #12 6609449
    pini0
    Poziom 14  
    Do
    If pinc.1 = 1 Then    ' jezeli jeden 1 to impuls
         
       if Zezwolenie = 0 then
          Y(C) = X 'zapisz czas na pozycji C
          incr c   ' nastepna pozycja
          Zezwolenie = 1'przelacz zezwolenie na zerowanie x
       end if 
    end if
    if pinc.1 = 0 then
       if  Zezwolenie = 1 then
       X = 0    ' zeruj licznik 1ms odczinkow czasu
       Zezwolenie = 0  ' przelacz zezwolenie na zapis y
       end if
    end if
    Waitms 1    ' odczekaj na koncu 1ms
    Incr X1    ' zwieksz licznik (ile w liczniku tyle msekund)
    
    Loop 


    Do
    If Zezwolenie = 1 Then    ' jezeli jeden 1 to impuls
       PortC.1 = 1    ' wlacz koncowke
       If X = 2 Then    ' odlicz dwie petle
          X = 0    ' zeruj licznik 1ms odczinkow czasu
          Zezwolenie = 0    ' przelacz zezwolenie na przerwe
          PortC.1 = 0    ' wylacz koncowke
       End If
    End If
    'C wybór tzw Y to znacz która przerwa
    'Y(10)
    If Zezwolenie = 0 Then   ' jezeli 0 to licz czas przerwy
    
          If X = Y(C) Then    ' pomijaj petle dopuki licznik nie zrowna sie z zapisanym czasem przerwy
          incr C 
          X = 0    ' zeruj licznik 1ms sekund
          Zezwolenie = 1    ' przelacz zezwolenie na impuls
       End If
    End If
    
    Waitms 1    ' odczekaj na koncu 1ms
    Incr X1    ' zwieksz licznik (ile w liczniku tyle msekund)
    
    Loop 



    Czy o to ci chodzi?
    zmienna Y musisz zdefiniować 'Dim Y(10) As long'
    a C musi mieścić ilość przerw
    zastosuj timer jak koledzy napisali i generuj pwm programowy. Jak by co to mogę wstawić kod od stopera który odlicza sekundy jak jest stan wysoki BA ten programik zlicza czas równolegle na 4 wejściach
  • #13 6613448
    danthe
    Poziom 30  
    Kolego pini0 dlaczego zmienne typu long? Maksymalny potrzebny czas przerwy ok. 3 sekundy, a przy zmiennej typu word i minimalnej "podziałce" 1ms daje się zapisać czas 65,535 sek.
    Pamiętać trzeba że zmienna typu word to dwa bajty, a long to aż 4 bajty.
    Czasy jakie można by w ten sposób odmierzać używając zmiennej long przekraczają 1000 godzin :D .
REKLAMA