Arduino Mega, Ошибка работы с COM портом

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Доброе время всем! Я написал программу для ардуино, и программу для компа, которая работает с ардуино по modbus протоколу через виртуальный COM порт. По сути с компа задаются некоторые параметры в ардуино и ардуино уже сама работает с утройствами. Программа только опрашивает некоторые параметры в ардуино, чтобы видеть пользователю процесс. Опрос идет цикличный, бесконечный. Где-то через час-два работы в программе выскакивает ошибка "writefile function failed error 31", после чего опрос и дальнейшая работа с ардуино невозможна, при попытке закрыть и открыть порт повторно - выдает другую ошибку "setcommstate function failed 31" и кроме как перезапуска компа (или отключение и включение ардуино заново) ничего не помогает... (а перезапуск любого устройства болезнено влияет на процесс) При этом сама ардуино продолжает выполнять свой алгоритм без сбоев. Получается, что я теряю только управление к ней. Может кто сталкивался с этим?

ОС: Windows 7 x64

Arduino Mega 2560

Программа на Delphi, с использованием компоненты TComPort

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Дополню: ардуино питается от usb порта, скорость соединения 19200.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Я тут тоже написал программу, так она мне дату Пасхи на понедельник насчитала. Не подскажете где у меня ошибка?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Предлагаете чтоб я выложил коды программы и прошивки? ))) Пока хочу теорию получить, гуглю много тем по этой ошибке, но толком все связанно с программаторами, а тут не то совсем... сама ошибка "writefile function failed error 31" выпадывает при каких возможных вариантах?

ZIA
ZIA аватар
Offline
Зарегистрирован: 04.02.2017

Dr_grizzly пишет:

Предлагаете чтоб я выложил коды программы и прошивки? ))) Пока хочу теорию получить, гуглю много тем по этой ошибке, но толком все связанно с программаторами, а тут не то совсем... сама ошибка "writefile function failed error 31" выпадывает при каких возможных вариантах?

так и ищите в Паскале вашу ошибку, ОС: Windows 7 x64, я так понимаю USB-COM, а драйвера подписаны?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

ZIA пишет:

Dr_grizzly пишет:

Предлагаете чтоб я выложил коды программы и прошивки? ))) Пока хочу теорию получить, гуглю много тем по этой ошибке, но толком все связанно с программаторами, а тут не то совсем... сама ошибка "writefile function failed error 31" выпадывает при каких возможных вариантах?

так и ищите в Паскале вашу ошибку, ОС: Windows 7 x64, я так понимаю USB-COM, а драйвера подписаны?

USB-COM верно, в диспетчере у виртуального порта эти данные: Изготовитель: Arduino LLC (www.arduino.cc)

ВРоде как подписаны ))

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

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Dr_grizzly пишет:

Предлагаете чтоб я выложил коды программы и прошивки? ))) 

Нет, не предлагаю. Мне это не нужно. Проблема-то у Вас, а не у меня :)

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Докопал чуток проблему и теперь каждый ее сможет смоделировать. Ардуино шлет в порт Serial постоянно данные, хоть какие. Программа на компе запускатся, подключается к порту и читает эти данные. Все вроде нормально, но если нажать на ардуине кнопку Reset (имитация сбоя) программа перестанет читать данные из порта, хотя ардуино исправно станет их слать снова. Теперь вопрос - как восстановить подключение не выключая ардуино и программу? Пока удается только отключится от порта в программе, нажать повторно кнопку резет на ардуине, и снова включить порт в программе. Но это не есть айс, т.к. рестартовать ардуино нельзя. Нужно подключится к ней и мониторить просиходящее в настоящем времени.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Используя компоненту Tcomport для дельфи - исправил в ней процедуру

procedure TCustomComPort.AbortAllAsync;
begin

  try
    if not PurgeComm(FHandle, PURGE_TXABORT or PURGE_RXABORT) then
      raise EComPort.Create(CError_PurgeFailed, GetLastError);
  except
  end;

end;

Заключив  в обработчик try/except. Это позволяет не вывешить программу наглухо зацикливая на ошибке порта PurgeComm function failed (Error 5)... Теперь кнопка закрыть и открыть порт работают. Но похоже что-то в коде ардуины нужно прописать для переинициализации порта???

DESArt
Offline
Зарегистрирован: 26.02.2017

Попробуйте через модуль работать

unit dlComPort;

interface

 uses Sysutils, Windows, Classes;

 type

  TByteArray = array of Byte;
  TComPort = class(TThread)
   public
    Enable: Boolean;
    constructor Create(CreateSuspennded: Boolean);

    procedure OpenPort(pCom: String; pSpeed: Cardinal);
    procedure WriteByte(pByte: Byte); //Записать байт
    procedure WriteArrayByte(pByteArray: TByteArray);
    procedure ClosePort;
   private
    Com      : TDCB;
    ComHandle: THandle; //Ссылка на файл
    Overlap  : TOverlapped;

    RecvData    : array[0..255] of Char;
    TransmitData: array[0..255] of Char;

    TransMask   : DWORD;
    Errors      : DWORD;
    Status      : TComStat;
    RecvCount   : DWORD;

    BufferData  : String;
   protected
    procedure Execute; override;
    procedure WriteBuffer;
  end;

implementation

uses myPort;

 constructor TComPort.Create(CreateSuspennded: Boolean);
 begin
  inherited Create(CreateSuspennded);

   Self.Enable          := False;
   Self.Priority        := tpNormal;
   Self.FreeOnTerminate := False;
 end;

 procedure TComPort.OpenPort(pCom: String; pSpeed: Cardinal);
 begin
   ComHandle:= CreateFile(PChar(pCom), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0);
   PurgeComm(ComHandle, PURGE_TXABORT and PURGE_RXABORT and PURGE_TXCLEAR and PURGE_RXCLEAR);
   SetCommMask(ComHandle, EV_RXCHAR and EV_RXFLAG);

   GetCommState(ComHandle, Com);
   Com.BaudRate:= pSpeed;
   Com.Parity  := NOPARITY;
   Com.ByteSize:= 8;
   Com.StopBits:= OneStopBit;
   Com.EvtChar := chr(13);
   SetCommState(ComHandle, Com);
 end;

 procedure TComPort.WriteByte(pByte: Byte);
 var sByte: Cardinal;
 begin
  TransmitData:= '';
  TransmitData[0]:= chr(pByte);
   WriteFile(ComHandle, TransmitData, 1, sByte, @Overlap);
 end;

 procedure TComPort.WriteArrayByte(pByteArray: TByteArray);
 var FID: Integer;
     sByte: Cardinal;
 begin
  if (pByteArray = nil) or (High(pByteArray) > High(TransmitData)) then Exit;

  TransmitData:= '';
   For FID:= Low(pByteArray) to High(pByteArray) do
    TransmitData[FID]:= chr(pByteArray[FID]);

     WriteFile(ComHandle, TransmitData, High(pByteArray) + 1, sByte, @Overlap);
 end;

 procedure TComPort.ClosePort;
 begin
  CloseHandle(ComHandle);
 end;

 procedure TComPort.WriteBuffer;
 begin
   if Trim(Self.BufferData) = '' then Exit;
   
    fmMain.Memo1.Lines.Add('Rcv: ' + Self.BufferData);    
     Self.BufferData:= '';
 end;

 procedure TComPort.Execute; //readport
 begin
  while Enable do
  begin
   PurgeComm(ComHandle, PURGE_TXABORT and PURGE_RXABORT and PURGE_TXCLEAR and PURGE_RXCLEAR);
   WaitCommEvent(ComHandle, TransMask, @Overlap);
   WaitForSingleObject(Overlap.hEvent, INFINITE);

   RecvData:= '';

    if (TransMask and EV_RXCHAR) = EV_RXCHAR then
    begin
     ClearCommError(ComHandle, Errors, @Status);
     RecvCount:= Status.cbInQue;
     ReadFile(ComHandle, RecvData, RecvCount, RecvCount, @Overlap);
     Self.BufferData := Self.BufferData + Self.RecvData;
    end;
     
	 Self.Synchronize(Self.WriteBuffer);
	 
  end;
 end;

end.

 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Копаю этот модуль и разобрать чуток не могу, вообщем собрал простенькую прогу

var
  Form1: TForm1;
  MyPort: TComPort;

implementation

procedure TForm1.ButtonOpenClick(Sender: TObject);
begin
MyPort:=TComPort.Create(true);
MyPort.OpenPort('COM6',19200);

end;

procedure TForm1.ButtonSendClick(Sender: TObject);
var
MyAr : TByteArray;
begin
 SetLength(MyAr, 8);
MyAr[0]:=50;
MyAr[1]:=03;
MyAr[2]:=00;
MyAr[3]:=32;
MyAr[4]:=00;
MyAr[5]:=01;
MyAr[6]:=28;
MyAr[7]:=44;

MyPort.WriteArrayByte(myar);
end;

И чет не пойму в какой момент начинается чтение данных из порта... На ардуине вижу маргает лед порта когда жму Send, но в ответ ничего... на форму бросил мемо1 как прописано внутри кода...

DESArt
Offline
Зарегистрирован: 26.02.2017
 
MyPort:=TComPort.Create(true);
10 MyPort.OpenPort('COM6',19200);
 
 Добавьте ещё сюда 
 MyPort.Enable := True;
 MyPort.Resume;
DESArt
Offline
Зарегистрирован: 26.02.2017

при закрытии формы

 MyPort.Suspend;
 MyPort.ClosePort;
 
чтобы ексепшены не валились
DESArt
Offline
Зарегистрирован: 26.02.2017

Self.Synchronize(Self.WriteBuffer); -< тут можно собирать свои пакеты

например я сделал так <функция (1 byte)Порт(1 byte)Получение или выставление значения(4 byte)>

<g30000> - примерно такой 1 пакет

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Интересная штуковина получилась, но одно пока странно - если нажать пару раз на кнопку ButtonOpen то потом не получается закрыть ни один )))

DESArt
Offline
Зарегистрирован: 26.02.2017

тут только руками следить )) можно доделать но пока некогда

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Новая вводная )) Подключил к ардуине блок реле. В ардуине только 4 таймера (не делей). Решил запитать блок реле от ардуины (там 5-и вольтовые реле и оптическая развязка на управлении реле стоит). В ардуине использую ту же библиотеку с Модбас протоколом.  Все работает здорово, пока не запускаю цикл с переключениями реле. Т.е. перед запуском я задаю разные интервалы времени в ардуино с компа через USB используя протокол Модбас, все пишет, все читает, все здорово. Как только нажимаю Старт алгоритма, т.е непосредственное исполнение таймеров и переключение реле - порт тут же отваливается при следуюем обращении во время работы алгоритма с ошибкой writefile function failed error 31. А алгоритм продолжает выполнятся.  Вот тут я стал размышлять, алгоритм простой, всего три таймера, ничего она не отправляет в порт, только принимает, но управляют они 4мя релюшками. И я решил снять нагрузку с ардуины и поставить отдельный блок питания на 5В. И все заработало! Теперь собственно вопрос - что не хватает ардуине? Как можно исправить это?

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Dr_grizzly пишет:
И я решил снять нагрузку с ардуины и поставить отдельный блок питания на 5В. И все заработало! Теперь собственно вопрос - что не хватает ардуине? Как можно исправить это?

Ну вы же уже нашли решение - применить отдельный БП...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Dr_grizzly пишет:

Новая вводная )) Подключил к ардуине блок реле. В ардуине только 4 таймера (не делей). Решил запитать блок реле от ардуины (там 5-и вольтовые реле и оптическая развязка на управлении реле стоит). В ардуине использую ту же библиотеку с Модбас протоколом.  Все работает здорово, пока не запускаю цикл с переключениями реле. Т.е. перед запуском я задаю разные интервалы времени в ардуино с компа через USB используя протокол Модбас, все пишет, все читает, все здорово. Как только нажимаю Старт алгоритма, т.е непосредственное исполнение таймеров и переключение реле - порт тут же отваливается при следуюем обращении во время работы алгоритма с ошибкой writefile function failed error 31. А алгоритм продолжает выполнятся.  Вот тут я стал размышлять, алгоритм простой, всего три таймера, ничего она не отправляет в порт, только принимает, но управляют они 4мя релюшками. И я решил снять нагрузку с ардуины и поставить отдельный блок питания на 5В. И все заработало! Теперь собственно вопрос - что не хватает ардуине? Как можно исправить это?

какие-то у вас сержантские замашки )))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Вот вроде бы нашел решение, но в голове не укладывается, ведь схема у меня работает на ULN2003 и ULN2002 это полевые транзисторные сборки, как я могу просаживать питанием ардуино - не укладывается в голове... Вот та схема подключения. J1  это порт Arduino Mega, порт J7 выходы на нагрузку (Между контактом J7 и +24 стоит нагрузка). J3 это входы от датчиков (24Вольта). На J4 подаю +5 от самой ардуины. Может где резисторов не хватает??

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Dr_grizzly пишет:

ULN2003 и ULN2002 это полевые транзисторные сборки, 

Кто Вам сказал?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Где то тут http://www.joyta.ru/4575-mikrosxema-uln2003-opisanie-i-sxemy-primeneniya/
И тут https://ru.m.wikipedia.org/wiki/Составной_транзистор
Хотя утвержать 100% не могу)) но вроде как по этому принципу работает.... А что? Проблема может быть в этом закопана?))) я только ЗА решить ее)))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

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

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Чудеса... Вы сами то внимательно читали по этим ссылкам?

По первой ссылке: "Микросхемы ULN2003 это транзисторная сборка Дарлингтона"

По второй ссылке: "Составной транзистор (или схема) Дарлингтона (часто — пара Дарлингтона) была предложена в 1953 году инженером Bell Laboratories Сидни Дарлингтоном (Sidney Darlington). Схема является каскадным соединением двух (редко — трех или более) биполярных транзисторов"

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

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

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

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

Dr_grizzly, узнайте для начала, чем полевой транзистор отличается от биполярного.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Dr_grizzly пишет:

чем транзисторная сборка Дарлингтона отличается от полевого транзистора в общем принципе действия? 

А чем вообще биполярный транзистор отличеатся от полевого?  Как только Вы узнаете ответ на этот вопрос, остальные отпадут сами собой.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Отличие в том, что полевой транзистор управляется напряжением, биполярный- током. А ULN2002-2003 тогда чем?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Мы немного в дебри лезем, я руководствовался этой статьей http://www.getchip.net/posts/062-kak-podklyuchit-k-mikrokontrolleru-nagr...

Обвязал резисторами от шума. Но похоже что ловлю перегруз на порту. Вот и сомневаюсь а правильно ли все подключил

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Dr_grizzly пишет:

Отличие в том, что полевой транзистор управляется напряжением, биполярный- током. А ULN2002-2003 тогда чем?

Ну Вы же читали по Вашей ссылке, что ULN-ка - массив биполярных транзисторных сборок. Так сами и ответьте, чем она управляется.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Хорошо, ULN2003 на схеме управляет нагрузкой. С ней вроде проблем нет, а вот с ULN2002 подозрения. Она обрабатывает оптические датчики, которые работают на 24 вольтах. Когда датчик перекрыт - он коммутирует 24 вольта и ключ ULN подает 5 вольт на порт ардуины. И получается, что когда датчики начинают работать группой, то в какой-то момент вылетает ошибка COM порта 31. Как-то можно продиагностировать эту проблему? Подтвердить или опровергнуть ошибку в схеме подключения, или может что-то добавить на нее нужно, для правильной работы с датчиками? Пока мысль у меня - вывести отдельное 5-и вольтовое питание всей этой схемы. Т.е не брать 5 вольт с платы ардуино мега.

fusic
Offline
Зарегистрирован: 08.02.2017

Dr_grizzly, чем закончилось ? Разобрались вы с проблемой? Выручайте если разобрались. 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Проблема оказалась в том, что не хватало ресурсов самой ардуине работать на 2 порта в режиме нон/стоп. Чип отвечающий за USB просто отказывался обрабатывать данные. Решил просто - купил чип max232 распаял выводы и зацепил к Меге к Serial1/2/3 не важно. ПРосто отказался от usb. И все просто замечательно работает уже несколько лет.