Перейти к содержанию

Visual Studio SerialPort_приём данных


Рекомендуемые сообщения

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

Описание проекта. 
- микроконтроллер подключён к ПК через COM-порт;
- программа раз в секунду шлёт МК символы поочерёдно "0","1"или "2";
- МК в зависимости от пришедшего символа даёт соответствующий ответ: если "0", то возвращает "333", "1" - "322", "2" - "655";
- Программа получив ответы, разлаживает их в соответствующие элементы: Если было отправлено "0", то вернувшийся ответ "333" положить в label14;          "1" - "322" = label15;          "2" - "655" = label10

Вот такая тестовая незамысловатая логика для теста работоспособности.

Проблема в том, что значения не всегда выводятся полным значением. Как можно видеть на скрине, первое значение вместо "333" вывелось только "33", "322" вывелось полностью, и "655" только "55".
При следующей итерации может уже получиться другой вывод....

Краткое описание кода программы:
- код имеет подключенный Таймер, прерывание которого срабатывает раз в 1000 мс
- после соединения по КОМ-порту включается таймер и раз в секунду отправляется значение "0" "1" либо "2".
- в функции serialPort1_DataReceived происходить приём данных в переменную типа string dataIN
- в функции ShowData происходит работа с содержимым dataIN. В зависимости от отправленного символа, ответ помещается в соответствующий элемент

Скрытый текст

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace AstroCanon
{
    public partial class Form1 : Form
    {
        string dataIN;
        private int counter_timer; // хранит передаваемое число плате для получения данных
        private int q;
        private int count;
        private int label_2, label_3;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string[] myPort;

            myPort = System.IO.Ports.SerialPort.GetPortNames();
            comboBox1.Items.AddRange(myPort);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.BaudRate = 115200;
            serialPort1.PortName = comboBox1.Text.ToString();
            if (serialPort1.IsOpen == false)
                serialPort1.Open();

            button1.Enabled = false;
            timer1.Enabled = true;

            label1.Text = "ON";
            label1.ForeColor = Color.Green;            // изменить цет на зелёный 

            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            button1.Enabled = true;

            label1.Text = "OFF";
            label1.ForeColor = Color.DarkRed;

            timer1.Enabled = false;
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            dataIN = serialPort1.ReadExisting();
            this.Invoke(new EventHandler(ShowData));



     


        }

        private void ShowData(object sender, EventArgs e)
        {
            richTextBox1.Text += dataIN;

             if (count == 0)
            {
                // int data0 = Convert.ToInt32(str);
                label14.Text = dataIN;
                return;
            }
            if (count == 1)
            {
                //  int data1 = Convert.ToInt32(str);
                label15.Text = dataIN;
                return;
            }
            if (count == 2)
            {
                //  int data2 = Convert.ToInt32(str);
                label10.Text = dataIN;
                return;
            } 

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

            if (count <= 3) count++;                    // инкрементирует значение для дальнейшей передачи в устройство;
            if (count >= 3) count = 0;                 

            string str_с = Convert.ToString(count);
            serialPort1.Write(str_с);

           

            

           // label7.Text = data0;


            //  string str = Convert.ToString(counter_timer);

            //  serialPort1.Write(str);

            //  richTextBox1.Text += dataIN;
            //  int a = Convert.ToInt32(dataIN);
            //  return;
            //label2.Text = Convert.ToString(a);

            // label2.Text = Convert.ToString(counter_timer);
            // if (count == 3)   label3.Text = Convert.ToString(label_3);

        }

        private void button3_Click(object sender, EventArgs e)
        {
            count = 2;
            string str = Convert.ToString(count);
            serialPort1.Write(str);



            // string str = Convert.ToString(counter_timer);
            //serialPort1.Write((string)counter_timer);
            // serialPort1.Write("3");
            //label2.Text = Convert.ToString(dataIN);


        }

        private void button4_Click(object sender, EventArgs e)
        {
            count = 3;
            string str = Convert.ToString(count);
            serialPort1.Write(str);
        }

        private void button6_Click(object sender, EventArgs e)
        {

        }

        private void label16_Click(object sender, EventArgs e)
        {

        }

        private void label20_Click(object sender, EventArgs e)
        {

        }

        private void label2_Click(object sender, EventArgs e)
        {

        }
    }
}

 

 

Безымянный1.jpg

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Тут надо знать, что функция serialPort1_DataReceived() вызывается на каждый принятый байт. К примеру, посылаете от МК на компьютер строку "655". Строка поылается символ за символом, т.е. сначала принимается символ "6". Приняли только первый символ, как тут же вызывается serialPort1_DataReceived(), и в переменную dataIN записывается "6".

Затем принимаемся следующий байт "5". Но Windows не система реального времени, в ней вызов функций может происходить с задержкой. Поэтому пока вызывается serialPort1_DataReceived() может успеть приняться следующий байт. В буфере КОМ-порта уже будет сидеть "55", и в переменную dataIN это и запишется, предыдущая "6" пропадёт.

После этого всё успокоится, и настанет время выводить данные в label, и нарисуется только последний принятый обрывок строки, т.е."55".

Надо поступить так, например. Перед посылкой в МК команды, надо очистить переменную

dataIN = "";

Затем при приёме в переменной dataIN накапливать полученные байты операцией +=

dataIN += serialPort1.ReadExisting();

Как только приняли 3 байта - можно выводить  накопленную строку в label

if(dataIN.Length >= 3 ) this.Invoke(new EventHandler(ShowData));

 

 

Изменено пользователем Yurkin2015
Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

2 часа назад, Yurkin2015 сказал:

Тут надо знать, что функция serialPort1_DataReceived() вызывается на каждый принятый байт. К примеру, посылаете от МК на компьютер строку "655". Строка поылается символ за символом, т.е. сначала принимается символ "6". Приняли только первый символ, как тут же вызывается serialPort1_DataReceived(), и в переменную dataIN записывается "6".

Затем принимаемся следующий байт "5". Но Windows не система реального времени, в ней вызов функций может происходить с задержкой. Поэтому пока вызывается serialPort1_DataReceived() может успеть приняться следующий байт. В буфере КОМ-порта уже будет сидеть "55", и в переменную dataIN это и запишется, предыдущая "6" пропадёт.

После этого всё успокоится, и настанет время выводить данные в label, и нарисуется только последний принятый обрывок строки, т.е."55".

Надо поступить так, например. Перед посылкой в МК команды, надо очистить переменную


dataIN = "";

Затем при приёме в переменной dataIN накапливать полученные байты операцией +=


dataIN += serialPort1.ReadExisting();

Как только приняли 3 байта - можно выводить  накопленную строку в label


if(dataIN.Length >= 3 ) this.Invoke(new EventHandler(ShowData));

 

 

Замечательно!
Спасибо. Вечером обязательно попробую реализовать и после тпишусь.
А пока еще небольшой вопрос. 
В коде, в функции serialPort1_DataReceived есть такая стока как:
 

this.Invoke(new EventHandler(ShowData));

Что она делает??? не могу понять

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Ваша программа состоит из нескольких частей-потоков, которые работают параллельно, то есть якобы одновременно выполняются разные части программы. Один поток рисует лэйблы на экране, другой принимает данные из КОМ-порта. В C# нельзя просто так использовать один ресурс из разных потоков. Функция приёма байтов может активизироваться внезапно при поступлении байта в порт, из неё нельзя рисовать лэйбл, потому что , может, в этот же момент другой поток тоже что-то рисует на этой же лэйбле. Возникает конфликт "кто главнее". 

Вместо прямого рисования при поступлении байта функция генерирует событие ShowData в системе, мол, обнови метку на экране. Это событие помещается в общую очередь событий. И когда у рисовального потока дойдут руки и он среагирует на это событие, тогда метка спокойно обновится на экране новой строкой.

Ссылка на комментарий
Поделиться на другие сайты

2 минуты назад, Yurkin2015 сказал:

Ваша программа состоит из нескольких частей-потоков, которые работают параллельно, то есть якобы одновременно выполняются разные части программы. Один поток рисует лэйблы на экране, другой принимает данные из КОМ-порта. В C# нельзя просто так использовать один ресурс из разных потоков. Функция приёма байтов может активизироваться внезапно при поступлении байта в порт, из неё нельзя рисовать лэйбл, потому что , может, в этот же момент другой поток тоже что-то рисует на этой же лэйбле. Возникает конфликт "кто главнее". 

Вместо прямого рисования при поступлении байта функция генерирует событие ShowData в системе, мол, обнови метку на экране. Это событие помещается в общую очередь событий. И когда у рисовального потока дойдут руки и он среагирует на это событие, тогда метка спокойно обновится на экране новой строкой.

Спасибо за объяснение. Да, принцип другой нежели у микроконтроллеров, где один поток, да прерывания....

Ссылка на комментарий
Поделиться на другие сайты

8 часов назад, Yurkin2015 сказал:

Тут надо знать, что функция serialPort1_DataReceived() вызывается на каждый принятый байт. К примеру, посылаете от МК на компьютер строку "655". Строка поылается символ за символом, т.е. сначала принимается символ "6". Приняли только первый символ, как тут же вызывается serialPort1_DataReceived(), и в переменную dataIN записывается "6".

Затем принимаемся следующий байт "5". Но Windows не система реального времени, в ней вызов функций может происходить с задержкой. Поэтому пока вызывается serialPort1_DataReceived() может успеть приняться следующий байт. В буфере КОМ-порта уже будет сидеть "55", и в переменную dataIN это и запишется, предыдущая "6" пропадёт.

После этого всё успокоится, и настанет время выводить данные в label, и нарисуется только последний принятый обрывок строки, т.е."55".

Надо поступить так, например. Перед посылкой в МК команды, надо очистить переменную


dataIN = "";

Затем при приёме в переменной dataIN накапливать полученные байты операцией +=


dataIN += serialPort1.ReadExisting();

Как только приняли 3 байта - можно выводить  накопленную строку в label


if(dataIN.Length >= 3 ) this.Invoke(new EventHandler(ShowData));

 

 

Сделал всё так как Вы описали.
Всё заработало. 
Большое Вам спасибо!

Ссылка на комментарий
Поделиться на другие сайты

9 часов назад, Yurkin2015 сказал:

Тут надо знать, что функция serialPort1_DataReceived() вызывается на каждый принятый байт. К примеру, посылаете от МК на компьютер строку "655". Строка поылается символ за символом, т.е. сначала принимается символ "6". Приняли только первый символ, как тут же вызывается serialPort1_DataReceived(), и в переменную dataIN записывается "6".

Затем принимаемся следующий байт "5". Но Windows не система реального времени, в ней вызов функций может происходить с задержкой. Поэтому пока вызывается serialPort1_DataReceived() может успеть приняться следующий байт. В буфере КОМ-порта уже будет сидеть "55", и в переменную dataIN это и запишется, предыдущая "6" пропадёт.

После этого всё успокоится, и настанет время выводить данные в label, и нарисуется только последний принятый обрывок строки, т.е."55".

Надо поступить так, например. Перед посылкой в МК команды, надо очистить переменную


dataIN = "";

Затем при приёме в переменной dataIN накапливать полученные байты операцией +=


dataIN += serialPort1.ReadExisting();

Как только приняли 3 байта - можно выводить  накопленную строку в label


if(dataIN.Length >= 3 ) this.Invoke(new EventHandler(ShowData));

 

 

Если строка  if (dataIN.Length >= 3) this.Invoke(new EventHandler(ShowData)); ожидает пока не наберётся масссив на три элемента , то как сделать так, чтобы оператор if ждал пока не появится стоп-символ? Например, "%"

Ссылка на комментарий
Поделиться на другие сайты

  • 1 год спустя...

Вот вроде все точно также. Делал по видео... Но не принимает и все данные... Передает нормально .. геркулесом их вижу.. а вот обратно не выдает ничего. Подсобите кто чем может ) 

Спойлер

код

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Data.OleDb;

namespace Homeserver
{
    public partial class fmAddbutton : Form
    {
        public static string SQLadr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source = Database.mdb";// строка подключение к базе
        private OleDbConnection SQLcon; //класс подключение
        //private SerialPort Serial;
        
        string Ports;
        int Speed;
        string readstring;
        public fmAddbutton()
        {
            InitializeComponent();
        }

        private void btCancel_Click(object sender, EventArgs e)
        {
            Form Main = Application.OpenForms[0];
            Main.Show();
            this.Close();
        }

        private void fmAddbutton_Load(object sender, EventArgs e)
        {

            SQLcon = new OleDbConnection(SQLadr);
            string query = "SELECT Port,Speed FROM USB WHERE id = 1";
            SQLcon.Open();
            OleDbCommand command = new OleDbCommand(query, SQLcon);
            command.Connection = SQLcon;
            OleDbDataReader reader = command.ExecuteReader();
            reader.Read();
            Ports = reader[0].ToString();
            Speed = int.Parse(reader[1].ToString());
            reader.Close();
            try
            {                
                Serial = new SerialPort(Ports, Speed, Parity.None, 8, StopBits.One);
                Serial.Open();
            }
            catch
            {
                MessageBox.Show("Ошибка открытия порта "+Ports, "Внимание!");
            }
            Serial.Write("find");
        }


        private void fmAddbutton_FormClosing(object sender, FormClosingEventArgs e)
        {
            SQLcon.Close();// закрываем базу данных
            Serial.Close();
        }

        private void btFind_Click(object sender, EventArgs e)
        {
            Serial.Write("FIND");
        }

        private void Serial_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
        {
            readstring = Serial.ReadExisting();
            this.Invoke(new EventHandler(ShowData));

        }

        private void ShowData(object sender, EventArgs e)
        {
            lbSerial.Items.Add("readstring");
        }
    }
}

 

 

Изменено пользователем Flat
Украшение
Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
  • Сообщения

    • Вот здесь человек описывает похожий метод, только в домашних условиях: https://www.kondratev-v.ru/zaryadnye/zaryadnoe-ustrojstvo-dlya-avtomobilnyx-akkumulyatorov.html
    • Доковырялся с макеткой так, что все перестало работать( И посмотрев внимательнее обнаружил, что в рабочем варианте у меня используется TPL5111 (ZFVX), а на макетке TPL5110 (ZALX). Китайцы видать напутали со сборкой положили и то и то. В одной статейке написано :  TPL5110 — таймер для управления внешним ключом питания, в качестве которого используется МОП-транзистор TPL5111 — таймер для управления внешним ключом питания, в качестве которого используется LDO-стабилизатор с функцией разрешения Что используется в качестве этого "LDO стабилизатора" пока не разобрался( Теперь только после праздников. пысы  Не получается блин просто))))))  
    • Тут я уже писАл, какой ток что на самом деле протекает.  
    • Как к модеру к нему конечно были вопросы. Ну и правила его не касались, когда кидался оскорблениями в адрес Василича. А за ответы на оскорбления Василич баны выхватывал
    • Смотрю, многие в усилителях избегают катодного повторителя. Либо сразу берут токовые лампы с хорошим усилением, либо два каскада последовательно на токовых лампах с низким усилением. Вроде бы на звук не влияет...
    • Имел дело с зарядкой батареек еще с советских времен. Тогда еще в магазине (!) купил специальную зарядку для ртутно-цинковых батареек, очень миниатюрная, зарядка шла от встроенного солнечного элемента (и это еще в советские времена!). Использовал для зарядки батареек для наручных часов, после первой зарядки батарейки хватало примерно на полгода, потом на 3-4 месяца. Потом (когда батарейка служила меньше двух месяцев) батарейка отправлялась на упокой. Спасала студента тогда очень эта вещица. Жалею что тогда не срисовал ее внутренности. А вот с зарядкой щелочных батареек пришлось заниматься уже значительно позже. Мне кто-то подарил такой набор (зарядка с комплектом перезаряжаемых батареек) - вот его обзор https://aphnetworks.com/reviews/pure_energy_xl  Все было нормально, но у всех этих батареек ресурс очень ограничен, примерно 25 циклов максимум. После чего емкость уменьшается и нет смысла их дальше использовать. После каждой зарядки емкость уменьшается, но не сильно. Реально раз десять заряжать можно точно без проблем. После того как выработался ресурс последней батарейки стал вопрос - а можно ли заряжать обычные батарейки тоже? Зарядка-то осталась... И как раз в то время приобрел обычные (т.е. "незаряжаемые") батарейки той же фирмы (PureEnergy). Оказалось что они заряжаются точно также, как и "заряжаемые"! Возможно что у них та же химия... Пробовал батарейки разных фирм, степени разряда. Короче говоря, фирменные всякие Дюраселлы и Энержайзеры не заряжаются вообще, и даже могут потечь во время зарядки. А вот самые дикие и дешевые нонейм чаще всего заряжаются без проблем. Насчет емкости - конечно емкость полностью не восстанавливается, но для работы в беспроводной клаве,, мышке или пульте вполне хватает и достаточно надолго.  Но занимаюсь этим нечасто, просто когда лень ехать в магазин за очередной партией батареек.  А если есть возможность, то предпочитаю переделывать питание под литий. Очень сильно достает саморазряд всяких Ni-Cd, Ni-MH - разряжаются даже те, которые якобы должны долго держать заряд. Схему зарядки еще не срисовывал (лень было разбирать), но схема сложнее чем все что я видел в Интернете. Напряжение заряда примерно 1,7в. xlaa_tds.pdf
    • Я делаю ставку на контакты NC реле запуска и NO реле торможения. Тем более они такие хлипенькие.
  • Похожий контент

×
×
  • Создать...