Delphi soros adatátvitel AVR felől

Avatar
szepnorbee
Bitmanipulátor
Hozzászólások: 122
Csatlakozott: 2009. augusztus 31. hétfő, 6:00

Delphi ADC

HozzászólásSzerző: szepnorbee » 2011. december 5. hétfő, 19:15

Sziasztok!

Szeretnék írni egy egyszerű delphi programot ami kiírja nekem egy avr két ADC posrtján való mérés eredményét. A kapcsolat soros portron át menne és a delphis programban csak két szám lenne egymás alatt. A baj, hogy nem tudom hogyan formázzam az avr-ből kiküldött adatot, hogy azt a legkönnyebben fel tudjam dolgozni delphiben. Arra már rájöttem, hogy ha pontosvesszővel a parancsok végén printelek akkor nem küldi el az avr az új sor, kocsi vissza kódokat, csak a nyers adatot.

Kód: Egész kijelölése

Print W(1);
Print W(2);


A soros porton érkező adatot már be tudom tenni delphiben egy TEdit mezőbe, nade a két számérték nincs elválasztva egymástól. Igazából nem nagyon értek a delphihez, nade komoly dolgot nem is akarok vele, csupán ennyit. Próbáltam az uc-ből úgy kiküldeni az adatot, hogy legyen egy szeparátor karakter a két érték között, nade gyenge delphi tudásom miatt, nem tudom, hogy lehetne elválasztani a két értéket. Illetve hogy kezelem azt, ha mondjuk a delphi programmal épp akkor kapcsolódok be a post olvasásába amikor épp az üzenet közepétől kapom a választ? Két napja szórakozok vele, de nem haladok sajnos. Esetleg nem lenne egy hasonló kölcsön mintátok két vagy több bejövő adat megjelenítésére soros post felől?

AVR programom:

Kód: Egész kijelölése

$regfile = "m16def.dat"
$crystal = 7372800
$baud = 9600

Config Adc = Single , Prescaler = Auto , Reference = Avcc   'config ADC

Start Adc

Dim W(2) As Word
Echo Off

Do
  W(1) = Getadc(0)
  W(2) = Getadc(1)

  '-----------
  Print "A";
  Print W(1);
  Print "B";
  Print W(2);
  Print "END";

  Loop
End


Delphi Unit:

Kód: Egész kijelölése

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, CPort, CPortCtl, ExtCtrls, ComCtrls, XPMan;

type
  TForm1 = class(TForm)
    ComPort1: TComPort;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ComLed1: TComLed;
    ComLed2: TComLed;
    Label1: TLabel;
    Label2: TLabel;
    Button4: TButton;
    Button5: TButton;
    Edit1: TEdit;
    Label3: TLabel;
    ProgressBar1: TProgressBar;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Edit2: TEdit;
    ProgressBar2: TProgressBar;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Edit3: TEdit;
    ProgressBar3: TProgressBar;
    XPManifest1: TXPManifest;
    GroupBox1: TGroupBox;
    Edit4: TEdit;
    GroupBox2: TGroupBox;
    Edit5: TEdit;
    Edit6: TEdit;
    Edit7: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure ComPort1RxChar(Sender: TObject; Count: Integer);
    procedure ComPort1AfterClose(Sender: TObject);
    procedure ComPort1AfterOpen(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Close
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ComPort1.ShowSetupDialog
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  if ComPort1.Connected then
    ComPort1.Close
  else
    ComPort1.Open;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
//  ComPort.StoreSettings(stIniFile, 'e:\Test.ini');
  ComPort1.StoreSettings(stRegistry, 'HKEY_LOCAL_MACHINE\Software\Dejan');
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  ComPort1.LoadSettings(stRegistry, 'HKEY_LOCAL_MACHINE\Software\Dejan');
//  ComPort.LoadSettings(stIniFile, 'e:\Test.ini');
end;

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  Str:String;
  szamok : TStringList;            // Define our string list variable
  i    : Integer;
begin

ComPort1.ReadStr(Str, Count);
  szamok := TStringList.Create;
  szamok.Delimiter := ' ';        // Each list item will be blank separated
  szamok.QuoteChar := 'I';        // And each item will be quoted with |'s
  szamok.DelimitedText := Str;
  Edit4.text := Str;
for i := 0 to cars.Count-1 do
 Edit5.Text:= Cars[0];
 Edit6.Text:= Cars[1];
  // Free up the list object
  cars.Free;
//sleep(60);
end;

procedure TForm1.ComPort1AfterClose(Sender: TObject);
begin
  if Button3 <> nil then
    Button3.Caption := 'Open';
end;

procedure TForm1.ComPort1AfterOpen(Sender: TObject);
begin
  Button3.Caption := 'Close';
end;

end.


Na pl. ez is hasonló csak a kód nem letölthető:
http://myavr.wordpress.com/2011/06/03/access-multi-sensor-using-tcomport-delphi-and-avr-microcontroller/

Avatar
Robert
Elektronbűvölő
Hozzászólások: 9917
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

HozzászólásSzerző: Robert » 2011. december 5. hétfő, 20:36

print "[";adat1;"#";adat2;"]"

Így szeparált adatot küldesz.


Vagy:
print "A";adat1
print"B";adat2
szeparálsz (stringvágás) : 1. karakter A vagy B és a maradék a mért adat.

Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3234
Csatlakozott: 2008. augusztus 29. péntek, 6:00
Tartózkodási hely: Újkígyós

HozzászólásSzerző: kapu48 » 2011. december 5. hétfő, 21:00

Például használhatod ezt:
IO.DLL
http://www.geekhideout.com/iodll.shtml
Vagy:
Innen tölsd le a TComport komponenst és telepítsd a Delphi alá!
http://www.vclcomponents.com/Delphi/Tel ... -info.html
Soros port kezelésre rengetegen ezt használják!
8)

Avatar
szepnorbee
Bitmanipulátor
Hozzászólások: 122
Csatlakozott: 2009. augusztus 31. hétfő, 6:00

HozzászólásSzerző: szepnorbee » 2011. december 6. kedd, 0:48

Köszi. Én is a CPortLib-et próbálom használni, több kevesebb sikerrel.

Már meg tudom jeleníteni a 3 fogadott értéket, de sajna nem frissül. Ez persze logikus mert én a Memo1 első három elemét olvasom csak ki, és az újabbak nagyobb sorszámot viselnek. Szal jelenleg elakadtam, köszi a helpet. AVR oldalon betettem a szeparálást.

Kód: Egész kijelölése

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);

var
  Str:String;
  st : TStringList;            // Define our string list variable
  i    : Integer;
begin

  ComPort1.ReadStr(Str, Count);
  Memo1.Text := Memo1.Text + Str;
  // Edit4.Text := Edit4.Text+Str;
  st:=TStringList.Create;
  try
  st.Delimiter:='|';
  st.DelimitedText:= Memo1.Text;
Edit5.Text:= st[0];
Edit6.Text:= st[1];
Edit7.Text:= st[2];

 finally
st.Free
end;
end;


Ha esetleg valaki tudná a megoldást, megsúghatja. Nade ígérem mostmár nem Offolom tele a topicot delphivel. Ha kell, törlöm. Bocs utólag.

Avatar
BCsoft
Újonc
Újonc
Hozzászólások: 7
Csatlakozott: 2009. október 16. péntek, 6:00
Tartózkodási hely: Nyárlőrinc
Kapcsolat:

HozzászólásSzerző: BCsoft » 2011. december 13. kedd, 15:06

Az AVR szeparálás rendeben is van, de egy fontos szeparáció még hiányzik. A teljes adat kiküldés után használj még egy adatvége jelet. A programod indításakor várd meg amíg megérkezik az első adat vége jel, és csak utána kezd el feldolgozni az a adatokat a következő vég jelig. Így nem fogsz darab adatot kapni.

A frissülés:

Kód: Egész kijelölése

  ComPort1.ReadStr(Str, Count);
  Memo1.Clear //Így törlöd memo1 egy tartalmát
  Memo1.Text := Memo1.Text + Str;


Mellesleg ez teljesen felesleges mivel str változóban ott van minden vagyis:

Kód: Egész kijelölése

  st.DelimitedText:= Memo1.Text; //helyett


st:=TStringList.Create;
  try
  st.Delimiter:='|';
  st.DelimitedText:= srt;


A valóban korrekt megoldás a kérdés-felelet.
Küldesz az AVR-nek egy kérést, mérje meg az adatokat és a mérés végén küldje az eredményt vissza. Nem hiszem, hogy másodpercenként szükséged van 100 adatra. :D

Küld el privátban a forrásokat. Már írtam ilyen progit, egy mérleghez. De nem akarom becsatolni, mivel mint írtad a DELPHI nem igazán az a erősséged. A végeredményt majd megosszuk itt is.

Avatar
BCsoft
Újonc
Újonc
Hozzászólások: 7
Csatlakozott: 2009. október 16. péntek, 6:00
Tartózkodási hely: Nyárlőrinc
Kapcsolat:

HozzászólásSzerző: BCsoft » 2011. december 15. csütörtök, 11:41

Megkaptam a forrásokat.

Első ránézésre az alábbi problémákat látom:
AVR

Kód: Egész kijelölése

Dim My_string As String * 1
Dim W(3) As Word
Dim W1 As String * 1
Dim W2 As String * 1
Dim W3 As String * 1

Az ADC 10 bites vagyis 1024-ig tud értéket előállítani, ami ugye 4 karakter. Te viszont csak egy karakteresnek definiáltad a változókat amit később elküldesz a PC-nek.
A helyes AVR kód:

Kód: Egész kijelölése

 
Dim W1 As String * 4
Dim W2 As String * 4
Dim W3 As String * 4

Az első kérdezés előtt indokolt volna lekérdezni az ADC értékeket, ezzel a változóidat is alaphelyzetbe állítod és biztosan nem valami szemetet kapsz.

Kód: Egész kijelölése

 
Dim W3 As String * 1

'Indulásnál célszerű beolvasni az adatokat
'Init
   W(1) = Getadc(0)
   W(2) = Getadc(1)
   W(3) = Getadc(2)
   W1 = Str(w(1))
   W2 = Str(w(2))
   W3 = Str(w(3))

Do...

DELPHI

Kód: Egész kijelölése

ComPort1.WriteStr('A');
ComPort1.ReadStr(buffer,2);

AVRtől érkezik egy karakter Te viszont kettőt vársz. Pedig a ProgressBarok maximális értéke helyesn 1024-re van állítva.
A fenti AVR kód négyet fog küldeni. Te is négyet várj.

Kód: Egész kijelölése

ComPort1.WriteStr('A');
ComPort1.ReadStr(buffer,4);

A képernyő frissítése és a program külvilág felé való kommunikációja érdekében a Timer újra indítása előtt célszerű kommunikálni az OP rendszerrel.

Kód: Egész kijelölése

    Application.ProcessMessages;
 sleep(200);

Igyekeztem minden kódrészletet úgy illeszteni, hogy egyértelmű legyen hová való.
Sok sikert.

Avatar
Robert
Elektronbűvölő
Hozzászólások: 9917
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

HozzászólásSzerző: Robert » 2011. december 15. csütörtök, 12:41

Kérdés a partszélről:
- az AVR nem 4, hanem 6 karaktert küld (max):
ADCérték karaktersor + {010} + {013}

Az ADCérték az 1...4 számjegy!

:?

Avatar
BCsoft
Újonc
Újonc
Hozzászólások: 7
Csatlakozott: 2009. október 16. péntek, 6:00
Tartózkodási hely: Nyárlőrinc
Kapcsolat:

HozzászólásSzerző: BCsoft » 2011. december 15. csütörtök, 13:17

Jogos.
De ha jól tudom akkor a CR LF jelet automatikusan küldi, ezért nincs szükség a változó 6 hosszúságúra való definiálására az AVRben (W1,W2..).
Delphiben is csak az első 4 karakterre van szükség, a CR LF a bufferben marad, amit a következő írás-olvasási ciklusban ürít. Így megtudunk spórolni néhány órajelnyi műveletet (nem kell a karakter sorozatot vágni).

Amennyiben az AVR csak 1-et + CR LF jelet küld, az három karakter(bár ha 4 hosszú akkor kiküldi mind a négyet, de ebben nem vagyok biztos). A delhiben való ilyen típusú feldolgozást már a kérdezőre bíznám, tanulás céljából. A hozzászólásom, mindössze az alapvető hibákra mutat rá.

Természetesen ha nincs igazam, várom a vissza jelzésedet, AVR-ben Te vagy a guru. :lol:

Avatar
szepnorbee
Bitmanipulátor
Hozzászólások: 122
Csatlakozott: 2009. augusztus 31. hétfő, 6:00

HozzászólásSzerző: szepnorbee » 2011. december 16. péntek, 13:16

Üdv re. BCSoft segítségével sikerült összehoznom a dolgot. Nem mondhatnám még valami professzionálisnak a dolgot, mert ha rosszkor állítom le a programot, vagy ha az AVR-t váratlanul resetelem és be-be ugrik 1-2 "nem szám" karakter akkor összeomlik, nade menet közben, ha már jön az adat, akkor kiválló. Annyi még hogy az AVR programjában lekezeltem at 1000-nél, 100-nál és 10-nél kisebb értékú számokat is, mindent 4 karakterre konvertálva (kis számok elé mindíg plussz egy 0 karakter) Illetve a Print W1; utasítások végére pontosvesszőt rakva, nem jön át az új sor, kocsi vissza kombó.

Íme a delphi Unit:

Kód: Egész kijelölése

unit Delphi_Simple_ADC;

interface

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

type
  TForm1 = class(TForm)
    ProgressBar1: TProgressBar;
    ProgressBar2: TProgressBar;
    ProgressBar3: TProgressBar;
    XPManifest1: TXPManifest;
    ComPort1: TComPort;
    Timer1: TTimer;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    StatusBar1: TStatusBar;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
Application.Terminate;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ComPort1.ShowSetupDialog;
statusbar1.Panels[0].Text:='Használt port ' + comport1.Port;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 if ComPort1.Connected then
      begin
      timer1.Enabled:=false;
      Button2.Enabled:=True;
      ComPort1.Close;
      Button3.Caption:='Kapcsolódás';
      statusbar1.Panels[1].Text:='Szétkapcsolva';

     end

    else
      begin
      timer1.Enabled:=true;
      Button2.Enabled:=False;
      ComPort1.Open;
      Button3.Caption:='Szétkapcsol';
      statusbar1.Panels[1].Text:='Kapcsolódva';

      end
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Timer1.Enabled := False;
statusbar1.Panels[0].Text:='Használt port ' + comport1.Port;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
buffer: string;
begin
Timer1.Enabled := False;

ComPort1.WriteStr('A');
ComPort1.ReadStr(buffer,4);
  if Length(buffer) > 0 then
    begin
    label4.Caption := buffer;
    Progressbar1.Position := StrToInt(buffer);
    end;
Application.ProcessMessages;
//sleep(100);

ComPort1.WriteStr('B');
ComPort1.ReadStr(buffer,4);
  if Length(buffer) > 0 then
    begin
    label5.Caption := buffer;
    Progressbar2.Position := StrToInt(buffer);
    end;
Application.ProcessMessages;
//sleep(100);

ComPort1.WriteStr('C');
ComPort1.ReadStr(buffer,4);
  if Length(buffer) > 0 then
    begin
    label6.Caption := buffer;
    Progressbar3.Position := StrToInt(buffer);
    end;
Application.ProcessMessages;
//sleep(100);

Timer1.Enabled := True;
end;

end.


Ez pedig az AVR programja:

Kód: Egész kijelölése

$regfile = "m16def.dat"
$crystal = 7372800
$baud = 9600

'Config Lcdpin = Pin , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2 , E = Portc.6 , Rs = Portc.7
'Config Lcd = 20 * 4

Config Adc = Single , Prescaler = Auto , Reference = Avcc   'config ADC
Start Adc

Cls
Cursor Off

Dim My_string As String * 1
Dim W(3) As Word
Dim W1 As String * 4
Dim W2 As String * 4
Dim W3 As String * 4

   W(1) = Getadc(0)
   W(2) = Getadc(1)
   W(3) = Getadc(2)
   W1 = Str(w(1))
   W2 = Str(w(2))
   W3 = Str(w(3))

If W(1) < 1000 Then
      W1 = "0" + W1
      End If

If W(1) < 100 Then
      W1 = "00" + W1
      End If

If W(1) < 10 Then
      W1 = "000" + W1
      End If

'------------------

If W(2) < 1000 Then
      W2 = "0" + W2
      End If

If W(2) < 100 Then
      W2 = "00" + W2
      End If

If W(2) < 10 Then
      W2 = "000" + W2
      End If

'------------------

If W(3) < 1000 Then
      W3 = "0" + W3
      End If

If W(3) < 100 Then
      W3 = "00" + W3
      End If

If W(3) < 10 Then
      W3 = "000" + W3
      End If

'------------------
Do

   My_string = Inkey()
   'If My_string <> Chr(0) Then
   '   Locate 2 , 1
   '   Lcd "Adat<" ; My_string ; ">"
   'End If

   If My_string = "A" Then
   Print W1;
   End If

   If My_string = "B" Then
   Print W2;
   End If

   If My_string = "C" Then
   Print W3;
   End If

   W(1) = Getadc(0)
   W(2) = Getadc(1)
   W(3) = Getadc(2)
   W1 = Str(w(1))
   W2 = Str(w(2))
   W3 = Str(w(3))

'-------------------------

If W(1) < 1000 Then
      W1 = "0" + W1
      End If

If W(1) < 100 Then
      W1 = "00" + W1
      End If

If W(1) < 10 Then
      W1 = "000" + W1
      End If

'------------------

If W(2) < 1000 Then
      W2 = "0" + W2
      End If

If W(2) < 100 Then
      W2 = "00" + W2
      End If

If W(2) < 10 Then
      W2 = "000" + W2
      End If

'------------------

If W(3) < 1000 Then
      W3 = "0" + W3
      End If

If W(3) < 100 Then
      W3 = "00" + W3
      End If

If W(3) < 10 Then
      W3 = "000" + W3
      End If

'------------------

Loop

End


Nem ártana még delphibe valami hibakezelés, nade az már nekem magas.... Kicsit még bújnom kell a könyveket.

Avatar
BCsoft
Újonc
Újonc
Hozzászólások: 7
Csatlakozott: 2009. október 16. péntek, 6:00
Tartózkodási hely: Nyárlőrinc
Kapcsolat:

HozzászólásSzerző: BCsoft » 2011. december 16. péntek, 14:44

Húúúúúú
Ez nem túl szép :(

Estére segítek kicsit az OOP terén és a hiba kezelésben. Ha valaki meg nem előz. :D

Avatar
szepnorbee
Bitmanipulátor
Hozzászólások: 122
Csatlakozott: 2009. augusztus 31. hétfő, 6:00

HozzászólásSzerző: szepnorbee » 2011. december 16. péntek, 15:25

BCsoft írta:Húúúúúú
Ez nem túl szép :(

Estére segítek kicsit az OOP terén és a hiba kezelésben. Ha valaki meg nem előz. :D


Hát igaz ami igaz, erősen BÉTA :) De annál már jóval többet csinál mint mielőtt segítettél :)

Avatar
strigo
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2006. február 17. péntek, 7:00
Tartózkodási hely: Budapest

HozzászólásSzerző: strigo » 2011. december 21. szerda, 21:23

sziasztok!
szepnorbee ezt a kivételkezelést próbáld ki:

Kód: Egész kijelölése

try
    Progressbar1.Position := StrToInt(buffer);
  except
    on Exception : EConvertError do
      ShowMessage(Exception.Message);
  end;
Üdv:
Zsolt


Vissza: “C, C++, Visual C”

Ki van itt

Jelenlévő fórumozók: nincs regisztrált felhasználó valamint 1 vendég