таймер за nS

19 отговора 0 прегледа
#1

таймер за nS

Възможно ли е да се реализира таймер примерно за 20 наносекунди.
Предварително благодаря

Отговор
в отговор на svetlin #2

Re: таймер за nS

Таймер в смисъла, който според мен влагаш в питането си - не. Имай предвид, че все пак програмата ти работи в една много задачна среда, процесорът не е само твой и твоят код от периодично спира да се изпълнява, за да може да се изпълнява друг код през това време. Тези периоди, през които твоят код не се изпълнява определено са по-продължителни от наносекунди, така че ще пропускаш тикове на един такъв хипотетичен таймер. И изобщо замисли се над това какво точно искаш да постигнеш, защото нещо не е в ред щом търсиш такъв таймер
Иначе можеш да засичаш времена от такъв порядък използвайки функциите QueryPerformanceCounter и QueryPerformanceFrequency (ако това ти върши работа...)

Linux isn't free, it's worthless.


Отговор
в отговор на andrew_nikoloff #3

Re: таймер за nS

Задачата е следната, имам АЦП което е 12 битово с 25милиона замера за секунда и тези данни трябва да влязат в компютъра.
Започнах да работя с RS232 но трябва да използвам много голяма памет за буфер. За съжаление с USB нямам никакъв опит макар че хардуерно мога да го синтезирам. Та сега ми се ще да пробвам да вкарам данните през LPT. Но и там излизат ред питанки -
-как да синхронизирам замерите към време
- възможно ли да се използва DMA
имам някакави стари спомени как порта ставаше двупосочен ECP EPP , но при опит да подам напрежение на данните порта ги чете но консумацията е огромна 60 mA, а контролните и входните битове са само 9

та се балтая и не знам от къде да почна

Търсих тръпка но определено се нахендрих.

Отговор
в отговор на svetlin #4

Re: таймер за nS

Нямам голяма практика с такъв тип хардуер. Обаче като гледам с каква скорост ти пристигат данните - най-добре е да се ползва USB интерфейса, и то в bulk режим на трансфер. И ще ти трябват големи буфери - няма как да избягаш от това
За USB най-лесно става и доста масово ползвано е с FTDI чипа (сигурно го знаеш). Има много примери из нета за ползването му от страната на PC-то, включително и на Делфи. Освен това можеш да го ползваш и като виртуален COM порт.
Ако можем да ти помогнем нещо с делфийската част - казвай. Иначе - успех

Linux isn't free, it's worthless.


Отговор
в отговор на svetlin #5

Re: таймер за nS

благодаря за съвета,
прегледах описавието на FTDI чиповете но ги оставям за последен вариант.
- схемотехника на чипа
- синтезиране на кода на VHDL /голям набор функции на интерфейса
- външен буфер на данните
- и отново примането в реално време
- най вече МЪРЗЕЛ ако може по лесно защо да е сложно

За сега съм се спрял на LPT защото
- директно приема 12 битови данни -тествано
- безкрайно упростява а и поефтинява периферията
- не е необходим външен буфер/или ако се наложи ще е мнго малък/

функцията QueryPerformanceCounter е чудесна и
- ми дава маркер за време така че и липсващите замери могат да се
екстраполират

- стойността коята ми връща зависи основно от машината и има много малка девиация около 100 Hz което за това измерване е пренебрежимо.
- не се влияе от приоритета на процеса и от натоварването на машината

Не бях уточнил че замерът ще бъде само 1 секунда и даните ще се записват в масив , който след това ще се обработва, така че за това време компютъра дори и да "зависне" не е проблем.

Та след цялата хвалба ще дойде и мрънкането
не знам как QueryPerformanceCounter да ми инициира събитие в което да прочета LPT

Черпенето ще е от мен /а се сещам в коя кръчма в Пловдив ще отидем с танциорки певачки и едни блюда 1метър/
Благодаря ти предварително

Отговор
в отговор на svetlin #6

Re: таймер за nS

Няма как " QueryPerformanceCounter да ти инициира събитие". Ако мога да направя следната аналогия - това е чаовник, а не будилник. Ти го питаш кажи ми колко е часа, а не му казваш събуди ме в 8:10.
Не виждам друг начин да го направиш през паралелния порт, освен да се въртиш в цикъл и да четеш постоянно данните от него, но няма да можеш да гарантираш непрекъснатостта на това четене. Трябва ти хардуер, който да буферира получените данни, докато твоята програма не е активна (т.е. COM или USB).

Linux isn't free, it's worthless.


Отговор
в отговор на andrew_nikoloff #7

Re: таймер за nS

прав си
пробвах го в цикъл, но пропуските на приетите даннни са огромни.
Явно ще се върна към матрицата, там ацп,rs са готови трябва само да буферирам данните
RS от матрицата ми е на 115200 и работи добре, евентуално мога да го променя на 256000bps


не ми ясно дали как ще го обслужа в PS До сега го бях направил тъпичко-в един таймер 50 мс чета порта

Отговор
в отговор на svetlin #8

Остави COM порта да те вика

Ами остави COM порта да си те вика, когато има данни. Ако работиш директно с CreateFile използвай overlapped I/O. Ако ползваш някакъв компонент за четене от порта, то той трябва да си има събитие OnReadData или нещо подобно. Така няма да изпускаш данни предадени на порта.

Linux isn't free, it's worthless.


Отговор
в отговор на andrew_nikoloff #9

Re: Остави COM порта да те вика

Cid := CreateFile(ComTemp,GENERIC_WRITE OR GENERIC_READ,0,nil,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);

чета го с
ReadFile(Cid,Input,2,Result,@Overlapped)

Отговор
в отговор на svetlin #10

Re: Остави COM порта да те вика

В такъв случай можеш да си изчакаш резултата от четенето с GetOverlappedResult или с някоя от wait функциите или да използваш ReadFileEx, която приема параметър callback, който да ти бъде викнат директно след приключване на четенето.

Linux isn't free, it's worthless.


Отговор
в отговор на andrew_nikoloff #11

беше лесно да се каже

НЯМА ДА СЕ СПРАВЯ.
помогни

0886608575

Редактирано от svetlin на

Отговор
в отговор на svetlin #12

Re: беше лесно да се каже

Ето ти един пример, как да стане:
[линк]
В твоя случай, когато трябва да четеш всъщност трябва да викнеш Read_ComPort_UIButtonClick, както и да си вдигнеш таймаутите на нещо повече от секунда (например 2 секунди).

Linux isn't free, it's worthless.


Отговор
в отговор на andrew_nikoloff #13

Re: беше лесно да се каже

нещо такова ли трябва да стане

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, ComCtrls, shellapi, Spin;


type
TForm1 = class(TForm)
Label1: TLabel;
Read_ComPort_UIButton: TButton;
ReadToString_UIButton: TButton;
Memo1: TMemo;

procedure FormCreate(Sender: TObject);
procedure Read_ComPort_UIButtonClick(Sender: TObject);
procedure ReadToString_UIButtonClick(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var //hCommFile : THandle; // Global variable set elsewhere

Form1: TForm1;

TimeoutBuffer: PCOMMTIMEOUTS;
hCommFile: Integer;
ComTemp : PChar;


implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
GetMem(TimeoutBuffer, sizeof(COMMTIMEOUTS));

GetCommTimeouts (hCommFile, TimeoutBuffer^);
TimeoutBuffer.ReadIntervalTimeout := 2000;
TimeoutBuffer.ReadTotalTimeoutMultiplier := 2000;
TimeoutBuffer.ReadTotalTimeoutConstant := 2000;
SetCommTimeouts (hCommFile, TimeoutBuffer^);

FreeMem(TimeoutBuffer, sizeof(COMMTIMEOUTS));
ComTemp := 'COM1';
// 115200
hCommFile := CreateFile(ComTemp,GENERIC_WRITE OR GENERIC_READ,0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

end;

procedure TForm1.Read_ComPort_UIButtonClick(Sender: TObject);
var
InputBuffer : byte;
NumberOfBytesRead : dword;

Buffer : array[0..255] of byte;
i: Integer;
begin
if hCommFile=INVALID_HANDLE_VALUE then exit;

if ReadFile(hCommFile, Buffer, sizeof(Buffer),
NumberOfBytesRead, nil) = false then
begin
ShowMessage('Unable to read from comport');
exit;
end;
InputBuffer := 0;
for i := 0 to NumberOfBytesRead - 1 do
begin
InputBuffer := InputBuffer + Buffer;

memo1.Lines.Add(inttostr(i)+' '+inttostr(InputBuffer)); //label1.caption := inttostr(InputBuffer);
end;
end;

procedure TForm1.ReadToString_UIButtonClick(Sender: TObject);
var
InputBuffer : string;
NumberOfBytesRead : dword;
MaxBytesToRead : dword;
begin
if hCommFile=INVALID_HANDLE_VALUE then exit;

InputBuffer := '11111111111111'; // the string must be longer than
// the number of bytes you expect to read
//InputBuffer :=''; // This fails, the string must have a length

MaxBytesToRead := 14; // could use sizeof(InputBuffer) instead

if ReadFile(hCommFile, PChar(InputBuffer)^, MaxBytesToRead,
NumberOfBytesRead, nil) = false then
begin
ShowMessage('Unable to read from comport');
exit;
end;
InputBuffer := copy(InputBuffer, 1, NumberOfBytesRead);
// label1.caption := InputBuffer;

end;


end.

0886608575
Отговор
в отговор на svetlin #14

Горе-долу

Горе-долу, но...
Четенето от порта ще трябва да е повече от веднъж. Така четеш до 256 байта, а твоите данни би трябвало да са повече. Може да сложиш четенето в цикъл. Ти само си знаеш кога трябва да свърши той (имаш ли някакъв протокол за предаването на данните?).
Това, дето си го написал в цикъла в момента е грешно. InputBuffer ти е byte, а Buffer - масив от байтове. Не можеш да напишеш InputBuffer := InputBuffer + Buffer; Вероятно си искал InputBuffer да е голям масив от байтове, в който да натрупваш малкия Buffer? За да го направиш това можеш да ползваш например Move или да си въртиш цикъл и да си копираш байт по байт.
Втората процедура (ReadToString_UIButtonClick) не ти трябва.

Linux isn't free, it's worthless.


Отговор
в отговор на andrew_nikoloff #15

май става

не бях го усмислил добре

ето го променения
Buffer : array[0..2000] of byte;
i: Integer;
begin
NumberOfBytesRead:=8;
if hCommFile=INVALID_HANDLE_VALUE then exit;

if ReadFile(hCommFile, Buffer, sizeof(Buffer),
NumberOfBytesRead, nil) = false then
begin
ShowMessage('Unable to read from comport');
exit;
end;

for i := 0 to NumberOfBytesRead - 1 do
begin
memo1.Lines.Add(inttostr(i)+' '+inttostr(Buffer)); //label1.caption := inttostr(InputBuffer);
Buffer:=0;
end;

на този етап искаках само да го визуализирам после лесно ще го вкарам в масив.
матрицата ми праща 16 битово число и като измерената стойност е в младшите 8 бита съответно старшите 8 бита са 0 и MEMO1 започнаха да ми се появява 0 и измерената стойност

Протокол за приемането няма. Идеята е всяко приемане да да влиза в масив като индекса му е номера на приемането /примерно buffer/този индекс ми е и маркер за време
Не ми харесва че насила чета буфера а не ми извиква той

как може да се промени кода че да приемам 16 битово число

0886608575

Редактирано от svetlin на

Отговор
в отговор на svetlin #16

Re: май става

16 битовото число са две 8 битови едно след друго
За да те вика той можеш да ползваш ReadFileEx (виж последния параметър - процедура, която да бъде извикана след приключване на четенето) или да си изнесеш комуникацията в отделна нишка.

Linux isn't free, it's worthless.


Отговор
в отговор на svetlin #17

Re: таймер за nS

Ако наистина ще четеш само една секунда, можеш да си сложиш REALTIME_PRIORITY_CLASS на процеса за това време със SetPriorityClass - това ти гарантира 100% процесорното време, като дори спира критичните задачи на операционната система. Но ако забравиш да върнеш нормалния приоритет или приложението ти забие, цялата система зависва - дори и мишката не можеш да мръднеш :)

Виж също и SetThreadPriority в MSDN.

Mixy
Отговор
в отговор на Mixy #18

Re: таймер за nS

и аз имах някяква подобна идея каго се борих с LPT но така и увисна

0886608575
Отговор
в отговор на svetlin #19

Re: таймер за nS

пробвах го с LPT чете без загуба на данни през 1 микро секунда

0886608575
Отговор
в отговор на svetlin #20

Re: таймер за nS

Големи и естествени; Nelli Roono

Отговор