You are on page 1of 14

ndice general

2. Programacin RS-232 en C

2.1. Objetivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2. Librera Serie utilizada. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.1. Funcin OpenSerialPort. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.2. Funcin SerialSendByte. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.3. Funcin SerialReceiveByte. . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.4. Funcin CloseSerialPort.

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3. Ejemplos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.1. Envo y recepcin de un byte y un float. . . . . . . . . . . . . . . . . . . .

2.3.2. Envo y recepcin de vectores y struct. . . . . . . . . . . . . . . . . . . . .

2
Programacin RS-232 en C
2.1.

Objetivos.

El sistema operativo Windows tiene la librera para la programacin del puerto serie RS232. Para utilizar dicha librera hay que incluir en los programas en C el fichero de cabecera
windows.h mediante la directiva de preprocesamiento #include. La librera que se va a
utilizar en prcticas es la librera serie (serie.h). Est basada en las funciones originales de
windows.h. Al final de la prctica el alumno debe ser capaz de:

1. Programar en C la comunicacin RS-232 utilizando la librera de serie.h.


2. Enviar informacin entre aplicaciones C de diferente tipo: byte, float, vectores y estructuras.

2.2.

Librera Serie utilizada.

Como se ha dicho anteriormente, se va a utilizar una librera serie en concreto (serie.h).


Esta librera permite realizar transferencias byte a byte o de ficheros, opcin esta ltima que
no se estudiar. Tambin, en las funciones originales de windows.h, se pueden hacer otro
tipo de transferencias que no se estudiarn. Las 4 funciones a utilizar son las siguientes:
1. Abrir un puerto serie: Captura el puerto para realizar el intercambio de informacin a
travs de l. Slo lo puede tener una aplicacin simultneamente.
2. Transferir un byte por un puerto: Enva un byte por el puerto.
3. Obtener un byte por un puerto: Recibe un byte por un puerto.

2.2. Librera Serie utilizada.

|3|

4. Cerrar un puerto serie: Liberar un puerto. Es muy importante terminar los programas
implementados correctamente, ya que es necesario liberar el puerto para que otra
aplicacin lo capture de nuevo.
A continuacin se detallar el funcionamiento de las funciones.

2.2.1.

Funcin OpenSerialPort.

La funcin para abrir un puerto es OpenSerialPort y tiene la siguiente estructura:


// Abre el puerto serie
HANDLE OpenSerialPort(
char *psPort,
// "COM1","COM2"
DWORD bBaudRate,
// CBR_9600, CBR_19200. CBR_56000
BYTE bByteSize,
// 7,8
BYTE bParity,
// NOPARITY, EVENPARITY, ODDPARITY
BYTE bStopBits,
// ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS
DWORD ReadTimeout
// Programmable Read Timeout
);
Los parmetros son:
psPort: Indica que puerto es el que se desea abrir. Es una cadena del tipo COM1, COM2,
. . ., COM9. Valores con ms de un dgito en la identificacin han dado problemas en
las pruebas de la librera serie.
bBaudRate: Tasa de transferencia de baudios. Las etiquetas a usar sern: CBR_9600,
CBR_19200, CBR_56000, etc. En las prcticas siempre se usar 9600 baudios.
bByteSize: Nmero de bits transmitidos. Las posibilidades son 7 u 8 (en realidad entre 5 y
8, este caso no lo he probado). En las prcticas se utilizarn 8 bits, es decir, un byte.
bParity: Paridad utilizada para la deteccin de errores. Las posibles etiquetas son NOPARITY, EVENPARITY y ODDPARITY. En las prcticas no se utilizar comprobacin de
paridad, etiqueta NOPARITY.
bStopBits: Nmero de bits de stop. Los posibles valores son ONESTOPBIT, ONE5STOPBITS
y TWOSTOPBITS. En las prcticas se utilizar un bit de stop (ONESTOPBIT ).
ReadTimeout: La librera permite definir un timeout que indica el tiempo que se esperar
para que se lea/escriba un valor. En nuestro caso no se definir timeout, se pasar un
valor FALSE.
Como puede verse, esta funcin devuelve un valor de tipo HANDLE. Este tipo puede ser
definido como un manejador, y es el identificador del puerto que se usa dentro del programa C. En el resto de las funciones, las operaciones sobre el puerto se definen utilizando
dicho manejador (a partir de ahora ser denominado HANDLE).
Un ejemplo de invocacin de esta funcin sobre el puerto COM8 es:

2.2. Librera Serie utilizada.

|4|

HANDLE hPort; // HANDLE para manejar el puerto


BOOL timeout = FALSE; // No se usa el timeout
// hPort es asignado al HANDLE devuelto por OpenSerialPort
hPort = OpenSerialPort("COM8",CBR_9600,8,NOPARITY,ONESTOPBIT,timeout);

2.2.2.

Funcin SerialSendByte.

La funcin para enviar un byte por un puerto es SerialSendByte y tiene la siguiente


estructura:
// Transferencia de un BYTE, el del parametro byte
BOOL SerialSendByte(HANDLE hPort, BYTE byte);
// Devuelve TRUE si todo correcto
Los parmetros son:
hPort: Es el HANDLE sobre el que se transmite, previamente hay que haberlo inicializado
con la funcin OpenSerialPort.
byte: Es el byte a transferir.
Esta funcin devuelve un valor del tipo BOOL, TRUE si todo ha ido correctamente y
FALSE en caso contrario.
Este ejemplo muestra cmo enviar un BYTE (el valor 2 como carcter, su cdigo ASCII)
por un puerto:
HANDLE hPort;
BOOL bRes;
BYTE opc;
// Primero se debe colocar la apertura de puerto y otras acciones previas
opc = 2;
// envio de variable opc
bRes = SerialSendByte(hPort,opc);
El siguiente ejemplo muestra cmo enviar un valor float, BYTE a BYTE, utilizando la
funcin SerialSendByte:
HANDLE hPort;
BOOL bRes;
BYTE *v;
float f;
int i;
// Primero se debe colocar la apertura de puerto y otras acciones previas
v = (BYTE *) &f;
f = 23.45;
for(i=0; i<(int)sizeof(float); i++) {
bRes = SerialSendByte(hPort,v[i]);
}

2.2. Librera Serie utilizada.

|5|

La idea consiste en que, dado que un float tiene sizeof(float) bytes (usualmente 4 bytes),
se utiliza un puntero de tipo BYTE que permite enviar byte a byte los bits del float. Entonces,
en el ejemplo, para enviar un float se utiliza el puntero v (de tipo BYTE) que apunta al float,
y posteriormente se enva el float como 4 (sizeof(float)) envos de 1 byte utilizando el puntero
v (ver bucle en el ejemplo).

2.2.3.

Funcin SerialReceiveByte.

La funcin para recibir un byte por un puerto es OpenSerialPort y tiene la siguiente


estructura:
// Recibe un byte en pbyte
BOOL SerialReceiveByte(HANDLE hPort, BYTE *pbyte, BOOL *pTimeout);
// Si recibe OK devuelve TRUE & pTimeout a TRUE
// Si error al recibir devuelve FALSE
Los parmetros son:
hPort: Es el HANDLE del puerto por el que se recibe el byte, previamente hay que haberlo
inicializado con la funcin OpenSerialPort.
pbyte: Es un puntero a donde se desea que se copie el byte recibido (paso por referencia).
pTimeout: Se utiliza para que la funcin devuelva si ha ocurrido un timeout.
Esta funcin devuelve un valor del tipo BOOL, TRUE si todo ha ido correctamente y
FALSE en caso contrario.
El siguiente ejemplo muestra cmo recibir un byte por un puerto:
BOOL timeout = FALSE, bRes;
HANDLE hPort;
BYTE byte;
// Primero se debe colocar la apertura de puerto y otras acciones previas
// se recibe el byte en la variable byte por referencia
bRes = SerialReceiveByte(hPort,&byte,&timeout);
printf("Valor recibido = %d\n", byte);
El siguiente ejemplo muestra cmo recibir un valor float utilizando la funcin SerialReceiveByte que solamente recibe un byte.
HANDLE hPort;
BOOL timeout = FALSE, bRes;
BYTE *v;
float f;
int i;
// Primero se debe colocar la apertura de puerto y otras acciones previas
v = (BYTE *) &f; // El puntero v apunta al float f
// Realiza el bucle tantas veces como bytes tiene un float

2.3. Ejemplos.

|6|

for(i=0; i<(int)sizeof(float); i++) {


bRes = SerialReceiveByte(hPort,&v[i],&timeout);
}
// La informacion se recibe byte a byte en la memoria del float
printf("Valor recibido = %.f\n", f);
La idea es la misma que en el caso anterior pero a la inversa, un puntero de tipo BYTE
que permite recibir byte a byte los bits del float. Para recibir un float se utiliza el puntero v
(de tipo BYTE) que apunta al float, y posteriormente se recibe el float como 4 (sizeof(float))
recepciones de 1 byte utilizando el puntero v (ver bucle en el ejemplo).

2.2.4.

Funcin CloseSerialPort.

La funcin para cerrar un puerto es CloseSerialPort y tiene la siguiente estructura:


/// Cerrar el puerto serie
BOOL CloseSerialPort(HANDLE hPort);
El nico parmetro que tiene es hPort, que es el HANDLE que se quiere cerrar y que
previamente se ha inicializado con la funcin OpenSerialPort. Esta funcin tambin devuelve
un valor del tipo BOOL, TRUE si todo ha ido correcto y FALSE en caso contrario.
HANDLE hPort;
hPort = OpenSerialPort("COM8",CBR_9600,8,NOPARITY,ONESTOPBIT,timeout);
// Codigo que trabaja sobre el puerto
CloseSerialPort(hPort); // Cerrar el puerto cuando se haya terminado
La orden CloseSerialPort debe ejecutarse obligatoriamente en todo programa para liberar
el puerto, ya que slo una aplicacin puede disponer de l simultneamente. El programa
debe estar correctamente implementado para que en todos los casos se ejecute la orden
para cerrar el puerto.

2.3.

Ejemplos.

Todos los ejemplos mostrados utilizan un esquema basado en la arquitectura Cliente/Servidor. Constan de un programa que es el cliente (cliente.cpp) y otro programa servidor
(servidor.cpp). El programa cliente enviar una peticin al cliente, y ste la realizar y devolver un resultado al cliente si se le debe devolver algo.

2.3.1.

Envo y recepcin de un byte y un float.

En este ejemplo el programa servidor se encarga de la gestin de una variable de tipo


float que se va incrementando o decrementando en 0,1 unidades segn reciba por el puerto
RS-232 el valor 1 o 2 (en un byte) respectivamente. A continuacin se muestra el cdigo
fuente, en cada uno de los programas hay que aadir la librera serie comentada en la
Seccin 2.2.

2.3. Ejemplos.

Programa Cliente
#include "serie.h"
#include "windows.h"
#include "stdio.h"
int main(){
HANDLE hPort;
BOOL bRes, timeout=FALSE;
BYTE opc, *v;
int i;
float f;
// Se leera una zona como un grupo de 4 (sizeof(float)) bytes
// o como float, segun interese
v = (BYTE *) &f;
hPort=OpenSerialPort("COM8",CBR_9600,8,NOPARITY,ONESTOPBIT,0);
if (hPort==INVALID_HANDLE_VALUE) {
printf("Error abriendo puerto COM8");
return 1;
}
while(opc!=0){
printf("0) Salir\n");
printf("1) Incrementar real\n");
printf("2) Decrementar real\n");
scanf("%c", &opc);getchar();
if (opc==0) {
// envio de peticion de servicio
bRes = SerialSendByte(hPort,opc);
} else {
if ((opc==1) || (opc==2)) {
// envio de peticion de servicio
bRes = SerialSendByte(hPort,opc);
// lectura de resultado
// Realiza el bucle tantas veces como bytes tiene un float
for(i=0; i<(int)sizeof(float); i++) {
bRes = SerialReceiveByte(hPort,&v[i],&timeout);
}
printf("Valor variable float = %f\n", f);
// error en recepcion
if (!bRes) {
printf("Error leyendo de puerto com3");
CloseSerialPort(hPort);
return 1;
}
}
} // fin del else
} // fin del while
CloseSerialPort(hPort);// MUY IMPORTANTE: cerrar el puerto
return 0;
}

|7|

2.3. Ejemplos.

Programa Servidor
#include "serie.h"
#include "windows.h"
#include "stdio.h"
int main(){
HANDLE hPort, timeout = FALSE;
BOOL bRes;
BYTE byte = a, *v;
int i;
float valor;
// Se leera una zona como un grupo de 4 (sizeof(float)) bytes
// o como float, segun interese
v = (BYTE *) &valor;
hPort=OpenSerialPort("COM9",CBR_9600,8,NOPARITY,ONESTOPBIT,0);
if (hPort==INVALID_HANDLE_VALUE) {
printf("Error abriendo puerto COM9");
return 1;
}
valor = 0;
printf("SERVIDOR DE MANEJO DE FLOAT\n");
while (byte!=0) {
// lectura de servicio
bRes = SerialReceiveByte(hPort,&byte,&timeout);
if ((byte==1) || (byte==2)) {
printf("Peticion de servicio %c. ", byte);
// realizacion de accion
switch(byte) {
case 1:
valor = valor + 0.1;
break;
case 2:
valor = valor - 0.1;
break;
}
printf("Valor variable float = %f\n", valor);
for(i=0; i<(int)sizeof(float); i++) {
bRes=SerialSendByte(hPort,v[i]);
}
if (!bRes) {
printf("Error escribiendo en puerto COM1");
// MUY IMPORTANTE: cerrar el puerto
CloseSerialPort(hPort);
return 1;
}
} // fin del if ((byte==1)...
} // fin del while
CloseSerialPort(hPort);// MUY IMPORTANTE: cerrar el puerto
}

|8|

2.3. Ejemplos.

2.3.2.

|9|

Envo y recepcin de vectores y struct.

En este ejemplo se mostrar el envo y recepcin de vectores y estructuras. El servidor


atiende peticiones para manejar la siguiente estructura mediante un mdulo software:
struct operadores {
int a;
int b;
float result;
};
Los atributos a y b son dos enteros que podrn ser asignados mediante sendas peticiones.
El atributo result tomar el valor segn la peticin recibida: mximo de a o b, mnimo de a o
b, o media de a o b. Las posibles actuaciones sobre la estructura son:
1. Asignar atributo a.
2. Asignar atributo b.
3. Asignar atributo result con el mnimo de a o b.
4. Asignar atributo result con el mximo de a o b.
5. Asignar atributo result con la media de a o b.
6. Devolver al cliente el valor del campo result.
7. Devolver al cliente la estructura completa.

Figura 2.1: Mensajera del ejemplo.


La Figura 2.1 muestra cmo funciona la mensajera entre cliente y servidor. Para la
comunicacin de las peticiones del cliente al servidor se utiliza un vector de enteros de
tamao 2, donde cada componente toma los siguientes valores:
v[0]: Un valor comprendido entre 1 y 7 que representa la peticin.
v[1]: Valor del parmetro de la peticin si es necesario. Este parmetro slo se utiliza
en las peticiones 1 y 2 para indicar el valor a asignar en a o b respectivamente.

2.3. Ejemplos.

|10|

Respecto a las respuestas del servidor en base a la peticin pedida el servidor slo debe
responder a 2 de las 7 peticiones. En la peticin 6 devuelve un float al cliente que es el valor
del atributo result de la estructura, mientras que en la peticin 7 devuelve la estructura
completa.
Programa Cliente
#include "serie.h"
#include "windows.h"
#include "stdio.h"
struct operadores {
int a;
int b;
float result;
};
int main(){
HANDLE hPort;
BOOL bRes, timeout=FALSE;
int i, vector[2]; // servicio en posicion 0 y parametro en posicion 1
BYTE *v, *r;
float f;
struct operadores estruc;
v = (BYTE *) vector; // v lee y escribe el vector de byte en byte
hPort=OpenSerialPort("COM8",CBR_9600,8,NOPARITY,ONESTOPBIT,5000);
if (hPort==INVALID_HANDLE_VALUE) {
printf("Error abriendo puerto COM8");
return 1;
}
vector[0] = -1; // distinto de 0
printf("CLIENTE\n");
while(vector[0]!=0){
printf("\n0) Salir\n")
printf("1) Asignar A\n");
printf("2) Asignar B\n");
printf("3) Minimo\n");
printf("4) Maximo\n");
printf("5) Media\n");
printf("6) Recibir float resultado\n");
printf("7) Recibir struct completo\n");
vector[1] = -1; // no parametro
// Leer peticion en v[0]
scanf("%d", &vector[0]);getchar();
if ((vector[0]>=0) && (vector[0]<=7)) {
if ( (vector[0]==1) || (vector[0]==2) ) {
printf("Dame el parametro\n");
scanf("%d",&(vector[1]));getchar();
}
printf("Valor peticion = %d, %d\n", vector[0], vector[1]);
// envio de peticion de servicio

2.3. Ejemplos.

|11|

for(i=0; i<(int)sizeof(int)*2; i++) {


bRes = SerialSendByte(hPort,v[i]);
}
// lectura de resultado, si procede
if (vector[0]==6) {
r = (BYTE *) &f;
for(i=0; i<(int)sizeof(float); i++) {
bRes = SerialReceiveByte(hPort,&(r[i]),&timeout);
}
printf("El resultado es %.2f\n", f);
}
if (vector[0]==7) {
r = (BYTE *) &estruc;
for(i=0; i<(int)sizeof(struct operadores); i++) {
bRes = SerialReceiveByte(hPort,&(r[i]),&timeout);
}
printf("variable = (%d, %d, %.2f)\n\n", estruc.a, estruc.b, estruc.result);
}
// error en recepcion
if (!bRes) {
printf("Error leyendo de puerto COM3");
// MUY IMPORTANTE: cerrar el puerto
CloseSerialPort(hPort);
return 1;
}
} // Fin del if ((vector[0]>=0 ...
} // Fin del while
// MUY IMPORTANTE: cerrar el puerto
CloseSerialPort(hPort);
return 0;
}
Programa Servidor
#include
#include
#include
#include

"serie.h"
"windows.h"
"stdio.h"
"estruct.h"

int main(){
HANDLE hPort;
BOOL bRes, timeout = FALSE;
int i, vector[2];
BYTE *v, *r;
float f;
struct operadores estruc;
v = (BYTE *) vector; // v lee y escribe el vector de byte en byte
hPort=OpenSerialPort("COM9",CBR_9600,8,NOPARITY,ONESTOPBIT,timeout);
if (hPort==INVALID_HANDLE_VALUE) {

2.3. Ejemplos.

printf("Error abriendo puerto COM9");


return 1;
}
vector[0] = -1; // distinto de 0 para entrar en while
printf("SERVIDOR\n\n");
while (vector[0]!=0) {
// lectura de servicio
for(i=0; i<(int)sizeof(int)*2; i++) {
bRes = SerialReceiveByte(hPort,&(v[i]),&timeout);
}
if ((vector[0]>=0) && (vector[0]<=7)) {
printf("Valor peticion = %d, %d\n", vector[0], vector[1]);
// realizacion de accion
switch(vector[0]) {
case 1:
asignarA(vector[1]);
break;
case 2:
asignarB(vector[1]);
break;
case 3:
minimo();
break;
case 4:
maximo();
break;
case 5:
media();
break;
case 6:
f = LeerResult();
r = (BYTE *) &f;
for(i=0; i<(int)sizeof(float); i++) {
bRes = SerialSendByte(hPort,r[i]);
}
break;
case 7:
CopiaStruct(&estruc);
r = (BYTE *) &estruc;
for(i=0; i<(int)sizeof(struct operadores); i++) {
bRes = SerialSendByte(hPort,r[i]);
}
break;
} // fin del switch
MostrarStruct();
if (!bRes) {
printf("Error escribiendo en puerto COM9\n");
// MUY IMPORTANTE: cerrar el puerto
CloseSerialPort(hPort);

|12|

2.3. Ejemplos.

return 1;
}
} // fin del if ((vector[0]>=0) ...
} // fin del while
// MUY IMPORTANTE: cerrar el puerto
CloseSerialPort(hPort);
}

|13|

You might also like