欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

串口通讯相关

程序员文章站 2022-07-13 21:04:01
...
https://bbs.csdn.net/wap/topics/350150286
https://blog.csdn.net/wzmsltw/article/details/50723267
https://blog.csdn.net/henhen2002/article/details/4485186
https://www.cnblogs.com/chucks123/p/7545660.html
https://blog.csdn.net/alaseven/article/details/8875906
https://www.cnblogs.com/memset/archive/2012/12/24/common.html
https://www.cnblogs.com/wangweifeng/p/7599888.html
https://www.cnblogs.com/chucks123/p/7545660.html

/*************************************************************************************************/
/*!
    \file SerialPort.h

    \attention
        Copyright (c) 2018 XXX.
        All Rights Reserved.

    \History
        [V1.00][2018-11-05][Jacky] - Init Version
*/
/*************************************************************************************************/
#ifndef SERIAL_PORT_H
#define SERIAL_PORT_H

/*** Include files *******************************************************************************/
#include <windows.h>

#ifdef __cplusplus
extern "C"
{
#endif

/*** Defines/Macros/Constants/Typedefs ***********************************************************/
#define    SERIAL_PORT_READ_BUFFER_SIZE   1024

typedef enum EM_SERIAL_PORT_PARITY
{   /*0-4=None,Odd,Even,Mark,Space*/
    SerialPort_NoParity = NOPARITY,
    SerialPort_OddParity = ODDPARITY,
    SerialPort_EvenParity = EVENPARITY,
    SerialPort_MarkParity = MARKPARITY,
    SerialPort_SpaceParity = SPACEPARITY
}SERIAL_PORT_PARITY;

typedef enum EM_SERIAL_PORT_STOPBITS
{   /* 0,1,2 = 1, 1.5, 2 */
    SerialPort_OneStopBit = ONESTOPBIT,
    SerialPort_OneFiveStopBits = ONE5STOPBITS,
    SerialPort_TwoStopBits = TWOSTOPBITS
}SERIAL_PORT_STOPBITS;

typedef enum EM_SERIAL_PORT_DATABITS
{/* Number of bits/byte, 4-8        */
    SerialPort_4DataBits = 4,
    SerialPort_5DataBits = 5,
    SerialPort_6DataBits = 6,
    SerialPort_7DataBits = 7,
    SerialPort_8DataBits = 8
}SERIAL_PORT_DATABITS;

typedef enum EM_SERIAL_PORT_FLOWCONTROL
{/* Number of bits/byte, 4-8        */
    SerialPort_FlowControl_None = 0,
    SerialPort_FlowControl_HW = 1,
    SerialPort_FlowControl_SW = 2
}SERIAL_PORT_FLOWCONTROLS;


typedef struct tag_SerialPortSetting
{
    DWORD dwBaudRate;       /* Baud rate at which running       */
                            // The value should be equals followings which defined in WinBase.h
                            //CBR_110/CBR_300/CBR_600/CBR_1200/CBR_2400/CBR_4800/CBR_9600
                            //CBR_14400/CBR_19200/CBR_38400/CBR_56000/CBR_57600/CBR_115200/CBR_128000/CBR_256000

    SERIAL_PORT_DATABITS emDataBits;
    SERIAL_PORT_PARITY emParity;
    SERIAL_PORT_STOPBITS emStopBits;
    SERIAL_PORT_FLOWCONTROLS emFlowControl;
    DWORD dwIntervalTimeout;

    tag_SerialPortSetting()
    {
        dwBaudRate = CBR_115200;
        emDataBits = SerialPort_8DataBits;
        emParity = SerialPort_NoParity;
        emStopBits = SerialPort_OneStopBit;
        emFlowControl = SerialPort_FlowControl_None;
        dwIntervalTimeout = MAXDWORD;
    }
}SerialPortSetting, *PSerialPortSetting;

/*************************************************************************************************/
/*!
    \brief OpenSerialPort
    Opens a serial port(I/O).

    \param[in]  strPort - The name of the file or device to be created or opened. 
             You may use either forward slashes (/) or backslashes () in this name.

    \param[in]  cSerialPortSetting - Detailed settings for the serial port.

    \return  If the function succeeds, the return value is an open handle to the specified file,
         device, named pipe, or mail slot.
             If the function fails, the return value is INVALID_HANDLE_VALUE.
*/
/*************************************************************************************************/
HANDLE OpenSerialPort(IN CONST CString strPortName, IN CONST SerialPortSetting cSerialPortSetting);

/*************************************************************************************************/
/*!
    \brief CloseSerialPort
    Closes a serial port(I/O).

    \param[in]  hSerialPort - Pointer to the handle of the serial port.

    \return  Return TRUE if the function succeeds else return FALSE.
*/
/*************************************************************************************************/
BOOL CloseSerialPort(IN CONST HANDLE hSerialPort);

/*************************************************************************************************/
/*!
    \brief WriteDataToSerialPort
    Send data to specific serial port.

    \param[in]  hSerialPort - Pointer to the handle of the serial port.
    \param[in]  pbyData - Pointer to the  buffer that specifies the data you want to send.
    \param[in]  dwSize - The size of data buffer.

    \return  Return TRUE if the function succeeds else return FALSE.
*/
/*************************************************************************************************/
BOOL WriteDataToSerialPort(IN CONST HANDLE hSerialPort, IN CONST BYTE* pbyData, IN CONST DWORD dwSize);

/*************************************************************************************************/
/*!
    \brief ReadDataFromSerialPort
    Stores received data into a destination buffer.

    \param[in]  hSerialPort - Pointer to the handle of the serial port.
    \param[in]  pbyBuffer - Pointer to the raw destination buffer.
    \param[in/out]  dwSize - The total size of data buffer/Used data buffer size.

    \return  Return TRUE if the function succeeds else return FALSE.
*/
/*************************************************************************************************/
BOOL ReadDataFromSerialPort(IN CONST HANDLE hSerialPort, OUT BYTE* pbyBuffer, IN OUT DWORD& dwSize);

#ifdef __cplusplus
}

#endif

#endif//SERIAL_PORT_H


/*************************************************************************************************/
/*!
    \file SerialPort.cpp

    \attention
        Copyright (c) 2018 XXX.
        All Rights Reserved.

    \History
        [V1.00][2018-11-05][Jacky] - Init Version
*/
/*************************************************************************************************/

/*** Include files *******************************************************************************/
#include "stdafx.h"
#include "SerialPort.h"

#ifdef __cplusplus
extern "C"
{
#endif
/*************************************************************************************************/
/*!
    \brief OpenSerialPort
    Opens a serial port(I/O).

    \param[in]  strPort - The name of the file or device to be created or opened. 
             You may use either forward slashes (/) or backslashes () in this name.

    \param[in]  cSerialPortSetting - Detailed settings for the serial port.

    \return  If the function succeeds, the return value is an open handle to the specified file,
         device, named pipe, or mail slot.
             If the function fails, the return value is INVALID_HANDLE_VALUE.
*/
/*************************************************************************************************/
HANDLE OpenSerialPort(CONST CString strPortName, CONST SerialPortSetting cSerialPortSetting)
{
    HANDLE hSerialPort = INVALID_HANDLE_VALUE;

    hSerialPort = CreateFile(strPortName,
                    GENERIC_READ | GENERIC_WRITE,
                    0, // exclusive share
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL);
    if (INVALID_HANDLE_VALUE == hSerialPort)
    {
#ifdef DEBUG
        OutputDebugString(_T("Failed to open serial port!\n"));
#endif

        return hSerialPort;
    }

    //Get Current Settings
    //////////////////////////////////////////////////////////////////////////
    DCB cPortDCB;
    cPortDCB.DCBlength = sizeof(DCB);
    if (!GetCommState(hSerialPort, &cPortDCB))// Get the default serial parameter.
    {
#ifdef DEBUG
        OutputDebugString(_T("Failed to call GetCommState()!\n"));
#endif

        CloseHandle(hSerialPort);
        return INVALID_HANDLE_VALUE;
    }
    else
    {
        //Apply serial port settings
        //////////////////////////////////////////////////////////////////////////
        cPortDCB.BaudRate = cSerialPortSetting.dwBaudRate; 
        cPortDCB.ByteSize = cSerialPortSetting.emDataBits;
        cPortDCB.Parity = cSerialPortSetting.emParity;
        cPortDCB.StopBits = cSerialPortSetting.emStopBits;

        switch(cSerialPortSetting.emFlowControl)
        {
        case SerialPort_FlowControl_HW:
            {
                cPortDCB.fOutxCtsFlow = 1;
                cPortDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
                cPortDCB.fOutX = 0;
                cPortDCB.fInX = 0;

                break;
            }
        case SerialPort_FlowControl_SW:
            {
                cPortDCB.fOutxCtsFlow = 0;
                cPortDCB.fRtsControl = 0;
                cPortDCB.fOutX = 1;
                cPortDCB.fInX = 1;

                break;
            }
        case SerialPort_FlowControl_None:
        default:
            {
                cPortDCB.fOutxCtsFlow = 0;
                cPortDCB.fRtsControl = 0;
                cPortDCB.fOutX = 0;
                cPortDCB.fInX = 0;

                break;
            }
        }

        if (!SetCommState(hSerialPort, &cPortDCB))
        {
            //config the serial port failed.
            CloseHandle(hSerialPort);
            return (INVALID_HANDLE_VALUE);
        }
    }

    //Config the serial port timeout property.
    //////////////////////////////////////////////////////////////////////////
    COMMTIMEOUTS CommTimeouts;
    if (!GetCommTimeouts(hSerialPort, &CommTimeouts))//Get the serial port default timeout.
    {
        CloseHandle(hSerialPort);
        return INVALID_HANDLE_VALUE;
    }
    else
    {
        CommTimeouts.ReadIntervalTimeout = cSerialPortSetting.dwIntervalTimeout;
        CommTimeouts.ReadTotalTimeoutMultiplier = 10;
        CommTimeouts.ReadTotalTimeoutConstant = 10;
        CommTimeouts.WriteTotalTimeoutMultiplier = 50;
        CommTimeouts.WriteTotalTimeoutConstant = 100;

        if (!SetCommTimeouts(hSerialPort, &CommTimeouts))
        {
            //config the serial port timeout failed;
            CloseHandle(hSerialPort);
            return INVALID_HANDLE_VALUE;
        }
    }

    return hSerialPort; //Everything should be fine. (~v~) - Cheers!!!
}

/*************************************************************************************************/
/*!
    \brief CloseSerialPort
    Closes a serial port(I/O).

    \param[in]  hSerialPort - Pointer to the handle of the serial port.

    \return  Return TRUE if the function succeeds else return FALSE.
*/
/*************************************************************************************************/
BOOL CloseSerialPort(CONST HANDLE hSerialPort)
{
    return CloseHandle(hSerialPort);
}

/*************************************************************************************************/
/*!
    \brief WriteDataToSerialPort
    Send data to specific serial port.

    \param[in]  hSerialPort - Pointer to the handle of the serial port.
    \param[in]  pbyData - Pointer to the  buffer that specifies the data you want to send.
    \param[in]  dwSize - The size of data buffer.

    \return  Return TRUE if the function succeeds else return FALSE.
*/
/*************************************************************************************************/
BOOL WriteDataToSerialPort(CONST HANDLE hSerialPort, CONST BYTE* pbyData, CONST DWORD dwSize)
{
    BOOL bRet = FALSE;
    DWORD nHasBeenSend = 0;
    DWORD dwRet = 0;

    while (TRUE)
    {
        DWORD dwSendBytes = 0;
        if (!WriteFile(hSerialPort, pbyData+nHasBeenSend, dwSize-nHasBeenSend, &dwSendBytes, NULL))
        {
#ifdef DEBUG
            OutputDebugString(_T("Failed to call WriteFile()!\n"));
#endif
            dwRet = GetLastError();
            bRet = FALSE;

            break;
        }
        else
        {
            if (dwSendBytes > 0)
            {
                nHasBeenSend += dwSendBytes;
            }

            if (nHasBeenSend > dwSize)
            {
#ifdef DEBUG
                OutputDebugString(_T("OverStack!\n"));
#endif
                bRet = FALSE;
                break;
            }
            else if (dwSize == nHasBeenSend)
            {
                bRet = TRUE;
                break;
            }
        }
    }

    return bRet;
}

/*************************************************************************************************/
/*!
    \brief ReadDataFromSerialPort
    Stores received data into a destination buffer.

    \param[in]  hSerialPort - Pointer to the handle of the serial port.
    \param[in]  pbyBuffer - Pointer to the raw destination buffer.
    \param[in/out]  dwSize - The total size of data buffer/Used data buffer size.

    \return  Return TRUE if the function succeeds else return FALSE.
*/
/*************************************************************************************************/
BOOL ReadDataFromSerialPort(CONST HANDLE hSerialPort, BYTE* pbyBuffer, DWORD& dwSize)
{
    //SetCommMask (hSerialPort, EV_RXCHAR);
    DWORD dwHasBeenReadSize = 0;
    BYTE byTempBuffer = 0x00;
    BOOL bRet = FALSE;
    DWORD dwMask = EV_RXCHAR;

#ifdef DEBUG
    DWORD dwError = 0;
#endif

    if (!WaitCommEvent(hSerialPort, &dwMask, NULL))
    {
#ifdef DEBUG
        OutputDebugString(_T("Failed to call WaitCommEvent()!\n"));
#endif

       dwError = GetLastError();

       //return FALSE;
    }

    if (!SetCommMask(hSerialPort, EV_RXCHAR))
    {
#ifdef DEBUG
        OutputDebugString(_T("Failed to call SetCommMask()!\n"));
#endif

       //return FALSE;
    }

    while (TRUE)
    {
        DWORD dwReadBytes = 0;
        if (ReadFile(hSerialPort, &byTempBuffer, 1, &dwReadBytes, 0))
        {
            if (dwReadBytes > 0) 
            {
                if (dwHasBeenReadSize+dwReadBytes > dwSize)
                {
                     //out of bounds ?
#ifdef DEBUG
                     OutputDebugString(_T("out of bounds!\n"));
#endif

                    bRet = FALSE;
                    break;
                }
                else
                {
                    memcpy(&pbyBuffer[dwHasBeenReadSize], &byTempBuffer, dwReadBytes);
                    dwHasBeenReadSize += dwReadBytes;
                }
            }
            else 
            {
                bRet = TRUE;
                break;
            }
        }
        else
        {
#ifdef DEBUG
            OutputDebugString(_T("Failed to call ReadFile!\n"));
#endif
            bRet = FALSE;
            break;
        }
    }

    dwSize = dwHasBeenReadSize;
    return bRet;
}

#ifdef __cplusplus
}
#endif






//===========================SerialPort.H的开始=========================

#pragma once
#include <windows.h>
#include <string>

using namespace std;
HANDLE OpenSerialPort(string & strPort, ULONG ulBaudrate);
void CloseSerialPort(HANDLE hSerial);
bool WriteSerial(char* btData, ULONG ulSize, HANDLE hSerial);
bool ReadSerial(BYTE *btData, ULONG *ulSize, HANDLE hSerial);

//===========================SerialPort.H的结束=========================


#include "SerialPort.h"

HANDLE OpenSerialPort(string & strPort, ULONG ulBaudrate)
{
    HANDLE hSerial;
    hSerial = CreateFile((strPort.c_str()),
    GENERIC_READ | GENERIC_WRITE,
    NULL,
    NULL,
    OPEN_EXISTING,
    NULL,
    NULL);
    
if (hSerial == INVALID_HANDLE_VALUE)//Open serial port failed.
{
    return hSerial;
}

//Config serial port
DCB PortDCB;
PortDCB.DCBlength = sizeof(DCB);

// Get the default serial parameter.
GetCommState(hSerial, &PortDCB);
PortDCB.BaudRate = ulBaudrate;      // baudrate
PortDCB.ByteSize = 8;               // Number of bits/byte, 4-8 
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;

if (!SetCommState(hSerial, &PortDCB))
{
    //config the serial port failed.
    CloseHandle(hSerial);
    return (INVALID_HANDLE_VALUE);
}

//Config the serial port timeout property.
COMMTIMEOUTS CommTimeouts;
GetCommTimeouts(hSerial, &CommTimeouts);        //Get the serial port default timeout.
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 10;
CommTimeouts.ReadTotalTimeoutConstant = 10;
CommTimeouts.WriteTotalTimeoutMultiplier = 50;
CommTimeouts.WriteTotalTimeoutConstant = 100;

if (!SetCommTimeouts(hSerial, &CommTimeouts))
{
    //config the serial port timeout failed;
    CloseHandle(hSerial);
    return (INVALID_HANDLE_VALUE);
}
    return (hSerial);
};

void CloseSerialPort(HANDLE hSerial)    
{
    CloseHandle(hSerial);
};

bool WriteSerial(char* btData, ULONG ulSize, HANDLE hSerial)
{
    DWORD dwNumBytes, dwRet;
    dwRet = WriteFile(hSerial, //Handle
    btData, //Data buffer
    ulSize, //Buffer size
    &dwNumBytes, //written bytes
    NULL); //don't support

    return (dwRet != 0);
};

bool ReadSerial(BYTE *btData, ULONG *ulSize, HANDLE hSerial)
{
    //SetCommMask (hSerial, EV_RXCHAR);
    ULONG ulRdSize = 0;
    BYTE Byte;
    DWORD dwBytes;
    bool blRd = false;
    DWORD dwMask = EV_RXCHAR;
    //WaitCommEvent(hSerial,&dwMask,NULL);
    SetCommMask(hSerial, EV_RXCHAR);
    while (ReadFile(hSerial, &Byte, 1, &dwBytes, 0) != 0) 
    {
    if (dwBytes>0) 
    {
        btData[ulRdSize++] = Byte;
        
        if (ulRdSize == *ulSize) 
        {
            blRd = true;
            break;
        }
    }

    else 
    {   
        blRd = true;
        break;
    }
}

    *ulSize = ulRdSize;
    return (blRd);
};


///////////////////////////////main.cpp////////////////////////////////////////

//使用代码示例: 
#include "SerialPort.h"
#include <iostream>
using namespace std;

HANDLE hSerialPort;

int main()
{
    string portname = "COM4:";
    string buff = "HELLO!";
    char c[20];
    strcpy_s(c, buff.c_str());

    hSerialPort = OpenSerialPort( portname, 9600);//Open serial port com1

    if (hSerialPort != INVALID_HANDLE_VALUE)
    {
        if (!WriteSerial(c, 7, hSerialPort))//Send data hello to com1
        
        //MessageBox(0, "ERROR", "ERROR", MB_ICONWARNING);//show error message
        printf("ERROR!!");
        //CloseSerialPort(hSerialPort);
    }
    system("pause");
}