Controlar dispositivos por el puerto serie

Si alguna vez has pensado en controlar algún dispositivo desde tu PC puede que este truco pueda servirte. En este caso se activa o desactiva un rele, que a su vez actúa como un interruptor que permite encender o apagar "cualquier cosa" (una luz, una puerta automática, etc.).

Para realizar esto vamos a usar el puerto serie del PC, mas concretamente el pin RTS que en un conector de 9 pines es el numero 7. El circuito se ha reducido para que resulte sencillo y no utilice demasiados componentes, su funcionamiento es muy básico cuando activamos RTS tendremos una tensión positiva que activara el rele, si desactivamos RTS tendremos una tensión negativa y el rele volverá a su estado de reposo. (Siento no entrar en más detalles, intento no utilizar palabras técnicas para que todos puedan entenderlo, pero resulta difícil)

El circuito sería el siguiente (no es fácil dibujar con letras):

                                  V+
                                  |
                           +------+
                           |      |
                           _   -------
                        D2 ^  |   /   |  RELE
                           |   -------
                           |      |
                           +------+
                                  |
                                  | c
                                | /
        D1        R1            |/
RTS >--->|-+--/\/\/\/\----------|   T1
                 R2     |       |\
           +--/\/\/\/\--+       | \ e
           |                      |
GND >------+----------------------+-----< GND
 
R1,R2 10K
D1,D2 1N4007
T1 BC517
V+ 6V..12V

En cuanto al software, tenemos esta función que, pasándole como parámetros el puerto y el tiempo de espera en milisegundos, activa RTS y la mantiene activa durante el tiempo de espera para después volver a desactivarla.

function Activar_RTS(Puerto: String; Espera: Cardinal): String;
var
  hPort: THandle;
  DCB: TDCB;
begin
  Result:= '';
  Puerto:= Uppercase(Puerto);
  // Cambiar esto si es necesario un puerto diferente
  if (Puerto<>'COM1') and (Puerto<>'COM2') then
    exit;
  hPort:= CreateFile(PChar('\\.\'+Puerto), GENERIC_READ or GENERIC_WRITE,0, nil,
    OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if hPort<>INVALID_HANDLE_VALUE then
  begin
    DCB.DCBlength:= sizeof(DCB);
    if GetCommState(hPort,DCB) then
    begin
      with DCB do
      begin
        BaudRate := CBR_9600;
        ByteSize := 8;
        Parity   := NOPARITY;
        StopBits := ONESTOPBIT;
        Flags    := $01;
      end;
      if SetCommState(hPort, DCB) then
      begin
        EscapeCommFunction(hPort,SETRTS);
        Sleep(Espera);
        EscapeCommFunction(hPort,CLRRTS);
      end;
    end;
    CloseHandle(hPort);
  end;
end;

Ejemplo de uso:

  Activar_RTS('COM1',5000);

Ahora bien, seria interesante poder activar y desactivar el rele a discrepcion. Para eso, vamos a tener una funcion que lo encienda y otro que lo apague. Pues bien lo primero que tenemos que hacer es declarar la variable hPort como global, y separar la función de arriba en 4:

var
  hPort: Thandle;
 
procedure AbrirPuerto(Puerto: String);
var
  DCB: TDCB;
begin
  Puerto:= Uppercase(Puerto);
  // Cambiar esto si es necesario un puerto diferente
  if (Puerto<>'COM1') and (Puerto<>'COM2') then
    exit;
  hPort:= CreateFile(PChar('\\.\'+Puerto), GENERIC_READ or GENERIC_WRITE,0, nil,
    OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if hPort<>INVALID_HANDLE_VALUE then
  begin
    DCB.DCBlength:= sizeof(DCB);
    if GetCommState(hPort,DCB) then
    begin
      with DCB do
      begin
        BaudRate := CBR_9600;
        ByteSize := 8;
        Parity   := NOPARITY;
        StopBits := ONESTOPBIT;
        Flags    := $01;
      end;
      if SetCommState(hPort, DCB) then
        Exit;
    end;
    CloseHandle(hPort);
    hPort:= INVALID_HANDLE_VALUE;
  end;
end;
 
procedure CerrarPuerto;
begin
  if hPort <> INVALID_HANDLE_VALUE then
  begin
    CloseHandle(hPort);
    hPort:= INVALID_HANDLE_VALUE;
  end;
end;
 
procedure ActivarRTS;
begin
  if hPort <> INVALID_HANDLE_VALUE then
    EscapeCommFunction(hPort,SETRTS);
end;
 
procedure DesactivarRTS;
begin
  if hPort <> INVALID_HANDLE_VALUE then
    EscapeCommFunction(hPort,CLRRTS);
end;

Antes de usar el puerto tienes que llamar la función AbrirPuerto y cuando dejes de usarlo CerrarPuerto. Las funciones ActivarRTS y DesactivarRTS hacen lo que parece activar y desactivar RTS, para que funcionen el puerto tiene que estar abierto.

Comentarios

Amigo disculpa, no podrías decirme como se hace esto mismo en visual basic. Yo se que esta pagina esta dedicada a delphi, pero nunca he programado en este lenguaje.. gracias

Pues hace mucho tiempo que no toco el vb, pero si no recuerdo mal se podía acceder a las APIs sin ningún problema por lo que no hay razón para que no puedas usar las funciones EscapeCommFunction, SetCommState, CreateFile, etc ... Por otro lado si estas usando .NET entonces la cosa cambia ya que no puedes acceder directamente a esas APIS, tendrás que buscar algún componente que maneje el puerto serie, pero como ya te dije, de vb se bastante poco.

disculpa la molestia lo que necesito es enviar toda una trama bajo protocolo RS232, por ejemplo enviar una cadena de caracteres ASCII. Lo que no se es que si es posible hacerlo bajo WinXP, ya que me dijeron que los accesos a puertos están restringidos. De ante mano muchas gracias por todo.

En Windows XP lo que no se puede es acceder directamente a los puertos, como si se podía por ejemplo en windows 95/98 usando instrucciones en ensamblador. Pero si que se puede enviar y recibir datos por el puerto serie sin problemas.

Por ejemplo, en el código de arriba, la función "AbrirPuerto" obtiene un handle (manejador) y lo guarda en la variable hPort, observa también que dentro de esta función se configuran los parámetros de la comunicación (velocidad, paridad, etc ...). Una vez que tenemos ese handle podemos usar las funciones WriteFile y ReadFile para leer y escribir en el puerto como si lo estuviéramos haciendo en un archivo. solo tienes que tener en cuenta, que al leer, si no hay bastantes bytes almacenados en el buffer la función readfile se quedara parada hasta que reciba los bytes que le has pedido, por eso es aconsejable utilizar la función ClearCommError para determinar el numero de bytes que hay almacenados en el buffer.

En resumen busca información sobre, ReadFile, WriteFile y ClearCommError, o si prefieres algo mas sencillo busca algún componente para delphi que realice todo esto por ti, hay algunos muy populares.

Tengo una rutina en VB 6 para leer el puerto serial, pero cuando me mando una cadena de 80 caracteres la lee en dos partes y algunas veces la lee toda y la mayoría de las veces la lee truncada, 20 , 50 o 70 caracteres, podrias orientarme como puedo hacerle para que la lea en una sola vez??.

Saludos y Gracias.

Lamentablemente mis conocimientos de VB 6 son limitados así que no puedo ayudarte demasiado, pero lo que yo haría en tu caso es usar algún carácter para separar las cadenas. Ten en cuenta que leyendo el buffer del puerto serie no sera capaz de distinguir el final de una cadena y el comienzo de otra si no las separas de alguna manera.

Estimado:

Estoy experimentando poder utilizar este circuito y programacion para que al hacer un click en un programa de broadcasting se encienda una luz de ON AIR. es factible? Gracias desde ya!!
Un cordial abrazo.-

Pues no veo porque no, siempre que la luz pueda ser activada por medio de un relé. Consulta en las características del relé que compres para comprobar que se ajustan al voltaje y potencia de la luz que quieres encender.

Buenos Días:

Gracias por compartir tus conocimientos con la humanidad ! : )

Haciendo un llamado a tu amabilidad y abusando de ella quiero hacerte unas preguntas esperando que me las puedas contestar:

Antes que eso, soy programador, no muy bueno pero lo soy, y de electrónica realmente no se mucho pero estoy elaborando un sistema
de control de acceso a una escuela por medio de credenciales con codigo de barras. Se trata entonces de que cuando una credencial pase la prueba de acceso, la computadora mande una señal a una "chapa" eléctrica de una puerta y se abra. Son muy comunes en los consultorios médicos para que la secretaria no se tenga que parar a abrir la puerta o en otros lados.
Normalmente ese tipo de chapas ya vienen listas para conectarles un par de cablecitos que vienen de un transformador o "eliminador" como les llamams en Mexico..de esas cajitas negras que venden para dar la corriente adecuada a dispositivos electrónicos de casa como juguetes, aparatos eléctricos domesticos como lamparas, celulares etc.

Este tipo de chapas funciona de tal manera que cada vez que se aprieta un boton..se envia una corriente electrica y se activa el mecanismo de la chapa y abre..asi de facil. ¿Esté circuito tuyo me sirve para eso?

Otra pregunta.. en el diagrama hasta arriba viene una V+ y supongo que esa se conecta al PIN Numero 7 del puerto y entonces:
Se conecta unicamente 1 solo cable a ese pin?? nomas así?

Que es el RTS y el GND?
El T! es un relay o que es? ¿EN caso de que alguno de los dispositivos tengan 3 patitas..cuales se deben usar?

Que partes de este circuito debo variar por ejemplo si resulta que la "chapa" de la puerta ocupa un voltaje mayor que el que da este circuito?

Es posible que "truene" la computadora si me equivoco y conecto mal algo?

Gracias. Perdón por el abuso de preguntas..pero me gustaría mucho entender esto.

Intentare responder a tus preguntas Ivan.

- Si, este circuito sirve para activar ese tipo de mecanismos.
- V+ Es la tensión de alimentación, es decir, estaría conectado al polo positivo del trasformador.
- Gnd se corresponde al polo negativo del trasformador y del lado del puerto al pin número 5 (en un conector de nueve pines)
- T1 es un transistor, en cuanto a que "patitas" usar consulta las especificaciones del fabricante.
- RTS se corresponde con el pin número 7 del puerto serie (en un conector de 9 pines). Aquí puedes encontrar un esquema de los pines de un puerto serie http://www.beyondlogic.org/serial/serial.htm

Y por ultimo ... si que es posible que tu computadora sufra daños e incluso se queme la placa base si te equivocas, por eso es mejor que busques ayuda de alguien con un poco de experiencia. En cualquier caso son muy importantes los diodos d1 y d2, sobre todo d2 que protegerá tu ordenador de picos de tensión (chispazos) provocados al conectar o desconectar el relé.

Mira a mi me encargaron que hiciera un lector asignador (asi me dijo el profe) de codigos para tarjeta chip (como las de los celulares GSM) pero la verdad es que no he encontrado la forma de hacerlo podrias ayudarme la idea es que haga algo asi mas o menos como lo digo el colega Ivan solo que pues tu codigo me resuelve el abrir la puerta pero necesito que sea con ciertas claves que lo haga ye so la verdad es que no se

Si tienes que abrir una puerta el circuito y el código del que hablo puede ayudarte, pero para leer y escribir la tarjeta chip vas a tener que buscar información en otro sitio. Yo empezaría por consultar la documentación o la web del fabricante del lector para saber si tiene alguna librería que puedas usar.

Hola esta muy buena la ayuda pero hay algo que me tiene loco, trate de hacer uno de estos procedimientos desde una DLL y la verdad no pude o no supe como ponerlo a funcionar, esta es mi función:

function AbrirPuerto: Boolean;stdcall;
var
  DeviceName: array[0..80] of Char;
  ComFile:Thandle;
begin
 
   { primero se abre la comunicacion para lectura y escritura.
     se utiliza la funcion de Win32 "create file".}
  StrPCopy(DeviceName, 'COM1:');
 
  ComFile := CreateFile(DeviceName,    GENERIC_READ or GENERIC_WRITE,      0,    nil,    OPEN_EXISTING,     FILE_ATTRIBUTE_NORMAL,   0);
 
 if ComFile = INVALID_HANDLE_VALUE then
    Result := False
  else
    Result := True;
end;

Pero inmediatamente me sale 6 errores cada uno perteneciente a los parámetros usados por la función "Create File" en las 2 lineas a continuación:

  ComFile := CreateFile(DeviceName,    GENERIC_READ or GENERIC_WRITE,    0,    nil,    OPEN_EXISTING,    FILE_ATTRIBUTE_NORMAL,    0);
 
  if ComFile = INVALID_HANDLE_VALUE then............

La verdad no se que estoy haciendo mal o que me falta colocar dentro de la DLL, sera alguna declaración dentro de "Uses" porque cuando lo hago en un form normal me funciona.

Me gustaría me pudieras ayudar.

Prueba añadiendo Windows a las uses.

Hola , Tengo 0 Conocimientos de electrónica, Como tengo que hacer para conectar una salida del puerto serie a un relé(donde lo compro) y luego para encender o apagar un Aire creo que necesito un Contactor, este puedo conectarlo al relé???

Quiero empezar con lo mas simple que es encender y apagar una luz, que elementos de hardware tengo que comprar y como los tengo que conectar para desde la computadora poder controlar el encendido y apagado de una luz??? Mi objetivo final es el de arriba pero pienso que primero debo poder prender y apagar una lamparita

Muchas Gracias

Hola, es interesante el circuito. Mi preguta es la siguiente, ¿Este ciruito funciona para activar solamente un torniquete de contacto seco? si es asi, ¿Como se conecta a la tarjeta del torniquete? Consulte al fabricante y me comentó que los contactos secos NO pueden recivir ningún tipo de voltaje. El contacto seco es simplemente hacer un puente entre los dos pin y eso activa el torniquete para permitir el acceso, cuando gira la perilla metálica, el mecanismo interno del torniquete pulsa un boto de un interuptor y bloquea nuevamente el torniquete. Disculpa tantas palabras, espero su respuesta. Gracias, y que tengan un buen tiempo todos en este importante foro.

Si he entendido bien quieres activar un dispositivo que normalmente se controla por medio de un interruptor, que puentea dos pines. Si es así sencillamente usa el relé que muestro en el esquema para puentear esos dos pines. Al fin y al cabo un relé no es mas que un interruptor controlado por un circuito eléctrico.

http://es.wikipedia.org/wiki/Relé

Hola muy bueno muchas gracia todavía mucho no entiendo .. pero me va a servir jeje grax

Hola. Hice el programa, pero, como se que esta funcionando sin poner el relé. Como hago para poner mensajes de error en caso que no se active el puerto, hay alguna excepción que devuelva Windows?
Es interesante el programa, pero siento que falta eso. Por favor ayúdenme.

Revisa el valor que devuelven las funciones CreateFile y EscapeCommFunction. La primera devolverá INVALID_HANDLE_VALUE si el puerto esta ocupado por otra aplicación o no esta disponible, y la segunda devolverá cero si no es capaz de activar la patilla RTS. Haciendo los ajustes convenientes en el código para controlar que valores devuelven esas dos funciones, no tendrás ningún problema.

Muy buen articulo, enhorabuena. Espero no haber llegado muy tarde y que el hilo no esté cerrado. He probado el código y me funciona perfectamente. Con un led consigo encender, apagar, destellos a distintas velocidades .. con un pequeño control slide en delphi.

El siguiente paso era poder encender/apagar un bombilla común de una casa. He intentado probar a poner directamente a la salida de los pines del puerto un relé de 6v y no consigo que se mueva. (Como si no tuviese fuerza). Lo de simplificar ... como que quitar el transistor es pasarse n? xD

Voy a pillarme el transistor para probar. El único problema es q .. ¿el circuito debe alimentarse al usarse un transistor n?.
En caso que esto funcione .. a ver si se pudiese hacer algo similar mediante usb.

Gracias.

PD: Soy programador en delphi. Me gustan mucho estos temas relacionados con la "domotica" .. si puedo ayudar en algún proyecto.. estaría encantado. Enhorabuena!!

Es normal que no puedas activar el relé directamente desde el puerto serie, la intensidad que puede suministrar este puerto esta muy limitada, y si bien llega para encender un led o hacer funcionar un ratón de los antiguos, los que iban por puerto serie, no es suficiente para un rele.

Si utilizas el circuito con el transistor, claro que necesitas alimentación externa. Precisamente esa alimentación externa es la que suministrara esa potencia extra que se necesita para activar el relé.

Pero si tu objetivo es encender una luz, o algún otra carga de tipo resistivo, y no quieres usar alimentación externa busca en google información sobre "solid state relay" o también puedes echarle un vistazo a esta pagina donde salen varios ejemplos con optoacopladores, para el puerto paralelo, pero básicamente es lo mismo.

http://www.epanorama.net/circuits/parallel_output.html

Hola, estoy queriendo abrir un portero electrónico con un sistema en delphi.
Esta función me sirve para tal caso?. El portero abre con 12volts.
SLDS y gracias.

Si, si que sirve.

Solo tienes que usar el relé como un interruptor para aplicar los 12 voltios al portero.

Incluso, por ahorrar componentes, se podría sustituir en el esquema el relé por el propio portero automático, siendo así el propio transistor el encargado de activar el portero. Aunque esta opción ya requiere algunos conocimientos de electrónica si no quieres quemar el puerto serie por error.

Ahora, si la pc no tiene puerto serie disponible... se podrá poner un adaptador serie-usb ?. será lo mismo , no quemará nada?
SLDS y mil gracias por tus respuestas!

No veo porque no. No lo he probado, pero si el adaptado Usb-Serie cumple con todos los estándares de la comunicación serie debería de funcionar.

AGRADECIMIENTO

Mis mas sinceros agradecimientos para el admin del tema.
Quisiera saber si el código de este proyecto me podría servir para
lograr controlar un lector de etiquetas RFID y recuperar el numero del identificador
en una variable del programa, no se como leer el valor obtenido por el lector
que tiene conexión RS232.

Gracias de antemano.

El código que describo mas arriba no utiliza el puerto para establecer una comunicación serie, se limita a usar uno de los pines del puerto para activar y desactivar un interruptor.

En el caso que tu propones te recomendaría usar algunos de los múltiples componentes que hay disponibles para delphi y que permiten leer datos a través del puerto serie.

Si quieres profundizar mas en el tema te recomiendo que preguntes en alguno de estos foros:
www.delphiaccess.com
www.clubdelphi.com

Seguro que en cualquiera de los dos te podrán ayudar

Saludos

Hola, estoy por utilizar el circuito, pero no me queda claro la conexión del relevador y la toma de corriente eléctrica. Necesito encender/apagar una luz desde C#. Espero puedas aclarar un poco mas el circuito, tengo un relevador de 5 pines (JQC-3FC T73) azul.

Pues el relé tiene dos patillas que corresponden a la bobina, que son las que aparecen en el circuito. La otras tres pertenecen al interruptor que activa la bobina, y es lo que debes utilizar para manejar la bombilla. Si necesitas mas aclaraciones consulta el manual del relé o pregunta en la tienda donde lo compraste.

Saludos Amigo:

La verdad es un excelente trabajo este diagrama, lo he probado y funciona a la perfeccion. Solo tengo una duda: para hacer el control de dos dispositivos con el mismo puerto, segun alguna vez leí, se tenian que utilizar las lineas de rts y gnd para uno y cts y gnd para el otro, es asi de simple?

es decir, seria el mismo circuito y funciones para cts? o me dieron informacion equivocada :D.

Muchas gracias por esta info, de verdad es muy valiosa

En concreto se usaría RTS y DTR (pin 4). El circuito sería el mismo para los dos dispositivos, cada uno conectado a un pin diferente (pin 4 y pin 7), y GND sería común para ambos.

Para controlar DTR debes usar las constantes CLRDTR y SETDTR al igual que usamos CLRRTS y SETRTS para RTS. Por lo demás el software no necesitaría mas modificación, aunque recuerda que el puerto solo lo debes de abrir una vez aunque lo uses para controlar dos señales diferentes.

Saludos, una gran duda donde puedo comprar ese dispositivo o una guía paso a paso para construirlo, mis conocimientos de electrónica son prácticamente nulos pero creo que eso es exactamente lo que necesito para activar un pistón neumático conectado a un relevador desde mi programa.

Pues no se donde puedes comprar algo similar, ya hecho, pero creo que si vas a una tienda de componentes electrónicos, les explicas lo que quieres hacer y le enseñas el esquema te darán alguna solución. Es importante que les expliques lo que quieres hacer porque puede que dispongan de algún dispositivo comercial que haga la misma función y sea barato.

Muchas gracias al administrador por este aporte... Muy bueno
Tengo una pregunta, yo estoy colocando el código, exactamente igual al primero de arriba y pienso hacerle un llamado con un botón es decir quedaría así:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Activar_RTS(COM1,4000);
end;

La pregunta sería, ¿como se yo cual es el COM que debo utilizar?, puesto que he hecho varias pruebas y midiendo con un voltimetro entre las patas RTS y GND, siempre obtengo casi 7 voltios y a pesar de que pasan 4 segundos, la señal siempre esta presente. ¿Cual podría ser mi error? saludos y muchísimas gracias

El COM que debes utilizar me imagino que sera el 1 o el 2 eso dependerá de tu placa base, normalmente estan numerados. El problema puede ser que no este usando los pines correctos, asegúrate que son el 5 y el 7, la mayoría de los conectores tienen numerados los pines con unos numeritos pequeños al lado de cada pin.

Por otro lado si estas usando un conversor USB/Serie puede que no maneje bien las señales de control, y que por eso no te funcione.

Para hacer pruebas incluso puedes usar un diodo LED conectado conectado directamente entre las patillas 7 y 5. Este se encenderá y apagara al activar o desactivar RTS. Ni siquiera te hace falta poner una resistencia en serie con el diodo, ya que el puerto serie ya se encarga de limitar la corriente que sale de sus patillas.

Saludos

Hola mi estimado muy buena aportación y muy interesante para mi en particular de verdad lo que yo estoy intentando hacer es tener lectura de un termistor (esos que sirven para leer temperatura) sin embargo quiero saber si es posible tener la impresión en pantalla en ohmios (a través de cualquier pin)del puerto serie

El trabajo que nos pidieron realizar es un psicrometro pero yo intento adaptar el psicrometro a una pc a través del puerto serie gracias de antemano.

El puerto serie solo tiene entradas digitales, no analógicas, así que no creo que te sirvan para medir directamente ninguna magnitud analógica (resistencia, voltaje, etc). Si estas decidido a usar el puerto serie deberas utilizar algo que convierta la señal analógica a digital, un microcontrolador por ejemplo.

Por otro lado, el que si puedes usar es el puerto para el joystick que tienen la mayoría de los PC (bien sea integrado en la placa base o a través de la tarjeta de sonido). Este puerto permite la convertir valores analógicos a digitales. Yo buscaría por este camino

Mi proyecto es encender una calefaccion con el pc, es decir solo on/off con un rele o algo parecido. con el esquema electrico no tengo problemas, puesto que puedo acoplarlo a mis necesidades, pero el tema del software seme escapa. ¿Alguien me puede pasar un programa para xp o vista que controle el pin rts? es decir, un click = on permanente, otro click off. gracias
P.D. Se admiten sugerencias pero estoy pez en programacion

Puedes pasarte por aquí http://www.delphiaccess.com/forum/delphi/ , a lo mejor encuentras a alguien que te haga un programita sencillo usando las funciones que puse arriba.

Pero ten en cuenta que el programa tiene que permanecer abierto, pues una vez que se cierra se pierde el control sobre el puerto serie, por lo que sería deseable que un programa de las características que pides, se pudiese ocultar sin tener que cerrarlo.

Muchas gracias!!!!

me vino más que muy bien esto, y apareció en google a la primera

Te felicito, y por siempre agradecido!!!

Y ya que estoy... (mangazo)
Estoy comenzando a usar a Anduino -nivel hobby-, pretendo manejar un par de servos desde la PC, en el microcontrolador tengo un muy pequeñisimo programa que lee el puerto USB (como puerto serie), al recibir una "A" incrementa en un grado un servo, con "S" decrementa en un grado, "K" y "L" para el otro servo, como notarás, nada complejo.

Ahora ya desde Delphi 2010: formulario, cuatro TButton... y aquí es justo donde encontré tu gran aporte, pregunta, ¿que cambio para enviar alguno de los caracteres mencionados?

ah!!!!
demás está que diga que acepto todo tipo de sugerencias para mi microproyecto.

Voy a tener que desempolvar mi Arduino.

Supongamos el siguiente sketch:

void setup() 
{                
  // Usamos el led que esta conectado al pin13
  pinMode(13, OUTPUT); 
  digitalWrite(13, LOW);  
  // Inicamos el puerto serie a 9600
  Serial.begin(9600);  
}
 
void loop() {
 
  char C;
 
  // Si hay datos esperando
  if (Serial.available() > 0)
  {
   C = Serial.read();
   if (C=='A') digitalWrite(13, HIGH); 
   if (C=='B') digitalWrite(13, LOW); 
  } 
}

Es decir tenemos que enviar una 'A' para activar el led y una 'B' para apagarlo. Pues desde delphi podemos hacer un simple programa, parecido al "Serial monitor" pero solo la parte de enviar.

El nucleo del programa seria el siguiente:

var
  DCB: TDCB;
  Str: AnsiString;
begin
  // Si no hay nada que enviar salimos
  if txtTexto.Text = EmptyStr  then
    Exit;
  // Si no hemos abierto ya el puerto lo abrimos
  if Puerto = INVALID_HANDLE_VALUE  then
    with cmbPuerto do
      if ItemIndex >= 0 then
        Puerto:= CreateFile(PChar('\\.\' + Items[ItemIndex]), GENERIC_READ or
          GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
      else
        Exit;
  // Si no conseguimos abrir el puerto salimos
  if Puerto = INVALID_HANDLE_VALUE then
  begin
    Mensaje('Error al abrir el puerto serie');
    Exit;
  end;
  // Si conseguimos abrir el puerto deshabilitamos la configuracion
  Groupbox1.Enabled:= FALSE;
  // Configuramos el puerto
  Str:= Trim(cmbComCfg.Text);
  DCB.DCBlength:= Sizeof(DCB);
  if GetCommState(Puerto,DCB) then
    if BuildCommDCB(PAnsiChar(Str),DCB) then
      if SetCommState(Puerto, DCB) then
      begin
        Str:= txtTexto.Text;
        // Enviamos el texto
        if FileWrite(Puerto,PAnsiChar(Str)^,Length(Str)) < 0 then
          Mensaje('Error al escribir en el puerto serie');
        Exit;
      end;
  Mensaje('Los parámetros de configuración no son correctos');
end;

El resto del programa lo puedes descarga de aquí

Por cierto cuando lo pruebes ten en cuenta que en la placa del Arduino esta conectada la patilla de reset a un pin del puerto serie, de tal manera que al abrir el puerto serie del PC el Arduino se resetea, por lo que en nuestro programa el primer envió siempre activa el reset.

Espero que te sirva de punto de partida

No esperaba una respuesta tan completa y tan rápida.

Muchas gracias por el tiempo que le dedicas a esto.

Te cuento, este finde, experimentando con mi proyectito, hice lo siguiente:

Prog en el Arduino:

const byte Servo1=8, Servo2=9, Min=20, Max=160, Ret=5;
byte AngServo1, AngServo2;
int  APP; //Ancho Pulso Positivo
int  APN; //Ancho Pulso Negativo
char val;
 
void setup(){
  pinMode(Servo1, OUTPUT);
  pinMode(Servo2, OUTPUT);
  Serial.begin(9600);
  Centrar(AngServo1, Servo1);
  Centrar(AngServo2, Servo2);}
 
void PulsoServo(int Pin, int Ang){
  APP = (Ang * 10) + 600;
  APN = (Max * 10) + 600 - APN;
  digitalWrite(Pin, HIGH);
  delayMicroseconds(APP);
  digitalWrite(Pin, LOW);
  delayMicroseconds(APN);}
 
void loop(){
  if(Serial.available() > 0){
    val = Serial.read();
    switch (val){
      case '1': {AngServo1++; break;}
      case '2': {AngServo1--; break;}
      case '3': {AngServo2++; break;}
      case '4': {AngServo2--; break;}
      case '5': {AngServo1++;AngServo2++; break;}
      case '6': {AngServo1++;AngServo2--; break;}
      case '7': {AngServo1--;AngServo2++; break;}
      case '8': {AngServo1--;AngServo2--; break;}
      case '9': {Centrar(AngServo1, Servo1); Centrar(AngServo2, Servo2); break;}
    }
    PulsoServo(Servo1, AngServo1);
    PulsoServo(Servo2, AngServo2);
    Serial.print("Angulo Servo_1: ");
    Serial.print(AngServo1, DEC);
    Serial.print(" - Angulo Servo_2: ");
    Serial.print(AngServo2, DEC);
    Serial.println();
    Serial.flush();
    delay(Ret);}
}
 
void Centrar(byte &A, byte S){
  for(A = 90; A >=Min; A--){PulsoServo(S, A);}    
  delay(Ret);
  for(A =Min; A <=Max; A++){PulsoServo(S, A);}
  delay(Ret);
  for(A =Max; A >= 90; A--){PulsoServo(S, A);}
  delay(Ret);
  A = 90;
  PulsoServo(S, A);}

Y en Delphi:

procedure AbrirPuerto(Puerto: String);
var DCB: TDCB;
 
begin
  Puerto := Uppercase(Puerto);
  hPort  := CreateFile(PChar('\\.\'+Puerto),
                       GENERIC_READ or GENERIC_WRITE,0, nil,
                       OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if hPort <> INVALID_HANDLE_VALUE then begin
    DCB.DCBlength := sizeof(DCB);
    if GetCommState(hPort,DCB) then begin
      with DCB do begin
        BaudRate := CBR_9600;
        ByteSize := 8;
        Parity   := NOPARITY;
        StopBits := ONESTOPBIT;
        Flags    := $01
      end;
      if SetCommState(hPort, DCB) then Exit
    end;
    CloseHandle(hPort);
    hPort:= INVALID_HANDLE_VALUE
  end else Form1.Error
end;
 
procedure CerrarPuerto;
begin
  if hPort <> INVALID_HANDLE_VALUE then begin
    CloseHandle(hPort);
    hPort:= INVALID_HANDLE_VALUE;
  end
end;
 
procedure Escribir(Dato: Char);
var
  NumberWritten: dword;
 
begin
  if hPort <> INVALID_HANDLE_VALUE
    then WriteFile(hPort,Dato,1,NumberWritten,nil)
    else Form1.Error
end;
 
 
Procedure TForm1.Error;
begin
  Label1.Caption := 'Hay un error con el puerto COM3.' + #13#10 +
                    'Probablemente esté ocupado.';
  Button1.Enabled := False;
  Button2.Enabled := False;
  Button3.Enabled := False;
  Button4.Enabled := False;
  ....
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  Escribir('1')
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  Escribir('2')
end;
 
.......
casi lo mismo para todos los demás tbutton´s
.......
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  CerrarPuerto
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  AbrirPuerto('COM3')
end;
 
end.

Y esto es todo, voy a probar YA lo que vos hiciste.

ah!!!!

Y para leer el puerto?? Cómo uso el ReadFile?? (es que la ayuda está en inglés...)

De nuevo, muchas gracias

Aquí http://delphi.jmrds.com/node/60 publique un pequeño programa que simula ser una balanza. Si revisas el código veras como puedes usar la función ReadFile para leer datos del puerto serie, y lo que es mas importante como usar la función ClearCommError para saber si hay datos esperando para ser leídos y de esta forma evitar que la función ReadFile se quede esperando indefinidamente mientras le llega información.

Ojo!!!: Ten en cuenta que yo utilizo una version mas antigua que la tuya de delphi En mi versión (Turbo Delphi) los Strings no son Unicode como en tu versión, por eso si utilizas los códigos que publico puedes tener problemas con los tipos String y PChar. Si ocurre eso intenta declarar las variables String y PChar como AnsiString y PAnsiChar, en la mayoría de los casos eso solucionara el problema.

Muchísimas gracias por tu ayuda, ya descargué el simulador de balanza y a estudiar!!

Amigo estoy armando el circuito pero no consigo el BC517 y coloque fue un reemplazo BC617, pero no activa el rele, alguna sugerencia

Por lo que puedo ver en la hoja de características de ese transistor, el orden de las patillas esta invertido con respecto al BC517 ¿has tenido eso en cuenta?

Por lo demás el circuito es todo un clásico y no debería dar problemas. Así que si no te funciona asegúrate que los diodos estén orientados de forma correcta y que el relé tiene la alimentación adecuada.

No se que hago mal, pero no funciona, la bateria para el rele es 9v y el voltaje del puerto no se si excita al transistor porque no hace nada. Podrias por favor ayudarme

Donde se conecta el - de la pila 9v.

Pues el positivo donde pone V+ y el negativo a masa (GND)