Código Fuente COMSerial

Anuncio
Programación de los puertos Seriales sobre WIN32
Preparado por: J. Huircan
Departamento de Ingeniería Eléctrica
Universidad de La Frontera
Abril 2012
Introducción
La programación sobre Win32 es más complicada de que MSDOS, debido a que el manejo de puertos no es
directo Bayer (2008) plantea un ejemplo de uso de las funciones, éstas fueron modificadas de tal forma de
implementar un terminal básico sobre Windows, sin embargo, la visualización sigue siendo sobre la ventana de
comandos de Windows .
Implementación sobre Windows
El siguiente código une las funciones propuestas por Bayer, e incorpora algunos elementos de visualización
para el control y uso de los datos. Este código puede ser compilado sobre DevC++.
/*------------------------------------------------------------------------------Terminal básico implementado por jhuircan- 2011-2012 basado en Bayer (2008)
Solo envia
---------------------------------------------------------------------------------*/
#include "windows.h"
#include "commctrl.h"
#include "stdio.h"
#include "conio.h"
#include "string.h"
HANDLE hSerial;
DCB dcbSerial;
DCB dcbSerialParams;
int init_com()
{
char *p="COM1";
int status=0;
hSerial = CreateFile(p,GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if(hSerial==INVALID_HANDLE_VALUE)
{
if(GetLastError()==ERROR_FILE_NOT_FOUND)
{
printf("PUERTO %s NO EXISTE !! \n", p);
status=-1;
}
}
else {
dcbSerial.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams))
{
printf("Error get Status!!\n");
status=-2;
}
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
status=0;
}
return(status);
}
Código Fuente para Windows
Protocolos de Comunicación 2012
// Seria una funcion de acuerdo a articulo de [1]
char *rec_comChar()
{
DWORD dwBytesRead=1 ;
char szBuff[2] = {0,0}; // debe almacenar los datos
char n=1;
// Cantidad de datos rx
char *pBuff=NULL;
// Puntero a un buf para devolver
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL))
{
// Error occurred. Report to user
pBuff=NULL;
printf("%d ",GetLastError());
}
return (pBuff);
}
int env_com(char *data)
{
DWORD dwBytesWrite = 0;
char szBuff[1024], n=1;
strcpy(&szBuff[0],data);
n=strlen(&szBuff[0]);
szBuff[1]=0x00;
WriteFile(hSerial, szBuff, n, &dwBytesWrite, NULL);
return 0;
}
int main(void)
{
char c, *pbuff,buff[20];
printf("-- TTY - BASICO 1.0-jhuircan 2011--\n");
printf("-- Inicializando Puerto --\n");
if(!init_com())
{
printf("-- Puerto Configurado --\n");
printf("-- Puerto Abierto --\n");
while(1)
{
// pbuff=rec_comChar(); // Lectura deshabilidada – para rx
if(kbhit())
{
c=getch();
putchar(c);
if(c==0x1b) break;
env_com(&c);
c=0;
}
}
CloseHandle(hSerial);
printf("Puerto Cerrado\n");
printf("Presione Cualquier Tecla\n");
}
getch();
return 0;
}
El código está hecho para enviar datos por el puerto. Para recibir se debe deshabilitar el comentario indicado.
Sin embargo, el programa quedara trabado para enviar debido a que la función de recepción queda en espera.
De acuerdo a lo indicado por Bayer, debiera utilizarse un mecanismo para realizar un timeout.
Código Fuente para Windows
Protocolos de Comunicación 2012
Segunda versión de código
Este código fue desarrollado por J. Rodríguez, se divide en 4 archivos básicos, el primero es el serie.cpp, el
cual contiene las funciones básicas, serie.h el archivo de cabecera respectivo y dos códigos básicos uno
pare enviar (enviar.cpp) y el otro para recibir (recibir.cpp). El código permite enviar un carácter pulsado,
pero usa la consola de Windows. El código fue realizado para ser compilado por MinGW Developer Studio,
Studio en
modo proyecto.
/*------------------------------------------------------------------*/
/* UPCO ICAI - Departamento de Electrónica y Automática
*/
/*------------------------------------------------------------------*/
/* serie.cpp: Manejo comunicaciones serie
*/
/*
*/
/* Autor: José Antonio Rodríguez Mondéjar
*/
/* Fecha: 12/11/04
*/
/* Versión: 1.0
*/
/*------------------------------------------------------------------*/
#include "serie.h"
HANDLE OpenSerialPort(
char *psPort,
DWORD dwBaudRate,
BYTE bByteSize,
BYTE bParity,
BYTE bStopBits,
DWORD Timeout
//
//
//
//
//
//
"COM1","COM2"
CBR_9600, CBR_19200. CBR_56000
7,8
NOPARITY, EVENPARITY, ODDPARITY
ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS
Timeout
)
{
HANDLE hPort;
DCB dcbPort;
COMMTIMEOUTS commTimeouts;
DWORD dwError;
// Open Serial Port
hPort=CreateFile(
psPort,
GENERIC_READ |
0,
NULL,
OPEN_EXISTING,
0,
NULL);
//
//
//
//
port handler
Port configuration
Port Timeouts
Error code
// pointer to name of the file
GENERIC_WRITE,
// access (read-write) mode
// share mode: 0 the object cannot be share
// pointer to security attributes: NULL the handle cannot be inherited
// how to create: Comx exist
// file/port attributes
// handle to file/port with attributes to copy
// If the function fails, the return value is INVALID_HANDLE_VALUE
if ( hPort == INVALID_HANDLE_VALUE ) {
dwError = GetLastError ();
return hPort;
}
// Flush error code
// Set Port Configuration
FillMemory(&dcbPort, sizeof(dcbPort), 0); // Delete DCB configuration
dcbPort.DCBlength = sizeof(dcbPort);
// Current DCB in use for the communications port
GetCommState (hPort, &dcbPort);
// Update DCB with new parameters
dcbPort.BaudRate = dwBaudRate;
dcbPort.ByteSize = bByteSize;
dcbPort.Parity = bParity;
dcbPort.StopBits = bStopBits;
// Fixed parameters (Disable XON-XOFF and modem handshake)
dcbPort.fBinary = TRUE;
// Binary mode; no EOF check
dcbPort.fParity = TRUE;
// Enable parity checking
dcbPort.fOutxCtsFlow = FALSE;
// No CTS output flow control
dcbPort.fOutxDsrFlow = FALSE;
// No DSR output flow control
dcbPort.fDtrControl = DTR_CONTROL_ENABLE;
// DTR flow control type
Código Fuente para Windows
Protocolos de Comunicación 2012
//
//
//
//
//
//
//
//
//
//
dcbPort.fDsrSensitivity = FALSE;
dcbPort.fTXContinueOnXoff = TRUE;
dcbPort.fOutX = FALSE;
dcbPort.fInX = FALSE;
dcbPort.fErrorChar = FALSE;
dcbPort.fNull = FALSE;
dcbPort.fRtsControl = RTS_CONTROL_ENABLE;
dcbPort.fAbortOnError = FALSE;
Raises the DTR line when the device is opened
DSR sensitivity
XOFF continues Tx
No XON/XOFF out flow control
No XON/XOFF in flow control
Disable error replacement
Disable null stripping
RTS flow control Raises the RTS line when the
device is opened
Do not abort reads/writes on error
// Set new configuration
if (!SetCommState (hPort, &dcbPort)) {
dwError = GetLastError ();
CloseSerialPort(hPort);
hPort = INVALID_HANDLE_VALUE;
return hPort;
}
// Flush error code
// Set Port Timeouts
// Timeouts preparation MORE INFORMATION IN WIN32 API: COMMTIMEOUTS
commTimeouts.ReadIntervalTimeout = 0; // Specifies the maximum time, in milliseconds, allowed to elapse
// between the arrival of two characters on the communications line
// A value of zero indicates that interval time-outs are not used.
commTimeouts.ReadTotalTimeoutMultiplier = 50;
// Specifies the multiplier, in milliseconds, used to
// calculate the total time-out period for read operations
// For each read operation, this value is multiplied by the requested number of bytes to be read.
commTimeouts.ReadTotalTimeoutConstant =Timeout; // Specifies the constant, in milliseconds, used to
// calculate the total time-out period for read operations
commTimeouts.WriteTotalTimeoutMultiplier = 10; // Specifies the multiplier, in milliseconds, used to
// calculate the total time-out period for write operation
// For each write operation, this value is multiplied by the number of bytes to be written.
commTimeouts.WriteTotalTimeoutConstant = 1000; // Specifies the constant, in milliseconds, used to
// calculate the total time-out period for write operations
// See de win32 api for more information
Set Timeouts
if (!SetCommTimeouts (hPort, &commTimeouts)) {
dwError = GetLastError ();
CloseSerialPort(hPort);
hPort = INVALID_HANDLE_VALUE;
return hPort;
}
return hPort;
// Flush error code
}
BOOL SerialSendByte(HANDLE hPort, BYTE byte)
{
BOOL bRes;
DWORD dwError, dwNumBytesWritten=0;
bRes=WriteFile(
hPort,
&byte,
1,
&dwNumBytesWritten,
NULL
);
if ((!bRes)||(dwNumBytesWritten!=1)){
dwError = GetLastError ();
}
return bRes;
//
//
//
//
//
handle to file or serial port to write to
pointer to data to write to file
number of bytes to write
pointer to number of bytes written
NULL
// Flush error code
}
Código Fuente para Windows
Protocolos de Comunicación 2012
BOOL SerialReceiveByte(HANDLE hPort, BYTE *pbyte, BOOL *pTimeout)
{
BOOL bRes;
DWORD dwError, lpNumberOfBytesRead=0;
*pTimeout=FALSE;
bRes=ReadFile(
hPort,
// handle of file or serial port to read
pbyte,
// address of buffer that receives data
1,
// number of bytes to read
&lpNumberOfBytesRead,
// address of number of bytes read
NULL
// NULL
);
if (!bRes) {
dwError = GetLastError ();
}
if ((bRes)&&(lpNumberOfBytesRead==0)){
*pTimeout = TRUE;
}
return bRes;
// Flush error code
}
BOOL CloseSerialPort(HANDLE hPort){
BOOL bRes;
DWORD dwError;
bRes=CloseHandle(hPort);
if (!bRes) {
dwError = GetLastError ();
}
return bRes;
// Flush error code
}
Se lista el código fuente para enviar correspondiente a un archivo enviar.cpp. Este programa llama a la
función OpenSerialPort y configura de una vez el puerto. A través de getchar lee el teclado y envía el
código de la tecla usando la función SerialSendByte.
#include "serie.h"
#include "windows.h"
#include "stdio.h"
int main(){
HANDLE hPort;
BOOL bRes;
char c;
hPort=OpenSerialPort("COM1",CBR_9600,8,NOPARITY,TWOSTOPBITS,5000);
if (hPort==INVALID_HANDLE_VALUE) {
printf("Error abriendo puerto com1");
return 1;
}
while (1) {
c=getchar();
bRes=SerialSendByte(hPort,c);
if (!bRes) {
printf("Error escribiendo en puerto com1");
return 1;
}
if (c=='x') {
break;
}
}
CloseSerialPort(hPort);
}
Código Fuente para Windows
Protocolos de Comunicación 2012
Se lista el código para recibir, en este caso se inicializa el puerto serie, a través de un loop se ejecuta la función
SerialReceiveByte, la cual espera el dato un tiempo y luego sale.
#include "serie.h"
#include "windows.h"
#include "stdio.h"
int main(){
HANDLE hPort;
BOOL bRes;
BYTE byte;
BOOL timeout;
hPort=OpenSerialPort("COM4",CBR_9600,8,NOPARITY,TWOSTOPBITS,5000);
if (hPort==INVALID_HANDLE_VALUE) {
printf("Error abriendo puerto com4");
return 1;
}
while(1){
bRes=SerialReceiveByte(hPort,&byte,&timeout);
if (!bRes) {
break;
}
if (timeout){
printf("\n--->timeout\n");
} else {
putchar(byte);
}
}
if (!bRes) {
printf("Error leyendo de puerto com4");
return 1;
}
CloseSerialPort(hPort);
return 0;
}
Similitudes y diferencias en los códigos Listados
Ambos códigos listados usan las mismas funciones (solo hay cambio de nombre). En el caso de la segunda
aplicación, se encapsula el manejo de las funciones del puerto en el archivo serie.cpp. Se incorporan
funciones para el manejo del timeout. Bayer (2008) hace referencia a este aspecto pero no lo revisa
extensamente. Esto es importante ya que permite no dejar la función de lectura en permanente ejecución.
El código realizado por jhuircan puede ser modificado incorporando el timeout, esto ser realiza agregando el
siguiente código en la función de inicialización init_com().
commTimeouts.ReadIntervalTimeout = 1;
commTimeouts.ReadTotalTimeoutMultiplier = 10;
commTimeouts.ReadTotalTimeoutConstant = 100;
commTimeouts.WriteTotalTimeoutMultiplier = 10;
commTimeouts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts (hSerial, &commTimeouts);
Referencias
[1] Robertson Bayer, Windows Serial Port Programming, March 30, 2008
[2] Allen Denver, Serial Communications in Win32, Microsoft Windows Developer Support, December 11,
1995.
Código Fuente para Windows
Protocolos de Comunicación 2012
Código Fuente para Windows
Protocolos de Comunicación 2012
Descargar