Call Search
     

New to Ham Radio?
My Profile

Community
Articles
Forums
News
Reviews
Friends Remembered
Strays
Survey Question

Operating
Contesting
DX Cluster Spots
Propagation

Resources
Calendar
Classifieds
Ham Exams
Ham Links
List Archives
News Articles
Product Reviews
QSL Managers

Site Info
eHam Help (FAQ)
Support the site
The eHam Team
Advertising Info
Vision Statement
About eHam.net

   Home   Help Search  
Pages: [1] 2 Next   Go Down
  Print  
Author Topic: Hdwr Ctrl, Timers, Serial Port Access in VB6  (Read 2458 times)
W4PQK
Member

Posts: 10




Ignore
« on: December 06, 2003, 03:34:38 PM »


Thanks to all who comment.

My objectives are to learn:
1. how to access STABLE millisecond timers in VB6
2. how to set/reset serial port bits (RTS, DTR, etc) for external on/off control or possibly the parallel port
3. how to communicate over serial port
4. if its possible to run a DOS (Pascal) program from VB without the DOS timer being disrupted by the VB multiplexing/time sharing of cpu

Previous posts on ProgrammersHeaven VB forums indicate #1 and #4 above are probably too much to hope for but another suggested that using a timer from the sound card would give millisecond or better timing with stability.

My desire(s), for starters, are to:
a) write a VB Morse code program producing sound via sound card, key a transmitter via serial port pins.
b) write a radio (IC706MkGII) control program for some foxhunting applications, etc, via the serial port and/or also over the CI-V input.
The Morse project is primarily for learning "how to" in VB6.


Several years ago I did the Morse program in Pascal (less the sound card stuff) which was satisfactory and feel confident I could do limited Icom control in Pascal but would like to have a VB6 user interface on the program.  I have completed a first course in VB6 and have the VB6Pro version.  I have been programming (Basic, Quick Basic, Fortran, Pascal) at the Hobby level for years, off and on.

I know this is a lot to learn.  I don't understand all the Windows stuff (APIs, DX8 add ins, etc) and am not asking someone to write this stuff for me.  I just want to get enough detail to get me started in the right direction and resources to help me when I get stuck.

I have experimented with some VB6 Morse programs downloaded from PlanetSourceCode and ran into timing problems.  The code speed via the sound card would noticeably change if the cursor was dragged across a control and there was a definite limit to the maximum code speed - perhaps about 15-20 wpm (memory fails).

Also, at a book fair I bought a JBuilder 2.0 starter kit for $5 and wonder if its worth getting into.  From what I have read it seems Java is a DOS like language with Windows features available via "Swing".  Would Java provide stable millisecond timers and serial port pin control?

Dave, I'm familiar with DXLab and read the reflector - how do you do it all?  Thanks.

I will be using Win95(300MHz), WinMe(700MHz?) and/or XP(1.5GHz?)

Well here's a tall order.  Thanks for your efforts folks.  

73 Jess, w4pqk
Logged
AA6YQ
Member

Posts: 1750


WWW

Ignore
« Reply #1 on: December 07, 2003, 01:43:02 AM »

The only way I know of to achieve long-term stable timing is by reference to a hardware timing source -- either a soundcard, or a serial port.

Programming a serial port - including DTR and RTS -- is quite straightforward if you use the MSCOMM control. Take a look at the online help (MSDN) for this control. If you have questions, I'll be happy to answer them.

Its a lot easier to learn serial port programming if you can see what you're doing. Since you have multiple computers, set one up to run a terminal emulator configured to its serial port. Wire this serial port to your development PC. Now you can write test programs that transmit data and see the results on the terminal emulator. You can also key in data from the terminal emulator and verify that your program can receive and process it correctly. Transceivers are very unforgiving, so its best to get your low-level serial port mechanisms working reliably in a friendlier environment.

If you build a T-cable, you can use the terminal emulator to monitor messages between your PC and transceiver, although this works better with radios that use an ASCII protocol like Kenwood or Elecraft than with a hex/BCD protocol like Icom and Yaesu.

   73,

       Dave, AA6YQ


Logged
W4PQK
Member

Posts: 10




Ignore
« Reply #2 on: December 08, 2003, 05:22:01 PM »

Thanks Dave.  I'll start digging into MSCOMM.  

With respect to the timers, I'm not sure what long-term stability implies in terms of the needs of cw timing.  Where would I find discussion or examples of how to use a sound card or serial port timer?  I would expect the approach to be something like:
.
.
key down
delay dottime (this delay would be appropriate # ms)
key up
.
.
but I'm sure setting up the timer is not going to be quite as straight forward.  Maybe MSCOMM will shed some light.

Thanks, Jess, w4pqk
Logged
AA6YQ
Member

Posts: 1750


WWW

Ignore
« Reply #3 on: December 09, 2003, 03:25:06 AM »

With the soundcard, you would either use the multimedia APIs or the DirectX APIs -- try a search for either one on the Microsoft site and you'll find the API reference info.

The basic idea is to set the hardware up to generate events a know rates. There will be a variable delay between the actual event occurence and the point at which your event handler gains control, but these delays won't accumulate.

If you're using the serial port as a source of timing, then you could for example set the baud rate to 9600 and the word length to 8. With one start bit and one stop bits, thats 10 bits per word, which works out close to 1 ms. per "new character" event. Again, the jitter between hardware event and event handler execution won't accumulate.

    73,

       Dave, AA6YQ
Logged
K3AN
Member

Posts: 787




Ignore
« Reply #4 on: December 19, 2003, 10:26:23 PM »

There is a DLL that will let you access an internal timer that has one millisecond resolution. I found the suggestion on some VB newsgroup site several years ago. It lets me generate accurate Morse via the serial port at speeds up to 30 WPM, and I'm sure I could go higher.

Put the following line at the beginning of the Declarations section of the form's code, before any Dim statements:

Public Declare Function timeGetTime Lib "winmm.dll" () As Long


You can then have delay intervals with 1 msec granularity, as per the following:

Dim DummyVariable As Integer, Interval As Long
Dim Endms As Long, Startms As Long
...
...
Interval = 5       ' e.g. for a 5 msec interval
Startms = timeGetTime
Do
     Endms = timeGetTime
     DummyVariable = DoEvents()
Loop While Endms - Interval < Startms
...
...

(The line with the DoEvents statement allows the PC to process other events while waiting for the interval to be completed.)

The best book about VB6 programming is that I have personally utilized is "Visual Basic 6 from the ground up" by Gary Cornell. It's published by Osborne/McGraw-Hill.
Logged
W4PQK
Member

Posts: 10




Ignore
« Reply #5 on: December 20, 2003, 05:22:56 PM »

Thanks, K3AN -- for the info, example code and text suggestion.  I'll check out the .dll.  Does the book get into hardware control or is it a general entry level VB6 text?  What edition if there are more than one?

Several questions regarding the loop, DoEvents() and the dll.

1.  Is the dll timer hardware based?  By hardware based, I'm thinking that a counter (register?) is set to some number, and a microsecond (?) hardware clock signal drives a countdown counter and when the count is satisfied (zero) a hardware interrupt occurs and appropriate action is taken [to update a millisecond clock (timeGetTime)].  It seems that if it is software based then anything happening as a result of other events would steal CPU time and cause a timing error.

2.  Assuming the dll timer is hardware based and regardless of DoEvents() produces accurate timing,  the DoEvents() will consume some CPU cycles if other events are happening.  Is there a maximum limit on the time taken by a DoEvents()? Is such a limit fixed or can it be specified?

3.  Assuming the dll timer is accurate and, suppose I need a 60ms delay for a dit (or dah?).  Would it be better to set the interval to 1 ms and call the function 60 times, or set the interval to 5 ms and call it 12 times, or set the interval to 60 and call it once?  I assume there are trade-offs.

4.  In other code samples I have seen DoEvents() used alone, not assigned to a variable.  What is the advantage of assigning it to a variable as you show?  Is DoEvents always an integer value?

5.  If I set up a loop with an interval of 1000 (1sec) and call it 600 times (10 minutes), should I get good correlation with a 10 minute interval on wwv?  I'll try something like that.

Thanks for the info.

73, Jess, w4pqk
Logged
K3AN
Member

Posts: 787




Ignore
« Reply #6 on: December 21, 2003, 11:44:21 AM »

Jess,

I don't have answers to all your questions, but here's what I know and also what I assume.

1. The dll timer is most likely software based. I assume this because once in a while a code element (dot, dash, or space) will be noticeably stretched while sending a message. Even on a slow, old 100 MHz first generation Pentium laptop, this occurs maybe once in an hour of contest operation.

2. According to Gary Cornell's book, if a DoEvents statement is present, Windows will process ALL of the events in its "event queue" before returning control to the VB application. I imagine you wouldn't want a taskbar full of open applications if precise timing is desired!

3. I would set the interval to the time I wanted and call the loop once. Why have the program track two variables (the delay time and the number of repetitions) when only one is needed.

4. DoEvents can be used alone according to Cornell. I guess the code snippet I found used the dummy variable.

5. I would think VB's Timer function would be as accurate as the winmm function for intervals longer than a minute or so.

Cornell's book really doesn't address hardware, other than capturing mouse events.

73,
Bill
 
Logged
W4PQK
Member

Posts: 10




Ignore
« Reply #7 on: December 21, 2003, 04:15:41 PM »

Thanks Bill, for your response(s).  

#3) As for calling the delay loop once, that makes good sense (KISS - keep it simple...).  

#2) Hadn't thought about this - obvious.

Maybe I'll write some code and see if I can time how long it takes DoEvents to be processed.  I'm not sure this is practical for modern computers with clocks in the hundreds of MHz.  A 1ms delay is a LONG time.

Thanks, Jess, w4pqk

Logged
AA6YQ
Member

Posts: 1750


WWW

Ignore
« Reply #8 on: December 22, 2003, 02:43:06 AM »

While this does allow events to be processed within the wait-loop, do other simultaneously-running applications get any CPU time while you are transmitting CW?

   73,

       Dave, AA6YQ
Logged
K3AN
Member

Posts: 787




Ignore
« Reply #9 on: December 22, 2003, 12:10:11 PM »

Yes, that's the purpose of DoEvents. But with other programs running, you will encounter the occasional random "stretched" dot, dash or space as I mentioned. I would imagine that the more programs you have running, the worse the CW would become. If any of the other programs is a real "CPU Hog," the CW may become indecipherable.
Logged
HB9SWLTOM
Member

Posts: 3




Ignore
« Reply #10 on: January 29, 2004, 03:31:47 PM »

Gr├╝tzi,
And sorry, didn't find another efficient way to ask for
HELP.
 
Would you have a look at my question, please.

http://www.vbarchiv.net/forum/id2_i70353t70353.html

SH.. forgot that it's in German.

O.K. Access 2002, home-made Swl-Database (Frequency,RST...)

I would like the (typed input) frequency to be transmitted to my FRG-8800.

Got all neccessary Data-Bytes and CAT-cable works fine with ScanCat Gold.
But there is a lack of knowledge about VB and MS Access.

I would really appreciate any comment.

Big 73,
Tom
Logged
AA6YQ
Member

Posts: 1750


WWW

Ignore
« Reply #11 on: January 30, 2004, 03:34:51 AM »

You can easily reference Access databases via Visual Basic, but the general topic is more broad than can be easily discussed here. Most any good book on VB6 will cover this.

    73,

        Dave, AA6YQ
Logged
HB9SWLTOM
Member

Posts: 3




Ignore
« Reply #12 on: January 30, 2004, 04:41:43 AM »

Thanks for your attention. Don't want anything complicated, just a simple event-procedure doing something like this:

Private Sub Send_Data_Click()
Dim filenr As Integer

filenr = FreeFile
Open "COM1" For Output As #filenr
MsgBox " Filenumber :" + Str(filenr)

' Frequency = 14 210 Khz (backwards)
Print #filenr, &H1
Print #filenr, &H10
Print #filenr, &H42
Print #filenr, &H1
Print #filenr, &H1

Close #filenr
MsgBox "Data sent"
End Sub

Any Ideas ?
Greetings from Switzerland
Logged
AA6YQ
Member

Posts: 1750


WWW

Ignore
« Reply #13 on: January 31, 2004, 02:27:07 AM »

Here's the code I use in Commander, DXLab's transceiver control application. CommControl is an instance of the Microsoft MSCOM control; you'll need to place it on the form in which the following code resides.

In your application, you should invoke OpenPort, use WritePort to send control strings to your radio, and when done call ClosePort.

     73,

          Dave, AA6YQ



Option Explicit
 
Const ReceiveBufferLen = 1024
Const TransmitBufferLen = 1024
   
Const ModemControlOff = 0
Const ModemControlOn = 1
Const ModemControlTransmit = 2
Const ModemControlFlowControl = 3
   
Dim Opened As Boolean

Function PortOpened() As Boolean
    On Error GoTo Abort

    PortOpened = Opened
    Exit Function

Abort: Common.ProgramError Err.Number, "CIVComm.PortOpened"

End Function

Sub InitializePort()
    On Error GoTo Abort

    Opened = False
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.InitializePort"

End Sub

Sub FlushPort()

    On Error Resume Next
    Me.CommControl.PortOpen = False
    Me.CommControl.PortOpen = True
End Sub

Sub Transmit()

    On Error GoTo Abort

    If CIVModule.GetDTRControl = ModemControlTransmit Then
        CommControl.DTREnable = True
    End If
   
    If CIVModule.GetRTSControl = ModemControlTransmit Then
        CommControl.RTSEnable = True
    End If
   
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.Transmit"

End Sub

Sub Receive()

    On Error GoTo Abort

    If CIVModule.GetDTRControl = ModemControlTransmit Then
        CommControl.DTREnable = False
    End If
   
    If CIVModule.GetRTSControl = ModemControlTransmit Then
        CommControl.RTSEnable = False
    End If
   
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.Receive"

End Sub

Function ModemControlEnabled(ModemControl As Integer) As Boolean

    On Error GoTo Abort

    Select Case ModemControl
   
        Case ModemControlOff
            ModemControlEnabled = False
           
        Case ModemControlOn
            ModemControlEnabled = True
           
        Case ModemControlTransmit
            ModemControlEnabled = False
       
        Case ModemControlFlowControl
            ModemControlEnabled = True
           
    End Select
   
    Exit Function

Abort: Common.ProgramError Err.Number, "CIVComm.ModemControlEnabled"

End Function

Sub ConfigureRTS(RTSControl As Integer)
    On Error GoTo Abort
   
    CommControl.RTSEnable = ModemControlEnabled(RTSControl)
   
    If RTSControl = ModemControlFlowControl Then
        CommControl.Handshaking = comRTS
    Else
        CommControl.Handshaking = comNone
    End If
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.SetRTS"

End Sub

Sub OpenPort(Port As Integer, Speed As Long, Parity As String, WordLength As String, StopBits As String, DTRControl As Integer, RTSControl As Integer)

    Dim CommString As String
    Dim ErrorMessage As String
   
    On Error GoTo Abort

    If Port = 0 Then Exit Sub
   
    If Opened Then CommControl.PortOpen = False 'reconfigure
   
    CommControl.CommPort = Port
   
    CommControl.DTREnable = ModemControlEnabled(DTRControl)
    CIVComm.ConfigureRTS (RTSControl)
   
    CommControl.InBufferSize = ReceiveBufferLen
    CommControl.InputLen = 0                  'get everything received
    CommControl.NullDiscard = False
    CommControl.InputMode = comInputModeText  'get strings
    CommControl.RThreshold = 1                'enable receive events
    CommControl.OutBufferCount = 0            'clear the output buffer
    CommControl.OutBufferSize = TransmitBufferLen
    CommControl.SThreshold = 0                'disable transmit events
    CommControl.InBufferCount = 0             'flush anything laying around from before
   
    CommString = Format$(Speed) + "," + Parity + "," + WordLength + "," + StopBits
    'Debug.Print CommString
    CommControl.Settings = CommString
   
    CommControl.EOFEnable = False
    CommControl.Handshaking = comNone
   
    On Error GoTo OpenFailed
    CommControl.PortOpen = True               'try opening the port
    On Error GoTo Abort
   
    Opened = True
    CIVModule.SetCommCaption ""
    CIVModule.UpdateCaption
       
    Exit Sub

OpenFailed:

    If Err.Number = 8005 Then
        CIVModule.SetCommCaption " - selected Com port already in use"
        CIVModule.UpdateCaption
        MsgBox "Already in use", vbOKOnly, "Unable to open Com" + Format$(Port)
        Opened = False
    Else
        ErrorMessage = Err.Description + " (" + Format$(Err.Number) + "), port = " + Format$(Port) + ", settings = " + CommString
        CIVModule.SetCommCaption " - selected Com port failed to open: " + Err.Description
        CIVModule.UpdateCaption
        MsgBox ErrorMessage, vbOKOnly, "Unable to open Com" + Format$(Port)
        Opened = False
    End If
   
    Exit Sub
   
Abort:
    Common.ProgramError Err.Number, "CIVComm.OpenPort"
End Sub

Sub ClosePort()
    On Error Resume Next
    If Opened = True Then
        CommControl.PortOpen = False
        Opened = False
    End If

End Sub

Function ReadPort() As String

    On Error GoTo Abort
   
    If Not Opened Then Exit Function

    If CommControl.InBufferCount = 0 Then
        ReadPort = ""
        Exit Function
    End If

    ReadPort = CommControl.Input
   
    Exit Function

Abort: Common.ProgramError Err.Number, "CIVComm.ReadPort"

End Function

Sub WritePort(WriteData As String)
   
    On Error GoTo Abort
   
    If Not (Opened) Then Exit Sub
       
    On Error Resume Next 'in case port closed
    CommControl.Output = WriteData

    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.WritePort"

End Sub

Sub DisableCommRXEvents()
    On Error GoTo Abort

    CommControl.RThreshold = 0
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.DisableCommRXEvents"

End Sub

Sub EnableCommRXEvents()
    On Error GoTo Abort

    CommControl.RThreshold = 1
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.EnableCommRXEvents"

End Sub

Private Sub CommControl_OnComm()

    On Error GoTo Abort
   
    Select Case CommControl.CommEvent
    ' Handle each event or error by placing
    ' code below each case statement

    ' Errors
    Case comEventBreak      ' A Break was received.
        CommError "Break"
     
    Case comEventFrame      ' Framing Error
        CommError "Framing Error"
       
    Case comEventOverrun    ' Data Lost.
        CommError "Overrun"
       
    Case comEventRxOver     ' Receive buffer overflow.
        CommError "RX buffer overflow"
       
    Case comEventRxParity   ' Parity Error.
        CommError "RC parity"
       
    Case comEventTxFull     ' Transmit buffer full.
        CommError "TX buffer full"
       
    Case comEventDCB        ' Unexpected error retrieving DCB]
        CommError "DCB error"

   ' Events
    Case comEvCD            ' Change in the CD line.
        'CommError "CD change"
       
    Case comEvCTS           ' Change in the CTS line.
        'CommError "CTS change"
       
    Case comEvDSR           ' Change in the DSR line.
        'CommError "DSR change"
       
    Case comEvRing          ' Change in the Ring Indicator.
        'CommError "Ring change"
       
    Case comEvReceive       ' Received RThreshold # of chars
        CIVModule.HandleIncomingChar ""
     
    Case comEvSend          ' There are SThreshold number of
                            ' characters in the transmit buffer
     
    Case comEvEOF           ' An EOF charater was found in
                            ' the input stream
                     
    End Select
   
    Exit Sub

Abort:
    Common.ProgramError Err.Number, "CIVComm.OnComm"
End Sub

Private Sub CommError(Error As String)
    On Error GoTo Abort

    Common.DebugLog "CIVComm.CommError: " + Error
    'Debug.Print "Comm Error: " & Error
    Exit Sub

Abort: Common.ProgramError Err.Number, "CIVComm.CommError"

End Sub

Private Sub Form_Load()
    On Error GoTo Abort
    Common.DebugLog "CIVComm.Form_Load"
    InitializePort
    Common.DebugLog "CIVComm.Form_Load complete"
    Exit Sub
   
Abort:
    Common.ProgramError Err.Number, "CIVComm.Form_Load"
End Sub

Private Sub Form_Unload(Cancel As Integer)
    On Error GoTo Abort
    ClosePort
    Exit Sub
   
Abort:
    Common.ProgramError Err.Number, "CIVComm.Form_Unload"
End Sub
Logged
HB9SWLTOM
Member

Posts: 3




Ignore
« Reply #14 on: February 01, 2004, 01:18:49 PM »

THANKS !
I love learning. In fact, the code looks quite "readable".
Now, imagine you install MS Office XP, learn to understand Access, create a form, and then a button on the form with a connected event-procedure.
Open the procedure and you find yourself in VB-Editor.
All you want to do, is to send a few bytes to COM1.
Really straightforward.
How on earth do I get MSCOMM to work there ?

P.S.: I mentioned that I love learning. Education comes from having been educated. Since I can't ask my dad, I appreciate advice from anyone else, who has the patience.
Logged
Pages: [1] 2 Next   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!