Usando o controle MSComm no Visual Basic


Neste artigo vamos mostrar como usar controle MSComm da Microsoft e como detectar as portas COM disponíveis.

Cada computador possui portas seriais denominadas sucessivamente : COM1 , COM2 , etc. Geralmente o mouse usa a porta COM1 o modem a porta COM2 o scanner a COM3 e assim por diante. Assim as portas seriais possibilitam um canal de transmissão de dados a partir destes dispositivos.

Se você tentar verificar a disponibilidade das portas COM de sua máquina provavelmente você irá obter o erro 8002 - Número de porta Inválida . Entretanto você pode fazer o feitiço virar contra o feiticeiro usando este erro para detectar quais portas estão disponíveis e exibir somente as portas realmente disponíveis.

Vamos então mostrar um projeto que pode ser usado para detectar as portas COM disponíveis ( deve funcionar bem no Win95/98 e NT)

1- Inicie um novo projeto no Visual Basic e no formulário padrão - form1 - insira um botão de comando - command1 , uma label - Portas COM disponíveis , e um controle ComboBox conforme abaixo:

2- Inclua um módulo no seu projeto e a seguir insira o seguinte código no módulo:

Type DCB
  DCBlength As Long
  BaudRate As Long
  fBitFields As Long
  wReserved As Integer
  XonLim As Integer
  XoffLim As Integer
  ByteSize As Byte
  Parity As Byte
  StopBits As Byte
  XonChar As Byte
  XoffChar As Byte
  ErrorChar As Byte
  EofChar As Byte
  EvtChar As Byte
  wReserved1 As Integer
End Type

Type COMMCONFIG
  dwSize As Long
  wVersion As Integer
  wReserved As Integer
  dcbx As DCB
  dwProviderSubType As Long
  dwProviderOffset As Long
  dwProviderSize As Long
  wcProviderData As Byte
End Type
'
Declare Function GetDefaultCommConfig Lib "kernel32" _
Alias "GetDefaultCommConfigA" (ByVal lpszName As String, _
lpCC As COMMCONFIG, lpdwSize As Long) As Long

3- Ainda no módulo insira o seguinte código para a função DetectaPortaCOM :

Public Function DetectaPortaCOM(port As Integer) As Long
'retorna zero se a porta com não existir
Dim cc As COMMCONFIG, ccsize As Long

ccsize = LenB(cc)

DetectaPortaCOM = GetDefaultCommConfig("COM" + Trim(Str(port)) + Chr(0), cc, ccsize)

End Function

4- Inclua o código abaixo no evento click do botão de comando - command1 :

Private Sub Command1_Click()
Dim i As Integer

Combo1.Clear
For i = 1 To 16
   If DetectaPortaCOM(i) <> 0 Then
       Combo1.AddItem "COM" & i
   End If
Next
Combo1.ListIndex = 0
End Sub

Ao executar o projeto e clicar no botão para detectar as portas a combobox irá exibir as portas disponíveis. Ver figura acima.

Usando o Controle MSComm - Propriedades

A primeira coisa a fazer para usar o controle MSComm em seu projeto e incluir o componente no seu formulário. Clique em Project | Components e selecione : Microsoft Comm Control 6.0

Obs: Este controle somente esta disponível na versão Professional do VB.

O controle MSComm fornece a interface para um conjunto de comandos de comunicação padrão : conectar com uma porta serial , conectar com outro dispositivo de comunicação , trocar dados , monitar e responder a vários eventos durante uma comunicação serial. Podemos usar o controle para realizar as seguintes tarefas:

  1. Discar um número de telefone
  2. Monitarar a porta serial para entrada de dados
  3. Criar sistemas de comunicação
Ao lado temos o controle MSComm sendo incluido no formulário e as propriedades que podemos configurar.

Uma das primeiras propriedades que podemos configurar é a propriedade Settings. Esta propriedades permite configurar :

O formato da propriedade Settings é : "BBBB,P,D,S"

Onde :

Os valores padrão para esta propriedade é : "9600,N,8,1"

Se a propriedade for configurada com valores inválidos , ao tentar abrir uma porta COM iremos obter o erro : 380 - Invalid Property value

Para usar o controle MSComm e estabelecer uma comunicação com uma porta serial usamos as seguintes propriedades:

Propriedade Descrição
CommPort Define e retorna o número a porta de comunicação
Settings Define e retorna : baud rate, parity, data bits, e stop bits como uma string
PortOpen Define e retorna o estado da porta de comunicação. Também abre e fecha a porta.

Vejamos um exemplo de código para realizar esta tarefa:

'Abre a porta serial
MSComm1.CommPort = 2
MSComm1.Settings = "9600,N,8,1"
MSComm1.PortOpen = True

Como funciona:

  1. A propriedade CommPort define qual porta serial vai ser aberta . O número 2 indica que abrimos a porta COM2. Podemos usar valores entre 1 e 16. O valor padrão é 1.
  2. A propriedade Settings permite definir as propriedades discutidas acima : baud rate, parity, data bits, e stop bits
  3. A propriedade PortOpen para estabelecer a conexão . Ela retorna um valor Verdadeiro (True) ou Falso ( False)
Podemos configura estas propriedades em tempo de projeto clicando em Custom na janela de propriedades do controle e definindo os valores na janela Property Pages .

Usando um Modem

Podemos usar o controle MSComm com um modem através dos comandos compatíveis com o padrão Hayes; tanto para discar um número de telefone como para efetuar uma conexão com outro modem.

Apos definir as propriedades CommPort, Settings e PortOpen para estabelecer a conexão , usamos a propriedade Output para ativar e interagir com o modem. Exemplo:

MSComm1.Output = "ATDT 235-4545" & vbCr

Onde :

Nota: Os comandos Hayes são padronizados e permitem que o programa de comunicação controle as funções do modem. Porém, nem todos os modems compatíveis com o padrão Hayes (hoje, maioria absoluta) aceitam todos os comandos, e alguns possuem comandos especiais. O manual do modem deve conter essas informações e também os valores default (pré-configurados na fábrica). 

Os comandos são dados a partir do programa de comunicação, em modo terminal, ou já estão embutidos no próprio soft de comunicação. Normalmente, começam com os caracteres AT, que fazem o modem prestar atenção ao que é comandado a seguir, podem ter (conforme o modem) de 40 a 255 caracteres na linha de comando e terminam, como qualquer comando em computador, com o sinal <CR> (Carriage Return - sinal obtido quando se pressiona a tecla [Enter] ou [Return] - em código <CR> equivale a usar CHR$(13) ou vbcr)

Lista de comandos Hayes

Os comandos Hayes são enviados na forma AT[primeiro comando] [segundo comando] [terceiro comando etc.] [Enter/Return].

AT é o código de atenção, usado no início de cada linha de comando, tenha ela um ou mais comandos Hayes. Apenas o comando [A/] não usa o código de atenção, e serve para repetir o último comando executado. A seguir uma lista dos principais comandos Hayes :

Comando Hayes Descrição
A conecta em modo de resposta
Dx Discar (Dial) ; onde x pode assumir P(Pulso) , T(Tom) , R (modo de resposta) , W (espera por tom de discar)
Ex Ecoa ou não os caracteres para o micro em modo local , onde o x pode assumir : 0 ( retira o eco) ou 1 (inclui o eco)
Hx Controla a conexão do modem. O x pode assumir: 0 (desconecta) ou 1 (conecta)
Vx Formato de resposta, onde x pode ser : 0 (formato numérico) ou 1 (formato texto)
Z Reseta o modem.

Ex: ATZ - reseta o modem , ATA - coloca o modem em estado de resposta , ATH0 - Desconecta o modem.

Alocação do Buffer de Memória

Quando uma porta é aberta , são criados buffers para transmitir e receber dados. Para gerenciar estes buffers podemos usar a janela de Property Pages clicando em Custom na janela de propriedades do controle.

As propriedades InBufferSize e OutBufferSize definem quanto de memória é alocado para receber e transmitir buffers. ( armazenam os dados de chegada e de saida). Quanto maior o valor usado , menor a memória disponível para sua aplicação. Se o valor for muito pequeno você corre o risco de um transbordamento de buffer a menos que você use Handshaking. Atualmente , devido a quantidade de memória dos computadores , podemos usar valores maiores para alocar memória.

As propriedades RThreshold e SThreshold

As propriedades RThreshold e SThreshold ajustam ou retornam o número de caracteres que são recebidos nos buffers de transmissão e recepção antes que o evento OnComm seja disparado.

O evento OnComm é usado para monitorar e responder ás mudanças no estado da comunicação. Se cada propriedade for definida com o valor 0 ( este é o padrão ) evita que o evento OnComm seja disparado. Qualquer outro valor diferente de zero fará com que o evento OnComm seja disparado sempre que um caractere for recebido no buffer.

As propriedades InputLen e EOFEnable

Definir a propriedade InputLen com o valor 0 faz com que o controle leia todo o conteúdo do buffer de recepção quando usamos a propriedade Input . Ao ler dados de uma máquina cuja saída esta formatada para blocos de dados de tamanho de comprimento fixo podemos ajustar o valor desta propriedade de forma correta.

A propriedade EOFEnable é usada para indicar quando um caracter de fim de arquivo ( End of File) for encontrado duranta uma entrada de dados. Definir esta propriedade como True faz com que a entrada de dados pare e o evento OnComm seja disparado para informar a condição acabou de ocorrer.

Gerenciando os buffers de transmissão e recepção

Quando uma porta é aberta os buffers de transmissão e recepção de dados são criados . Eles são usados para receber os dados que chegam e transmitir os dados que saem. O controle MSComm permite gerenciar estes buffers através de propriedades que permitem receber e transmitir dados , determinar o tamanho de cada buffer e manipular dados do tipo teto e dados do tipo binário.

O buffer de recepção

A propriedade Input é usada para armazenar e retornar dados de um buffer de recepção. Assim se você que receber dados de um buffer de recepção e exibí-los em uma caixa de texto ( text1.text ) pode usar o seguinte código:

Text1.text = MSComm1.Input

Se quiser receber e exibir todo o conteúdo do buffer deve definir a propriedade InputLen com valor 0 .

Para receber dados no formato Texto ou Binario você deve definir a propriedade InputMode para um dos seguintes valores : comInputModeText (dados no formato ANSI) ou comInputModeBinary(dados que contenham caracteres de controles , Nulls ,etc..)

Cada byte de dados recebido é movido para o buffer de recepção e a propriedade InBufferCount é incrementada de um ; assim podemos usar a propriedade InBufferCount para retornar o numero total de bytes no buffer de recepção. Para limpar o buffer de recepção definimos o valor desta propriedade para o valor igual a 0.

O buffer de transmissão

A propriedade Output é usada para enviar comandos e dados para o buffer de transmissão.

Da mesma forma que a propriedade Input , os dados podem ser enviados no formato Texto ou Binário. Podemos enviar comandos , tetos , ou uma matriz de dados : Veja o código exemplo a seguir:

Dim Out as byte
' Envia um comando AT 
MSComm1.Output = "ATDT 555-5555"

' Envia uma string 
MsComm1.Output = "Estou enviando uma string"

' Enviando uma matriz de dados
MSComm1.Output = Out
Ao final de uma linha de dados devemos usar o caracter de retorno - vbCr .

Para monitorar o buffer de transmissão usamos a propriedade OutBufferCount. Definindo o valor desta propriedade como igual a zero limparemos o buffer de transmissão.

Agora um exemplo prático

Vamos aplicar toda a teoria vista acima em um exemplo prático. Vamos criar um projeto para discar um número telefônico usando um modem.

1- Inicie um novo projeto no VB e no formulário padrão insira uma caixa de texto - text1.text

2- Faça uma referência ao componente MSComm - MSComm1 - no seu projeto - Microsoft Comm Control 6.0 ( MSCOMM32.ocx)

3- Inicialmente vamos configurar as seguintes propriedades do controle MSComm1 :

Propriedade Valor
RThreshold  1
SThreshold  1
InputLen      0
ComPort A porta do seu modem
Private Sub Command1_Click()

MSComm1.PortOpen = True
MSComm1.Output = "ATDT" & text1.Text & Chr$(13)

End Sub

Obs: precisamos incluir o codigo de controle CHR$(13) depois do comando. O número a ser discado deverá ser informado na caixa de texto - text1.text.

Como vamos ter certeza de que a discagem ocorreu com sucesso ??? Para isto vamos usar o evento OnComm.

Usamos o evento OnComm para verificar se os dados estão sendo recebidos. Para receber os dados checamos a propriedade Input , ocorre que os dados ficam por pouco segundos na propriedade Input. Aí é que entra o evento OnComm .

Para disparar o evento configuramos as propriedades RThreshold e SThreshold com valor igual a 1. Para obter o resultado de um comando enviado para o modem vamos usar o seguinte código no evento OnComm:

Private Sub MSComm1_OnComm()
  Select Case MSComm1.CommEvent
  'mensagens dos eventos
  Case comEvReceive
    Text1.Text = Text1.Text & StrConv(MSComm1.Input, vbUnicode)
  End Select
End Sub

Este código verifica qual evento ocorreu e se o for o evento Receive o conteúdo da propriedade Input é adicionada ao final da caixa de texto:

Podemos usar o evento OnComm também para monitorar erros durante a comunicação. Vejamos a seguir uma tabela com as constantes que podem ocorrer quando o evento OnComm ocorre.

Constante Valor Descrição
comEvSend 1 Numeros de caracteres no buffer de transmissão menor que RThreshold.
comEvReceive 2 Recebendo RThreshold número de caracteres.
comEvCTS 3 Alteraçao em Clear To Send line.
comEvDSR 4 Alteração na linha Data Set Ready.
comEvCD 5 Alteração em Carrier Detect line.
comEvRing 6 Chamado detectado. Alguns UARTs (universal asynchronous receiver-transmitters) podem não suportar este evento.
comEvEOF 7 Fim de arquivo (ASCII character 26)

Para encerrar o artigo vamos mostrar um projeto onde usamos as propriedades e eventos do controle MSComm discutidas.

1-) inicie um novo projeto no VB e no formulário padrão insira os controles conforme o layout abaixo:

Private Sub Form_Load()
Dim i As Integer
Dim sSettings As String
sSettings = MSComm1.Settings
cboBaubRate.Text = Left$(sSettings, 4)
cboParity.Text = Mid$(sSettings, 6, 1)
cboDataBits.Text = Mid$(sSettings, 8, 1)
cboStopBits.Text = Mid$(sSettings, 10, 1)
cboCommand.ListIndex = 0

'// obtem porta com
Show
DoEvents
ListaPortasCom

End Sub

Como podemos ver na carga do formulário , no evento Load , obtemos os valores da propriedade Settings e preenchemos as caixas de combinação extraindo os valores pertinentes a cada propriedade.

A seguir usamos a função ListaPortasCom para detectar e listar as portas COM disponíveis. A função é exibida a seguir:

Private Sub ListaPortasCom()
Dim i As Integer

cboComm.Clear
SetStatus "Verificando as portas disponíveis...", True
For i = 1 To 16
  If DetectaPortaCOM(i) Then
      cboComm.AddItem i
      SetStatus "COM" & i & " encontrada", False
  End If
Next
cboComm.ListIndex = 0
End Sub

Abaixo a tela de exibição do projeto:

A função DetectaPortaCOM foi discutida no inicio do artigo. O resto do código é trivial. Para fazer o download do projeto clique aqui : Exemplo de utilização do MSComm - Mscom.zip


 José Carlos Macoratti