Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/34: Рейтинг темы: голосов - 34, средняя оценка - 4.85
0 / 0 / 0
Регистрация: 25.05.2012
Сообщений: 4
1

Работа с COM-портом, с течением времени данные искажаются

25.05.2012, 18:42. Показов 7069. Ответов 6
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Доброго времени суток!

Потребовалось написать небольшую программу для работы с COM-портом, которая принимает от микроконтроллера пакет данных фиксированной длины. Решил использовать для своей задачи класс System.IO.Ports.SerialPort. Столкнулся со следующей проблемой: запускаю программу, сначала она выдаёт корректные данные, но по истечении некоторого времени данные "портятся". Смотрел лог принятых пакетов и выяснил, что время это зависит от размера входного буфера ReadBufferSize и если его увеличить, то "правильные" пакеты идут дольше, но буфер все равно переполнится. Таким образом сделал вывод, что команды чтения ReadByte и Read не очищают буфер.

Вот код программы:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
 
using System.IO.Ports; 
using System.Runtime.InteropServices;
using System.IO;
 
namespace COM_Test
{
    public partial class Form1 : Form
    {
        SerialPort Port = new SerialPort();        
 
        delegate void GetByteCallback(int Byte);   
 
        int[] Speed = new int[12] { 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200 };
        int[] DataBits = new int[2] { 7, 8 };
        Encoding[] Encodings = new Encoding[6] { Encoding.ASCII, Encoding.BigEndianUnicode, Encoding.Unicode, Encoding.UTF32, Encoding.UTF7, Encoding.UTF8 };
 
        private const int inPacketSize = 56;                 
        private byte[] inPacket = new byte[inPacketSize];    
      
 
        public Form1()
        {
            InitializeComponent();
        }
 
       
        private void GetByte(int Byte)
        {
            if (this.txtTerminal.InvokeRequired)
            {
                GetByteCallback GetB = new GetByteCallback(GetByte);
                this.BeginInvoke(GetB, new object[] { Byte });
                //this.Invoke(GetB, new object[] { Byte });               
            }
            else
            {                            
                txtTerminal.AppendText(Byte.ToString() + " ");
            }
        }
 
 
        private void btnBegin_Click(object sender, EventArgs e)
        {
            txtTerminal.Clear();
            
 
            Port.PortName = cbPort.SelectedItem.ToString();           
            Port.BaudRate = Convert.ToInt32(cbBaudRate.SelectedItem);
            Port.DataBits = Convert.ToInt32(cbDataBits.SelectedItem);
            Port.Encoding = (Encoding)cbEncoding.SelectedItem;
            Port.Parity = (Parity)cbParity.SelectedItem;
            Port.StopBits = (StopBits)cbStopBits.SelectedItem;
 
 
            Port.ReadBufferSize = 32768;
            
         
            Port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived); 
 
            try
            {
                Port.Open();                
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
           
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            string[] AvailablePorts = SerialPort.GetPortNames(); 
            
            for (int port = 0; port < AvailablePorts.Length; port++)
            {
                cbPort.Items.Add(AvailablePorts[port]);
            }
 
            cbParity.DataSource = Enum.GetValues(typeof(Parity));
            cbStopBits.DataSource = Enum.GetValues(typeof(StopBits));           
            cbBaudRate.DataSource = Speed;
            cbDataBits.DataSource = DataBits;
            cbEncoding.DataSource = Encodings;        
 
        }
 
 
        void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {                
                GetByte(Port.ReadByte());               
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
 
 
        private void btnClose_Click(object sender, EventArgs e)
        {
            try
            {
                Port.Close();            
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);  
            }                                   
        }
 
    }
}
Мое предположение относительно буфера верно или может быть я что-то неправильно делаю? Если предположение верно, то как тогда быть? Помогите советом, если кто сталкивался с похожей проблемой.

Заранее благодарю за ответ!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.05.2012, 18:42
Ответы с готовыми решениями:

Изменение цвета формы с течением времени
Здрасте! ) В C#, vs 2008. Вопрос вообщем в чем: Как изменить цвет формы с течением времени?...

Изменения чисел в TextBox с течением времени
Люди помогите сделать так, чтобы числа в текстбоксе менялся со временем(например через 1, 3 или 10...

Движение точки по эллипсу с течением времени
Здравствуйте! Подскажите, как заставить двигаться точки по эллипсоидной орбите с течением времени,...

Замедление объекта с течением времени
public void simulate(){ while(true){ ballPanel.move(); try...

6
687 / 601 / 139
Регистрация: 08.05.2009
Сообщений: 1,098
27.05.2012, 22:44 2
Если мне не изменяет память, то у класса SerialPort есть методы для очистки буфера: DiscardInBuffer(); DiscardOutBuffer();
0
Эксперт .NET
17790 / 12941 / 3381
Регистрация: 17.09.2011
Сообщений: 21,215
28.05.2012, 00:45 3
Так у вас происходит банальное переполнение буфера.
Приходят данные, вызывается событие, вы считываете из буфера один байт и все, спим до следующего возникновения события.
Если поток входящих данных довольно велик, то ваш код просто не успевает их все считывать из буфера.
1
0 / 0 / 0
Регистрация: 25.05.2012
Сообщений: 4
28.05.2012, 18:38  [ТС] 4
Использую свойство BytesToRead, но все равно не успеваю прочитать все данные из буфера. Это вывод в TextBox отнимает столько времени?
0
Эксперт .NET
17790 / 12941 / 3381
Регистрация: 17.09.2011
Сообщений: 21,215
28.05.2012, 18:43 5
Возможно. Чтобы сказать точно, надо знать примерное количество поступающих данных в единицу времени и видеть код, где этот поток обрабатывается (включая изменения с использованием BytesToRead).
0
0 / 0 / 0
Регистрация: 25.05.2012
Сообщений: 4
28.05.2012, 19:02  [ТС] 6
Ну код, в принципе, не сильно изменился

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {   
                while(Port.BytesToRead > 0) 
                {            
                    GetByte(Port.ReadByte());               
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
Всё остальное то же самое, что и в коде приведённом выше.

Когда уменьшаю частоту выдачи пакета от микроконтроллера до 1Гц, то проблема пропадает.
0
Эксперт .NET
17790 / 12941 / 3381
Регистрация: 17.09.2011
Сообщений: 21,215
28.05.2012, 21:22 7
Один пакет - это один байт? То есть при частоте 1Гц вы передаете 1,000,000,000 байтов в секунду?
Тогда конечно принимающая сторона просто не успевает обрабатывать этот поток.
Что вам может помочь:
1. Считывать байты из буфера не по одному, а пачками.
2. Считанные данные добавлять в промежуточный буфер (Queue подойдет).
3. Отдельным потоком считывать байты из очереди и выводить в текстовое поле. Желательно тоже пачками - меньше времени будет тратиться на прорисовку контрола.

Если при таком подходе (считывание и отрисовка входящих данных блоками, а не по одному) очередь будет в основном пустовать, то второй шаг можно отбросить.
0
28.05.2012, 21:22
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.05.2012, 21:22
Помогаю со студенческими работами здесь

график изменения угла с течением времени
Написать функцию, которая строит график изменения угла с течением времени \alpha (t). В качестве...

Изменение обоев рабочего стола с течением времени
Пускай я имею изображения. Как взять несколько изображений и сделать так, что бы они с течением...

задача с прямым течением времени, где ошибка?
исправьте пжл где моя ошибка,не могу понять где:wall: Вот код: #include &quot;stdafx.h&quot; #include...

Как заставить переменную наполнятся с течением времени?
Здравствуйте!Как заставить переменную наполнятся с течением времени?Например,переменную наполнить...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru