Serial Half-Data

Rootware
Offline
Зарегистрирован: 11.01.2018

Доброго времени суток.

Для общения между МК <-> ПК через Serial порт использую байт массивы определённой структуры (некое подобие пакетов). Но есть одна маленькая проблема. Данные считываемые платой не соответствуют действительности.

Код МК:

void serialEvent()
{
      while (Serial.available())
      {
            byte a = Serial.read();
            Serial.write(a);
      }
}

Отправляю из программы следующий байт массив:

AA AA AA 07 00 42 00 7B 00 00 00 55 55 55

Получаю обратно следующее:

AA AA AA 07 00 42 00

Т.е. возвращается ровно (!) половина пакета. Пробовал менять скорости передачи - ноль эмоций. Иные настройки COM порта со стороны МК я не знаю, поэтому со стороны компьютера использую дефолтные для SerialPort() модуля .NET Framework.

Если не использвать serialEvent(), а делать собственный обработчик в loop() без цикла, то практически всегда буфер чтения начинается с 4-х байт F0. И также практически всегда не соответствует действительности. Но если буфер чтения пуст, то МК отправляет правильный пакет сформированный после полного перебора буфера чтения. И не имеет значение длина пакета. У меня были от 10 до 40 байт.

Плата Arduino/Genuino Uno R3 (оригинал).

Подскажите в чём может быть проблема и какие дефолтные настройки Serial у Aduino плат?

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Rootware пишет:

Данные считываемые платой не соответствуют действительности.

Иногда действительность не соответствует ожидаемой действительности.

Дефолтные настройки 8n1 их можно поменять когда делаете Serial.begin()

Выкините сериалэвент (он на некоторых платах вообще не поддерживается).

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Не знаю, чего вы там делаете, но уже пару лет как использую SerialPort на C# в связке с дуней - ничто никуда не пропадает, данные ходят в обе стороны.

Rootware
Offline
Зарегистрирован: 11.01.2018

Penni пишет:

Rootware пишет:

Данные считываемые платой не соответствуют действительности.

Иногда действительность не соответствует ожидаемой действительности.

Дефолтные настройки 8n1 их можно поменять когда делаете Serial.begin()

Выкините сериалэвент (он на некоторых платах вообще не поддерживается).

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

Если вы посмотрите внимательно, то сигнарура начала и конца пакета присутствует (3 одинаковых байта). Проблема в том, что очень часто пакет приходит в МК без конца. Это было выявлено отправкой байта в ПК виз каждой контрольной точки обработки пакета. Обработка состоит из 3-х частей: чтение преамбулы, чтение тела пакета и чтение хвоста. так вот чтение обрывается чаще всего на чтении тела и хвоста.

Причин влияющих на это я понять не могу. Точнее логики "проглатывания" окончания пакета. В старой реализации всё работает нормально. НО, первый входящий пакет в МК обрабатывался только с 5-20-го раза.

Rootware
Offline
Зарегистрирован: 11.01.2018

DIYMan пишет:

Не знаю, чего вы там делаете, но уже пару лет как использую SerialPort на C# в связке с дуней - ничто никуда не пропадает, данные ходят в обе стороны.

Можно посмотреть вашу реализацию со стороны МК? Со стороны C# приложения всё прозаично.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Вот для интереса глянул

byte inBuffer[30];

void setup()
{
  Serial.begin(9600);
  Serial.setTimeout(100);
}

void loop()
{
  if(Serial.available() > 0)
  {
    Serial.readBytes(inBuffer, 30);
    Serial.write(inBuffer, 30);
  }
}

читаем что пришло в буфер и отправляем обратно в C#, все прекрасно работает. С шарпа отправляется вот так

private void btnSendArray_Click(object sender, EventArgs e)
        {
            byte[] array2arduino = new byte[] { 0xAA, 0xAA, 0xAA, 0x07, 0x00, 0x42, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, };
            if(!spArduino.IsOpen)
              spArduino.Open();
            spArduino.Write(array2arduino, 0, array2arduino.Length);
        }

Может Вы по прерыванию уходите и теряете буфер или, например, не хватает оперативки и данные теряются. Да что угодно, без кода можно долго гадать.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Rootware пишет:

Можно посмотреть вашу реализацию со стороны МК? Со стороны C# приложения всё прозаично.

Простейшая - вычитывание до признака конца пакета, потом - парсинг. Так же сделано у Nextion, например.

Rootware
Offline
Зарегистрирован: 11.01.2018

Вот мой тестовый пример для дебага интерфейса между МК <-> ПК.

Сам тестовый скетч:

boolean packetCompleted;

uint8_t eventState;
uint8_t packetState;

uint8_t packetOffset;
uint8_t countPreambula;
uint8_t countTail;
uint8_t packetSize;

byte packet[32];

void setup()
{
      packetCompleted = false;
      
      eventState = 0;
      packetState = 0;
      packetOffset = 0;
      countPreambula = 0;
      countTail = 0;
      packetSize = 0;
      
      Serial.begin(115200);
      Serial.setTimeout(100);
}

void loop()
{
     while (Serial.available())
      {
            // Get Preambula.
            if (eventState == 2)
            {
                   //Serial.write(0x20);
                   
                  byte data = Serial.read();
                  if (data == 0x55)
                  {
                        //Serial.write(0x21);
                        
                        countTail += 1;

                        if (countTail == 3)
                        {
                              //Serial.write(0x22);
                              
                              eventState = 3;
                              countTail = 0;
                              packetCompleted = true;
                        }
                  }
                  else
                  {
                        //Serial.write(0x23);
                        
                        eventState = 0;
                        countTail = 0;
                  }
            }
            
            // Packet processing
            if (eventState == 1)
            {
                  //Serial.write(0x10);
                  
                  // Get Packet Body.
                  if (packetState == 1)
                  {
                         //Serial.write(0x11);
                         
                        packet[packetOffset++] = Serial.read();

                        if (packetOffset == packetSize)
                        {
                               //Serial.write(0x12);
                               
                              eventState = 2;
                              packetState = 0;
                              packetOffset = 0;
                        }
                  }
                  
                  // Get Packet Size.
                  if (eventState == 1 && packetState == 0)
                  {
                         //Serial.write(0x14);
                        packetSize = Serial.read();
                        if (packetSize > 0)
                        {
                              //Serial.write(0x15);
                              
                              packetState = 1;
                        }
                        else
                        {
                               //Serial.write(0x16);
                              eventState = 0;
                              packetState = 0;
                        }
                  }
            }
            
            // Preambula processing
            if (eventState == 0)
            {
                  //Serial.write(0x00);
                  
                  byte data = Serial.read();
                  if (data == 0xAA)
                  {
                        //Serial.write(0x01);
                        
                        countPreambula++;

                        if (countPreambula == 3)
                        {
                              //Serial.write(0x02);
                              eventState = 1;
                              countPreambula = 0;
                        }
                  }
                  else
                  {
                        //Serial.write(0x03);
                        countPreambula = 0;
                  }
            }
      }
      
      if (packetCompleted)
      {
            for (int i = 0; i < packetSize; i++)
            {
                  Serial.write(packet[i]);
            }
            
            packetCompleted = false;
            eventState = 0;
      }
}

C# код Program.cs:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
using System.IO.Ports;
using System.IO;

namespace SerialPortConn
{
    static class Program
    {
        /// <summary>
        /// Главная точка входа для приложения.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Thread serialMonitor = new Thread(SerialMonitor);
            serialMonitor.IsBackground = true;
            serialMonitor.Start();

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

        private static void SerialMonitor()
        {
            Thread.Sleep(2000);

            while (true)
            {
                SerialPort port = new SerialPort("COM15");
                port.BaudRate = 115200;
                port.Open();

                while (true)
                {
                    if (port != null)
                    {
                        byte[] array = new byte[12] { 0xAA, 0xAA, 0xAA, 0x05, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0x55, 0x55, 0x55 };

                        string send = "Outgoing bytes: ";
                        for (int i = 0; i < array.Length; i++)
                            send += (send.Length > 0 ? " " + array[i].ToString("x2") : array[i].ToString("x2")).ToUpper();

                        print(send);

                        port.Write(array, 0, array.Length);

                        Thread.Sleep(100);

                        string recieve = "Incoming bytes: ";
                        for (int i = 0; i < port.BytesToRead; i++)
                            recieve += (recieve.Length > 0 ? " " + port.ReadByte().ToString("x2") : port.ReadByte().ToString("x2")).ToUpper();

                        print(recieve);
                    }


                    Thread.Sleep(500);
                }
            }
        }

        private static void print(string stack)
        {
            string line = DateTime.Now.ToString("dd.MM.yyyy, HH:mm:ss") + ": " + stack;

            if (!Directory.Exists("logs"))
                Directory.CreateDirectory("logs");

            using (FileStream file = new FileStream(@"logs\log_" + DateTime.Now.ToString("dd-MM-yyyy") + ".txt", FileMode.OpenOrCreate))
            {
                lock (file)
                {
                    StreamWriter sw = new StreamWriter(file);
                    file.Seek(0, SeekOrigin.End);
                    sw.WriteLine(line);
                    sw.Close();
                }
            }
        }
    }
}

Строение пакета следующее:

        // AA AA AA - [3 bytes] Preambula
        // XX - [1 byte] Packet size (Data Array)
        // XX XX XX - [n - bytes] Data Array
        // 55 55 55 - [3 bytes] Tail

Лог работы программы следующий:

23.01.2018, 19:53:53: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:53: Incoming bytes:  FF FE FD
23.01.2018, 19:53:54: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:54: Incoming bytes:  FC FB FF FE
23.01.2018, 19:53:54: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:55: Incoming bytes:  FD FC FB FF
23.01.2018, 19:53:55: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:55: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:56: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:56: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:56: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:56: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:57: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:57: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:58: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:58: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:58: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:58: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:59: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:53:59: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:53:59: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:54:00: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:54:00: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:54:00: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:54:01: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:54:01: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:54:01: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:54:01: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:54:02: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:54:02: Incoming bytes:  FE FD FC FB FF
23.01.2018, 19:54:03: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 19:54:03: Incoming bytes:  FE FD FC FB FF

А теперь расскажите, пожалуйста, какая магия нужна чтобы получить обратно тело пакета?

Спасибо.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Я совсем не так получаю данные из порта в C# - я просто использую событие DataReceived в SerialPort. Разбираться в выложенных выше простынях - чой-то не хочется, т.к. я на 100500% уверен, что проблема не в UART, а в подходе к нему.

Rootware
Offline
Зарегистрирован: 11.01.2018

DIYMan пишет:

Я совсем не так получаю данные из порта в C# - я просто использую событие DataReceived в SerialPort. Разбираться в выложенных выше простынях - чой-то не хочется, т.к. я на 100500% уверен, что проблема не в UART, а в подходе к нему.

Это событие в MSDN описано как "негарантированное для каждого полученного байта". Смысл тогда от него?

Цитата:

The E:System.IO.Ports.SerialPort.DataReceived event is not guaranteed to be raised for every byte received. Use the P:System.IO.Ports.SerialPort.BytesToRead property to determine how much data is left to be read in the buffer.

b707
Offline
Зарегистрирован: 26.05.2017

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

Вам надо сделать отладлчный вывод ваших пакетов, причем независимый - не через сериал.  Возьмите коротенький код Пенни из сообщения #5 и сразу по получении, без обработки выводите куда-нибудь все полученные ардуиной байты - в другой порт, на экран и тд

Ваша первая задача - выяснить, кто теряет - ваш код на С# при отправке, ваш код ардуины на приеме, код при отправке и тд

 

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Rootware пишет:

DIYMan пишет:

Я совсем не так получаю данные из порта в C# - я просто использую событие DataReceived в SerialPort. Разбираться в выложенных выше простынях - чой-то не хочется, т.к. я на 100500% уверен, что проблема не в UART, а в подходе к нему.

Это событие в MSDN описано как "негарантированное для каждого полученного байта". Смысл тогда от него?

Цитата:

The E:System.IO.Ports.SerialPort.DataReceived event is not guaranteed to be raised for every byte received. Use the P:System.IO.Ports.SerialPort.BytesToRead property to determine how much data is left to be read in the buffer.


 

Вы читать-то умеете? Там написано ровно следующее: Не гарантируется, что событие будет вызвано ДЛЯ КАЖДОГО принятого байта. Юзайте BytesToRead, чтобы узнать, сколько там байт лежит в буфере для чтения.

При приходе события - в приёмном буфере ГАРАНТИРОВАННО есть байты, вот только их кол-во - от 1 до N. Переводите с английского правильно.

Rootware
Offline
Зарегистрирован: 11.01.2018

b707 пишет:

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

Вам надо сделать отладлчный вывод ваших пакетов, причем независимый - не через сериал.  Возьмите коротенький код Пенни из сообщения #5 и сразу по получении, без обработки выводите куда-нибудь все полученные ардуиной байты - в другой порт, на экран и тд

Ваша первая задача - выяснить, кто теряет - ваш код на С# при отправке, ваш код ардуины на приеме, код при отправке и тд

Я начал с того... Данная беда мне уже месяц покоя не давала. Просто настал момент когда нужно не каждый 5й - 20й пакет (хотя бы) обрабатывать, а каждый первый.

Спасибо что ответили. Всё вышеизложенной было проверено.

Уже исправил. Не актуально.

b707
Offline
Зарегистрирован: 26.05.2017

Rootware пишет:

Я начал с того... Данная беда мне уже месяц покоя не давала. Просто настал момент когда нужно не каждый 5й - 20й пакет (хотя бы) обрабатывать, а каждый первый.

Спасибо что ответили. Всё вышеизложенной было проверено.

Уже исправил. Не актуально.

И что, работает? :)

Месяц отлажиливали передачу через сериал, которая у большинства новичков работает сразу... и тут раз - и исправили :)

Rootware
Offline
Зарегистрирован: 11.01.2018

b707 пишет:

Rootware пишет:

Я начал с того... Данная беда мне уже месяц покоя не давала. Просто настал момент когда нужно не каждый 5й - 20й пакет (хотя бы) обрабатывать, а каждый первый.

Спасибо что ответили. Всё вышеизложенной было проверено.

Уже исправил. Не актуально.

И что, работает? :)

Месяц отлажиливали передачу через сериал, которая у большинства новичков работает сразу... и тут раз - и исправили :)

23.01.2018, 21:21:13: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:13: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:13: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:13: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:14: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:14: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:14: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:15: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:15: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:15: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:16: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:16: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:16: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:16: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:17: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:17: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:17: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:18: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:18: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:18: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:19: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:19: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:19: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:19: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:20: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:20: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:20: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:21: Incoming bytes:  FF FE FD FC FB
23.01.2018, 21:21:21: Outgoing bytes:  AA AA AA 05 FF FE FD FC FB 55 55 55
23.01.2018, 21:21:21: Incoming bytes:  FF FE FD FC FB

Месяц руки не доходили до экспериментов с иной моделью работы с буфером чтения. Да, я новичок в Arduino. И уже жалею, что не ухожу на STM32 и C++.

b707
Offline
Зарегистрирован: 26.05.2017

Rootware пишет:

Месяц руки не доходили до экспериментов с иной моделью работы с буфером чтения. Да, я новичок в Arduino. И уже жалею, что не ухожу на STM32 и C++.

думаете, поможет? :)  для справки - нет языка ардуино - это С++

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Rootware пишет:

Месяц руки не доходили до экспериментов с иной моделью работы с буфером чтения. Да, я новичок в Arduino. И уже жалею, что не ухожу на STM32 и C++.

Начнём с того, что ардуино программируется на С++, т.е. не надо уходить с С++ на С++, знаете ли. Про STM - попробуйте, и вы увидите, что ваши слова "уже жалею, что не ухожу" быренько сменят окраску. В STM свои фишки и грабли, и новичку в программировании там уж точно не легче, чем на ардуине.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Rootware, правильный совет Вам дал DIYMan еще в 6-м сообщении: Вы вычитываете буфер, не дожидаясь, пока придет последний байт сообщения. Т.е Вы считали 4, 5-й еще принимается, но т.к. его пока нет Serial.available() выдает 0.

Нужно принимать до конца пакета, а не до того момента, когда опустошится буфер.

Rootware
Offline
Зарегистрирован: 11.01.2018

andriano пишет:

Rootware, правильный совет Вам дал DIYMan еще в 6-м сообщении: Вы вычитываете буфер, не дожидаясь, пока придет последний байт сообщения. Т.е Вы считали 4, 5-й еще принимается, но т.к. его пока нет Serial.available() выдает 0.

Нужно принимать до конца пакета, а не до того момента, когда опустошится буфер.

Да работает уже всё. Спасибо. Проблема была в другом. Мои "портянки" выше на 99,8% рабочие и имеют несколько логических ошибок, т.к. писались "на скорую руку".

b707
Offline
Зарегистрирован: 26.05.2017

Rootware пишет:

Да работает уже всё. Спасибо. Проблема была в другом. Мои "портянки" выше на 99,8% рабочие и имеют несколько логических ошибок, т.к. писались "на скорую руку".

Ваша проблема действительно в другом.

Вы, видимо, прошли теоретический курс по Си -С++. что создало у вас не вполне обоснованную уверенность в своих знаниях. Вам кажется, что в целом, то, что вы кодируете - правильно и проблемы лишь в мелких ошибках или в глюках железа. Вы задаете ответы. но ответов не слушаете, если они нарушают ваше "эго".

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

 

Rootware
Offline
Зарегистрирован: 11.01.2018

b707 пишет:

Rootware пишет:

Да работает уже всё. Спасибо. Проблема была в другом. Мои "портянки" выше на 99,8% рабочие и имеют несколько логических ошибок, т.к. писались "на скорую руку".

Ваша проблема действительно в другом.

Вы, видимо, прошли теоретический курс по Си -С++. что создало у вас не вполне обоснованную уверенность в своих знаниях. Вам кажется, что в целом, то, что вы кодируете - правильно и проблемы лишь в мелких ошибках или в глюках железа. Вы задаете ответы. но ответов не слушаете, если они нарушают ваше "эго".

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

 

Никаких курсов я не проходил. Просто в детстве прочитал книжку "Basic - это просто". Это все мои знания в программировании.