JohnOz Ответов: 2

Последовательный порт C# используется с таймером и в то время как


Привет, ребята, я написал код о связи последовательного порта, и я хочу использовать таймер, потому что я должен читать отправленные данные непрерывно, не пропуская никаких данных.Чтение и запись данных выполняются в одном и том же коде.Я открываю интерфейс 2 раза и после нажатия кнопки Пуск нажимаю кнопку Отправить.Данные начинают отправляться, и в том же интерфейсе данные получают также я настроил интервал времени приема 250 и интервал времени отправки 500, но я все еще пропускаю данные.Кроме того, иногда может быть задержка в коде.Где же моя вина ?Возможно, в этом есть что-то неправильное, но я не уверен.Я жду ваших ответов.Извините за мой английский.

Что я уже пробовал:

namespace SeriPort
{

    public partial class Form1 : Form
    {

        int i = 0;
        int offsetIndex = 0;
        byte[] sentData = new byte[10];
        byte[] message = new byte[10];
        byte[] byte_buffer = new byte[2048];
        int receivedValidMessageCounter = 0;
        string trial = "";
        int Freq = 0;
        
        public Form1()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();

        }
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {


            int bufferSize = serialPort1.BytesToRead;
            if (bufferSize > 0 && offsetIndex + 10 < byte_buffer.Length)
            {
                serialPort1.Read(byte_buffer, offsetIndex, message.Length);
                offsetIndex = offsetIndex + message.Length;//Read Index
                                                          
            }
            else
            {
                //int a = 0;
            }

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

            if (serialPort1.IsOpen)
            {
                sentData[0] = 0xF1;

                sentData[1] ++;
                sentData[2] = 70;
                sentData[3] = 11;
                sentData[4] = 85;
                sentData[5] = 74;
                sentData[6] = 11;
                sentData[7] = 10;
                sentData[8] = 154;
                sentData[9] = CalCheckSum(sentData);

                serialPort1.Write(sentData, 0, 10);

            }
            else { }


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


            try
            {
                //serialPort1.ReadTimeout = 10;
                timerReceive.Stop();
                while (IsReceivedMessageValid()) // burada headerı ve byte ı kontrol ettiren fonksioyon yaz
                {

                    message[0] = byte_buffer[i];
                    message[1] = byte_buffer[i + 1];
                    message[2] = byte_buffer[i + 2];
                    message[3] = byte_buffer[i + 3];
                    message[4] = byte_buffer[i + 4];
                    message[5] = byte_buffer[i + 5];
                    message[6] = byte_buffer[i + 6];
                    message[7] = byte_buffer[i + 7];
                    message[8] = byte_buffer[i + 8];
                    message[9] = byte_buffer[i + 9];//crc
                    Freq++;
                    receivedValidMessageCounter++;

                    for (int t = 0; t < 10; t++)
                    {
                        trial += message[t].ToString() + "\t";

                        i++;
                    }

                    trial += "\r\n";
                    Freq = 1000 * Freq / timerReceive.Interval;

                }
                textBox2.Text = trial;
                //Application.DoEvents();

                this.Text = "Frequency: " + Freq.ToString() + "Hz" + "- TotalDataReceived:" + receivedValidMessageCounter.ToString();
                Freq = 0;
                //timerReceive.Start();
                timerReceive.Start();
            }

            catch { }

        }

        private bool IsReceivedMessageValid()
        {
            //int bufferSize = serialPort1.BytesToRead;
            if (byte_buffer[i] == 0xF1)
            {
                byte control = 0x00;
                for (int l = 0; l < 9; l++)
                {
                    control ^= byte_buffer[i + l];
                }
                if (control == byte_buffer[i + 9])
                    return true;

            }
            i++;
            return false;





            // header crc kontrolu
            // mesaj byte sayısı kontrolu
            //

        }

        private void Form1_Load(object sender, EventArgs e)
        {


            string[] portlar = SerialPort.GetPortNames();
            comboBox1.Items.AddRange(portlar);

            textBox1.Text = Properties.Settings.Default.textbox;
            //comboBox1.Text = Properties.Settings.Default.combobox;

            if (comboBox1.Items.Contains(Properties.Settings.Default.combobox))
                comboBox1.SelectedIndex = comboBox1.Items.IndexOf(Properties.Settings.Default.combobox);
        }
        bool c = false;

        private void button1_Click(object sender, EventArgs e)
        {

            if (c)
            {
                c = false;

                button1.Text = "Start";
                textBox1.ReadOnly = false;
                comboBox1.Enabled = true;
                label9.Text = "Paused";
                label9.ForeColor = Color.Red;
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();

                }
                else { }
                timerSend.Stop();
                timerReceive.Stop();
            }
            else
            {
                c = true;
                try
                {

                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(textBox1.Text);
                    serialPort1.DataBits = 8;
                    serialPort1.Parity = Parity.None;
                    serialPort1.StopBits = StopBits.One;
                    if (!serialPort1.IsOpen)
                    {
                        serialPort1.Open();
                        // serialPort1.ReadTimeout = 1200;

                    }

                    else
                    {

                    }

                    button1.Text = "Stop";
                    textBox1.ReadOnly = true;
                    comboBox1.Enabled = false;
                    label9.Text = "Sending...";
                    label9.ForeColor = Color.Green;
                    timerReceive.Start();



                }
                catch
                {
                    MessageBox.Show("Please enter number", "Error");
                    c = false;
                }
            }
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (checkBox1.Checked)
            {

                Properties.Settings.Default.textbox = textBox1.Text;
                Properties.Settings.Default.combobox = comboBox1.Text;
                Properties.Settings.Default.Save();
            }
            else { }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            timerSend.Start();

        }
        static private byte CalCheckSum(byte[] byteBuffer)
        {
            byte _CheckSumByte = 0x00;
            for (int a = 0; a < byteBuffer.Length - 1; a++) //CheckSumı headerdan itibaren kontrol ettir!
                _CheckSumByte ^= byteBuffer[a];

            return _CheckSumByte;
        }



    }
}

2 Ответов

Рейтинг:
5

raddevus

Первая и самая очевидная вещь, которую я вижу, - это два обработчика событий тика таймера:

timer1_Tick

timer2_Tick


Внутри этих обработчиков таймера вам нужно останавливать таймер каждый раз, когда выполняется код таймера. Если вы этого не сделаете, то обработчик событий таймера может быть снова введен в другой поток, и ваши данные могут выйти из синхронизации, что, вероятно, является причиной отсутствия чтения и/или записи.

В верхней части кода (в каждом обработчике событий таймера), как только вы введете нужный вам обработчик
private void timer1_Tick(object sender, EventArgs e)
 {
      timer1.Stop();
      try{
         // all your other code here
       }
      finally{
       // finally code will run even if there is an exception so you 
       // want to insure the timer gets started again, so you put it in this 
       /// finally section
       timer1.Start();
      }
}


Это, вероятно, исправит ваш код. Но могут быть и другие проблемы. Это только одна вещь, которую я сразу заметил, которую нужно изменить, чтобы заставить ее работать.
:)


JohnOz

Спасибо мой друг ты мой герой :)

raddevus

Я так долго ждал, чтобы стать героем, но я знал, что однажды у меня это получится. :D рад, что это помогло.

Рейтинг:
2

CPallini

Почему вы используете таймер для чтения? Используйте DataReceived[^] вместо этого обработчик событий. Смотрите, например Последовательная связь в C# для начинающих[^].


TheRealSteveJudge

Хороший совет! 5*

CPallini

Спасибо, Стив.

JohnOz

Мой директор сказал мне ,что я должен использовать таймер, на самом деле я также не знаю, почему я должен использовать таймер:(

CPallini

Ты не должен этого делать.

Richard MacCutchan

Использование таймеров-плохая идея, так как вы понятия не имеете, как быстро или медленно будет работать последовательный порт на самом деле. Используйте обработчики событий, как предлагает CPallini, чтобы вы получали уведомления, когда в системе есть какие-то данные для чтения.