Jump to content
NicksonWer

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

Recommended Posts

Доброго времени!
За несколько дней пришлось в спешке освоить 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

Share this post


Link to post
Share on other sites

Тут надо знать, что функция 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));

 

 

Edited by Yurkin2015

Share this post


Link to post
Share on other sites

Изготовление 2-х слойных плат от 2$, а 4-х слойных от 5$!

Быстрое изготовление прототипа платы всего за 24 часа! Прямая доставка с нашей фабрики!

Смотрите видео о фабрике JLCPCB: https://youtu.be/_XCznQFV-Mw

Посетите первую электронную выставку JLCPCB https://jlcpcb.com/E-exhibition чтобы получить купоны и выиграть iPhone 12, 3D-принтер и так далее...

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));

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

Share this post


Link to post
Share on other sites

Высокая надежность SiC! Как они этого добились?

За несколько лет кропотливых исследований и совершенствования технологии компания Infineon смогла довести показатели надежности и стабильности параметров высоковольтных и быстродействующих карбид-кремниевых транзисторов линейки CoolSiC практически до уровня их кремниевых собратьев.

Подробнее

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

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

Share this post


Link to post
Share on other sites

Материалы вебинара: МЭМС-датчики ST для работы со звуком – новые возможности

На вебинаре мы рассказали о микрофонах, их топологиях применения и возможностях, а так же о новых мультирежимных широкодиапазонных микрофонах с нижним портом и PDM-интерфейсом для систем с батарейным питанием. Вы можете посмотреть видеозапись вебинара, ознакомиться с презентацией и ответами на вопросы.

Подробнее

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

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

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

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

Share this post


Link to post
Share on other sites

Использование экосистемы STMicroelectronics: подключение датчиков к STM32G4

В статье описаны основные составляющие экосистемы STMicroelectronics для работы с микроконтроллерами STM32, а также приведен пример ее практического применения: создание проекта на базе STM32G4 с подключением датчиков и использованием отладочной платы NUCLEO-G474RE и платы расширения X-NUCLEO-IKS01A2.

Подробнее

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));

 

 

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

Share this post


Link to post
Share on other sites
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 ждал пока не появится стоп-символ? Например, "%"

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Сообщения

    • Бред какой то и Брагина и Зуева уже обосрал
    • Если крутится и воздух дует - ремонт окончен. Если не нравятся искры под щётками, поставьте параллельно двигателю ёмкость 0,01 - 0,1 мкФ на 50 или больше вольт. Искр будет чуть меньше. Дроссели, что на фото, можете выбросить.
    • У него расчёт вообще непонятно на что. Вёз из 404й в Германию чемодан со 157й серией, и после этого он рассказывает, кто на чьи деньги рассчитывает? Неужели сразу не понятно, что это бред сумасшедшего, равно как и всё остальное?  Значит, мы сами не знаем, что слепили. А как же тогда получается, что он не слепил вообще ничего, но, сцуко, всё про всех знает!  Может быть, он слишком много знает? Оверкилл ? 
    • Может просто пора поменять батарейку?   Не совет по ремонту. Так, размышления, где найти нужный оптический сенсор... Нужный сенсор с доставкой из Китая - 240 - 280 рублей. Плюс ожидание пару недель, аккуратная пайка хорошим инструментом ... Новая мышка Defender Dacota MS-155 Nano в ближайшем магазине, работающая, в упаковке, в комплекте с приёмником, с гарантийным сроком - 500 р.
    • Недобросовестная конкуренция помогает зарабатывать.)))  Вот и коммерческая деятельность. Думаю, наборы для сборки продаются за символическую плату, или кому сколько не жалко заплатить.   )))
    • В наушниках, мне в большинстве случаев хватает "мощщи" усилителя, встроенного в звуковую карту компьютера. Сколько там, десятки милливатт? Притом, ещё и не мешаю никому. Затраты - ноль рублей.

  • Ассорти SMD светодиодов 0402 0603 0805 1206, 100 шт.

  • Similar Content

    • By StasBronja
      Здравствуйте товарищи!
      При подключении омеги через FT232RL или ардуины нано (в качестве usb uart) получаю
        хотя должен что то типо этого 
      Скорость устанавливаю как в документации 115200.
    • By vseriousv
      Здравствуйте! Пытаюсь отправить слово с МК Avr attiny2313 через com port и выловить его программой, пока что просто программой "терминал".
      Прошу помощи! Почему присылаются какие-то арабские символы или что угодно, но не то, что я отсылаю?
      Сейчас я думаю дело в частоте, но как бы я ее точно не пытался откорректировать, все равно присылается какая-то белиберда.

      # define F_CPU 3993600UL #include <avr/io.h> #include <avr/iotn2313.h> #include <avr/interrupt.h> void USART_Transmit( unsigned char data ); void USART_Init (unsigned int baud); void USART_Init (unsigned int baud) { UBRRH = (unsigned char)(baud>>8); UBRRL = (unsigned char)baud; // 9600 UCSRB = (1<<RXEN)|(1<<TXEN); //|(1<<TXCIE)|(1<<UDRIE) UCSRC = (1<<USBS)|(1<<UCSZ0); //|(1<<UPM1)|(1<<UPM0) } void USART_Transmit( unsigned char data ) { while ( !(UCSRA & (1<<UDRE)) ); UDR = data; } int main(void) { //const unsigned int BAUDRATE = 9600; //const unsigned int BAUDDIVIDER = ((F_CPU/(16UL*BAUDRATE))-1); USART_Init(25); while(1) { USART_Transmit('h'); USART_Transmit('e'); USART_Transmit('l'); USART_Transmit('l'); USART_Transmit('o'); USART_Transmit('1'); USART_Transmit('2'); USART_Transmit(0x01); USART_Transmit(0x02); USART_Transmit(0x0A); USART_Transmit(0x0D); } }


    • By Maguark
      День добрый.
      Я имел малый опыт написания программы на С++ под малиной.
      До этого момента мои проекты я писал в редакторе "nano" и компилировал с помощью gcc.
      Но теперь передо мной стоит задача написать достаточно большую и сложную программу.
      И мне необходима IDE для разработки и отладки кода.
      Я решил поставить себе на рабочий компьютер Visual studio 2010, нашел замечательный вариант сопряжения рабочего компьютера и малины http://visualgdb.com/tutorials/raspberry/ .
      Я смог запустить приложение, написанное на рабочей машине, на малине. И даже проводить отладку. Но я пока нашел только как скомпилировать и запустить простой Сишный файл.
      Для реализации моих задач мне необходимо использовать UART. И ранее, компилируя и запуская код непосредственно на малине, я делал следующее:
      1-Редактировал сам код Си: nano uart1.c
      2-Компилировал файл: gcc -o uart1 -l rt uart1.c
      3-Запускал проект, с использованием UART : ./uart1 /dev/ttyAMA0
      Собственно вопрос который у меня и вызвал затруднения:
      Как мне запустить мой проект в VS, что-бы он корректно работал на малине, и я мог его отлаживать.
      Или может есть какие-то IDE которые я могу установить непосредственно на Малине?
×
×
  • Create New...