Работа с COM - портом в C# (Visual Studio)

На работе возникла задача программирования судового GPS приемника. Необходимо посылать в com-порт последовательность байт в hex, но нет приложения для работы с com-портом. Я решил написать его на c# и написал. Теперь делюсь кодом и приложением.



Код:

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.IO;

namespace ERNC_COMPort
{
    public partial class Form1 : Form
    {
        string str;
        delegate void SetTextCallback(string text);


        public Form1()
        {
            InitializeComponent();
        }
//**** **** **** **** **** **** **** **** **** ****
        private void SetText(string text)
        {
            if (this.textBox1.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                textBox1.Text += text + @"\r\n";
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                string[] availablePorts = SerialPort.GetPortNames();
                foreach (string port in availablePorts)
                {
                    comboBox5.Items.Add(port);
                }
                comboBox5.Text = comboBox5.Items[0].ToString();
                comboBox4.Text = "1";
                serialPort1.StopBits = StopBits.One;
                serialPort1.DataBits = 8;
                serialPort1.BaudRate = 9600;
                serialPort1.PortName = comboBox5.Text;
                serialPort1.Parity = Parity.None;
                serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
                groupBox2.Visible = false;
                groupBox5.Visible = false;
            }
            catch (Exception e9)
            {
                MessageBox.Show(e9.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                byte[] b = new byte[128];
                serialPort1.Read(b, 0, b.Length);
                SetText(Encoding.ASCII.GetString(b));
            }
            catch (Exception e3)
            {
                MessageBox.Show(e3.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.Open();
                if (serialPort1.IsOpen)
                {
                    groupBox2.Visible = true;
                    groupBox5.Visible = true;
                    button1.Enabled = false;
                    button5.Enabled = true;
                }
            }
            catch (Exception e1)
            {
                MessageBox.Show(e1.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void comboBox5_SelectedIndexChanged(object sender, EventArgs e)
        {
            comboBox5.Text = comboBox5.SelectedItem.ToString();
            serialPort1.PortName = comboBox5.Text;
        }
//**** **** **** **** **** **** **** **** **** ****
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            comboBox1.Text = comboBox1.SelectedItem.ToString();
            serialPort1.BaudRate = Int32.Parse(comboBox1.Text);
        }
//**** **** **** **** **** **** **** **** **** ****
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                string[] tmp = textBox3.Text.Split(new char[] { ' ' });
                byte[] a = new byte[tmp.Length];
                for (int i = 1; i < tmp.Length; i++)
                {
                    a[i] = Convert.ToByte(tmp[i], 16);
                }
                serialPort1.Write(a, 0, a.Length);
                textBox2.Text += " " + textBox3.Text;
            }
            catch (Exception e7)
            {
                MessageBox.Show(e7.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void button5_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.Close();
                if (!serialPort1.IsOpen)
                {
                    button1.Enabled = true;
                    button5.Enabled = false;
                    groupBox2.Visible = false;
                    groupBox5.Visible = false;
                    textBox1.Text = "";
                    textBox2.Text = "";
                    textBox3.Text = "";
                }
            }
            catch (Exception e2)
            {
                MessageBox.Show(e2.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void button3_Click(object sender, EventArgs e)
        {
            BinaryWriter bw = null;
            FileStream fs = null;
            try
            {
                string tmp = DateTime.Now.ToString().Replace(":", "_");
                tmp = tmp.Replace(".", "_");
                tmp = tmp.Replace(" ", "_");
                fs = File.Open(@"r_" + tmp + ".txt", FileMode.CreateNew, FileAccess.Write);
                bw = new BinaryWriter(fs);
                bw.Write(textBox1.Text);
                MessageBox.Show("Успешно!");
            }
            catch (Exception e4)
            {
                MessageBox.Show(e4.Message);
            }
            finally
            {
                bw.Close();
                fs.Close();
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void button4_Click(object sender, EventArgs e)
        {
            BinaryWriter bw = null;
            FileStream fs = null;
            try
            {
                string tmp = DateTime.Now.ToString().Replace(":", "_");
                tmp = tmp.Replace(".", "_");
                tmp = tmp.Replace(" ", "_");
                fs = File.Open(@"t_" + tmp+ ".txt", FileMode.CreateNew, FileAccess.Write);
                bw = new BinaryWriter(fs);
                bw.Write(textBox2.Text);
                MessageBox.Show("Успешно!");
            }
            catch (Exception e5)
            {
                MessageBox.Show(e5.Message);
            }
            finally
            {
                bw.Close();
                fs.Close();
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void button6_Click(object sender, EventArgs e)
        {
            string tmp = comboBox6.Text + comboBox7.Text;
            textBox3.Text += " " + tmp;
        }
//**** **** **** **** **** **** **** **** **** ****
        private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (comboBox3.Text == "нет - 00")
                {
                    serialPort1.Parity = Parity.None;
                }
                else if (comboBox3.Text == "четный")
                {
                    serialPort1.Parity = Parity.Even;
                }
                else if (comboBox3.Text == "нечетный")
                {
                    serialPort1.Parity = Parity.Odd;
                }
                else serialPort1.Parity = Parity.None;
            }
            catch (Exception e6)
            {
                MessageBox.Show(e6.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
        private void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (comboBox4.Text == "1")
                {
                    serialPort1.StopBits = StopBits.One;
                }
                else if (comboBox4.Text == "1.5")
                {
                    serialPort1.StopBits = StopBits.OnePointFive;
                }
                else if (comboBox4.Text == "2")
                {
                    serialPort1.StopBits = StopBits.Two;
                }
            }
            catch (Exception e8)
            {
                MessageBox.Show(e8.Message);
            }
        }
//**** **** **** **** **** **** **** **** **** ****
    }
}


Приложение

В архиве лежат эмулятор COM порта и эмулятор COM устройства. Очень хорошие.

Исходники проекта

Если есть вопросы или предложения пишите в коментах.

Комментарии (15)

RSS свернуть / развернуть
+
+1
Только начал изучать с#
Подскажите. Как отправить на модем команду. Например. ATDT +79XXXXXXXX
И как увидеть полученный ответ?
avatar

kain

  • 02 февраля 2012, 10:08
+
0
Можно использовать код приведенный выше, только посылать команды «AT», нужно только найти как правильно они пишутся, ну и получать тем же кодом. Должно работать. Ну или можно использовать следующий пример. В любом случае Вы работаете с COM-портом и не важно что Вы туда будете писать, так, что мой код подойдет. Скачайте пример, немного измените и проверьте. Должно работать. Я отправляю команды в hex, а вы сделайте отправку сформированной и необходимой Вам строки.
avatar

admin

  • 02 февраля 2012, 11:23
+
0
если что, спрашивайте, разберемся вместе)
avatar

admin

  • 02 февраля 2012, 11:26
+
0
Пока у меня другие задачи, но мы еще вернемся к этому вопросу… :)
avatar

kain

  • 02 февраля 2012, 11:34
+
+1
Начал изучать C#, первая задача как раз работа со сканером штрих кодов.

Необходимо реализовать:

1.Программа свернута в трее, при нажатии на нее открывается меню настроек сканера (номер порта, скорость, размер байта ...)

2.При сканировании информация (в моем случае серийный номер) должен попадать в место где установлен курсор при печати (будь то ячейка в excel или поле формы на сайте)

Подскажите пожалуйста в какую сторону копать.
avatar

Pandemonium

  • 23 апреля 2012, 10:27
+
0
Добрый день. Спасибо, что воспользовались нашим ресурсом. Надеюсь, что смогу Вам помочь.

1. Посмотрите вот это, подробно описано сворачивание в трей, про иконку и меню. Меню создадите свое. Или вот этот ресурс.

2. Думаю подойдет это. Вам надо будет получать значение активной ячейки (ActiveCell) и потом смещаться после вставки на новую.

Вообще много информации в интернете по Вашим вопросам. Что касается COM порта, то того, что я описал выше в данном блоге будет достаточно.

Будут трудности обращайтесь.

P.S. Если это возможно, после того как справитесь с проектом, не могли бы Вы опубликовать статью на эту тему на данном сайте. Буду очень признателен.
avatar

admin

  • 23 апреля 2012, 11:12
+
+1
Да с недавних пор начал часто пользоваться Вашим ресурсом. Много хорошей информации. Да по завершению выложу все наработки. Вы дали ссылку на работу с excel из .NET, но я бы не хотел привязываться к одной направленности, необходимо что бы информация со сканера попадала вместо где стоит курсор печати, например в Word в тексте или в тот же блокнот. Вот пока что не как не решу как это реализовать.
avatar

Pandemonium

  • 23 апреля 2012, 12:48
+
0
Это довольно сложно, я сам такого не делал. Но думаю, что алгоритм должен быть следующий:
1. Получить активное окно (смотреть в сторону GetGUIThreadInfo() или GetForegroundWindow())
2. У активного окна получить поле ввода с фокусом или переместиться в него (может быть вот это)
3. Вставить значение.
avatar

mastersoftna

  • 23 апреля 2012, 13:24
+
+1
Я думал что алгоритм должен быть такой:
1. Программа работает в фоновом режиме
2. Пришел серийный номер по COM
3. Эмулируя клавиатуру пишем то что получили
4. Ожидаем следующего серийника в фоновом режиме

Эмулировать нажатие вроде может SendKeys.Send. Но какие могут быть минусы в таком подходе?
avatar

Pandemonium

  • 23 апреля 2012, 14:04
+
0
Вот про SendKeys. Особенно интересно примечание. Вам в любом случае нужно будет искать активное окно приложения в которое будет делаться ввод серийника или делать его активным.
Поскольку отсутствует управляемый метод, позволяющий активировать другое приложение, то для принудительного перевода фокуса в другое приложение можно использовать этот класс в текущем приложении или собственные методы Windows, такие как FindWindow и SetForegroundWindow.
avatar

mastersoftna

  • 23 апреля 2012, 15:42
+
0
Если приложение предназначено для международного использования с различными клавиатурами, применение метода Send может привести к непредсказуемым результатам, и его следует избегать.
avatar

mastersoftna

  • 23 апреля 2012, 15:47
+
+1
Пример 1: FindWindow

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices; //required for APIs
namespace Find
{

    public partial class Form1 : Form
    {
        //Import the FindWindow API to find our window
        [DllImportAttribute("User32.dll")]
        private static extern int FindWindow(String ClassName, String WindowName);

        //Import the SetForeground API to activate it
        [DllImportAttribute("User32.dll")]
        private static extern IntPtr SetForegroundWindow(int hWnd);

        
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Find the window, using the CORRECT Window Title, for example, Notepad
            int hWnd = FindWindow(null, "Untitled - Notepad");
            if (hWnd > 0) //If found
            {
                SetForegroundWindow(hWnd); //Activate it
            }
            else
            {
                MessageBox.Show("Window Not Found!");
            }
      

        }
    }
}


Пример 2: Поиск процесса

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ProcessWindows
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern bool SetForegroundWindow(IntPtr hWnd);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process[] p = System.Diagnostics.Process.GetProcessesByName("notepad");
            if (p.Length > 0)
            {
                SetForegroundWindow(p[0].MainWindowHandle);
            }
        }
    }
}
avatar

mastersoftna

  • 23 апреля 2012, 15:55
+
+1
Что-то не до конца не пойму как работать со сканером. Как отлавливается получение информации со сканера. Подскажите минимум для работы со сканером из консоли.

using System;
using System.IO.Ports;

namespace Scaner
{
    class Program
    {
        static void Main()
        {
            SerialPort mySerialPort = new SerialPort();

            // Указываем порт
            mySerialPort.PortName = "COM1";
            // Скорость
            mySerialPort.BaudRate = 9600;
            // Паритет
            mySerialPort.Parity = Parity.None;
            // Стоп быты
            mySerialPort.StopBits = StopBits.One;
            // Размер байтов
            mySerialPort.DataBits = 8;

            // Открытие порта
            mySerialPort.Open();

            //РАБОТА СО СКАНЕРОМ

            // Закрытие порта
            mySerialPort.Close();
        }
    }
}
avatar

Pandemonium

  • 24 апреля 2012, 16:08
+
0
Добрый день!!! Очень хороший пример… Он очень помог при разборе c COM портом… Но у меня есть вопросик… Не подскажите ли как надо отформатировать сообщение, которое мы посылаем? Источник приема, допустим Hyper Terminal.
avatar

mahnati89

  • 10 мая 2012, 11:29
+
0
Добрый день!!! Очень хороший пример… Он очень помог при разборе c COM портом… Но у меня есть вопросик… Не подскажите ли как надо отформатировать сообщение, которое мы посылаем? Источник приема, допустим Hyper Terminal.
avatar

mahnati89

  • 10 мая 2012, 11:27

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.