C# datareceive Problemi

Başlatan hadesi, 19 Haziran 2022, 10:12:24

hadesi

arduinodan gelen verimi sıkıntısız bir şekilde c# a çekiyorum ancak bir süre sonra herhangibir butona tıkladığımda timer 2 yi hiç bir şekilde çalıştıramıyorum porta bağlanmadan basınca sıkıntı yok çalışıyor ama porta bağlandıktan sonra timerı hiç bir türlü çalıştıramıyorum. Yardım ederseniz sevinirim. C# ta biraz amatörüm umarım sorunumu anlatabilmişimdir.
public partial class Form1 : Form
    {
        string[] portlar = SerialPort.GetPortNames();
        public Form1()
        {
            InitializeComponent();
            serialPort1.BaudRate = 9600;
            Control.CheckForIllegalCrossThreadCalls = false;
        }
        int x, y = 0,bekleme=30,calisma=5,bekleme1=30,a=0;
        double ec1 = 5;
        

        private void Form1_Load(object sender, EventArgs e)
        {
            foreach (string port in portlar)
            {
                comboBox1.Items.Add(port);
                comboBox1.SelectedIndex = 0;

            }
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
            
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string data;
            string[] splitted_data;
            data=serialPort1.ReadLine();
            splitted_data = data.Split('-','.');

            label1.Text = data;

            double a, b, c, d,isi,ec;
            a = Convert.ToInt32(splitted_data[0]);
            b = Convert.ToDouble(splitted_data[1]);
            c = Convert.ToInt32(splitted_data[2]);
            d = Convert.ToDouble(splitted_data[3]);

            /////ısı-hesaplama/////
            d = d / 100;
            isi = c + d;
            label2.Text = "derece: " + isi.ToString();
            ////Ec Hesaplama/////
            b = b / 100;
            ec = a + b;
            label3.Text = "EC: " + ec.ToString();
            if (ec<ec1)
            {
                if (bekleme == bekleme1)
                {
                    
                    bekleme = 0;
                    
                    label12.Text = "Motor Çalışıyor";
                    timer2.Start();
                    button5.BackColor = Color.Green;

                    
                }
            }
            else
            {
                label12.Text = "Motor Çalışmıyor";
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)
            {
                serialPort1.PortName = comboBox1.Text;
                try
                {
                    serialPort1.Open();
                }
                catch (Exception)
                {
                    
                    throw;
                }
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            y = Convert.ToInt32(trackBar1.Value);
            label9.Text = trackBar1.Value.ToString();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            
        }

        private void button3_Click_1(object sender, EventArgs e)
        {
            ec1 = Convert.ToDouble(textBox1.Text);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            label15.Text = "b";
        }

        private void timer3_Tick(object sender, EventArgs e)
        {

        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            a++;
            label17.Text = a.ToString();
            /*if (bekleme==calisma)
            {
                bekleme = 0;
                label12.Text = "motor durdu";
                timer2.Enabled = false;
            }*/
        }

        private void button7_Click(object sender, EventArgs e)
        {
            timer2.Start();
        }

        private void label3_Click(object sender, EventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            label4.Text = DateTime.Now.ToString();
            byte i;
            string[] yazi;
            yazi = label4.Text.Split(':', '.', ' ');

            for (i = 0; i <= yazi.Length - 1; i++)
            {
                x = Convert.ToInt32(yazi[5]);
                if (y>x)
                {
                    label7.Text = "Motor Çalıştı";
                    button4.BackColor = Color.Green;
                    if (serialPort1.IsOpen)
                    {
                        serialPort1.Write("0");
                    }
                }
                else
                {
                    label7.Text = "Motor Durdu";
                    button4.BackColor = Color.Red;
                    if (serialPort1.IsOpen)
                    {
                        serialPort1.Write("0");
                    }
                }
            }
        }
    }

foseydon

hocam debug edebilir musun? timer2'yi datarecived icerisinde calistiriyorsun ustelik kosul var. bu durumda 2 alternatif var.
1. datareceived giriyor, kosul calismiyor.
2. datareceived hic girmiyor, yani veri gelmiyor.

bu arada serialport eventleri sikintili. ben burada daha once bi makale paylasmistim konu ile alakali. bunun yerine timer kullanin daha guvenli olur demisti. usenmezsen benim iletilere bak, C# diye aratirsan cikar sanirim. yazilari bi kontrol et gorursun. bu konularda daha onceden baya yazmistim cunku. tekrar yazmaya useniyorum

hadesi

#2
datareceived a giriyor sıkıntısız veri çekiyor ama koşul ile timerı çalıştıramıyorum. Koşuldamı sıkıntı var diye butonun içine timer attım serial porta bağlanmadan sıkıntısız çalışıyor ama serial porta bağlandığımda çalışmıyor bir süre sonra. Bundan önce verileri timer ile çekiyordum ondada sıkıntı çıkıyor program donuyor.
şu dersteki kodları uyguladım açıkça söylemek gerekirse

muhittin_kaplan

#3
thread nedir, c# da thread kullanımı nasıldır?

hadesi

thread i bilmiyordum araştırdım genelde örnekler for döngüsüyle açıklanmış c# form da thread ile timer çalıştıranı bulamadım. Bulabilsem sorunum hallolacak gibi.

hadesi

public void thread()
        {
            for (int i = 0; i < 1000000; i++)
            {
                try
                {
                    string sonuc = serialPort1.ReadLine();
                    string[] pot = sonuc.Split('-', '.');
                    label1.Text = sonuc + "";
                    
                    a = Convert.ToInt32(pot[1]);
                    label3.Text = a.ToString();
                    if (a>1)
                    {
                        if (bekleme==30)
                        {
                            bekleme = 0;
                            timer1.Start();
                        }
                    }
                    Thread.Sleep(1000);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    throw;
                }
            }
şöyle bişey yaptım verileri timer yerine for ile çekmeye çalıştım sıkıntısız çekiyor ama thread ile çalıştırdığım for döngüsünün içine timer1.start yazdığımda timer buga giriyor. normal butona atadığımda timerı sıkıntısız çalışıyor.

yas

C# kullanmıyorum, ama öneride bulunmak istedim acaba timer nesnesini public olarak mı atamak gerek.

muhittin_kaplan

uzun zamandır c# yazmıyorum.
Masaüstünde bir işi yaparken, mesala bir form u ekranda göstermek gibi, başka bir işle mesgul olmak isterseniz mesela prt dinlemek gibi (veri geldiğini nerden anlayacak)işte burada thread, multiprocess gibi ayrık işler kullanmanız gerekir.
Neden ?
ekranda bir form u göstermk bile bir iş parcasıdır ve devamlı yapılmalıdır ki kullanıcı formu biryere taşırken boyutlandırırken, işlemcinin diğer iş parçacını yapması dolayısıyla donmalar yaşamasın.

Bunun için yeni bir thread yaratılıp bu theradın ana thread ı (form işlemleri örneğin) kesintiye ugratmadan port u dinlemesi ve gelen bir veri olursa ana thread la iletişim kurup "bak bu geldi alabilirsin formuna demesi gerekir.

https://www.picproje.org/index.php/topic,76385.msg583218.html#msg583218

https://www.picproje.org/index.php/topic,70627.msg541714.html#msg541714

https://www.picproje.org/index.php/topic,64626.msg500784.html#msg500784

https://www.picproje.org/index.php/topic,59768.msg461826.html#msg461826

https://www.picproje.org/index.php/topic,50376.msg379540.html#msg379540

foseydon

hemen bisey ekliyim. timer GUI'nin calistigi thread'de calisir. bu yuzden veri isleme isini timer'da yaparsaniz sorununuz cok hizli cozulur.

muhittin_kaplan

Alıntı yapılan: foseydon - 25 Haziran 2022, 19:43:24hemen bisey ekliyim. timer GUI'nin calistigi thread'de calisir. bu yuzden veri isleme isini timer'da yaparsaniz sorununuz cok hizli cozulur.
Bence hatalı bir öneri.
Timer ile bir portu dinliyorsanız veri kaçırma ihtimaliniz yüksektir.
Timer ı kurdunuz. Timer veri geldi dedi. Almaya başladınız. Bu esnada gui nin threadı ne durumda olacak ?

foseydon

Alıntı yapılan: muhittin_kaplan - 25 Haziran 2022, 20:13:00Bence hatalı bir öneri.
Timer ile bir portu dinliyorsanız veri kaçırma ihtimaliniz yüksektir.
Timer ı kurdunuz. Timer veri geldi dedi. Almaya başladınız. Bu esnada gui nin threadı ne durumda olacak ?

veriyide timer'in icerisinde toplayacaksiniz zaten? ben bu sekilde yapiyorum. veri hic kacmaz.

muhittin_kaplan

Timer i ntervali nedir, eğer timer intervali çok hızlıysa form da donmalar, yavaş ise veride kaçaklar oluşur. Keskin kılıç. Doğrusu Thread dır.

foseydon

Alıntı yapılan: muhittin_kaplan - 25 Haziran 2022, 22:30:58Timer i ntervali nedir, eğer timer intervali çok hızlıysa form da donmalar, yavaş ise veride kaçaklar oluşur. Keskin kılıç. Doğrusu Thread dır.

hocam threadpool kullandim, backgroundworker kullandim vs. en randuman aldigim sistem timer. illa 1 tane timer olacak diye birsey de yok. 2-3 tane timer kurupta yapabilirsin islerini. timer sureleri degisken. 100mste olur 1000mste olur. data hizina gore ayarlarsin. 9600 baud standart 1200 byte yapar saniyede. islemesi citir cerez bilgisayar icin zaten. seriaport buffer'ini da tasiman pek olasi degil ki zaten buffer boyutunu da buyutebilirsin, seriport'un buffersize property sini kullanarak. formda donmasi icin cok uzun sure islem yapman lazim. oyle agir islem gerektiren birsey varsa, o zaman iste arka planda isletip sonra guncellemek daha dogru oluyor. ama o kadar agir islem gerektirecek bisey de lazim olmuyor. sonucta bilgisayarda genelde yaptigin is gelen veriyi goruntuleme, parametre gonderip degistirme.

tunayk

Thread ile çalışmanın korukulacak bir yanı yoktur.  Form uygulamalarında, hertürlü IO işlemlerinin (Dosya, Ağ, Ser port, veritabanı işlemleri  vb.) timer ile yapılması genel olarak doğru bir yol değildir.  Yapılmaz değil ancak önerilen yol değildir. Bunu MSDN deki örneklerde de farklı referanslarda da açıkça görebilirsiniz. 
Buradaki temel prensip, dış kaynak kullanacak işlemlerde dış kaynağın dönüş hızı keskin olarak garanti edilemeyeceğinden formla aynı thread içinde yapılacak hareketler az veya çok donmaya neden olur. Miktarı uygulamanın karmaşıklığına bağlı olarak değişir. Yorum farkları biraz buradan kaynaklanıyor.  250ms de bir 10byte gönderen bir uygulamada bu hissedilmez. Aynı uygulama hem seri portta haberleşme yapıp, hem veritabanına birşeyler yazıp okuyacak, hem ekranda hızlı grafikler çizecekse işler değişir. Hepsini form timer ile çözelim derseniz uygulama ancak çok güçlü makinalarda çalışabilecektir.

Seri portta veri kaçırma ihtimali görece düşük bir itimal.  Windows tarafında 2k kadar bir input buffer olduğundan pek sorun yaşanmaz. Ancak alınan dataya hızlı reaksiyon gerekli ise daha farklı düşünmek lazım.

Sözün özü windows uygulamasında kurgulanan mimari ile uygulama örtüşüyor ise sorun yok. Ancak bu çözüm her zaman en iyi çözüm olmayabilir.

bocek


Sorunun çözümü burada anlatılıyor.

Salih Cantekin'in anlatımı çok güzel.
Ele aldığı konuları sıfırdan başlayarak anlatıyor.
1 ya da 0. işte 'bit'ün mesele..