Serial Port (RS232) communication with Visual C++ 2010

吃可爱长大的小学妹 提交于 2019-12-01 01:45:55

Serial Communications: http://msdn.microsoft.com/en-us/library/ff802693.aspx

This article still remains actual after so many years... Code sample included.

Here it is a two samples of the same program, one for visual studio 2013 and the other for minGW in Eclipse in Windows 7 32 bits

for visual studio:

stadfx.h

#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>

// TODO: mencionar aquí los encabezados adicionales que el programa necesita
#include <conio.h>
#include <string.h>

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <iostream>
using namespace std;

terminal.cpp

#include "stdafx.h"

void error_de_sistema(char *name) {
    // Recupera, formatea y despliega el mensaje del ultimo error
    // 'name' que es el argumento pasado al momento del error debe ser una     frase en presente
    //  como por ejemplo "abriendo archivo".
    //
    //char *ptr = NULL;
    WCHAR ptr[1024];
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM,
        0,
        GetLastError(),
        0,
        //(char *)&ptr,
        ptr,
        1024,
        NULL);
    //fprintf(stderr, "\nError %s: %s\n", name, ptr);
    //fprintf(stderr, "\nError %s: %s\n", name, &ptr);
    wcout << endl << "Error " << name << ": " << ptr << endl;
    LocalFree(ptr);
}


int _tmain(int argc, _TCHAR* argv[])
{
    int ch;
    char buffer[1];
    HANDLE file;
    COMMTIMEOUTS timeouts;
    DWORD read, written;
    DCB port;
    HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode;
    //char port_name[128] = "\\\\.\\COM3";
    LPCWSTR port_name = L"\\\\.\\COM5";
    char init[] = ""; // v.gr., "ATZ" resetea un modem por completo.

    if (argc > 2)
        swprintf_s((wchar_t *)&port_name, 128, L"\\\\.\\COM%c", argv[1][0]);
    //sprintf(port_name, "\\\\.\\COM%c", argv[1][0]);

    // abre el puerto.
    file = CreateFile(port_name,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if (INVALID_HANDLE_VALUE == file) {
        error_de_sistema("abriendo archivo");
        return 1;
    }

    // obtiene el block de control del dispositivo DCB, y ajusta unos cuantos bits para nuestro enlace.
    memset(&port, 0, sizeof(port));
    port.DCBlength = sizeof(port);
    if (!GetCommState(file, &port))
        error_de_sistema("obteniendo el estado del puerto");
    //if (!BuildCommDCB("baud=19200 parity=n data=8 stop=1", &port))
    if (!BuildCommDCB(L"baud=9600 parity=n data=8 stop=1", &port))
        error_de_sistema("creando el bloque DCB de comunicaciones");
    if (!SetCommState(file, &port))
        error_de_sistema("ajustando la configuracion del puerto");

    // Configura los tiempos fuera cortos para el puerto.
    timeouts.ReadIntervalTimeout = 1;
    timeouts.ReadTotalTimeoutMultiplier = 1;
    timeouts.ReadTotalTimeoutConstant = 1;
    timeouts.WriteTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 1;
    if (!SetCommTimeouts(file, &timeouts))
        error_de_sistema("configurando los time-outs. del puerto");

    // Configura el teclado para una lectura raw (aleatoria y libre).
    if (!GetConsoleMode(keyboard, &mode))
        error_de_sistema("obteniendo el modo del teclado");
    mode &= ~ENABLE_PROCESSED_INPUT;
    if (!SetConsoleMode(keyboard, mode))
        error_de_sistema("configurando el modo del teclado");

    if (!EscapeCommFunction(file, CLRDTR))
        error_de_sistema("apagando el DTR");
    Sleep(200);
    if (!EscapeCommFunction(file, SETDTR))
        error_de_sistema("encendiendo el DTR");

    if (!WriteFile(file, init, sizeof(init), &written, NULL))
        error_de_sistema("escribiendo datos en el puerto");

    if (written != sizeof(init))
        error_de_sistema("porque no todos los datos se enviaron al puerto");

    // ciclo basico de la terminal:
    do {
        // checa por datos en el puerto y los despliega en pantalla.
        ReadFile(file, buffer, sizeof(buffer), &read, NULL);
        if (read)
            WriteFile(screen, buffer, read, &written, NULL);

        // checa por tecla presionada, y lo envia al puerto.
        if (_kbhit()) {
            ch = _getch();
            WriteFile(file, &ch, 1, &written, NULL);
        }
    } while (ch != 127);    // hasta que el usuario pulse ctrl-backspace.

    // cierra todo y bye bye.
    CloseHandle(keyboard);
    CloseHandle(file);
    return 0;
}

y para eclipse con minGW

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <iostream>
using namespace std;

void error_de_sistema(char *name) {
    // Recupera, formatea y despliega el mensaje del ultimo error
    // 'name' que es el argumento pasado al momento del error debe ser una frase en presente
    //  como por ejemplo "abriendo archivo".
    //
    char *ptr = NULL;
    //WCHAR ptr[1024];
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM,
        0,
        GetLastError(),
        0,
        //(char *)&ptr,
        ptr,
        1024,
        NULL);
    //fprintf(stderr, "\nError %s: %s\n", name, ptr);
    //fprintf(stderr, "\nError %s: %s\n", name, &ptr);
    wcout << endl << "Error " << name << ": " << ptr << endl;
    LocalFree(ptr);
}


int main(int argc, char **argv)
{
    int ch;
    char buffer[1];
    char mensaje[256];
    HANDLE file;
    COMMTIMEOUTS timeouts;
    DWORD read, written;
    DCB port;
    HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode;
    char port_name[128] = "\\\\.\\COM5";
    //LPCWSTR port_name = L"\\\\.\\COM5";
    char init[] = ""; // v.gr., "ATZ" resetea un modem por completo.

    if (argc > 2)
        //swprintf_s((wchar_t *)&port_name, 128, L"\\\\.\\COM%c", argv [1][0]);
        sprintf(port_name, "\\\\.\\COM%c", argv[1][0]);

    // abre el puerto.
    file = CreateFile(port_name,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if (INVALID_HANDLE_VALUE == file) {
        strncpy(mensaje, "abriendo archivo", sizeof(mensaje));
        error_de_sistema(mensaje);
        return 1;
    }

    // obtiene el block de control del dispositivo DCB, y ajusta unos  cuantos bits para nuestro enlace.
    memset(&port, 0, sizeof(port));
    port.DCBlength = sizeof(port);
    if (!GetCommState(file, &port)){
        strncpy(mensaje, "obteniendo el estado del puerto", sizeof(mensaje));
        error_de_sistema(mensaje);
    }
    if (!BuildCommDCB("baud=9600 parity=n data=8 stop=1", &port)){
    //if (!BuildCommDCB(L"baud=9600 parity=n data=8 stop=1", &port))
        strncpy(mensaje, "creando el bloque DCB de comunicaciones", sizeof(mensaje));
        error_de_sistema(mensaje);
    }
    if (!SetCommState(file, &port)){
        strncpy(mensaje, "ajustando la configuracion del puerto", sizeof(mensaje));
        error_de_sistema(mensaje);
    }

    // Configura los tiempos fuera cortos para el puerto.
    timeouts.ReadIntervalTimeout = 1;
    timeouts.ReadTotalTimeoutMultiplier = 1;
    timeouts.ReadTotalTimeoutConstant = 1;
    timeouts.WriteTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 1;
    if (!SetCommTimeouts(file, &timeouts)){
        strncpy(mensaje, "configurando los time-outs. del puerto", sizeof(mensaje));
        error_de_sistema(mensaje);
    }

    // Configura el teclado para una lectura raw (aleatoria y libre).
    if (!GetConsoleMode(keyboard, &mode)){
        strncpy(mensaje, "obteniendo el modo del teclado", sizeof(mensaje));
        error_de_sistema(mensaje);
    }
    mode &= ~ENABLE_PROCESSED_INPUT;
    if (!SetConsoleMode(keyboard, mode)){
        strncpy(mensaje, "configurando el modo del teclado", sizeof(mensaje));
        error_de_sistema(mensaje);
    }
    //Mandamos un reset por hardware (algunos sistemas se resetean con el DTR)
    if (!EscapeCommFunction(file, CLRDTR)){
        strncpy(mensaje, "apagando el DTR", sizeof(mensaje));
        error_de_sistema(mensaje);
    }
    Sleep(200);
    if (!EscapeCommFunction(file, SETDTR)){
        strncpy(mensaje, "encendiendo el DTR", sizeof(mensaje));
        error_de_sistema(mensaje);
    }

    if (!WriteFile(file, init, sizeof(init), &written, NULL)){
        strncpy(mensaje, "escribiendo datos en el puerto", sizeof (mensaje));
        error_de_sistema(mensaje);
    }
    //Por si es necesario enviar algun dato al comenzar el proceso
    if (written != sizeof(init)){
        strncpy(mensaje, "porque no todos los datos se enviaron al  puerto", sizeof(mensaje));
        error_de_sistema(mensaje);
    }

    // ciclo basico de la terminal:
    do {
        // checa por datos en el puerto y los despliega en pantalla.
        ReadFile(file, buffer, sizeof(buffer), &read, NULL);
        if (read)
            WriteFile(screen, buffer, read, &written, NULL);

        // checa por tecla presionada, y si hay alguna, envia el caracter leido al puerto.
        if (_kbhit()) {
            ch = _getch();
            WriteFile(file, &ch, 1, &written, NULL);
        }
    } while (ch != 127);    // termina el ciclo hasta que el usuario pulse ctrl-backspace.

    // cierra todo y bye bye.
    CloseHandle(keyboard);
    CloseHandle(file);
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!