Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Solved] BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń

Elektromechanik88 04 Jul 2020 21:54 2328 27
Optex
  • #1
    Elektromechanik88
    Level 3  
    Witam, drogich forumowiczów.
    Mam problem z komunikacją kilku urządzeń w sieci rs485. A tak prawdę mówiąc to z komunikacją pomiedzy dwoma, jednym "master" i jednym "slave".

    Normalnie staram się zadawać pytania w ostateczności na forum Elektroda, ale po prawie 3 tygodniach siedzenia przy problemie, przeglądaniu masy poradników i postów związanych z rs485 w wolnym czasie, moja frustracja osiąłgneła poziom zenitu.

    Przesyłam dwa filmiki na których mam 3 płytki ewaluacyjne z procesorami atmega328, atmega32, atmega8. Dwa pierwsze procki taktuję zewnętrznym kwarcem 8MHz, trzeci wewn.

    Przepraszam, że nie korzystam z wbudowanego playera, ale coś nie chce mi wstawić filmu
    1.mp4 Download (50.24 MB)
    2.mp4 Download (119.87 MB)

    Pomiędzy atmega328 i 32 zastosowałem kabel skrętkę rj45 4metry, pomiędzy atmega32 i 8 jakiś zwykły kabel lekko ponad 1m. Oczywiście pod każde wyjście AB podpięty terminator, nie połączyłem tylko wspólnych GND bo to mi teraz nic nie dawało i nie robiło żadnej różnicy przy problemie.



    Na 1filmie pokazane są 3 płytki
    1wsza atmega328 z największym LCD (MASTER)
    2ga atmega32, wysw 4x16 (SLAVE)
    3cia atmega8, wysw 2x16 (SLAVE ta nic nie robi, tylko teraz nasłuchuje)
    każda atmega dostała w programie numer ID 0,1,2

    Po 2 tygodniach dumania napisałem coś takiego

    Dla Mastera

    Code: vbnet
    Log in, to see the code


    Dla Slave

    Code: vbnet
    Log in, to see the code



    Oba programy są tym samym programem, tylko różnią się ustawieniem pinów procesora, stanu wyjścia startowego na rs485, numerem ID i zmienną string do wysłania na inny proc

    wyświetlacze 4x20 i 4x16 wyświetlają kilka parametrów, ulokowanych w tych samych miejscach
    1 wiersz strona lewa "Odebrane dane z drugiego procka"
    1 wiersz strona prawa "stan Ischarwaiting() "
    2 wiersz str lewa "wykryty przecinek"
    2 wiersz str prawa "rejestr udr( tylko tam jest nie umiem go używać)"
    3 wiersz str lewa "tutaj wyświetla się nr ID wycięty z wysłanej ramki"
    4 wiersz str lewa "porównanie Id odebranego z ramki z tym co jest w procku, jeżeli stan flagi 1 to przechodzi do wykonywania programu"

    Diody mrugające na płycie sygnalizują po lewej 2diody stan przerwania w timer0, przerwanie w pętli gł
    po prawej str, lewa dioda to odbiór, prawa nadawanie.

    Problemem jest gdzieś z główna pętlą w programie, gdyż w miejscu gdzie wyświetla się na lcd nr ID odebrany z przychodzącej ramki czasem zdarza się że w pętli zostanie on pominięty z pobieranej ramki i w to miejsce wpada to co powinno być w pierwszym wierszu wyświetlacza.
    Ten problem crash-uje mi program i kończy nadawanie od Mastera (problem pojawia się zarówno na master jak i na slave).
    Program nieraz potrafi wymieniać pomiędzy sobą dane nawet ponad 10min i to na 3 urządzeniach a czasem po pierwszej sekundzie się sypie.

    Nie wiem dlaczego czasem pomija ten id w odebranej ramce, nie potrafię stwierdzić czy w pętli gł jest jakaś kolizja, która to powoduje

    Program działa w oparciu o przerwanie ok. 100ms (zarówno zwiększanie jak i zmniejszanie czasu przerwania nic nie daje),
    BAUD 9600

    Format wysyłanej ramki to ID#dane, po napotkaniu hash wycina numer ID, po napotkaniu przecinka zmienia się stan komunikacji na rs485

    Pomysły mi się wyczerpały a bardzo potrzebuję to wsadzić do mojego głównego projektu liczącego ponad 2000lini kodu.

    Wpadłem jeszcze na jeden pomysł że gdy w miejscu odbieranego nr Id pojawi mi się ten błąd to mogę wysłać do mastera np kod błędu np(nieprawidłowy format danej, ponów wysyłanie) ale wolał bym by wszystko działało w podstawowej idei , tzn. każde odpytane urządzenie slave zwraca jakąś daną spowrotem do mastera.

    Bardzo proszę o pomoc, bo może program który napisałem, lub format wysyłanej ramki to bubel.

    Pozdrawiam
  • Optex
  • Helpful post
    #2
    kamyczek
    Level 38  
    Bardziej profesjonalnie jest wszystkie układy potraktować jako slave . Każdy słucha i czeka na przerwanie z uarta , jak je otrzymuje odbiera zawartość z udr porównuje i albo odbiera dalej albo ignoruje i czeka na kolejny adres . Atmel wyposażył układy w tryb multimaster ,który się do tego świetnie nadaje i warto o nim przeczytać w dokumentacji . Poza tym należało by przewidzieć sterowanie układem odpowiadającym za komunikację RS485 i najlepiej do tego użyć jednego z przerwań sygnalizującego zakończenie transmisji . Powinieneś się postarać o jakiś analizator dzięki niemu można wychwycić wiele błędów . Poza tym układ który działa z oscylatorem RC wymaga kalibracji przy uruchomieniu , inaczej błąd może być za duży by poprawnie odbierać i wysyłać dane . Do testów możesz połączyć txd mastera i rxd układów slave o ile wszystkie pracują przy tym samym napięciu zasilania i mają wspólną masę. Pomijając konwerter rs485 wykluczysz błędy w polaryzacji i sterowaniu tym układem .
  • #3
    bart-projects
    Level 26  
    Może gubisz przesyłane znaki bo gdzieś pętla jest za wolna. Jeśli taką komunikację wrzucisz do większego programu to problem się tylko pogłębi.
    Lepiej skonfiguruj bufor i Bascom będzie odbierał wszystkie znaki w przerwaniu. Nie przegapi żadnego znaku. ->Config Serialin0

    Widać, że dodajesz Enter na końcu stringów. Możesz to monitorować i parsować dane dopiero jak nadejdzie Enter. Potem sprawdż w którym miejscu jest Hash # czyli Helpb = Instr(dane,"#") i jeśli Helpb > 0 znaczy że jest hash a ID znajduje sie w miejscu Helpb+1
  • #4
    Elektromechanik88
    Level 3  
    Witam

    Quote:
    Bardziej profesjonalnie jest wszystkie układy potraktować jako slave . Każdy słucha i czeka na przerwanie z uarta , jak je otrzymuje odbiera zawartość z udr porównuje i albo odbiera dalej albo ignoruje i czeka na kolejny adres . Atmel wyposażył układy w tryb multimaster ,który się do tego świetnie nadaje i warto o nim przeczytać w dokumentacji . Poza tym należało by przewidzieć sterowanie układem odpowiadającym za komunikację RS485 i najlepiej do tego użyć jednego z przerwań sygnalizującego zakończenie transmisji .


    Pogrzebałem troszkę w dokumentacji atmeg i znalazłem informacje na temat multimaster, choć z moim angielskim jest dość krucho więc zamieszczam kawałek przetłumaczonej noty katalogowej translatorem znanej firmy.

    1452486AA – AVR – 02 / 2013ATmega8 (L) Zalecenia dotyczące błędu maksymalnej prędkości transmisji w odbiorniku zostały sformułowane przy założeniu, że odbiornik i nadajnik równo dzielą maksymalny błąd całkowity. Istnieją dwa możliwe źródła błędu prędkości transmisji w odbiorniku. Zegar systemowy odbiornika (XTAL) zawsze będzie miał niewielką niestabilność w zakresie napięcia zasilania i zakresu temperatur. Podczas generowania zegara systemowego przy użyciu kryształu rzadko stanowi to problem, ale w przypadku aresonatora zegar systemowy może różnić się o więcej niż 2% w zależności od tolerancji rezonatorów. Drugie źródło błędu jest bardziej kontrolowane. Generator prędkości transmisji nie zawsze może dokonać dokładnego podziału częstotliwości systemu, aby uzyskać żądaną prędkość transmisji. W takim przypadku, jeśli to możliwe, można zastosować wartość UBRR, która daje dopuszczalny niski błąd. Tryb komunikacji wieloprocesorowej Ustawienie bitu trybu komunikacji wieloprocesorowej (MPCM) w UCSRA umożliwia funkcję filtrowania przychodzących ramek odbieranych przez odbiornik USART. Ramki, które nie zawierają informacji o adresie, zostaną zignorowane i nie zostaną umieszczone w buforze odbiorczym. To skutecznie zmniejsza liczbę ramek przychodzących, które muszą być obsługiwane przez CPU, w systemie z wieloma jednostkami MCU, które komunikują się za pośrednictwem tej samej magistrali szeregowej. Nadajnik nie ma wpływu na MPCMsetting, ale musi być używany inaczej, gdy jest częścią systemu wykorzystującego tryb komunikacji wieloprocesorowej. Jeśli odbiornik jest skonfigurowany do odbierania ramek zawierających od 5 do 8 bitów danych, to pierwszy przystanek bit wskazuje, czy ramka zawiera dane lub informacje adresowe. Jeśli odbiornik jest skonfigurowany dla ramek z dziewięcioma bitami danych, dziewiąty bit (RXB8) jest używany do identyfikacji ramek adresu i danych. Gdy bit typu ramki (pierwszy bit lub dziewiąty bit) to jeden, ramka zawiera adres. Gdy bit typu ramki jest równy zero, ramka jest ramką danych. Tryb komunikacji wieloprocesorowej umożliwia kilku jednostkom MCU slave otrzymywanie danych z jednostki MCU master. Odbywa się to najpierw dekodując ramkę adresu, aby dowiedzieć się, który MCU został adresowany. Jeśli konkretna jednostka MCU urządzenia podrzędnego została zaadresowana, otrzyma następujące ramki danych w normalny sposób, podczas gdy inne jednostki MCU urządzenia podrzędnego będą ignorować odebrane ramki, dopóki nie zostanie odebrana inna ramka adresu. Używanie MPCM Aby MCU działało jako Master MCU, może użyć 9 -bitowy format ramki znaków (UCSZ = 7). Następnie dziewiąty bit (TXB8) należy ustawić, gdy ramka adresu (TXB8 = 1), lub wyczyścić, gdy ramka danych (TXB = 0) jest przesyłana. W tym przypadku jednostki MCU urządzeń podrzędnych muszą być skonfigurowane do korzystania z 9-bitowego formatu ramki znaków. Do wymiany danych w trybie komunikacji wieloprocesorowej należy zastosować następującą procedurę: 1. Wszystkie MCU urządzenia podrzędnego są w trybie komunikacji wieloprocesorowej (ustawiony jest MPCM w UCSRA) 2. Master MCU wysyła ramkę adresową, a wszyscy slave'y odbierają i odczytują tę ramkę. W jednostkach MCU urządzeń podrzędnych flaga RXC w UCSRA zostanie ustawiona jako normalna3. Każda jednostka podrzędna MCU odczytuje rejestr UDR i określa, czy został wybrany. Jeśli tak, kasuje bit MPCM w UCSRA, w przeciwnym razie czeka na następny bajt adresu i zachowuje ustawienie MPCM4. Zaadresowana jednostka MCU będzie odbierać wszystkie ramki danych, dopóki nie zostanie odebrana nowa ramka adresu. Inne jednostki MCU slave, które wciąż mają ustawiony bit MPCM, zignorują ramki danych 5. Gdy ostatnia ramka danych jest odbierana przez zaadresowaną MCU, zaadresowana MCU ustawia bit MPCM i czeka na nową ramkę adresu od Master. Proces jest następnie powtarzany od 2UUżywanie dowolnego z 5-bitowych do 8-bitowych formatów ramek znakowych jest możliwe, ale niepraktyczne, ponieważ odbiornik musi zmieniać między użyciem formatów n i n + 1 znaków. Utrudnia to działanie w trybie pełnego dupleksu, ponieważ nadajnik i odbiornik używają tego samego ustawienia wielkości znaków. Jeśli używane są ramki od 5 do 8 bitów, nadajnik musi być ustawiony tak, aby używał dwóch bitów stopu (USBS = 1), ponieważ pierwszy bit stopu jest używany do wskazywania typu ramki.

    Teraz mam takie pytania odnośnie tej noty
    Komunikacja szeregowa to dla mnie nowość i nie mam za bardzo doświadczenia w tym temacie.
    Jak wiadomo jest kilka możliwości przesyłania danych w prockach AVR, jak ISP, A2c, 1wire i Usart, Ten ostatni najbardziej nadaje się do wysyłania na większe odległości

    Usart posiada kilka rejestrów specjalnych do sterowania, prawdę mówiąc nie za bardzo je rozumiem z tej noty.

    1. na które rejestry trzeba zwracać największą uwagę przy komunikacji?

    W nocie katalogowej rejestr TXC służy do sprawdzenia czy przesyłane są jakieś dane, to chyba na tej zasadzie działa funkcja ischarwaiting() w bascomie.

    2. o co chodzi z tym rejestrem UDR i porównywaniem, co to są i jak prawidłowo wyglądają te ramki wysyłanych danych?

    cyt. Master MCU wysyła ramkę adresową, a wszyscy slave'y odbierają i odczytują tę ramkę. W jednostkach MCU urządzeń podrzędnych flaga RXC w UCSRA zostanie ustawiona jako normalna3. Każda jednostka podrzędna MCU odczytuje rejestr UDR i określa, czy został wybrany. Jeśli tak, kasuje bit MPCM w UCSRA, w przeciwnym razie czeka na następny bajt adresu i zachowuje ustawienie MPCM4. Zaadresowana jednostka MCU będzie odbierać wszystkie ramki danych, dopóki nie zostanie odebrana nowa ramka adresu. Inne jednostki MCU slave, które wciąż mają ustawiony bit MPCM, zignorują ramki danych 5.

    3.Co to są te 9-cio bajtowe ramki danych

    4. Bardzo ważne, P. kolega kamyczek wspomniał o synchronizacji/kalibracji oscylatorów, w jaki sposób można to zrobić w prockach.

    Quote:
    Może gubisz przesyłane znaki bo gdzieś pętla jest za wolna. Jeśli taką komunikację wrzucisz do większego programu to problem się tylko pogłębi.
    Lepiej skonfiguruj bufor i Bascom będzie odbierał wszystkie znaki w przerwaniu. Nie przegapi żadnego znaku. ->Config Serialin0


    Tutaj może mieć P. kolega rację, chociaż na to nie wygląda.
    Zmodyfikowałem lekko program, tzn, wyłączyłem sprawdzanie nr ID i w rezultacie dana wyświetla się cała w pierwszej lini lcd.
    Program oczywiście cały czas odbija dane jak piłeczkę, ale zauważyłem że przy ustawieniu Baud na28800 i błędzie 7,84% zdarza mu się czasem pominąć pierwszy znak.

    filmik z prawidłową według mnie pracą, Baud na 9600 dodałem zmianę przyciskiem wysyłanej ramki od master.
    4.mp4 Download (44.26 MB)

    co do konfiguracji serialin to mogę zastosować tam jeszcze Bytematch, CTS i RTS
    ale jak ich używać?





    Przy odbieraniu Ramki danych, jak program jest bez zabezpieczenia z wykrytym znakiem "," zauważyłem, że po ramce występują jeszcze jakieś zakłócenia wygląda to mniej więcej tak Atmel,mmmeeeaaatt%$%$%^ , dlatego zrobiłem przecinek odcinający resztę krzaków.

    czy to tak ma być z tą resztą krzaków?
    3.mp4 Download (19.35 MB)

    Quote:
    Potem sprawdż w którym miejscu jest Hash # czyli Helpb = Instr(dane,"#") i jeśli Helpb > 0 znaczy że jest hash a ID znajduje sie w miejscu Helpb+1

    Tego jeszcze nie sprawdzałem

    A gdybym wstawił jeszcze np rozpoczęcie nadawanej ramki np start#ID#Dane#stop ale jak to zrobić?
  • Optex
  • Helpful post
    #5
    bart-projects
    Level 26  
    Łap bo jak zaczniesz z tym Multimaster to się nigdy z tego nie wygrzebiesz a odkrywasz tu koło na nowo :D

    Po pierwsze nie zauważyłem wcześniej, że już skonfigurowałeś Serialin0. Błędem natomiast jest jest używanie Serialout0 a potem zamiast to wrzucić do bufora to wycinasz po jednej literce ze stringa i nadajesz pojedynczo...
    Po prostu napisz Print String i zapomnij. Bascom sobie to sam wyśle. Tobie radzę na razie nie korzystać z Serialout0 w ogóle. Naotwierasz tych przerwań i coś przegapisz.

    Poniższy program działa na wewnętrznym oscylatorze 8MHz i obsługuje jakby cztery Slave`y na raz i to co 100ms...przy prędkości 38400...bez problemu jeszcze pisząc po LCD.

    Nie nadawałem mu ID, ale w kodzie znajdziesz że kiedy otrzyma ID od 1 do 4 to ustawia się na odpowiadającej ID linii wyświetlacza i pisze co dostał. Jeśli więc nadasz mu jakiś "My_ID" to potem porównasz czy Id = My_ID. Tutaj to jest pominięte i tylko ID < 5 jest ważne bo nie mam więcej linii na LCD :D

    Napisałem krótki program nadawczy. Ramka wygląda tak #ID*DANE i Enter który dodaje Bascom.

    Odbiornik czeka na ENTER. Należy dodać w programie zabezpieczenie na wypadek przepełnienia Stringa, ale Bascom chyba też tego pilnuje. Kiedy widzi Enter to sprawdza gdzie jest Hash# i bierze następną literkę/cyferke. Jeśli to cyfra to szuka Gwiazdki*. Jak znajdzie Gwiazdke* to wszystko za gwiazdką drukuje na LCD.

    Nie chciało mi się łaczyć MAX`ów więc zwyczajnie chodzi to po RS`ie, ale to nie ma znaczenia. Skonfiguruj Config Print0 jak ja i Bascom sam będzie machał pinem RE/DO.

    Miłego rozkminiania.
    PS. Zerknij na $projecttime ;)

    Code: vbnet
    Log in, to see the code




  • Helpful post
    #6
    kamyczek
    Level 38  
    Z tego co pamiętam to serial in i out używały programowego uarta co oznaczało mniej więcej tyle ,że jak nie czeka na znak to gubi to co dostaje . Dlatego podstawą jest sprzętowy uart obsługiwany w przerwaniach i w taki sam sposób zrealizowane sterowanie przełączanie sygnałów nadawanie , odbiór w konwerterze RS485. Uart generuje szereg przerwań informujących o tym że bufor nadawania jest pusty , że zakończono nadawanie ostatniego znaku , że w buforze odbiorczym jest znak który odebrano . Każde z nich może służyć do automatyzacji całego procesu komunikacji . Co do prędkości transmisji i błędów Moim zdaniem maksymalny błąd który jest do zaakceptowania to 1% powyżej zaczynają się pojawiać różne dziwne znaki . Jeśli używasz uarta To wybierz przyjazny rezonator kwarcowy 11,0592MHz 7,3728MHz będzie łatwiej i można będzie wybrać wiele prędkości z minimalnym błędem .
  • #7
    bart-projects
    Level 26  
    Co innego Serin, Serout lub Open COMx.x, bo są programowe, a co innego Config SerialinX który konfiguruje bufor FIFO i odbiera wszystko w przerwaniu. Wszystko automatyczne a sprawdza się tylko stan bufora.
    Co innego prędkości "typowe" i tutaj przy 8MHz i 38400bps błąd wynosi 0.2%, a co innego jeśli mamy własne urządzenia/sieć i możemy je jednakowo do siebie skonfigurować, po czym spokojnie bujać się przy 8MHz i 200kbps lub 250kbps z 0% błędu przy U2X=1. Można się domyślić, że przy 16MHz można nawet więcej ;)
  • #8
    Elektromechanik88
    Level 3  
    Witam.

    Quote:
    Po pierwsze nie zauważyłem wcześniej, że już skonfigurowałeś Serialin0. Błędem natomiast jest jest używanie Serialout0 a potem zamiast to wrzucić do bufora to wycinasz po jednej literce ze stringa i nadajesz pojedynczo...
    Po prostu napisz Print String i zapomnij. Bascom sobie to sam wyśle. Tobie radzę na razie nie korzystać z Serialout0 w ogóle. Naotwierasz tych przerwań i coś przegapisz.


    Co do config serialin i serialout to zasugerowałem się tym tematem na elektrodzie,
    https://www.elektroda.pl/rtvforum/topic1427104.html#14753874
    Pytane w nim było o komunikację po rs323 ale to na tej bazie właśnie wzorowałem się z moim programem.

    Ów program dobrze działał z komendami Print X i input X ale, że input zatrzymywał mi działanie reszty programu w oczekiwaniu na ramkę zmieniłem na inkey() który to natomiast odbierał mi tylko pierwszy znak i dlatego iterowałem wysyłanego stringa, choć właśnie później zacząłem się domyślać że nie tędy droga :)


    Co do kolegi programu odbiorczego, nie rozumiem o co chodzi z tym cmd_timeout i jego parametrem 50

    i dlaczego znaki odebrane z bufora są w postaci byte i przekształcane na char(x)

    To przerwanie od timera też jest inne, moje działa na zasadzie opisanej z książki Marcina Wiązania

    Ja napisałem coś takiego "prostego" jako nadawanie, ale nie łączy się z programem kolegi.

    Code: vbnet
    Log in, to see the code


    Ok, teraz działa, zajrzałem do helpa i ma być zdefiniowany port jako wyjściowy.
    Code: vbnet
    Log in, to see the code
  • #9
    bart-projects
    Level 26  
    Jeśli chodzi o cmd_timeout to chodzi o to, że wejscie RX kiedy pin używany jest przez USART nie jest niczym podciągane. Kiedy jest podłączony do drugiego urządzenia np. procesora lub MAX485 to problemu nie ma bo pin jest podciągany wyjściem TX tego uC lub MAX485. Kiedy jednak odłączysz to na pinie stan jest nieustalony i wpadają na USART śmieci.
    Ten kawałek programu jest moim standardowym zabezpieczeniem przed śmieciami i zawsze go dołączam. Kiedy wpada jakiś znak to uC daje czas na to by wpadł kolejny. Każdy kolejny znak przedłuża timeout. Jak wpadnie string z Enterem na końcu to wszystko fajnie, ale jak wpadnie tylko jakiś śmieć typu "shd/;' " to po określonym czasie bufor (string) jest czyszczony i nie jest w ogóle parsowany. Podobnie czyta się ramki w Modbus tylko tam Timeout 1,5długości znaku wyznacza koniec ramki.

    To co robisz nadając to błąd bo Bascom sam dodaje LF i CR na końcu więc niepotrzebnie piszesz "Print String ; Chr(13)". Tak naprawdę otrzymujesz "String Chr13, Chr10, Chr13"
    To dlatego w mojej procedurze odbioru jest "Case 10 'swallow" co oznacza "połknij" -> nie rób nic, nie dodawaj do stringa.

    To nie jest przerwanie od Timera tylko sprawdzanie flagi Timera. Timer w trybie CTC sam się zeruje. Jest to dużo wygodniejsze i szybsze a przerwanie tu niepotrzebne. Wystarczy sprawdzić czy minęło 10ms. Flagi kasuje się wpisując jedynkę, nie zero.
    Te 10ms to też standardowy czas bo wykorzystuje go w wielu programach do sprawdzania klawiatury itp.

    Napisanie tego, jak widać po projecttime zajęło 18minut :D bo to copy paste z innych moich programów. O tym pinie jako output zapomniałem bo od początku planowałem nie używać Maxów. Wyszłoby pewnie w praniu :D
  • #10
    Elektromechanik88
    Level 3  
    Witam.
    Program wgrałem na 3 płytki ewal. które teraz odbierają to co nadaje master, czyli np taką ramkę "#2*Tomek123"

    Problem jest teraz z odesłaniem odpowiedzi z slave do mastera

    W procedurę parsowania wstawiłem coś takiego.
    Code: vbnet
    Log in, to see the code


    służy ona właśnie do odsyłania odpowiedzi przy jakiejś wartości odebranej z Helpstr.

    Teraz program nadawczy od master w oparciu o program P. Kolegi Bartka

    Code: vbnet
    Log in, to see the code


    Z tą flaga = 1 zmienianą na 0 kombinowałem by przełączać pomiędzy nadawaniem i odbiorem, teraz nie jest ona istotna.

    najdziwniejsze jest to że gdy nie ma w pętli gł

    Code: vbnet
    Log in, to see the code


    Master nie daje żadnej reakcji na odbiór

    A potrzebuję zrobić tak by master odpytywał każde urządzenie po kolei i każde odpytane urz od razu zwraca odpowiedź

    ZAPYTANIE: Master---> Slave1
    ODPOWIEDŹ: Slave1---> Master
    ZAPYTANIE: Master---> Slave2
    ODPOWIEDŹ: Slave1---> Master
    ZAPYTANIE: Master---> Slave3
    ODPOWIEDŹ: Slave1---> Master

    chciałem by tak było odpytywane do 5ciu urz.

    załączam film, duży czarny LCD to master.






    zastanawia mnie też dlaczego na lcd mastera po odebraniu Znaku najpierw jest int 225, przy 107 wyświetla odebraną ramkę, 177


    w moim programie nadawanie/ odbiór sprawdzałem na podstawie Ischarwaiting()
    tutaj to działa dla mnie w sposób niezrozumiały :)

    Pozdrawiam
  • Helpful post
    #11
    bart-projects
    Level 26  
    Łap. Przypomniałem sobie że miałem dwie płytki z RS485 na pokładzie i komplet kabli z innego projektu(most RS poprzez ETHERNET).

    W każdym miejscu gdzie podłączam RS`a mam zawsze dwa gniazda więc mogę je łączyć albo podglądać terminalem.

    W kodach Slave ustawiasz adres stałą My_ID. Z racji tego, że na szybko, miałem tylko dwa to testowałem adresy 3 i 5.
    Slave po rozpoznaniu swojego adresu sprawdza komendę. Komendy na razie są dwie: Tomek i Bartek :D
    Tomek włącza LED`a i odsyła Masterowi (pod adres 0) wiadomość że Slave "ten a ten" LED ON.
    Bartek wyłącza LED`a i odsyła Masterowi (pod adres 0) wiadomość, że Slave "ten a ten" LED OFF.
    Możesz więc dopisać sobie inne komendy...Oczywiście LED`y też działają ;)

    Master też ma adres - tutaj 0. Jeśli odbierze wiadomość do siebie to sprawdza kto odesłał i ustawia się na linii LCD.
    LCD jest sterowany TYLKO komendami zwrotnymi od Slave`ów.
    Do Slave`ów wysyła naprzemiennie komendy "Tomek" i "Bartek"

    To nie jest jakiś "efektywny" kod. Miał być prosty żeby przybliżyć zagadnienie. Można to napisać dużo lepiej :D
    Na filmie widać, że mogę całą komunikację podglądać w terminalu.

    P.S. Pomyśl, że można też każdemu Slave`owi nadać drugi adres 255 i wtedy Master nadaje jedną wiadomość do wszystkich Slave`ów i do każdego ten adres pasuje. Wszystkie na raz robią to samo. Taki Broadcast Address :P

    Code: vbnet
    Log in, to see the code


    Code: vbnet
    Log in, to see the code



  • #12
    Elektromechanik88
    Level 3  
    Witam.
    Kolego Bart_projects, bardzo dziękuję za podany program, jest Pan złotym człowiekiem :) . Dopiero wczoraj go dostosowałem do swoich procków, gdyż byłem na tygodniowym urlopie, w prawdzie lapka miałem ze sobą ale procków nie zabierałem z całym tym okablowaniem :P

    Jednak po próbach zrozumienia co kolega miał na myśli, mam kilka pytań.
    Dlaczego slave jest taktowany 16MHz a master 8M.
    Jak zrobiłem wszystkie na 8M to dość często mi coś krzaczyło, lub się wieszało.

    Czy numer Id każdego z urządzeń da się przerobić tak by nie był podany jako stała,
    chodzi mi tutaj o przypisywanie numeru id z zewnątrz, np. każdy slave ma przypisaną domyślną wartość na początku "255" lub "???" a master nadaje jednorazowo po kolei każdemu takiemu slavowi swój unikatowy numer id, który następnie jest zapisywany do eepromu odbiornika/slave i przy każdym kolejnym uruchamianiu jest już sczytywana wartość id z eeprom procka.

    Czy jest jakaś różnica w działaniu gdyby wszystkie urządzenia chodziły tylko na timer0, w podanym przykładzie są timer0 i 2

    Widzę że te programy chodzą w pętli gł i oczekując na flagę rejestru TIFR i dopiero po spełnieniu tego warunku robią coś dalej.
    Czy takie rozwiązanie spełni swoją funkcję w dłuższym kodzie?

    Do skompilowania tego kodu musiałem zainstalować nowszą wersję pakietu Bascom bo w starej wyskakiwały błędy:

    Print #com1 , "#0*Slave" ; Str(my_id) ; " LED ON " 'odpowiedz Masterowi pod adres 0

    error:42 xx Numeric parameter expected[3],

    Gdy stałą Id zmieniałem na zmienną byte, błąd znikał ale program nie działał prawidłowo.

    Mój stary IDE bascom 2.0.7.3 nie radzi sobie z definiowaniem stałymi więc z nich nie korzystałem,
    A nowy bascom gryzie się z moim innym programem :P

    Film przedstawia 4 slavey i mastera na atmedze328


  • #13
    bart-projects
    Level 26  
    Slave`y są taktowane 16MHz bo takie miałem tam wlutowane kwarce (płytki były gotowe). W Masterze użyłem już 8MHz ale przy tym taktowaniu prędkość 38400 to już prawie maksimum.
    Oczywiście adresy mogą być zmiennymi oraz pamiętane w Eeprom, jednak chyba nie przemyślałeś tego nadawania im adresów.
    Prościej było by napisać jeden wspólny kod dla wszystkich Slave`ów a po zaprogramowaniu jakąś przejściówką USB<>RS485 nadać im adresy komandami AT. Na przykład "AT+MYID=4" i one to sobie zapiszą. Komendami AT możesz zawsze odpytać później moduł "AT+MYID?"
    Parsowanie komend AT jest proste.

    To że po zmianie stałej My_id na zmienną Byte miałeś problem związany jest bug Bascoma który przypadkowo odkryłem pisząc ten kod dla Ciebie.
    Otóż funkcja Str() kiedy źródłem jest stała dodaje jedna spację przed wartością. Można to sprawdzić w symulatorze. Zgłosiłem to do supportu MCS i będzie poprawione w najnowszej wersji :D
    Zobacz screen symulacji. Widać, że dodało jedną, niepotrzebną, spację.
    BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń
    Po wstawieniu tam zmiennej wszystko wraca do normy więc w programie musiałbyś chyba zmienić to:
    Code: vbnet
    Log in, to see the code


    Bascoma radzę uaktualnić i właczyć -> View -> CodeExplorer. On sprawdza kod jeszcze przed kompilacją.

    Timery oczywiście możesz wybrać które chcesz. Często wykorzystuję takie gotowe szablony dla danej płytki i wtedy nie zastanawiam się nad tym jak podłączone są peryferia typu LCD itp. Pewnie jeden szablon wykorzystywał ten a drugi inny timer.

    Program sprawdza flagę timera i to jest zrobione specjalnie. Przez 10ms może sobie robić/reagować na inne zdarzenia w tym obsługiwać odbiór komend z pełną prędkością taktowania. Przerwanie nie jest potrzebne.
  • #14
    Elektromechanik88
    Level 3  
    Witam.

    Quote:
    Oczywiście adresy mogą być zmiennymi oraz pamiętane w Eeprom, jednak chyba nie przemyślałeś tego nadawania im adresów.
    Prościej było by napisać jeden wspólny kod dla wszystkich Slave`ów a po zaprogramowaniu jakąś przejściówką USB<>RS485 nadać im adresy komandami AT. Na przykład "AT+MYID=4" i one to sobie zapiszą. Komendami AT możesz zawsze odpytać później moduł "AT+MYID?"
    Parsowanie komend AT jest proste.


    Przemyślałem to nadawanie adresów na poziomie mojej jeszcze niewielkiej wiedzy w tematach komunikacji UART i jakiejkolwiek innej :D Czeka mnie jeszcze długa, ciężka droga z tym całym komunikowaniem się, ale wiem na pewno że będę stosował to rozwiązanie w moich przyszłych projektach.

    Cóż może zadałem to pytanie z wcześniejszego posta za bardzo powierzchownie.
    Zapytam jeszcze raz ale jaśniej wytłumaczę :)

    Chodzi mi o komunikację Tylko po między masterem i slave-ami nie może być stosowana przejściówka usb<>485 którą bym nadawał adresy przez komputer.

    Mój projekt po dodaniu komunikacji rs485 powinien zachowywać się tak:
    Pierwsze uruchomienie sterownika Master ->
    -> wstępna konfiguracja mastera (tutaj nadaje ile będzie slave-ów w sieci i resztę ustawień dla sterownika) ->
    -> koniec konfiguracji, ustawienia zapisane w wewn pamięci eeprom procka master, program znając ilość slave-ów jakie mu dałem w konfiguracji przechodzi do adresowania tego co jest do niego podpięte po RS.
    Chciał bym by wyglądało to tak (master wysyła nr id "1" a jeden z domyślnych slaveów łapie tą "1" zapisuje do eeprom i odsyła odpowiedź do master, że został zaadresowany. Master łapie tą odp i inkrementuje na adres id "2" i wysyła do pozostałych na linii rs i znów któryś tam łapie i odsyła "OK", itd)
    -> slave-y zaadresowane, program rozpoczyna pracę.

    Teraz wyłączam cały projekt i odpalam od nowa ->
    -> Master nie pyta o wstępną konfigurację bo wszystko zczytuje z eeprom ->
    -> master przechodzi do odpytywania slave-ów na linii, czy się zgłaszają prawidłowo
    *jeżeli wszystkie się zgłaszają, master uruchamia program
    *jeżeli jeden ze slave-ów nie odpowiada przez pewien czas, master robi z tego błąd i Wyświetla się na lcd mastera np "Błąd slave-a nr 3, zresetuj pamięć eeprom slave nr 3", po resecie 3 master nadaje na nowo id nr 3 domyślnemu zresetowanemu slave.
    (chodzi mi tu o to by nie było sytuacji, że gdy jeden slave się uszkodzi to nie będę mógł zastąpić go innym nowym, wziędym ze swojej półki i podłączyć go )

    Każdy ze slave-ów będzie miał podpięte dwa czujniki do zbierania danych ze swojego otoczenia (tym otoczeniem jest każde pomieszczenie w mieszkaniu/domu).


    Boję się tylko czy każdy z domyślnych urządzeń nie zaadresuje się w jednakowym czasie na linii RS tym id "1" bo będzie to bezsens :S wszystkie slave-y odeślą masterowi "OK jestem jedynką", musi być jakieś kolejkowanie na tej linii.
  • #15
    bart-projects
    Level 26  
    Sam chyba widzisz, że to będzie cięższe w realizacji. Taki długi post a jesteś w punkcie wyjścia.
    Może lepiej zainwestuj trzy piny Slave`a i na trzech bitach możesz zakodować w każdym adres 0-7. Slave wstaje i sprawdza swoje piny. Wpisuje sobie adres w RAM i gotowe. Master wstaje i sprawdza które adresy są na linii...Proste jak świński ogon :D
  • #16
    Elektromechanik88
    Level 3  
    Quote:
    Może lepiej zainwestuj trzy piny Slave`a i na trzech bitach możesz zakodować w każdym adres 0-7.


    hmm. No właśnie tego rozwiązania chciałem uniknąć, też na to wpadłem ale sieć chciał bym by miała potencjał do przyjęcia choć 20 slave-ów na przyszłość a to już 5 pinów i grubszy kabel.

    Mam kilka alternatyw.
    Każdy slave miał by na obudowie przycisk i mrugającego leda i tym przyciskiem wybierał bym adres id np. 1-10, każde naciśnięcie przycisku inkrementuje licznik od1 do 10. 4mrugnięcia leda oznaczało by wartość 4.

    Wpadłem również na pomysł by każdego slave-a osobno na początku pod mastera podpinać i on by każdemu z osobna nadawał.

    Mam jeszcze jeden alternatywny i najbliższy pomysł pierwotnemu, by każdy slave oryginalnie miał wgrany swój własny unikatowy wewn id (takie rozwiązanie jak w 1wire ds18b20, albo jak mac w kartach sieciowych do PC).
    Każdy slave domyślny został by poproszony przez mastera o podanie swojego maca i na tej podstawie adresował by im id od 1-5. Co kolega na to? :)

    Można by jeszcze na zasadzie kto ma tokena ten ma pierwszeństwo zrobić ale nie wiem jak to ugryźć, dość skomplikowana sprawa .


    A w przyszłości chciał bym to zrobić już w komunikacji radiowej, bluetooth lub wifi
  • #17
    bart-projects
    Level 26  
    A co Ty chcesz tam robić tym grubszym kablem z powodu wyższego adresu? Montujesz taki DIP SWITCH i ustawiasz adres.
    BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń
    Niepotrzebnie komplikujesz prostą sprawę. Jak chcesz im nadawać "niepowtarzalne MAC`i" to równie dobrze możesz im nadać adres we flash czy eeprom. To, że rzekomo Twój stary Bascom nie radzi sobie ze stałymi to najdziwniejsze tłumaczenie jakie na razie słyszałem. Co to za problem napisać:
    Code: vbnet
    Log in, to see the code

    Jesteś dziesięć wersji "do tyłu". Aktualny Bascom ma numer 2083.
  • Helpful post
    #18
    tmf
    Moderator of Microcontroller designs
    Elektromechanik88 wrote:
    hmm. No właśnie tego rozwiązania chciałem uniknąć, też na to wpadłem ale sieć chciał bym by miała potencjał do przyjęcia choć 20 slave-ów na przyszłość a to już 5 pinów i grubszy kabel.

    Możesz użyć multipleksowania, lub rejestru równoległo-szeregowego - np. na I2C - masz 8 wejść, a tylko dwoma pinami łączysz z MCU. Można też kodować analogowo - np. stosunkiem dwóch rezystorów i odczytywać kod przez ADC - wtedy to może załatwić tylko 1 pin.
    Jeśli zakładasz możliwość ingerencji użytkownika, to można też zrobić tak, że niezaprogramowany ukłąd nie odpowiada na żadne polecenia na magistrali. Użytkownik wciska przycisk programowanie, master nadaje kod określający adres urządzenia. Ponieważ użytkownik wprowadza tylko jeden układ w tryb programowania, więc nie ma konfliktu.
    Jeśli użyjesz nopwszych proków Atmela., które mają unikalne ID to można też zrobić tak, że odpytujesz o kolejne wartości bitów ID. Zgłaszają się np. te, które na kolejnych bitach mają np. 1, w końcu zostanie ci tylko jedno urządzenie, któremu nadajesz adres i w ten sposób usuwasz go z kolejki. następnie powtarzasz proces, aż do momentu, kiedy wszystkie urządzenia są zaprogramowane. Jeśli MCU nie ma ID to można wygenerować wystarczająco długą liczbę pseudolosową i postąpić analogicznie. Jest wiele rozwiązań, pytanie tylko, czy czasem niepotrzebnie sobie nie komplikujesz życia i takie funkcjonalności naprawdę są potrzebne?
  • #19
    Elektromechanik88
    Level 3  
    Quote:
    Jesteś dziesięć wersji "do tyłu". Aktualny Bascom ma numer 2083.


    Bascoma zaktualizowałem do najnowszej wersji, nie lubię zmieniać czegoś co działa i jest dobre, ale w przypadku bascoma ta zasada się nie sprawdza :)

    Co do stałych to próbowałem coś takiego zrobić, ale wywala błąd 258 w nowym również, ciąg zn jest zbyt długi, dla tego właśnie mówiłem że mam problem ze stałymi.

    Code: vbnet
    Log in, to see the code


    Quote:
    Niepotrzebnie komplikujesz prostą sprawę. Jak chcesz im nadawać "niepowtarzalne MAC`i" to równie dobrze możesz im nadać adres we flash czy eeprom.


    Quote:

    Jest wiele rozwiązań, pytanie tylko, czy czasem niepotrzebnie sobie nie komplikujesz życia i takie funkcjonalności naprawdę są potrzebne?


    Macie Panowie rację obaj, trochę mnie to przerasta jeszcze. Zastosuję się na razie do rozwiązania kolegi Bart-project z tym dip switchem. A kiedyś jak odpowiednio się podszkolę spóbuje zrobić taki automat.
    nie mam dip switchy więc na razie listwa kołkowa i zworki od kompa, działa tak samo ;)

    Z tym kablem źle zinterpretowałem pomysł kolegi i dlatego to nieporozumienie
  • #20
    bart-projects
    Level 26  
    Nie mogę potwierdzić tego co napisałeś bo przed chwilą dodałem to do swojego projektu a zaraz potem kompilowałem na próbę:

    Const Lista_znakow = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

    ..i nawet się nie zająknął. Kręcisz coś? :>

    Stałe chodzą jak marzenie i to nie od tej wersji a dla danych HTTP/ogólnie NET/ które maja więcej niż 256 znaków należy użyć dyrektywy $bigstrings

    Proszę zrób zrzut ekranu z kompilacji gdzie pisze "Error at line xxx" z najkrótszym kodem jaki się da. Bez dowodu to tak nieładnie ;)
    Poniżej screen po kompilacji tej stałej na najprostszym przykładzie - bez błędów.
    BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń
  • #21
    Elektromechanik88
    Level 3  
    Quote:
    Proszę zrób zrzut ekranu z kompilacji gdzie pisze "Error at line xxx" z najkrótszym kodem jaki się da. Bez dowodu to tak nieładnie ;)
    Poniżej screen po kompilacji tej stałej na najprostszym przykładzie - bez błędów.


    Proszę bardzo, oto screen. Może faktycznie coś robię źle, krótsze stałe typu string działają a ta zawsze mi błąd wywala.

    BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń

    Nie lubię pokazywać takich "wywijasów" jak mój kod mam obawę że ktoś mnie wyśmieje i powie "to normalnie jakiś cud że taki twór działa". No ale nie jestem zawodowym programistą i nie umiem pięknie pisać kodów ;)

    Code: vbnet
    Log in, to see the code


    ta zmienna działa z tym co poniżej

    Code: vbnet
    Log in, to see the code


    Code: vbnet
    Log in, to see the code


    Z tego co wkleiłem raczej nie da się odtworzyć tego co na filmie, ale tak to działa i się nie wiesza.


    [/youtube]


    ps> przepraszam za wstawioną zmienną dim cholota as byte , nazwy mi wtedy brakło :D
  • #22
    bart-projects
    Level 26  
    Napisz "wolny przesuw" przez u otwarte, "krótki" przez o zamknięte a "hołota" przez samo h i może ruszy :D
    ...a tak poważniej to na screenie widać, że błąd jest w liniach 479 i 711 więc tam należy szukać. Kliknij w linię informujacą o błędzie to Cię tam przeniesie. Czasem te komunikaty o błędach nie są precyzyjne i wcale nie musi chodzić o zmienną "lista_znakow" a o jakąś inną zmienną w tych liniach. Być może porównujesz gdzieś string do byte (lub odwrotnie). Na przykład Len(lista_znakow) to już jest Byte a nie String.
    W Bascom dodano kilka ułatwień. Można od razu w kodzie podglądać jakiego typu jest zmienna przytrzymując Shift i najeżdżając kursorem. Równie szybko można się przenieść do deklaracji takiej zmiennej przytrzymując Control i klikając w zmienną. Tak samo można w kodzie przeskakiwać do funkcji. Co ciekawe Control + Backspace pozwala szybko wrócić w miejsce z którego skoczyłeś. To pozwala szybciej "poprawiać" potrzebne sprawy bez nużącego przewijania kodu.

    W kodzie można też wstawić osiem markerów.
    Control + K + [1-8] stawia marker.
    Jak chcesz wrócić do markera klikasz Control + Q + np.1
    To również pozwala szybciej poruszać się po kodzie.
  • #23
    Elektromechanik88
    Level 3  
    Witam.

    Quote:
    ...a tak poważniej to na screenie widać, że błąd jest w liniach 479 i 711 więc tam należy szukać. Kliknij w linię informujacą o błędzie to Cię tam przeniesie.


    Sprawdzałem już te linie wcześnieśniej.

    Code: vbnet
    Log in, to see the code



    Konkretnie tu:
    Dodaj_litere = Mid(lista_znakow , Kursor_wybr_litera , 1)
    Wygląda na to że Mid nie przyjmuje stałych
  • #25
    Elektromechanik88
    Level 3  
    No tak, ale błąd wywala mi właśnie w momencie gdy z tej zmiennej robię stałą

    Code: vbnet
    Log in, to see the code



    Quote:
    ...a tak poważniej to na screenie widać, że błąd jest w liniach 479 i 711 więc tam należy szukać.


    błąd linii 479 po zmianie zmiennej Lista_znakow na stałą wskazuje na te linie.
    Linia 711 to ten sam błąd bo zrobiłem w kodzie dwie prawie identyczne procedury tyle że ta druga dopiero działa po wyłączeniu zasilania procka(kiedy sczyta on konfigurację ze swojej pamięci eeprom)

    Dodaj_litere = Mid(lista_znakow , Kursor_wybr_litera , 1)
  • #26
    Elektromechanik88
    Level 3  
    Witam.
    Kolego Bartku, odnośnie jeszcze ramki do rs485 czy jest możliwość wysłania ramki w formie 1 bajta i parsowania jej, tzn:

    mamy ramkę 1byte
    01110001 z czego cztery ostatnie bity 0111 to komenda a cztery pierwsze 0001 to ID(id od 0 do 15)
    Chciałem tak zrobić ponieważ dołączę do każdego slavea po 2 czujniki i w bajcie mogę przypisać im pozycję na określonych bitach np:
    KOMENDY:
    0001 to czujnik wiązki lasera
    0010 to czujnik ruchu
    0011 to czujnik ruchu + wiązka lasera

    Zrobiłem coś takiego tyle że int do przesłania konwertuję na ramkę string a później odbiornik dekoduję do int.

    BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń

    Id ustawiam jak kolega zalecił:

    BASCOM, AVR, RS485, kłopot z komunikacją kilku urządzeń

    Czy warto brnąć w takie rozwiązanie dla ramki?
  • Helpful post
    #27
    bart-projects
    Level 26  
    Rób sobie jak chcesz bo można zrobić dokładnie wszystko tak jak chcesz jeśli tylko sprzęt "wyrobi".
    Natomiast myślę, że nie masz tego projektu przemyślanego od początku do końca. Coś opracowaliśmy, teraz zmiana zdania/metody/ramki.

    Ograniczając się do jednego bajtu sam sobie ograniczasz cały system.
    Można to OD RAZU zrobić przyszłościowe i z zapasem na inne funkcje które pewnie za chwile będziesz chciał dołożyć. Apetyt rośnie...

    Takie "dekodowanie na bitach" to już bym rozwiązał jak modbus bez (lub nawet z) checksum.
    Modbus polega na tym że Układ otrzymuje bajt i ustawia Timer na czas 1,5 długości trwania nadawania/odbierania jednego Bajtu przy danej prędkości. Jak w czasie 1x nadejdzie nowy bajt to Timer liczy od nowa. Jak nic nie nadejdzie w przeciągu 1,5x to zaczyna parsować dane.
    Możesz więc wysłać 1, 2, 3 a nawet 4 bajty i coś tam odczytywać/sterować.

    Ogólnie rzecz biorąc jeden bajt to jeszcze pomniejszając o adres jest bardzo ograniczającym na przyszłość rozwiązaniem.
    Za miesiąc post "To i to mi działa super (z dumą). Co zrobić by dodać kolejną funkcję".

    Nawet podejście inne czyli nie "jeden bit oznacza konkretne wejście" a suma bitów daje na czterech bitach szesnaście możliwości.
    Przemyśl to dobrze bo szkoda klawiatury :D
  • #28
    Elektromechanik88
    Level 3  
    Dziękuję za pomoc, zamykam temat.