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

C# RS232 - Niepoprawne działanie programu przy pełnym uruchomieniu

bartek_zet 24 Lut 2007 01:00 7967 10
REKLAMA
  • #1 3610115
    bartek_zet
    Poziom 17  
    Posty: 311
    Pomógł: 15
    Ocena: 8
    Witam.
    Dopiero uczę się programować transmisję po RS'ie. Napisałem program do procka który odbiera wysyłany tekst z kompa i zamienia wszystkie małe litry na duże, a następnie odsyła zamieniony tekst z powrotem do komputera. Program na kompie wygląda w ten sposób:
    
                char[] bufor = new char[10];
                int cos = 0;
                string odebrany = "";
                
                serialPort1.Open();
                
                while (!serialPort1.IsOpen)
                {
                }
                
                serialPort1.WriteLine(TBwysylanie.Text);
              
                cos = serialPort1.Read(bufor, 0, 10);
                serialPort1.Close();
    
                for (int i = 0; i < 10; i++)
                {
                    odebrany = odebrany + bufor[i];
                }
    
                TBodbieranie.Text = odebrany;


    Jak uruchamiam go krokowo to wszystko jest ok. W tekstboxie wyświetla mi się zmieniony tekst. Natomiast jeżeli uruchomię program normalnie (bez żadnych breakpointów) to w tekstboxie pojawia mi się tylko zmieniona pierwsza litera.

    Dlaczego? Jakieś pomysły? Mile widziane komentarze na temat mojego kodu jeżeli widzicie jakąś dziwnie napisaną rzecz.
  • REKLAMA
  • #2 3612296
    Sam Sung
    Poziom 33  
    Posty: 2025
    Pomógł: 227
    Ocena: 604
    Nie wiem, jak to jest w C#, ale może powinieneś ponawiać próby odczytu z portu szeregowego, aż dostaniesz cały tekst. Metoda Read może wrócić po wczytaniu już pierwszego znaku. Uruchamiając program krokowo, dajesz mu więcej czasu pomiędzy WriteLine a Read.
  • REKLAMA
  • #3 3612413
    Badryk
    Poziom 13  
    Posty: 59
    Pomógł: 5
    Ocena: 4
    Nie ustaliłeś prędkości.
    Ja coś takiego wymodziłem w C#
    private void Form1_Load(object sender, EventArgs e)
    {
    int i,j;
    string[] ports = SerialPort.GetPortNames();
    i = ports.GetLength(0);
    for (j = 0; j < i; j++)
    {
    listBox1.Items.Add(ports[j]);
    }
    listBox1.SelectedItem = ports[0];
    comboBox1.SelectedItem = "110";
    }

    private void button2_Click(object sender, EventArgs e)
    {
    serialPort1.PortName = listBox1.SelectedItem.ToString();
    serialPort1.Open();
    serialPort1.BaudRate = int.Parse(comboBox1.SelectedItem.ToString());
    serialPort1.DataBits = 8;
    serialPort1.Write(textBox1.Text.ToString());
    if(0 == int.Parse(serialPort1.BytesToWrite.ToString()))
    serialPort1.Close();
    }
    Nie wiem czy dział jak byś miał możliwość sprawdzenia to daj znać ja nawet com`a nie mam w laptopie.
    Wiesz jak pisać w c# dla usb?[/code]
  • REKLAMA
  • #4 3612490
    bartek_zet
    Poziom 17  
    Posty: 311
    Pomógł: 15
    Ocena: 8
    Sam Sung napisał:
    Nie wiem, jak to jest w C#, ale może powinieneś ponawiać próby odczytu z portu szeregowego, aż dostaniesz cały tekst. Metoda Read może wrócić po wczytaniu już pierwszego znaku

    Ten fragment kodu...
    cos = serialPort1.Read(bufor, 0, 10);

    ...po mojemu odpowiada za odebranie do zmiennej bufor 10 znaków.

    Badryk napisał:
    Nie ustaliłeś prędkości.

    Wszystkie parametry transmisji ustawiłem we właściwościach kontrolki serialPort.
  • Pomocny post
    #5 3612715
    VanThor
    Poziom 19  
    Posty: 224
    Pomógł: 34
    Ocena: 5
    Z opisu metody Read kontrolki SerialPort "Reads a number of bytes from the SerialPort input buffer..." wynika, że pobiera ona bajty, które się znajdują w buforze kontrolki. Możesz otrzymać mniej znaków niż żądasz, jeśli przed upływem ustalonego timeout'u w buforze kontrolki nie znajdzie się odpowiednia liczba znaków.
    Czy i na jaką wartość ustawiłeś właściwość ReadTimeout i jak to się ma do prędkości transmisji i żądanej liczby bajtów?
  • #6 3614096
    bartek_zet
    Poziom 17  
    Posty: 311
    Pomógł: 15
    Ocena: 8
    WriteTimeout i ReadTimeout ustawione na 500ms
    Prędkość 9600 i 10 bajtów.
    W dalszym ciągu działa tylko w trybie krokowym.
  • Pomocny post
    #7 3615551
    VanThor
    Poziom 19  
    Posty: 224
    Pomógł: 34
    Ocena: 5
    To w takim razie opóźnienie wstawione pomiędzy wywołaniami WriteLine a Read też nic nie da? Próbowałeś odczekać np. 1 sekundę przed próbą odbioru? To, że działa w pracy krokowej to silny argument, że chodzi o zależności czasowe.

    A jak bardzo jesteś pewny poprawnego działania programu w mikroprocesorze? Może uwzględnij też ten program.
  • REKLAMA
  • #8 3615745
    bartek_zet
    Poziom 17  
    Posty: 311
    Pomógł: 15
    Ocena: 8
    VanThor napisał:
    To w takim razie opóźnienie wstawione pomiędzy wywołaniami WriteLine a Read też nic nie da?

    Tak właśnie zrobiłem i dało:) Teraz mam kolejne pytanie. Czy jest możliwość zrobienia tego trochę inaczej? Tzn. przykładowo, żeby sprawdzał jakiś znacznik czy zakończono wysyłanie/odbieranie itp i dopiero wtedy przechodził dalej? Czy istnieje jakaś gotowa metoda aby zrobić opóźnienie?
  • #9 3617164
    VanThor
    Poziom 19  
    Posty: 224
    Pomógł: 34
    Ocena: 5
    Do kompensacji opóźnień przy transmisjach są generalnie timeout'y, pozwalające na ustawienie maksymalnego czasu oczekiwania na określoną porcję danych.
    Opóźnienie można zrobić np. poprzez wywołanie metody Sleep z liczbą milisekund jako argumentem jednak wstawianie opóźnień pomiędzy fazy transmisji nie jest dobrym pomysłem i powinno być stosowane jak najrzadziej lub wcale.

    Czy jak ustawisz ReadTimeout na wartość będącą sumą obecnej wartości i wstawionego opóźnienia to działa? Powinno działać.

    Jeśli chcesz sprawdzić ile znaków odebrano do danego momentu możesz odczytać właściwość BytesToRead. Jeśli chcesz zostać powiadomiony o odebraniu danych to możesz wykorzystać event DataReceived z kontrolki SerialPort.
  • #10 3618334
    bartek_zet
    Poziom 17  
    Posty: 311
    Pomógł: 15
    Ocena: 8
    VanThor napisał:
    Czy jak ustawisz ReadTimeout na wartość będącą sumą obecnej wartości i wstawionego opóźnienia to działa? Powinno działać.

    Timeouty ustawione na -1, 100, 1000, 5000 itd. nic nie dają. Wstawienie Sleep(20) rozwiązuje sprawę. Nie wiem jak dokładnie działa metoda WriteLine bo tu w niej raczej jest problem. Dodam, że połączenie jest typu null modem.
  • #11 3621274
    VanThor
    Poziom 19  
    Posty: 224
    Pomógł: 34
    Ocena: 5
    Ten krótki Sleep sugerowałby, że Twój fragment programu nie może być wykonany w jednym kawałku, aby móc poprawnie odbierać. Ten Sleep ma taki efekt, że system przełącza się na inny proces (prawdopodobnie ten proces jest odpowiedzialny za transmisję), a potem wraca do Twojego programu i wywołania metody Read.
    Sam używałem tej kontrolki ale nie pamiętam takich zachowań, nie miałem większych problemów z nią.

    Czy jak ustawiasz ReadTimeout na 5000, to czy faktycznie wraca z wywołania metody Read po 5 sekundach?
    Czy możesz spróbować odczytywać inną metodą niż Read (czyli ReadTo lub ReadExisting) dane z portu i bez tego Sleepa?
    Próbowałeś nadawać za pomocą metody Write a nie WriteLine?

    Być może nie bez powodu w przykładzie w msdn-ie odczyt jest realizowany w osobnym wątku ;)

    Jeszcze kolejny głupi pomysł - może spróbuj poczekać, aż wszystko zostanie wysłane (właściwość BytesToWrite) i dopiero próbuj odczytu?
    Też nie wiem jak działa WriteLine dokładnie, ale nie wydaje mi się, by blokowało się na czas wysyłania.

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemów z transmisją danych przez port szeregowy RS232 w aplikacji napisanej w C#. Program ma za zadanie odbierać tekst z komputera, zamieniać małe litery na duże i odsyłać zmodyfikowany tekst z powrotem. Problem polega na tym, że program działa poprawnie tylko przy uruchomieniu krokowym, a w pełnym uruchomieniu odbiór danych jest niepoprawny. Przyczyną jest fakt, że metoda Read może zwracać mniej znaków niż oczekiwano, jeśli w buforze nie ma jeszcze wszystkich danych, co jest związane z czasem transmisji i brakiem synchronizacji. Zalecane jest stosowanie pętli ponawiającej odczyt do momentu odebrania pełnej liczby bajtów lub wykorzystanie zdarzenia DataReceived do asynchronicznego odbioru danych. Ustawienia timeoutów (ReadTimeout, WriteTimeout) oraz prędkości transmisji (np. 9600 baud) mają wpływ na działanie programu, jednak same timeouty nie rozwiązują problemu. Wstawienie krótkiego opóźnienia (np. Thread.Sleep) między wysłaniem a odczytem danych poprawia działanie, co wskazuje na konieczność uwzględnienia opóźnień transmisji. Alternatywnie można monitorować właściwość BytesToRead, aby sprawdzić, czy dane są dostępne do odczytu. Metoda WriteLine może wprowadzać dodatkowe opóźnienia, dlatego warto rozważyć użycie Write. Zalecane jest również uruchamianie odczytu w osobnym wątku, aby nie blokować głównego wątku aplikacji. Połączenie jest realizowane jako null modem.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA