Newsgroup: it.comp.lang.visual-basic
Titolo: [VB2008EE] Consiglio per timer minore 1 ms

Vorrei generare un segnale periodico (in uscita su un pin della porta
parallela) per ottenere un segnale PWM con caratteristiche (periodo e duty)
variabili impostabili utilizzando opportuni oggetti su un Windows.Form.
Intendevo pertanto utilizzare l'oggetto System.Windows.Forms.Timer
impostando la proprietą "interval" per 2 timer diversi: il primo per il
periodo vero e proprio del segnale ed il secondo "concatenato" al primo per
impostare il segnale a livello alto o basso a seconda del duty impostato.
Dall'help leggo che il timer.interval presenta il limite minimo di 1ms (gią
diminuito rispetto a VB2005EE dove corripondeva a 10ms) ma volendo
diminuire ancora l'intervallo del periodo (e quindi aumentare la frequenza
ad un valore maggiore di 1kHz) come č possibile fare?
Ho fatto il tentativo brutale, sulla sub Form1_Load, di un loop infinito di
toggle sul pin desiderato ed ottengo circa 100 kHz (verificati con
l'oscilloscopio) ma... ovviamente... l'applicazione rimane all'interno del
loop e non esegue nient'altro (nemmeno la visualizzazione del form). In
questo modo intendevo conteggiare il numero di loop/toggle eseguiti in un
tempo noto (determinato ad esempio con un timer di 1 secondo) ed in base a
questo valore trovato determinare la durata del segnale espresso in numro
di loop/toggle.
Perdonatemi sono un dilettante autodidatta, proveniente dal QBasic, molto
allo sbaraglio!
Grazie,
Robin2

 allo sbaraglio!
Non ho conoscenze di .net, ma ti posso dire che di solito il timer non č
sempre affidabile, indipendentemente dall'intervallo, almeno in vb6.
Forse quello che cerchi č eseguire un loop in un thread separato, ma vado
ad occhio.
Altri ti sapranno consigliare meglio.

 diminuire ancora l'intervallo del periodo
Prova a guardare questo articolo:
http://www.codeproject.com/KB/vb/vbnetstopwatch.aspx
-- 
news:it-alt.comp.software.openoffice : Il newsgroup dedicato a
OpenOffice.org, la suite open source di applicazioni per ufficio.
Saluti, VITRIOL

 Robin2
Potresti usare l'oggetto System.Threading.Timer
Prova a dare un'occhiata qui:
http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET/default.aspx
Bye
Raf


Ehm... con System.Threading.Timer non hai problemi di thread, però in 
effetti non scendi sotto 1 ms...
Dovresti allora usare un Multimedia Timer: 
http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx
Bye
Raf

 sempre affidabile, indipendentemente dall'intervallo, almeno in vb6.
Cosa intendi per "affidabile"? Se "non preciso" non ha importanza estrema:
sostanzialmente il segnale PWM generato su parallela dovrà pilotare un
motore in cc (con l'opportuna interfaccia di potenza) senza particolari
pretese.
Grazie per la risposta,
Robin

 
http://www.codeproject.com/KB/vb/vbnetstopwatch.aspx
Articolo molto interessante; ancora devo verificarlo in pratica ma sembra
essere proprio ciò che fa al mio caso.
Grazie mille per la puntuale disponibilità e consigli mirati ed efficaci.
Robin

 Raf
Non posso ancora verificare il contenuto dei sotto-link visualizzati nella
pagina indicata finché non mi registro...
provvederò non appena possibile!
Ti ringrazio per il consiglio Raf.
Robin



Ho fatto delle prove ed ottengo un controllo dell'ordine di alcuni
microsecondi (circa 2-3): ottimo risultato!
Se dovesse essere utile a qualcuno riporto sotto il mio listato; accetto
ogni suggerimento o critica.
Robin
        Dim PwmTimer As New Stopwatch()
        Dim HighLevelTimer As New Stopwatch()
        PwmTimer.Start()
        Do
            If PwmTimer.Elapsed.TotalMilliseconds >= periodo_us / 1000 Then
                PwmTimer.Reset()
                PwmTimer.Start()
                'segnale PWM settato
                If durata_us > 0 Then
                    If durata_us < periodo_us Then
                        HighLevelTimer.Reset()
                        HighLevelTimer.Start()
                    End If
                    'lo setta (out=1)
                    IO.BitSet(IndirizzoPorta, IndiceBitPwm)
                End If
            End If
            If HighLevelTimer.Elapsed.TotalMilliseconds >= durata_us / 1000
then
                If HighLevelTimer.IsRunning = True Then
                    HighLevelTimer.Reset()
                End If
                'lo resetta (out=0)
                IO.BitReset(IndirizzoPorta, IndiceBitPwm)
            End If
        Loop
 

Il Tue, 19 Feb 2008 09:39:06 +0100, Rafunk ha scritto:

ho visto gli esempi (sorgenti in VC, almeno credo, ma non lo conosco
affatto; non ho trovato riferimenti in VB che già conosco poco) ma anche
Multimedia Timer ha il limite di 1 ms !?!
Robin


È scritto in C#. Ma puoi compilare il progetto ed utilizzarlo come una class 
library esterna aggiungendolo ai riferimenti del tuo progetto VB.
Sob... ero convintissimo, ma rileggendo l'msdn vedo che in effetti però la 
risoluzione minima è 1ms anche per questo tipo di timer... :-(
Allora l'unica strada è usare l'API QueryPerformanceCounter, come nell'altro 
esempio di codeproject che ti hanno indicato.
Peccato perché sarebbe stato meglio poter disporre di una classe simil-timer 
che generi *eventi* ad una frequenza maggiore di 1 KHz.
Mi sa che si possa solo ricorrere a loop "stretti"+misurazioni precise del 
tempo trascorso, come hai fatto tu.
Ah, occhio che nel tuo codice in qualche modo si dovrà uscire dal loop.
Volendo, attenzione perché se esegui il loop nello stesso thread della GUI, 
essa rimarrà "congelata" finché non termina o finché non chiami 
(sconsigliatissimo) Application.DoEvents all'interno del loop stesso. 
Sconsigliatissimo perché potrebbe sballare il timing.
Ciao
Raf 

 Raf
Ciao
Robin

 rendere il tutto variabile, come posso fare?
Variabile nel senso che vorresti poter variare quei parametri dinamicamente, 
mentre il loop è in esecuzione?
Raf

 Raf
esattamente! Ma nessun evento mi fa uscire dal loop, giusto?
Hai nominato Application.DoEvents sconsigliandolo però perché altera il
timing (immagino solo temporaneamente) ma qualsiasi azione modificherà il
timing (sempre temporaneamente) poiché esco dal loop alterandone la
tempistica, corretto?
Robin


Ogni volta che si chiama Application.DoEvents l'esecuzione del codice 
corrente si interrompe per servire gli eventi che nel frattempo l'utente ha 
"innescato", ad esempio. E la durata di questa interruzione non è 
predicibile.
La strada più corretta, IMHO, è quella di creare un thread secondario 
(worker thread) nell'applicazione principale, controllato dal thread 
principale (GUI thread), e delegare ad esso l'esecuzione del loop.
Ma questo richiede parecchio studio, perché ha a che fare con concetti 
(multithreading) che se hai un "background" solo di QBasic difficilmente 
avrai chiari, all'inizio.
Bye
Raf 

 avrai chiari, all'inizio.
C'è il controllo BackgroundWorker, che aiuta molto in proposito.


 Raf
Grazie, con loop infinto, sia a te Raf che a Vitriol (mi riprometto di
studiare anche il controllo BackgroundWorker che non ho ancora utilizzato)
per ogni vostro gentilissimo consiglio. (Non posso dire "a buon rendere"
viste le mie conoscenze...)
Robin