Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/74: Рейтинг темы: голосов - 74, средняя оценка - 4.92
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 399
.NET 4.x

Прием сигнала по RS-232

01.02.2012, 15:38. Показов 14064. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, специалисты, помогите пожалуйста разобраться с приемом по RS-232, пол дня потратил впустую.
Я создал коротенкую программу, параметры порта и установки знакомой многим программе terminal, приведены в прилагаемом скрине. Я сейчас попробую все изложить чтобы не упустить какой-то момент, если где-то будет непонятно, переспросите я все разъясню.
В общем вот этот код
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
using System.IO.Ports;
using System.Threading;
 
namespace RS_VS
{
    public partial class Form1 : Form
    {
        public delegate void AddRichTextBox();
        public AddRichTextBox myDelegate;
        string messageOut = "";
 
        bool flagSoftChangedcomboBoxCountComPort = false; //смена програмно комбобокса чтобы не сработало событие
 
 
        public Form1()
        {
            myDelegate = new AddRichTextBox(AddRichTextBoxMethod);//объявление делегата
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
           foreach (string tempCountComPort in SerialPort.GetPortNames())// Получает массив имен последовательных портов для текущего компьютера.
            {
                this.comboBoxCountComPort.Items.Add(tempCountComPort);
            }
            flagSoftChangedcomboBoxCountComPort = true;
            comboBoxCountComPort.SelectedItem = serialPort1.PortName;
 
        
            
        }
 
               
        public void AddRichTextBoxMethod()
        {
            this.richTextBoxReceiveData.Text = messageOut+"\r\n";
        }
 
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)//Открыт новый поток
        {
            byte[] tempMas = new byte[3]; 
            try
            {
                messageOut = serialPort1.ReadLine();
                 
                this.Invoke(myDelegate);
                
                //if (serialPort1.IsOpen) MessageBox.Show("Порт открыт");
                //else MessageBox.Show("Порт закрыт");
 
            }
 
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message, "Время превышено", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
 
 
        private void comboBoxCountComPort_SelectedIndexChanged(object sender, EventArgs e)
        {
            
            if (flagSoftChangedcomboBoxCountComPort) //смена программно для простого отображения информации без обработчика
            {
 
                flagSoftChangedcomboBoxCountComPort = false;
            }
            else//обработчик при смене пользователем
            {
                serialPort1.PortName = comboBoxCountComPort.Text;
                
            }
        }
 
        private void buttonSend_Click(object sender, EventArgs e)
        {
            string message;
           
            message = "Send";
            serialPort1.WriteLine(message);//не торопимся закрыть порт
        }
 
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            serialPort1.Close();
        }
 
        private void buttonOpenPort_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen) serialPort1.Open();//если он был открыт то будет ошибка.
        }
 
        private void buttonClose_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
        }
 
    }
}

Работает идеально сам на себя. Если запустить вторую такую копию, назначить другой порт то эти две программы также замечательно обмениваются друг с другом. Но как только я захотел передать с программы terminal такое же слово, мой оптимизм испарился. В момент приема, моя программа весит в событии, затем заканчивается установленное время ожидания приема и выскакивает исключение "превышено время ожидания". Ни каких данных я не получаю, и непонятно почему срабатывает тогда событие по приему, если он ни чего не получает.
Помучавшись немного я заменил строку ReadLine на ReadChar, и у меня что-то получилось, я передал один символ и принял вместо символа число (но это понятно, надо его декодировать), попробовал другой метод Readbyte, и передал уже не один символ а три (123), и тут снова началась абракадабра, он принимает то 50, то 51 (последний, предпоследний). Я понимаю если бы он читал только первый символ (49), или последний (51), но это вообще рандом какой-то.
Что-то я пробовал еще, уже не помню, там вообще непонятные числа на приеме. И грешить на эту программку terminal не очень охото, пакеты она отправляет исправно, пачками, у меня контроллер их успешно ловил и оборабатывал.
Пожалуйста помогите, может есть какие-то принципы о которых я не знаю.
Заранее благодарю.
Миниатюры
Прием сигнала по RS-232  
1
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
01.02.2012, 15:38
Ответы с готовыми решениями:

RS-232. Передача и прием данных
Подскажите пожалуйста. не опытному программисту в чем может быть проблема с этим кодом: вставляю в форму не сохраняется((( буду очень...

Прием данных с RS-232 на больших скоростях. Выбор решения и вектор развития
Доброго дня! Есть устройство, которое шлет данные по интерфейсу RS-232. Стоит задача выводить данные раз в 150 мс. Сейчас это все...

Прием сигнала.
Здравствуйте уважаемые. Прошу помоч с одним вопросом. Есть прибор, уздающий аналоговый сигнал, который преобразован в цифровой сигнал....

10
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
01.02.2012, 15:59
Для правильной передачи данных настройки на обоих портах должны совпадать (Baud rate, data bits, stop bits, parity, handshake).

В приведенном вами коде отсутствуют какие-либо установки настроек порта. Вероятно, выставлены в дизайнере.
1
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 399
01.02.2012, 16:47  [ТС]
да, выставлены в дизайнере и вроде все совпадает, на приложенном скрине видно

Добавлено через 1 минуту
и главное моя програмка в этот терминал то кидает стабильно, а наоборот не очень
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
01.02.2012, 16:51
Цитата Сообщение от leonidSDF Посмотреть сообщение
на приложенном скрине видно...
... что у вас StopBits = One, а в терминале - 2.
1
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 399
02.02.2012, 05:35  [ТС]
блин...
мне кажется это я уже танцы с бубном начал устраивать.
сейчас ком порта нету под рукой, завтра попробую отпишусь.
Спасибо.

Добавлено через 12 часов 37 минут
Здравствуйте, поменял количество стопбитов на 1, потом везде сделал 2, и ни чего
Я помню, что я это уже от отчаяния начал колдовать. поэтому такое несоответствие отпечаталось.
В общем не работает.
Причем я заметил, что обработчик события
C#
1
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)//Открыт новый поток
срабатывает два раза при передаче 123, и соответственно ошибка выскакивает 2 раза.
0
 Аватар для ITDeveloper
86 / 86 / 6
Регистрация: 14.01.2011
Сообщений: 265
02.02.2012, 05:46
Попробуйте работу с com портом на чистом winapi!
Исходники для программ передачи/приёма символов через com-порты
2
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 399
02.02.2012, 08:57  [ТС]
короче я нашел разницу, вот тот рисунок строки 123, у которого сигнал длиннее, это моя программа (извините за анатомические подробности),
где короче, это сигнал terminala.
Причем эти два сигнала схожи, но последние три импульса в конце непонятны. Но terminal распознает эти импульсы легко. Подскажите пожалуйста, какая у меня стоит установка которая требует наличие эти три последних импульса?
Миниатюры
Прием сигнала по RS-232   Прием сигнала по RS-232  
1
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 399
02.02.2012, 13:51  [ТС]
вроде эти три импульса какое-то "А" в шестнадцатеричной.

Добавлено через 3 часа 16 минут
Я поиследовал еще немного и оказалось что толком работает только один метод чтения, все остальные имеют какие-то глюки, может кого натолкнет на какие-то мысли, каждый метод закоментирован и описание тоже.

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
 try
            {
                //При приеме символов 123 одним пакетом без излишек
 
                ////-------//такой режим выдает две ошибки
                //messageOut = serialPort1.ReadLine();
                ////-------
                
                ////------- // такой режим работает только с одним символом, при приеме подряд см.ниже
                //tempInt  = serialPort1.ReadByte(); 
                //messageOut = tempInt.ToString();
                ////-------
 
                ////------- // "считывает один байт" такой режим работает, но при передаче пакетов последний не ловится, а потом всплывает
                ////но при передаче информации 123, например получается так 4950|5149|5051 с каждым последующим приемом
                //tempInt = serialPort1.ReadByte();
                //messageOut += tempInt.ToString();
                ////-------
 
 
                ////------- //"считывает все" такой режим работает!!!!!!!!
                //messageOut = serialPort1.ReadExisting();
                ////-------
 
                ////-------//"Считывает строку до позиции" - считывает но последний не считает, а пробел указывать нельзя или "", будет снова ошибка
                //messageOut = serialPort1.ReadTo("3");;
                ////-------
 
                ////------- //"считывает один символ" беда такая же как и ReadByte()
                //messageOut += serialPort1.ReadChar();
                ////-------
 
                ////------- //"считывает байт в массив начиная с определенного момента" странно отпечатывает количество символов, если стоит count 3, тогда только 3, если 2, то печатает 21
                //messageOut += serialPort1.Read(tempMasChar,0,3);
                ////-------
 
                this.Invoke(myDelegate);
1
 Аватар для dimasamchenko
336 / 269 / 21
Регистрация: 30.03.2009
Сообщений: 500
02.02.2012, 14:09
Уважаемый leonidSDF, не выдержал Ваших плясок с бубном и поэтому решил вмешатся!

Цитата Сообщение от leonidSDF Посмотреть сообщение
Я поиследовал еще немного и оказалось что толком работает только один метод чтения, все остальные имеют какие-то глюки
нет там никаких глюков!!! Все работает как положено!!!
Просто разные методы предназначены для разных случаев чтения!

Цитата Сообщение от leonidSDF Посмотреть сообщение
////------- //"считывает все" такой режим работает!!!!!!!!
//messageOut = serialPort1.ReadExisting();
////-------
конечно, потому, что он считывает все доступные байты из буфера порта

Вам необходимо точно знать что Вы посылаете в порт и что хотите сосчитать!
Есть такое замечательное понятие как протокол обмена
Вы его не используете отсюда и все Ваши беды!
например, чтобы прочитать правильно всю строку (любой длины), поставте признак конца строки
C#
1
 serialPort.NewLine = "\r\n";
и строка будет принята полностью без пляски, при условии, что передатчик передает строку с таким признаком окончания строки!
и тогда Ваш код
C#
1
 messageOut = serialPort1.ReadLine();
удивительным образом избавится от глюков
2
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 399
02.02.2012, 17:03  [ТС]
Цитата Сообщение от dimasamchenko Посмотреть сообщение
serialPort.NewLine = "\r\n"
- это я уже узнал в самом конце дня, но спасибо что откликнулись на беду.
еще я узнал как пользоваться методом readByte()
оказывается что если написать такой кусочек
C#
1
2
3
4
5
6
 while (serialPort1.BytesToRead != 0)//дает количество непрочитанных байтов в буфере
                {
 
                    tempInt = serialPort1.ReadByte();
                    messageOut += tempInt.ToString();
                }
то все работает.
Но вот только странно, ведь этот метод, когда встречает пустое место в буфере то возвращает -1(так написано в описании), но если написать такой же кодик но в условии поставить tempInt !=-1, то ни чего не получится. Он считает три символа, а потом зависнит и будет ждать пока не закончится время.
И почему этот метод, в первой реализации, как-то странно отпечатывал байты - парами, а потом куски от оставшихся. Может быть я привык к контроллерам, будем считать что идет непрерывно передача данных, пришло прерывание(сработало событие) прочитал данные, буфер свободен, на его место уселось другое число, сново сработало событие и так далее, ведь ПК работает на гараздо большей частоте чем скорость 9600, а тут как будто не успевает.


И как например считать из буфера массив байтов или символов, он считывает все сразу в массив или тоже есть какие-то тонкости типа newLine(результат плясок я приводил выше).
Спасибо
1
 Аватар для dimasamchenko
336 / 269 / 21
Регистрация: 30.03.2009
Сообщений: 500
02.02.2012, 17:49
Лучший ответ Сообщение было отмечено как решение

Решение

Цитата Сообщение от leonidSDF Посмотреть сообщение
И как например считать из буфера массив байтов и символов, он считывает все сразу в массив или тоже есть какие-то тонкости типа newLine.
leonidSDF, я же Вам писал:
Цитата Сообщение от dimasamchenko Посмотреть сообщение
Есть такое замечательное понятие как протокол обмена
Чтобы считать из буфера массив байтов, надо сформировать протокол обмена
например рассмотрим посылку- в первом байте содержится число передаваемых байт, затем нужное число байт данных и байт контрольной суммы. И все! Прочитав первый байт, Вы уже знаете сколько Вам надо читать, байт КС всегда последний(кстати его можно и не передавать) это для надежности связи его передают и вычисляют КС, если не совпало-ошибка.
По поводу "тонкости типа newLine" я обычно при таком типе обмена, загоняю принятые байты в стек,и жду когда количество принятых будет равно необходимому
вот пример(не особо партесь по поводу переменных, это код готового проекта, я даю Вам принцип)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  public int ReceiveTicket(out byte Code)
         {
           byte Ch;
           byte[] B = new byte[3];
         //-------------------
           Code = 33;
           //******************************************
           if (AsyncBuffer.Count < 3)
           {
               int start = Environment.TickCount;
               //ждем полного буфера для ReceiveTicket =3!!!
               do
               {
                   Application.DoEvents();
                   if (AsyncBuffer.Count >= 3) break;
               }
               while ((Environment.TickCount < (start + GC.RTO)));             
           }
           //******************************************
Вот пример моего приема
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//----------------------------------------------------------------------------
 
    private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
      {
      this.Invoke(new EventHandler(DoUpdatePort));
      }
    //----------------------------------------------------------------------------
    public void DoUpdatePort(object s, EventArgs e)
    {
        FlagPortDataNo = true;
        IsBytePort = serialPort.BytesToRead;
 
        serialPort.Read(PortDataByteRead, 0, IsBytePort);
        for (int p = 0; p < IsBytePort; p++)
        { AsyncBuffer.Enqueue(PortDataByteRead[p]); }
          FlagPortDataNo = false;
      }
    //----------------------------------------------------------------------------
И почему этот метод, в первой реализации, как-то странно отпечатывал байты - парами, а потом куски от оставшихся. Может быть я привык к контроллерам, будем считать что идет непрерывно передача данных, пришло прерывание(сработало событие) прочитал данные, буфер свободен, на его место уселось другое число, сново сработало событие и так далее, ведь ПК работает на гараздо большей частоте чем скорость 9600, а тут как будто не успевает.
Винда по своему обрабатывает события порта и Вам разбираться с этим не очень-то и надо, если Вы делаете прикладное ПО. У Вас есть
C#
1
  private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
а больше ничего и не надо...

Добавлено через 26 минут
Вообще протокол должен содержать следующее
1-признак начала передачи(например байт 0x55)
2-байт числа байтов в кадре
...данные
3-байт контрольной суммы (КС)
4-признак конца передачи например байты соответствующие "\r\n" (0x0A, 0X0D)
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
02.02.2012, 17:49
Помогаю со студенческими работами здесь

[Windows Phone] Поиск и прием gps сигнала
Программирую в с# под windows phone. Но с кибернетикой реально не дружу. Даже осёл лучше знает творчество Пушкина. Короче надо сделать...

Attiny 13 прием и передача ик сигнала
Здравствуйте форумчане,объясните пожалуйста не опытному , как принять ик сигнал ,то есть с тиньки 13 я передаю ик сигнал с определенным...

Улучшить приём Wi-Fi и качество сигнала
Имеется П-образное здание. Источник Wi-Fi сигнала расположен в углу здания, в кабинете на 1 этаже. Необходимо, чтобы сигнал доходил до...

Прием сигнала с пульта радио управления
Всем привет. Хочу использовать stm32 для управления машинкой ( знаю что stm32 слишком круто для таких целей, но они у меня просто в...

Что отвечает за приём сигнала wi-fi, какой чип подобрать?
Есть желание проэкспериментировать с приёмом сигнала, поэтому хочется сделать, а лучше приобрести хороший модуль ля приёма, который буду...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. На мобильном - сканируйте QR-код. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru