Programowanie uC - wspoldzialanie przerwan i algorytmu - zasady sztuki
Stefcio Z. - 21-02-2007 01:46
Programowanie uC - wspoldzialanie przerwan i algorytmu - zasady sztuki Witam,
Chciałem spytać Was, nieco bardziej doświadczonych programistów o sposób
programowania uC, gdy program główny jest dość skomplikowany i zależy od
wielu sygnałów.
Dla ustalenia uwagi załóżmy, że uC ma współpracować m.in. z modułem
radiowym CC1100 (podłączonym przez SPI) oraz niekiedy z modułem Ethernet
(podłączony do USART) Główne zadania programu to dostęp do medium
radiowego (a'la CSMA/CA), analiza ramek radiowych (różnych-różnistych -
zgłoszenia, wiadomości sygnalizacyjne, wiadomości tekstowe, głos) i
reakcja na nie.
PODEJŚCIE 1.
Do tej pory (w innych projektach) robiłem tak:
1. Procedury obsługi przerwań możliwie najkrótsze (odczyt danych z
peryferiów, zapis do bufora w pamięci, pobieżna analiza i ustawianie
flag - np. FRAME_COMPLETE dla programu głównego).
2. Program główny po stwierdzeniu flagi FRAME_COMPLETE wywoływał funkcję
Analiza, która ustalała protokół, konkretne znaczenie ramki, ustalając
kolejne flagi "wyższej warstwy" (np. RECIEVED_CTS), które to flagi brane
były pod uwagę w głównym programie. Coś w stylu (pseudokod dla wysyłania
ramki w a'la CSMA/CA):
[IRQ]
....
Zapisuj bajty do bufora
if (ostatni bajt) then FRAME_COMPLETE
....
reti
[MAIN]
....
if (FRAME_COMPLETE) then FrameType = Analiza(bufor);
if (Stan == RTS_SENT and FrameType == CTS_RECIEVED and ChannelFree) then
Send(data);
Stan = DATA_SENT;
else if (Stan == DATA_SENT and FrameType == ACK_RECIEVED and
ChannelFree) then
Stan = IDLE;
i tu inne skomplikowane przejścia, zwłaszcza gdy np. wystąpią timeouty
....
[Analiza]
....
if (cośtam) then FRAME_TYPE = CTS_RECIEVED;
....
Zaletą jest fakt, że program główny zawsze może zareagować niemal na
wszystko. Wady - komplikacja warunków (kilka nałożonych na siebie
diagramów stanów: protokołów będzie kilka, typów ramek ok. 20-30) i
ogólnie wymięknąłem rozpisując program główny.
PODEJŚCIE 2.
Czy nie byłoby grzechem pisanie procedury nadawania ramki po prostu jako
funkcji:
[SendFrame]
Send(RTS);
WaitFor(CTS_RECIEVED);
if (Timeout) then return ERROR;
Send(data);
WaitFor(ACK_RECIEVED);
if (Timeout) then return ERROR;
RETURN OK;
Zaletą jest klarowny oczekiwany przebieg programu i uproszczenie
głównego programu. Problemem na pewno są funkcje WaitFor(*), podczas
których program jest obojętny na wiele innych sygnałów (np. pojawienie
się ramek innych typów, flagi ustawiane przez procedury innych przerwań
np. USART). Moim zdaniem można rozważyć w ciele WaitFor sprawdzanie
niektórych warunków(flag).
Jakie macie sposoby na programowanie uC obsługujących protokoły,
muszących brać pod uwagę wiele flag? Dziękuję za wszystkie odpowiedzi,
wskazówki, uwagi. Mam nadzieję, że nie zamąciłem zbytnio.
--
Pozdrawiam,
Stefcio Z.
Adam Dybkowski - 21-02-2007 02:46
Stefcio Z. napisał(a):
> Dla ustalenia uwagi załóżmy, że uC ma współpracować m.in. z modułem
> radiowym CC1100 (podłączonym przez SPI) oraz niekiedy z modułem Ethernet
[...]
> PODEJŚCIE 1.
> Do tej pory (w innych projektach) robiłem tak:
> 1. Procedury obsługi przerwań możliwie najkrótsze (odczyt danych z
> peryferiów, zapis do bufora w pamięci, pobieżna analiza i ustawianie
> flag - np. FRAME_COMPLETE dla programu głównego).
> 2. Program główny po stwierdzeniu flagi FRAME_COMPLETE wywoływał funkcję
> Analiza, która ustalała protokół, konkretne znaczenie ramki, ustalając
> kolejne flagi "wyższej warstwy" (np. RECIEVED_CTS), które to flagi brane
> były pod uwagę w głównym programie. Coś w stylu (pseudokod dla wysyłania
> ramki w a'la CSMA/CA):
I to jest najlepsze podejście. Zminimalizuj czas przebywania procesora w
przerwaniach. Zastosowanie automatu fsm albo nawet kilku do obsługi
wszystkich protokołów będzie bardzo dobrym i wygodnym rozwiązaniem.
Pewnie gotowych implementacji jest kilka i masz z czego wybierać, ja
napisałem po swojemu.
http://pl.wikipedia.org/wiki/Maszyna...o%C5%84czonych--
Adam Dybkowski
http://www.amwaw.edu.pl/~adybkows/Uwaga: przed wysłaniem do mnie maila usuń cyfry z adresu.
Pszemol - 21-02-2007 04:58
"Adam Dybkowski" <adybkows12@45wp.pl> wrote in message news:erg5bi$1pe$1@atlantis.news.tpi.pl...
> I to jest najlepsze podejście.
Niekoniecznie - w większych systemach opłaci się
zastosowanie jakiegoś systemu operacyjnego, lub
choćby kernela przełączającego taski i napisanie
łądnych driverów dla RS232, SPI a program główny
w kilku zsynchronizowanych muteksami wątkach, itp.
neuron - 21-02-2007 05:54
> PODEJŚCIE 2.
> Czy nie byłoby grzechem pisanie procedury nadawania ramki po prostu jako
> funkcji:
> [SendFrame]
> Send(RTS);
> WaitFor(CTS_RECIEVED);
> if (Timeout) then return ERROR;
> Send(data);
> WaitFor(ACK_RECIEVED);
> if (Timeout) then return ERROR;
> RETURN OK;
>
> Zaletą jest klarowny oczekiwany przebieg programu i uproszczenie głównego
> programu. Problemem na pewno są funkcje WaitFor(*), podczas których
> program jest obojętny na wiele innych sygnałów (np. pojawienie się ramek
> innych typów, flagi ustawiane przez procedury innych przerwań np. USART).
> Moim zdaniem można rozważyć w ciele WaitFor sprawdzanie niektórych
> warunków(flag).
semafory.
if semafor= 0 then return
if semafor= 1 then begin
SendFrame
semafor=2
return
end
if semafor = 2 then if cts_received then begin
send(data)
semafor:= 3
end
if semafor= 3 then if ack_recieved
itd
wywolujesz non stop taka funkcje - kiedy wpiszesz jeden w semafor to ruszy.
nieraz budowalem w ten sposob calkiem pokazne algorytmy
wojtek
www.neuron.com.plCMMS Maszyna
Golem OEE
Produkt- Baza Wiedzy
Adam Dybkowski - 22-02-2007 22:45
Pszemol napisał(a):
>> I to jest najlepsze podejście.
>
> Niekoniecznie - w większych systemach opłaci się
> zastosowanie jakiegoś systemu operacyjnego, lub
> choćby kernela przełączającego taski i napisanie
> łądnych driverów dla RS232, SPI a program główny
> w kilku zsynchronizowanych muteksami wątkach, itp.
Oczywiście - co nie zmienia faktu, że w przerwaniach najlepiej przebywać
jak najkrócej. Jeżeli robisz system czasu rzeczywistego to ważne także
jest, ile trwa najdłuższe przerwanie o wysokim priorytecie i na jaki
maksymalny czas blokujesz przerwania w głównym programie.
--
Adam Dybkowski
http://www.amwaw.edu.pl/~adybkows/Uwaga: przed wysłaniem do mnie maila usuń cyfry z adresu.
Stefcio Z. - 23-02-2007 00:45
Adam Dybkowski napisał(a):
> Pszemol napisał(a):
>
>>> I to jest najlepsze podejście.
>>
>> Niekoniecznie - w większych systemach opłaci się
>> zastosowanie jakiegoś systemu operacyjnego, lub
>> choćby kernela przełączającego taski i napisanie
>> łądnych driverów dla RS232, SPI a program główny
>> w kilku zsynchronizowanych muteksami wątkach, itp.
>
> Oczywiście - co nie zmienia faktu, że w przerwaniach najlepiej przebywać
> jak najkrócej. Jeżeli robisz system czasu rzeczywistego to ważne także
> jest, ile trwa najdłuższe przerwanie o wysokim priorytecie i na jaki
> maksymalny czas blokujesz przerwania w głównym programie.
Może nie wyraziłem się wystarczająco jasno - jestem całkowicie świadom
potrzeby maksymalnego skracania obsług przerwań i stosuję tę zasadę zawsze.
Główne pytanie polega na tym, czy ktoś stosuje zastępowanie
skomplikowanego diagramu stanów (który w kodzie bez dokumentacji
graficznej jest w zasadzie nieczytelny) funkcjami działającymi w sposób
"sekwencyjny" ("czekaj na konkretny sygnał, reaguj na inne
najistotniejsze sygnały) wg ustalonej w diagramie stanów kolejności -
tak jak to przedstawiłem w podejściu 2.
--
Pozdrawiam,
Stefcio Z.
Pszemol - 23-02-2007 00:45
"Stefcio Z." <stefcioz2@poc_ta.lonet.pl> wrote in message news:erl74p$cii$1@news.onet.pl...
> Może nie wyraziłem się wystarczająco jasno - jestem całkowicie świadom potrzeby maksymalnego skracania obsług przerwań i stosuję
> tę zasadę zawsze.
> Główne pytanie polega na tym, czy ktoś stosuje zastępowanie skomplikowanego diagramu stanów (który w kodzie bez dokumentacji
> graficznej jest w zasadzie nieczytelny) funkcjami działającymi w sposób "sekwencyjny" ("czekaj na konkretny sygnał, reaguj na inne
> najistotniejsze sygnały) wg ustalonej w diagramie stanów kolejności - tak jak to przedstawiłem w podejściu 2.
Gdybys chcial cos takiego napisac w jednym watku to bylby jeden
wielki balagan w programie obslugujacym kilka rownoleglych funkcji.
Wez pod uwage ze zdarzenia ze swiata zewnetrznego przychodza
w stosunku do siebie asynchronicznie.
Taki sposob pisania kodu jest wlasnie tylko mozliwy dzieki zastosowaniu
wielowatkowosci. System operacyjny udostepnia Ci bowiem mechanizmy
synchronizacji miedzywatkami i miedzy funkcjami obslugi przerwan
(muteksy, semafory, kolejki, flagi zdarzen itp).
W efekcie mozesz napisac sterownik np. do obslugi portu szeregowego
i napisac w kodzie glownym:
-wyslijpaczke(paczka);
-czekajNaOdpowiedz(2sekundy);
-przetwarzajodpowiedz();
A wewnatrz funkcji "wyslij paczke" Twoj watek bedzie spokojnie
czekal na zasygnalizowanie flagi w obsludze przerwania i to bez
marnowania czasu procesora gdy wazniejszy watek ma cos do roboty.
Polecam bardzo dobra ksiazke Labrosse "MicroC/OS-II".
W zasadzie ksiazka jest o konkretnym mikro-systemie operacyjnym
ale ma w bardzo latwy/przystepny sposob wyjasniona wielowatkowosc
i zasady wspolpracy watkow i obslugi przerwan w wiekszych programach.
zanotowane.pldoc.pisz.plpdf.pisz.plkonstruktor.keep.pl