čtení ze sériového portu   zodpovězená otázka

VB.NET

Prošel jsem si snad všechny zdejší příspěvky na téma komunikace přes sériový port, ale odpověď na řešení mého problému jsem nenašel.

Takže, takto komunikuji a portem:

Private Sub SpojitMon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SpojitMon.Click
        SerialPort3.PortName = PorMon.Text
        SerialPort3.BaudRate = CInt(BauMon.Text)
        SerialPort3.Parity = CInt(ParMon.Text)
        SerialPort3.DataBits = CInt(DatMon.Text)
        SerialPort3.StopBits = CInt(StoMon.Text)
        SerialPort3.ReceivedBytesThreshold = 1
        SerialPort3.Open()
End Sub

Private Sub SerialPort3_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort3.DataReceived
        If Me.InvokeRequired() Then
            Dim dr As New DataRecievedDelegate(AddressOf DataFromMontage)
            Me.Invoke(dr, e, SerialPort3.ReadExisting())
        Else
            DataFromMontage(e, SerialPort3.ReadExisting())
        End If
End Sub

Private Sub DataFromMontage(ByVal e As System.IO.Ports.SerialDataReceivedEventArgs, ByVal linka As String)
        Dim data As String = linka
        PokusLabel.Text = linka
End Sub

Private Sub Pokus_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Pokus.Click
        SerialPort3.Write(":CC#")
End Sub

Mělo by to fungovat tak, že po stisku tlačítka "Pokus", se přes port pošla do zařízení řetězec ":CC#", který řekne zařízení, že mi má poslat zpět desetiznakový řetězec, který se snažím zachytit přes "SerialPort3_DataReceived"...

Ale, po prvním stisku tlačítka "Pokus" se (většinou) v "PokusLabel" objeví to, co má (10znaků), ale po dalších stiscích tohoto tlačítka se v labelu už neobjeví těch potřebných 10 znaků, ale třeba jen 4, 6, nebo ale třeba i jen jeden znak.

Nemůžu přijít na to, co s tím. Pokud si do kódu vložím Breakpoint, třeba do "Sub Pokus_Click..." a pak po spuštění (F5), když se mi to zastaví na tom Breakpointu a já následně pokračuji pomocí stisků F8 a provádím jednotlivé kroky kódu, tak proměnná "linka" (nebo "data")a následně i "pokuslabel" VŽDY obsahuje to, co má- a to po každém stisku tlačítka "Pokus". Ale pokud to spustím bez toho Breakpointu, tak to dělá to, co jsem psal.

V zařízení rozhodně problém není, protože jiná aplikace, dodaná k zařízení, zobrazuje přijímaná data správně...

Máte někdo nápad, co s tím?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Naprosto přesně stejnou věc jsem řešil při psaní software pro automatizované odesílání a příjem zpráv SMS pomocí modemu připojeného do sériového portu.

Tento problém je značně závislý na použitém hardware, konkrétně čipové sady řídící sériový port. Dále to závisí na nastavení portu ve Windows a na konfiguraci sériového portu v samotném programu. Sral jsem se s tím několik dní, vyzkoušel všechny možné knihovny třetích stran pro komunikaci se sériovým portem, až nakonec vše zahodil a použil knihovnu pro práci s modemem, kde není nutné obsluhovat sériovou komunikaci.

U jedné knihovny, kterou jsem také zkoušel, jsem s tímto kontaktoval přímo jejího autora:

https://serialportstream.codeplex.com/di...

Co s tím? No mohu vám poradit jen to, co jsem bez úspěchu zkoušel já - knihovny třetích stran.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

A sakra, myslel jsem si, že mám jen někde nějakou stupidní chybu v kódu...

Ale pořád mi nejde na rozum, proč když to spouštím po řádcích pomocí F8, tak je VŽDY vše v pořádku, jakmile to ale spustím klasicky, bez Breakpointu, tak mám ten problém. Jako kdyby to prostě někde nějak něco nestíhalo.

Nemůžou na to mít vliv takové věci, jako ReadTimeout, RecievedBytes, ReadBufferSize, RecievedBytesThreshold...? Ani pořádně nevím, co tyto "věci" znamenají :(

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No nevím, ale začalo mi to fungovat. Jediné, co jsem změnil, je RecievedBytesThreshold=10 (nějak my to přijde logické, pokud chci načíst 10 znaků...)

Je ale zajímavé, že pokud nastavím např. RecievedBytesThreshold=1, tak přesto po prvním stisku tlačítka Pokus se mi v PokusLabel objeví všech potřebných 10 znaků, až další stisk udělá ty zmatky...

I tak dík.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nemyslete si, že jste to vyřešil. Strávil jsem s tím drahně času včetně experimentování s různými nastaveními. Ač se v jednu chvíli může zdát, že to začalo fungovat, při opakovaných pokusech se to může začít chovat naprosto nepředvídatelně. Uvidíte sám. Pokud nevíte, co ty vlastnosti ovlivňují, tak urychleně nastudovat.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dík za povzbuzení :).

OK, uvidím, jak dlouho a s jakou stabilitou to bude fungovat.

Bohužel ale,funkčnost této komunikace je pro můj projekt naprosto nutná.

Vlastnosti nastuduji...

Dík.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Problém je pravděpodobně v tom, že špatně používáte událost DataReceived. Ta totiž negarantuje, že je volána pro všechny přijatá data, ale pouze pokud je k dispozici alespoň ReceivedBytesThreshold bajtů.

viz. Tip 2 zde:

http://blogs.msdn.com/b/bclteam/archive/...

Řešením by mohlo být v obsluze události DataReceived koukat na vlastnost BytesToRead a opakovaným voláním Read načíst všechna tyto data.

Jiným řešením by bylo událost DataReceived vůbec nepoužívat a data načítat ve vlastním pomocném threadu hned tak jak přichází (opakovaně s nějakým timeoutem) a do UI je vrátit například pokud již nějakou dobu žádná data nepřichází.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Pročetl jsem si ten příspěvek, a myslím, že to chápu. Nicméně si myslím, že právě tím, že jsem si v příspěvku výše nastavil právě ten RecievedBytesTreshold=10, tak je to právě to správné (pokud chci číst deset znaků). Myslím, že pokud vím, kolik znaků by mi měl hardware vracet, tak by to mohlo fungovat. Zatím to funguje- uvidím, jak dlouho.

Jiným řešením by bylo událost DataReceived vůbec nepoužívat a data načítat ve vlastním pomocném threadu hned tak jak přichází (opakovaně s nějakým timeoutem) a do UI je vrátit například pokud již nějakou dobu žádná data nepřichází.

Toto bych asi sám nezvládl :( ...

Dík.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ten příjem bez použití události DataReceived by mohl v kódu vypadat nějak takto:

internal class SerialPortReader : IDisposable
{
    #region member varible and default property initialization
    private string COMPort;
    private Thread ComunicationThread;
    private AutoResetEvent InitializedResetEvent;
    private bool IsDisposed;
    #endregion

    #region constructors and destructors
    public SerialPortReader(string COMPort)
    {
        this.COMPort = COMPort;
        this.InitializedResetEvent = new AutoResetEvent(false);
        this.ComunicationThread = new Thread(new System.Threading.ThreadStart(ComunicationThreadProc));
        this.ComunicationThread.Start();

        //Čekání na dokončení inicializace vlákna
        this.InitializedResetEvent.WaitOne();
    }
    #endregion

    #region action methods
    public void Dispose()
    {
        if (!this.IsDisposed)
        {
            this.IsDisposed = true;
            if (!this.ComunicationThread.Join(5000))
            {
                this.ComunicationThread.Abort();
            }
            this.ComunicationThread = null;

            this.InitializedResetEvent.Close();
            this.InitializedResetEvent = null;
        }
    }
    #endregion

    #private member functions
    private void ComunicationThreadProc()
    {
        try
        {
            using (var port = new System.IO.Ports.SerialPort(this.COMPort, 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One))
            {
                port.Handshake = System.IO.Ports.Handshake.None;
                port.DtrEnable = true;
                port.RtsEnable = true;
                port.Open();

                DateTime? lastReceivedTime = null;
                var buffer = new StringBuilder();

                while (!this.IsDisposed)
                {
                    string receivedData = port.ReadExisting();
                    if (receivedData.Length != 0)
                    {
                        lastReceivedTime = DateTime.UtcNow;
                        buffer.Append(receivedData);
                    }

                    if (lastReceivedTime != null && DateTime.UtcNow.Subtract(lastReceivedTime.Value).TotalMilliseconds >= 400)  //Timeout na příjem všech dat
                    {
                        OnReceivedData(buffer.ToString());
                        lastReceivedTime = null;
                        buffer = new StringBuilder();
                    }

                    //Signalování dokončení inicializace threadu
                    InitializedResetEvent.Set();

                    Thread.Sleep(500);
                }
            }
        }
        catch (ThreadAbortException)
        {
            //Ignore exception
        }
        catch (Exception ex)
        {
            OnComunicationException(ex);
            //Signalování dokončení inicializace threadu
            InitializedResetEvent.Set();
        }
    }

    private void OnReceivedData(string receivedData)
    {
        //TODO: Send receivedData to UI
    }

    private void OnComunicationException(Exception ex)
    {
        //TODO: Display ex in UI
    }
    #endregion
}
nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Nechce se mi zakládat nové téma, tak budu pokračovat zde (jelikož se to stále týká Com portů):

Potřebuji zjistit jména všech dostupných COM portů. Není pro mě problém získat jména ve formátu:

COM1

COM3

COM4

...

, ale já bych potřeboval k těm "suchým" jménům i podrobnější popis, takový, který je např. ve Správci zařízení.

např: "COM1- Silicon COM Port emulator", prostě abych z popisu poznal, který hardware je připojený na který port.

Je možné se dostat k těmto informacím?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Už jsem na to přišel...

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback