Форум программистов, компьютерный форум, киберфорум
Delphi: WinAPI
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
0 / 0 / 0
Регистрация: 09.02.2015
Сообщений: 26
1

Работа с COM портом

13.01.2016, 20:42. Показов 3752. Ответов 5
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день, уважаемые знатоки!
Помогите пожалуйста выработать логику работы программы.
Имеется электродвигатель, с одним магнитом на валу. Имеется датчик Холла (магнитного поля) и имеется вот такой вот прибор (
HTML5
1
http://kernelchip.ru/Ke-USB24R.php
), прибор работает через COM порт. Необходимо считать обороты вала двигателя.
Принцип работы: когда магнита нет рядом с датчиком, то на логический вход прибора подается логический 0, если магнит рядом - то 1 соответственно. Прибор не умеет автоматически транслировать состояние логического входа. Для этого на форме есть таймер (10 мс), который отправляет запрос на состояние логического входа в прибор.
Загвоздка вот в чем, если обороты вала двигателя НЕ высокие, то магнит будет пролетать мимо датчика, например, 100 мс. За это время таймер 10 раз опросит вход и 10 раз получит единицу.
Далее есть еще время наполнения буфера из COM порта (100 мс). Итого я могу счетчиком считать кол-во полученных единиц, но они не будут соответствовать реальному кол-ву оборотов двигателя. По логике, надо ловить переход с 1 на 0. Как только в такой последовательности пришли данные - в счетчик +1. Ну а потом суммировать данные счетчика в секунду, в минуту и т.д.
Итак, как возможно организовать такой подсчет или как вообще реализовать данную программу?
Имеется такой код:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
procedure TForm1.StartPotok;
begin //При старте программы запускаем поток
Potok := TPotok.Create(False);
Potok.Priority:=tpLower;
end;
 
procedure TPotok.Execute;
begin
  repeat
    ReadPort; //процедура опроса порта будет производиться пока поток не будет прекращен
  until Terminated;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  s:='RD,1';
  buffer := KE +','+ s + AnsiChar(CRbyte) + AnsiChar(LFbyte);
  WriteFile(Port, PAnsiChar(buffer)^, Length(buffer), NumberWritten, nil);
  s:='';
end;
 
procedure TPotok.ReadPort;
var
  MyBuff: array[0..1023] of AnsiChar;
  ByteReaded: DWORD;
  a, s: TStringList;
  i: integer;
  //Rel_1, Rel_2: AnsiString; //Проверяем положение реле
begin
  FillChar(MyBuff, SizeOf(MyBuff), #0);
  ReadFile(Port, MyBuff, SizeOf(MyBuff), ByteReaded, nil);
    if ByteReaded > 0 then  //Если считанный буфер не пустой
      begin
        A:= TStringList.Create;
        S:= TStringList.Create;
        try
          A.Text:= string(MyBuff);
            for i:= 0 to A.Count-1 do
              begin
                S.CommaText:= A[i]; //Разделяем строки
                  if AnsiStartsStr('#RD,01', S.CommaText) then //Состояние I/O входа 1
                      begin
                      IO1:=StrToInt(AnsiMidStr(S.CommaText, 8, 1));
                      if IO1=1 then
                        begin
//Общение прибора, запрос: $KE,RD,1    Ответ: #RD,01,1 (или #RD,01,0)
                        end;
                      end;
                  {if AnsiStartsStr('#RD,02', S.CommaText) then //Состояние I/O входа 2
                      begin
                      Led2:=StrToInt(AnsiMidStr(S.CommaText, 8, 1));
                      Synchronize(SetIO2);
                      end;}
                  if (AnsiStartsStr('#ADC', S.CommaText))
                    OR (AnsiStartsStr('#RD', S.CommaText)) then  //begin - пусто
                    else
                      begin
                        Form1.Memo1.Lines.Add(TimeToStr(Time)+';'+A.Strings[i]);
                      end;
              end;
        finally
          A.Free;
          S.Free;
      end;
  end;
end;
 
//Настройки порта
      GetCommState(Port, DCB);
      DCB.BaudRate  := CBR_9600;
      DCB.Parity    := NOPARITY;
      DCB.ByteSize  := 8;
      DCB.StopBits  := OneStopBit;
      CommTimeOuts.ReadIntervalTimeout          := MAXDWORD;
      CommTimeOuts.ReadTotalTimeoutMultiplier   := 0;
      CommTimeOuts.ReadTotalTimeoutConstant     := 0;
      CommTimeOuts.WriteTotalTimeoutMultiplier  := 10;
      CommTimeOuts.WriteTotalTimeoutConstant    := 100;
      SetCommTimeouts(Port, CommTimeOuts);
      SetCommState(Port, DCB);
Добавлено через 6 часов 40 минут
Появилась вот такая идея:
раз в секунду запускать поток и считывать данные из порта. В теле потока при помощи флагов определяем последовательность 1-0. Если такая последовательность была, то с счетчику добавляем 1. В конце потока (окончании чтения данных из буфера порта) - синхронизация с телом программы, передача показания счетчика, и вычисления оборотов и т.д.
Допустимо ли такое решение?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.01.2016, 20:42
Ответы с готовыми решениями:

Работа с последовательным портом
Добрый день! В работе с железом я новичок, поэтому прошу объяснения и помощи. Заранее спасибо =)...

Работа с COM портом реальным и виртуальным
Добрый день. Есть программа обмена с устройствами ввода-вывода через преобразователь интерфейса...

работа с COM портом
помогите, пожалуйста, наладить правильную работу с COM- портом. У меня есть аналогово-цифровой...

Работа с COM портом
Cразу к делу ) Нужна программа где достаточно будет 1 кнопки Start которая по клику начнет...

5
Пишу на Delphi...иногда
1423 / 1278 / 286
Регистрация: 03.12.2012
Сообщений: 3,914
Записей в блоге: 5
13.01.2016, 21:52 2
стоит начать с того, что Windows - НЕ СРВ и конкретные значения времени, как написано каждые 100 мс, тут особо не поймаешь, имхо если требуется точность, то стоит посмотреть в сторону микроконтроллеров

Цитата Сообщение от korelland Посмотреть сообщение
Прибор не умеет автоматически транслировать состояние логического входа ... отправляет запрос на состояние логического входа в прибор... По логике, надо ловить переход с 1 на 0...
имхо, стоит поступить так: имеется поток, который с какой-либо периодичностью отправляет запросы и получает в ответ 0 или 1, хранит результат предыдущего запроса и как-то приблизительно подсчитывает требуемый временной интервал расчета. полученный ответ сравнивается с предыдущим, если это вожделенный переход с 1 на 0, то счетчик переходов +1, если время измерения закончилось, то отдаем основному потоку результат расчета скорости, сбрасываем счетчик времени и начинаем сначала
0
пофигист широкого профиля
4733 / 3167 / 859
Регистрация: 15.07.2013
Сообщений: 18,252
14.01.2016, 00:43 3
Имхо, самое нормальное решение - это дополнительная железяка, которая всё меряет. В данном случае считает обороты. А PC-программа уже в спокойном (нормальном для ОС Windows) режиме получает с этой железяки готовые данные.
0
0 / 0 / 0
Регистрация: 09.02.2015
Сообщений: 26
14.01.2016, 15:09  [ТС] 4
А как можно реализовать запоминание предыдущей переменной в зацикленном потоке? Лыжи не едут...

Добавлено через 57 минут
Пока придумал вот такое решение:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
procedure TPotok.Execute;
begin
  repeat
    if First=0 then
      begin
        if FLAG=true then
          begin
            Second:=0;
            FLAG:=false;
          end
          else
          begin
            Second:=1;
          end;
        FLAG:=false;
      end
      else
      begin
        FLAG=true;
      end;
    if (First=1) AND (Second=0) then Hz:=Hz+1;
    Form1.Label4.Caption:=IntToStr(Hz); //Вот тут большой вопрос...
    s:='RD,1';
    buffer := KE +','+ s + AnsiChar(CRbyte) + AnsiChar(LFbyte);
    WriteFile(Port, PAnsiChar(buffer)^, Length(buffer), NumberWritten, nil);
    s:='';
    ReadPort; //процедура опроса порта будет производиться пока поток не будет прекращен
  until Terminated;
end;
 
procedure TPotok.ReadPort;
var
  MyBuff: array[0..1023] of AnsiChar;
  ByteReaded: DWORD;
  a, s: TStringList;
  i: integer;
begin
  FillChar(MyBuff, SizeOf(MyBuff), #0);
  ReadFile(Port, MyBuff, SizeOf(MyBuff), ByteReaded, nil);
    if ByteReaded > 0 then  //Если считанный буфер не пустой
      begin
        A:= TStringList.Create;
        S:= TStringList.Create;
        try
          A.Text:= string(MyBuff);
            for i:= 0 to A.Count-1 do
              begin
                S.CommaText:= A[i]; //Разделяем строки
                  if AnsiStartsStr('#RD,01', S.CommaText) then //Состояние I/O входа 1
                    begin
                      IO1:=StrToInt(AnsiMidStr(S.CommaText, 8, 1));
                      if IO1=0 then
                        begin
                          First:=0;
                        end
                        else
                        begin
                          First=1;
                        end;
                    end;
              end;
        finally
          A.Free;
          S.Free;
      end;
  end;
end;
Теоретически при последовательности 1-0 к переменной Hz добавится +1. То есть это действие произойдет за один цикл потока. Теперь вопрос - как можно выполнять поток определенное количество времени, например 1 сек, 10 сек или минуту? Таймер выполняет действие РАЗ в заданный интервал времени. А как выполнять неограниченное кол-во раз в заданный интервал?

Добавлено через 2 часа 36 минут
Вопрос, надеюсь, решен полностью))
По нажатию кнопки запускается поток и таймер, таймер настроен на 1 секунду. При срабатывании таймера из потока получаю кол-во последовательностей 1-0, обрабатываю его и останавливаю поток с обнулением переменных, и таймер запускается снова. Цикл таймера повторяется. В итоге получаю довольно точное кол-во оборотов двигателя в секунду и минуту.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
procedure TForm1.Button6Click(Sender: TObject);
begin
//Запускаем таймер, обнуляем кол-во пойманных оборотов, запускаем поток
  Timer1.Enabled:=true;
  Hz:=0;
  FLAG:=false;
  StartPotok;
end;
 
procedure TForm1.StartPotok;
begin
  Potok := TPotok.Create(False);
  Potok.Priority:=tpLower;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  //Тормозим, считаем полученное кол-во оборотов, тормозим поток, и запускаем по кругу
  Timer1.Enabled:=false;
  Form1.Label4.Caption:=IntToStr(Hz)+' об/сек';
  Form1.Label5.Caption:=IntToStr(Hz*60)+' об/мин';
  Potok.Terminate;
  Timer1.Enabled:=true;
  Hz:=0;
  FLAG:=false;
  StartPotok;
end;
 
procedure TPotok.Execute;
begin
  repeat
  //Если на входе 0, то ничего
  //Если на входе 1, то ставим флаг (запоминаем, что была единица)
  //Если после 1 опять 1, то опять ставим флаг (запоминаем, что была единица)
  //Если после 1 получаем 0, то записываем в
    if First=0 then
      begin
        if FLAG=true then
          begin
            Hz:=Hz+1;
          end;
        FLAG:=false;
      end
      else FLAG:=true;
    s:='RD,1';
    buffer := KE +','+ s + AnsiChar(CRbyte) + AnsiChar(LFbyte);
    WriteFile(Port, PAnsiChar(buffer)^, Length(buffer), NumberWritten, nil);
    s:='';
    ReadPort;
    //процедура опроса порта будет производиться пока поток не будет прекращен
  until Terminated;
end;
 
procedure TPotok.ReadPort;
var
  MyBuff: array[0..1023] of AnsiChar;
  ByteReaded: DWORD;
  a, s: TStringList;
  i: integer;
begin
  FillChar(MyBuff, SizeOf(MyBuff), #0);
  ReadFile(Port, MyBuff, SizeOf(MyBuff), ByteReaded, nil);
    if ByteReaded > 0 then  //Если считанный буфер не пустой
      begin
        A:= TStringList.Create;
        S:= TStringList.Create;
        try
          A.Text:= string(MyBuff);
            for i:= 0 to A.Count-1 do
              begin
                S.CommaText:= A[i]; //Разделяем строки
                  if AnsiStartsStr('#RD,01', S.CommaText) then //Состояние I/O входа 1
                      //Получаем один символ, восьмой по счету (0 или 1)
                      First:=StrToInt(AnsiMidStr(S.CommaText, 8, 1));
              end;
        finally
          A.Free;
          S.Free;
      end;
  end;
end;
0
1 / 1 / 0
Регистрация: 12.07.2012
Сообщений: 46
18.01.2016, 18:57 5
Сделал такую примерно такую программу три года назад, в Си Билдер, используя сторонние библиотеки работы с компортом и таймера точного времени, ибо средствами ВИНАПИ ахинея полнейшая в качестве результата получалась с моими познаниями, правда, весьма правдоподобная. Нынче, решил её модифицировать, не используя чужое явно Ерунда в Билдере получается, причём, со страшным скрипом - насчёт спецов посоветовать или сказать, тут что-либо толковое, тут нету - зависит от версии Ембаркадеро Ну, Дельфи кондовей, думаю получится. А насчёт
Цитата Сообщение от northener Посмотреть сообщение
получает с этой железяки готовые данные
какие данные железяка ценой в полдоллара может дать, зачем тогда вычислительные возможности компьютера? Сегодня буквально установил Дельфи7, и только решил заняться, а тут... Почти готовые исходники Один вопрос - программа из под Дельфи7 будет на Виндовс7х64 работать?
Миниатюры
Работа с COM портом  
0
0 / 0 / 0
Регистрация: 09.02.2015
Сообщений: 26
18.01.2016, 19:18  [ТС] 6
Не в курсе даже. Могу исходниками поделиться на мыло, но допиливать самостоятельно придется.
И у меня стороннее железо, а не прямая работа с портом.
0
18.01.2016, 19:18
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.01.2016, 19:18
Помогаю со студенческими работами здесь

Работа с COM Портом
Привет Всем! У меня тут такая проблема. Для работы с одним внешним устройством, которое заведомо...

Работа с LPT портом
Добрый день форумчане, столкнулся с проблемой. Печатающее устройство получает информацию через...

Работа с LPT портом
Доброго времени суток. Имеется матричный принтер. Для вывода текста использую рулонную бумагу. При...

работа в delphi с СОМ-портом
Здравствуйте,пишу программу на пипломник, суть программы: через COM-порт отправляет и принимает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru