Получение данных на Делфи

Phantom
Offline
Зарегистрирован: 30.04.2012

Доброй ночи!

У меня возникла проблема при сравнении данных переданных с ардуино на делфи. вот собственно кусок кода:

procedure TMainForm.ReadDataClick(Sender: TObject);
Var
  RCBuf:TBytes;        //Буфер данных для приема
  nToRead:Cardinal;   //Число байт для чтения
  nRead:Cardinal;     //Число прочитанных байт

begin
  nToRead:=6;         //считываем число байт для чтения из структуры
  nToReadLabel.Caption:=IntToStr(nToRead);  //выводим на форму число байт для чтения
  SetLength(RCBuf,nToRead+1);
  RCBuf[nToRead+1]:=0;// конец строки PAnsiChar
  ReadFile(Port,RCBuf[0],nToRead,nRead,nil);  //считываем данные
  nReadLabel.Caption:=IntToStr(nRead);      //выводим на форму число прочитанных байт
  if (nRead <> 0) then begin
  if (PAnsiChar(RCBuf) = PAnsiChar('s')) then //вот это сравнение
    SLabel.Caption:='S';
  if (PAnsiChar(RCBuf) = PAnsiChar('a')) then //и это
    ALabel.Caption:='A';
  Finalize(RCBuf);
  end;
end;

что я делаю не правильно?

leshak
Offline
Зарегистрирован: 29.09.2011

>что я делаю не правильно?

Плохо задаете вопросы. Совершенно упускаете из виду, что остальные не в контексте вашей проблемы.

Это  ардуино.ru, а не  "шоу экстрасенсов" или клуб любителй "в угадайку".

Хотя может быть и найдутся любители поперебирать варианты "что и как вы шлете, что вы ожидаете увидеть, что вы видите, как подключили и т.п."

P.S. Еще можете поиском воспользоватся, Delphi иногда встречается на форуме, не уверен, но может и найдете чего полезного.

Phantom
Offline
Зарегистрирован: 30.04.2012

 Если проблема в коде то выкладываю полностью.

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TBytes=array of byte;

  TMainForm = class(TForm)
    OpenPort: TButton;
    ClosePort: TButton;
    SendData: TButton;
    Edit1: TEdit;
    ReadData: TButton;
    PortStateLabel: TLabel;
    Label1: TLabel;
    Label2: TLabel;
    nToReadLabel: TLabel;
    nReadLabel: TLabel;
    Label3: TLabel;
    RcDataLabel: TLabel;
    procedure OpenPortClick(Sender: TObject);
    procedure ClosePortClick(Sender: TObject);
    procedure ReadDataClick(Sender: TObject);
  end;

var
  MainForm: TMainForm;
  Port:THandle;

implementation
{$R *.dfm}

procedure TMainForm.OpenPortClick(Sender: TObject);
Var
 DCB:TDCB;    //структура, содержащая настройки порта
 CommTimeouts:TCommTimeouts;
begin
  Port:=CreateFile(
    '\\.\COM8',                   //открываем первый порт
    GENERIC_READ or GENERIC_WRITE,//открываем порт для чтения и записи
    0,                            //общий доступ к ресурсу запрещен, для портов всегда так
    nil,                          //атрибуты защиты, не используются и потому nil
    OPEN_EXISTING,                //атрибуты открытия, для портов OPEN_EXISTING
    FILE_ATTRIBUTE_NORMAL,         //для синхронной работы так
    0                           //хз что это, но должно быть так
  );


  GetCommState(port, DCB);        //что бы не заполнять всю структуру самим, сначал считываем ее, потом поменяем нужные поля
  DCB.BaudRate:=9600;             // скорость обмена
  DCB.Parity:=NoParity;           // нет контроля четности
  DCB.ByteSize:=8;                //байт из восьми бит
  DCB.StopBits:=ONESTOPBIT;       //один стоповый бит
  SetCommState(port, DCB);        //записываем измененную структуру, для открытого порта

  GetCommTimeouts(Port, CommTimeouts); //получаем структуру CommTimeouts что бы не заполнять все вручную
  CommTimeouts.ReadIntervalTimeout :=MAXDWORD;  //функция ReadFile возвращает
  CommTimeouts.ReadTotalTimeoutMultiplier := 0; //немедленно все имеющиеся
  CommTimeouts.ReadTotalTimeoutConstant := 0;   //байты в приемном буфере
  SetCommTimeouts(Port, CommTimeouts); //записываем измененную структуру

end;


procedure TMainForm.ClosePortClick(Sender: TObject);
begin
 if not CloseHandle(Port)                 //если порт  не закрылся
  then showmessage('Не закрылось')        //то пишем что он не закрылся
  else PortStateLabel.Caption:='Порт не открыт';   //если всетаки закрылся , то пишем, что закрылся :)
  Close();
end;



procedure TMainForm.ReadDataClick(Sender: TObject);
Var
  RCBuf:TBytes;        //Буфер данных для приема
  nToRead:Cardinal;   //Число байт для чтения
  nRead:Cardinal;     //Число прочитанных байт

begin
  nToRead:=6;         //считываем число байт для чтения из структуры
  nToReadLabel.Caption:=IntToStr(nToRead);  //выводим на форму число байт для чтения
  SetLength(RCBuf,nToRead+1);
  RCBuf[nToRead+1]:=0;// конец строки PAnsiChar
  ReadFile(Port,RCBuf[0],nToRead,nRead,nil);  //считываем данные
  nReadLabel.Caption:=IntToStr(nRead);      //выводим на форму число прочитанных байт
  if (nRead <> 0) then begin
  if (PAnsiChar(RCBuf) = PAnsiChar('s')) then //вот это сравнение
    SLabel.Caption:='S';
  if (PAnsiChar(RCBuf) = PAnsiChar('a')) then //и это
    ALabel.Caption:='A';
  Finalize(RCBuf);
  end;
end;
end.

просто уже сломал голову почему они неравные

if (PAnsiChar(RCBuf) = PAnsiChar('s')) then 
SLabel.Caption:='S';

step962
Offline
Зарегистрирован: 23.05.2011

Phantom пишет:

 просто уже сломал голову почему они неравные

if (PAnsiChar(RCBuf) = PAnsiChar('s')) then 
SLabel.Caption:='S';

Есть бредовая идея, что операнды не совпадают:

a) по типам и

b) по кодировкам

Любой из этих причин достаточно для того, чтобы порушить условие, а уж двух-то...

Кроме того - расскажите нам о том, что возвращает функция (или преобразование типа?) PAnsiChar?

leshak
Offline
Зарегистрирован: 29.09.2011

 

step962 пишет:

Есть бредовая идея...

Решили, таки, в угадайку поиграть?

>Кроме того - расскажите нам о том, что возвращает функция (или преобразование типа?) PAnsiChar?

Похоже что это, не функция, а преобразование типа.  Если это так, то возможно товарищь пытается сравнить указатели, а не значения куда они указывают. Причем правый вообще указывает на какой-то случайную ячейку памяти (с адресом 's').

Я уже не говорю, что не видно что-бы он бежал по символам в цикле. То есть если попался случайный мусор (например при включении дуины она плюнула пару символов в порт), то - привет. 

Да и, возможно, он должен обладать не дюженной реакцией, что-бы нажать на форме кнопку чтения из порта, ровно в тот момент когда дуина что-то послала (какого-нибудь while ожидания данных в порте  - тоже не видно).

А может тупо скорости не совпадают, или вообще порт не тот (скопированный из какого-то примера).

Да еще кучу всего нафантазировать можно. Только смысл? Если сам топик-стартер не торопится сузить область поиска. Значит не шибко оно ему и нужно. Обычное "Товарищи ученые, у меня в подполье уже третий год происходит какой-то стук. Объясните отчего и почему?"

 

Phantom
Offline
Зарегистрирован: 30.04.2012

> Кроме того - расскажите нам о том, что возвращает функция (или преобразование типа?) PAnsiChar?

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

я попытаюсь объяснить в чем проблема.

у меня ардуино посылает сигнал о нажатии кнопки, то есть передает символ "s". и мне надо на делфи сделать действие которое бы реагировала бы на это нажатие. так что бы если пришел символ "s", то сделать одно. а если "а", тогда - другое действие. в дальнейшем планирую эту проверку сделать на таймере. в интернете нашел этот исходник который соединяется к ком-порту и выводит с нее информацию. с этим проблем нету, если сделать SLabel.Caption:=PAnsiChar(RCBuf), то выводится нормальный символ.

> Я уже не говорю, что не видно что-бы он бежал по символам в цикле.

это как? дайте направление?

> что-бы нажать на форме кнопку чтения из порта, ровно в тот момент когда дуина что-то послала

на счет этого думаю проблем нету. так как SLabel.Caption:=PAnsiChar(RCBuf) выводит все то что отправлялась в порт.

> А может тупо скорости не совпадают, или вообще порт не тот

это все настроено

если требуется могу выложить код ардуино

step962
Offline
Зарегистрирован: 23.05.2011

 leshak вас таки опередил - вам необходимо сравнивать не указатели, а содержимое областей памяти, на которые указывают указатели.

Вам также необходимо быть пооисторожнее с кодировками - нен сравнивать ASCII-символ (именно такой вы скорее всего получите от микроконтроллера, c ANSI. Для латиницы это не слишком критично, а вот кириллица может доставить в этом отношении мноооого радости.

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

Phantom
Offline
Зарегистрирован: 30.04.2012

 спасибо! приятного вам времепровождения.

постараюсь разобраться

leshak
Offline
Зарегистрирован: 29.09.2011

 >у меня ардуино посылает сигнал о нажатии кнопки, то есть передает символ "s"

Может быть. А может и нет.

>если требуется могу выложить код ардуино

Ну а почему сразу этого не сделать? Тут же нет оплаты трафика. Зато сразу куча вариантов отпала бы.

Кстати, а обычным сериал монитором нормально видите посылки из ардуины?

>я попытаюсь объяснить в чем проблема.

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

>> Я уже не говорю, что не видно что-бы он бежал по символам в цикле.

>это как? дайте направление?

Ну это вообще не ардуино вопрос, а вопрос программирования на дельфи. Я уже лет десять его не видел/трогал.

Просто вот вы вычитали 6 симвовлов, своим сравнением (PAnsiChar(RCBuf) = PAnsiChar('s') вы какой из них стравниваете с 's', первый, третий, последний?

Возможно вам нужно сделать цикл и сравнивать как-то так (PAnsiChar(RCBuf+i) = PAnsiChar('s'), где i - номер символа который хотите сравнить. Как именно точно сразвинвать - смотрите книги по дельфи. Разделы работы со строками и указателями.

Но я бы даже, не бегал по этим массивам. Зачем читать сразу все 6-ть байт? Не проще читать по одному символу вычитать из порта и сравнивать?

Еще возможные грабли: Я так понял что PAnsiChar - это указатель. То есть "адрес в памяти" где хранится значение. Возможно вы сравниваете именно адресс буффера RCBuf с адресом где хранится символ 's'. Естественно они будут разными всегда. Вам же нужно сравнивать значения, а не "где они лежат". Возможно нужно делать как-то так PAnsiChar(RCBuf+i)^='s'

Гугланите "дельфи строки сравнение символы". Не думаю что вы останетесь в неведении как это делать.

Отложите, вначле в сторону ардуину. Научитесь в строке на дельфи находить символ. Напишите функцию которая говорит если в строке символ 's' или нет.

Почитайте базовые функции работы со строками. Наверняка у них есть, какая нибуть готовая функция типа contains, которая говорит есть подстрока/символ в строке или нет.

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

Следующие:

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

Обычно делают пустой цикл, ожидающий "пока что-нибудь не прийдет".

Примерно так:

while(!port.avaliable()){} // ждем пока в порту не появятся какие-то данные

Хотя, возможно это (ожидание)  уже сделанно внутри функции ReadFile. 

Но опять, таки сработает она только один раз. И выйдет. Больше не будет слушать дуину. 

Значить опять-таки нужно все это обернуть в какой-то цикл бесконечный (и прерывать его какой-нибудь кнопкой типа "прекратить слушать порт").

Общий подход такой (псевдокодом).

bool isListen=true; // делаем ее глобальной, сбрасываем в false какой-нибудь внешней кнопкой на форме, 

repeat
  
  while not(port.isAvaliable()) begin end // ждем пока в порту что-нибудь не появится

  char ch=readOneChar();
  if ch=='s" begin
   что-то делаем
  end 

   

until isListen==true;  // и опять пошли ждать-читать-обрабатывать следующий символ, пока кто-нибудь не поменяет isListen на false

 

 

 

 

 

 

Phantom
Offline
Зарегистрирован: 30.04.2012

 спасибо за ответ!

попробую разобраться с вашими советами.

за не информативность прошу прощения. первый раз пишу на форуме)))) в последующем постараюсь писать по конкретней.

выкладываю код для ардуино. на обычном сериал монитре вижу все нормально.

int led1 = 13, bPin1 = 5, led2 = 12, bPin2 = 4;              
boolean b1 = false, b2 = false;
 
void setup()
{
  Serial.begin(9600);
  pinMode(led1, OUTPUT);      
  pinMode(bPin1, INPUT);
  pinMode(led2, OUTPUT);
  pinMode(bPin2, INPUT);
}
 
void loop()
{
  if (digitalRead(bPin1) == HIGH)
    digitalWrite(led1, HIGH);
  else
    digitalWrite(led1, LOW);
    
  if (digitalRead(bPin2) == HIGH)
    digitalWrite(led2, HIGH);
  else
    digitalWrite(led2, LOW);
    
  if ((digitalRead(bPin1)==1)&&(b1==false)) {Serial.println("s");b1=true;}// нажали b1
  if ((digitalRead(bPin1)==0)&&(b1==true)) {Serial.println("a");b1=false;}// отпустили b1
  
  if ((digitalRead(bPin2)==1)&&(b2==false)) {Serial.println("q");b2=true;}// нажали b2
  if ((digitalRead(bPin2)==0)&&(b2==true)) {Serial.println("w");b2=false;}// отпустили b2  
    
}