C++之串口通讯

简介

串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口 (Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。

代码

头文件

SerialInterface.h

#ifndef __SerialInterface_H_
#define __SerialInterface_H_
#include <Windows.h>
#include <string>
using namespace std;

class SerialInterface
{
private:
    /* data */
    HANDLE hCom;
    string last_error;
public:
    SerialInterface();
    ~SerialInterface();
public:
    //同步方式打开串口,并配置默认信息
    bool openSyn(string serial_name,unsigned char baud_rate,unsigned char parity, unsigned char byte_size, unsigned char stop_bits);
    //同步方式打开串口(需自己配置串口参数)
    bool openSyn(string serial_name);

    //设置推荐的缓冲大小
    bool setBufferSize(DWORD inputBuff,DWORD outBuffer);
    //设置超时
    bool setTimeouts(COMMTIMEOUTS &timeouts);
    //设置串口信息
    bool setDCB(DCB& dcb);

    //刷新缓冲区
    bool purgeBuff(DWORD flags);
    //刷新缓冲区
    bool flushBuff();
    //写数据
    DWORD writeData(char *buffer,int length);
    //读数据
    DWORD readData(char *buffer,int length);
    //写字符串
    DWORD writeStr(string str);
    //关闭串口
    void closeComm();
    //判断串口是否打开
    bool isOpened();
    //得到最后一次失败的错误信息
    string getSerialLastError();
private:
    //设置最后一次的错误信息
    void setSerialLastError(string error_msg);
    //清chu最后一次的错误信息
    void clearSerialLastError();
};

#endif /*__SerialInterface_H_*/

源码文件

SerialInterface.cpp

#include "SerialInterface.h"

/*******************************************************************
* 名称: openSyn
* 功能: 同步方式打开串口,并配置默认信息
* 参数:
    serial_name:串口名称
    baud_rate  :波特率,取值如下
        ......
        CBR_9600    9600bps
        CBR_14400   14400bps
        ......
    parity     :校验方式
        EVENPARITY  偶校验
        MARKPARITY  标号校验
        NOPARITY    无校验
        ODDPARITY   奇校验
        SPACEPARITY 空格校验
    byte_size  :数据位大小
        4,5,6,7,8
    stop_bits  :停止位
        ONESTOPBIT      1个停止位
        ONE5STOPBITS    1.5个停止位
        TWOSTOPBITS     2个停止位
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
bool SerialInterface::openSyn(string serial_name, unsigned char baud_rate, unsigned char parity, unsigned char byte_size, unsigned char stop_bits)
{
    if (!openSyn(serial_name))
        return false;
    DCB dcb;

    if (false == GetCommState(hCom, &dcb))//获得当前串口的配置信息
    {
        setSerialLastError("SerialInterface::open() : GetCommState Error");
        return false;
    }

    dcb.DCBlength = sizeof(DCB);
    dcb.BaudRate = baud_rate;
    dcb.Parity = parity;
    dcb.ByteSize = byte_size;
    dcb.StopBits = stop_bits;

    if (false == SetCommState(hCom, &dcb))//用DCB结构重新配置串行端口信息
    {
        setSerialLastError("SerialInterface::open() : SetCommState Error");
        return false;
    }

    //超时处理
    COMMTIMEOUTS timeouts;
    timeouts.ReadIntervalTimeout = MAXDWORD; //读间隔超时
    // 把间隔超时设为最大,把总超时设为0将导致ReadFile立即返回并完成操作 

    timeouts.ReadTotalTimeoutMultiplier = 0; //读时间系数
    timeouts.ReadTotalTimeoutConstant = 0; //读时间常量
    timeouts.WriteTotalTimeoutMultiplier = 50; // 写时间系数
    timeouts.WriteTotalTimeoutConstant = 2000; //写时间常量
    //总的读/写超时时间 = Read(Write)TotalTimeoutMultiplier x 要读/写的字节数 + Read(Write)TotalTimeoutConstant. 
    if (false==SetCommTimeouts(hCom, &timeouts))
    {
        setSerialLastError("SerialInterface::open() : SetCommTimeouts Error");
        return false;
    }



    //清空缓冲区,为读写串口做准备
    if (false == PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT))
    {
        setSerialLastError("SerialInterface::open() : PurgeComm Error");
        return false;
    }
    return true;
}
/*******************************************************************
* 名称: openSyn
* 功能: 同步方式打开串口(需自己配置串口参数)
* 参数:
    serial_name:串口名称
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
bool SerialInterface::openSyn(string serial_name)
{
	hCom = CreateFileA(
		serial_name.data(),//普通文件名或者设备文件名,这里是串口名
		GENERIC_READ | GENERIC_WRITE,//访问模式,读和写
		0,//共享模式,独占模式
		NULL,//指向安全属性的指针,不使用,传NULL
		OPEN_EXISTING,//如何创建,在串口中必须设置为OPEN_EXISTING。表示不能创建新端口只能打开已有的端口。
		FILE_ATTRIBUTE_NORMAL,//文件属性,使用默认属性FILE_ATTRIBUTE_NORMAL。
		NULL//用于复制文件句柄,通常这个参数设置为NULL,为空表示不使用模板
	);


	if (INVALID_HANDLE_VALUE == hCom)//出错判断
	{
		hCom = NULL;
        setSerialLastError("open():CreateFileA Error!");
		return false;
	}
	return true;
}
/*******************************************************************
* 名称: closeComm
* 功能: 关闭串口
* 参数: 无
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
void SerialInterface::closeComm()
{
    if(NULL==hCom)
        return;
    CloseHandle(hCom);
    hCom=NULL;
}
/*******************************************************************
* 名称: closeComm
* 功能: 判断串口是否打开
* 参数: 无
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
bool SerialInterface::isOpened()
{
    return NULL == hCom ? false : true;
}

DWORD SerialInterface::readData(char *buffer,int length)
{
    DWORD writeSize=0;

    bool ret=false;

    ret=ReadFile(hCom,buffer,length,&writeSize,NULL);

    if(false==ret)
        return 0;

    return writeSize;
}


DWORD SerialInterface::writeData(char *buffer,int length)
{
    DWORD writeSize=0;

    bool ret=false;

    ret=WriteFile(hCom,buffer,length,&writeSize,NULL);

    if(false==ret)
        return 0;

    return writeSize;

}


DWORD SerialInterface::writeStr(string str)
{
	bool ret = false;

	DWORD writeSize = 0;


	ret = WriteFile(hCom, str.data(), str.length(), &writeSize, NULL);

    if (0 == ret)
    {
        last_error = "Error By writeStr(string str)";
        return 0;
    }
		

    last_error = "";
	return writeSize;

}
/*******************************************************************
* 名称: setTimeouts
* 功能: 设置超时
* 参数:
    timeouts:超时配置的COMMTIMEOUTS结构体
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
bool SerialInterface::setTimeouts(COMMTIMEOUTS &timeouts)
{

    if (false == SetCommTimeouts(hCom, &timeouts))
    {
        setSerialLastError("SerialInterface::setTimeouts() : SetCommTimeouts Error");
        return false;
    }
    return true;
}
/*******************************************************************
* 名称: setDCB
* 功能: 设置串口信息
* 参数:
    dcb:串口信息配置的DCB结构体
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
bool SerialInterface::setDCB(DCB& dcb)
{
    if (false == SetCommState(hCom, &dcb))
    {
        setSerialLastError("SerialInterface::setDCB() : SetCommState Error");
        return false;
    }
    return true;
}
/*******************************************************************
* 名称: purgeBuff
* 功能: 刷新缓冲区
* 参数: 
    flags:需要完成的操作,取值如下
        PURGE_RXABORT 终止所有未完成的重叠读取操作并立即返回,即使读取操作尚未完成。
        PURGE_RXCLEAR 清除输入缓冲区(如果设备驱动程序有一个)。
        PURGE_TXABORT 终止所有未完成的重叠写操作并立即返回,即使写操作尚未完成。
        PURGE_TXCLEAR 清除输出缓冲区(如果设备驱动程序有一个)。
* 返回: 正确返回为ture,错误返回为false
* 提示:PurgeComm()函数可以在读写操作的同时,清空缓冲区。当应用程序在读写操作时
调用PurgeComm()函数,不能保证缓冲区内的所有字符都被发送。
*******************************************************************/
bool SerialInterface::purgeBuff(DWORD flags)
{

    if (false == PurgeComm(hCom, flags))
    {
        setSerialLastError("SerialInterface::purgeBuff() : PurgeComm Error");
        return false;
    }
    return true;
}
/*******************************************************************
* 名称:flushBuff
* 功能:刷新缓冲区
* 参数:无
* 返回:正确返回为ture,错误返回为false
* 提示:该函数只受流量控制的支配,不受超时控制的支配,它在所有的写操作完成后才返回。
*******************************************************************/
bool SerialInterface::flushBuff()
{
    if(FlushFileBuffers(hCom))
    {
        setSerialLastError("SerialInterface::flushBuff() : FlushFileBuffers Error");
        return false;
    }
    return true;
}
/*******************************************************************
* 名称: setBufferSize
* 功能: 设置推荐的缓冲大小
* 参数:
    inputBuff:输入缓冲大小
    outBuffer:输出缓冲大小
* 返回: 正确返回为ture,错误返回为false
*******************************************************************/
bool SerialInterface::setBufferSize(DWORD inputBuff,DWORD outBuffer)
{
    if(inputBuff<=0||outBuffer<=0)
        return false;
    
    return SetupComm(hCom,inputBuff,outBuffer);
}
/*******************************************************************
* 名称: getSerialLastError
* 功能: 得到最后一次失败的错误信息
* 参数: 无
* 返回: 数据类型:string,错误信息
*******************************************************************/
string SerialInterface::getSerialLastError()
{
    return last_error;
}

void SerialInterface::setSerialLastError(string error_msg)
{
    last_error = error_msg;
}
void SerialInterface::clearSerialLastError()
{
    last_error = "";
}
SerialInterface::SerialInterface()
{
    hCom=NULL;
}
SerialInterface::~SerialInterface()
{

}

示例

创建两个虚拟串口

注意:这两个串口是连通的,给COM1发数据,COM2可以收到,反之亦然。
在这里插入图片描述## 用串口调试助手连接COM2来接数据

用串口调试助手连接COM2来接数据

在这里插入图片描述

编写测试代码发送数据

在这里插入图片描述
代码如下所示:

#include <iostream>
#include <cstdlib>
#include "SerialInterface.h"
#include <windows.h>
#include <tchar.h>

using namespace std;

int main()
{

    SerialInterface com;

    if(!com.openSyn("COM1", CBR_9600, NOPARITY,8, ONESTOPBIT))
    {
        cout << com.getSerialLastError() << endl;
        getchar();
        return 0;
    }
    //测试发送
    if (com.writeStr("Hello World!"))
    {
        cout << "send success" << endl;
    }
    else
    {
        cout << "send fail" << endl;
    }

    com.closeComm();


    //getchar();
    return 0;    
}

注意串口信息的配置要一致
在这里插入图片描述
参数的取值在函数的开头有详细的讲解,例如:

在这里插入图片描述

结果

在这里插入图片描述

总结

因为时间关系,只详细写了同步的串口操作,异步的情况后续有空会慢慢更新

此项目以经挂到GitHub:
https://github.com/LairdXavier/MyTool.git
在这里插入图片描述

### 回答1: C/C++控制台串口通讯编程是一种通过使用C/C++语言来实现与串口设备进行通信的编程技术。 在控制台串口通讯编程中,我们可以使用C/C++语言提供的相关库函数来访问和操作串口设备。其中,包括了打开串口、设置串口属性、读写串口数据等功能。 首先,我们需要使用C/C++的库函数来打开串口设备。通过指定串口的名称和访问权限,我们可以从操作系统中获得对串口设备的访问句柄。然后,我们可以使用该句柄来设置串口的属性,如波特率、数据位数、停止位等。设置好属性后,我们就可以通过该串口进行数据的收发。 在串口通讯中,数据的读写是通过调用读写函数来实现的。通常,我们可以使用读函数来从串口中读取数据,并将其存储到缓冲区中。而写函数则用于将数据从缓冲区中写入到串口中。通过读写函数的调用,我们可以实现与外部设备之间的数据交互。 此外,对于串口通讯编程,还需要注意处理错误和异常情况。在进行串口操作时,可能会出现一些错误,如无法打开串口、读写超时等。为了确保程序的可靠性,我们需要在代码中添加适当的错误处理机制,以便及时发现和处理异常情况。 总而言之,C/C++控制台串口通讯编程是一种实现与串口设备进行通信的编程技术。通过使用相关的库函数,我们可以打开串口、设置属性、读写数据,并处理可能出现的错误情况,以实现与外部设备的数据交互。 ### 回答2: C/C++ 控制台串口通讯编程是一种通过串口与外部设备进行数据通讯的编程技术。在控制台应用程序中,通过使用C/C++ 编程语言来实现与串口通讯的功能。 首先,需要了解操作系统提供的相关串口通讯 API 接口。在Windows系统中,可以使用Windows API函数来访问串口,如CreateFile()、ReadFile() 和 WriteFile() 等函数。在Linux系统中,可以通过打开文件描述符的方式来访问串口设备文件,并使用read() 和 write() 函数进行数据的读写。 其次,需要设置串口的参数,包括波特率、数据位、停止位、校验位等。这些参数需要根据外部设备的通讯规范进行设置,以确保正确的数据传输。 然后,可以通过编写串口数据发送和接收的函数来实现数据的收发。发送数据时,可以使用WriteFile() 或 write() 函数将数据写入串口缓冲区,并等待数据的发送完成。接收数据时,可以使用ReadFile() 或 read() 函数从串口缓冲区中读取数据。 此外,需要注意在编程过程中处理异常情况。例如,当串口无法打开、写入数据超时或读取数据错误时,应设置相应的错误处理机制,例如打印错误信息或重新尝试等。 最后,可以在控制台应用程序中实现用户交互界面,通过命令行参数或菜单选项来控制串口通讯的功能,例如设置参数、发送数据、接收数据等。 总之,C/C++ 控制台串口通讯编程需要理解串口通讯的原理和外部设备的通讯规范,熟悉操作系统提供的串口访问函数,并编写相应的发送和接收函数来实现数据的传输。 ### 回答3: C/C++控制台串口通讯编程是指使用C/C++编程语言,在控制台环境中通过串口与外部设备进行通讯的编程过程。 串口通讯是一种常见的硬件通讯接口,用于计算机与外围设备的数据传输。C/C++是一种常见的程序设计语言,提供了丰富的库函数和语法特性,可以方便地进行串口通讯编程。 在进行C/C++控制台串口通讯编程时,首先需要引入相关的库文件,如Windows.h或者Linux的unistd.h header文件,这些文件包含了一些API函数,用于读取和写入串口数据。然后,通过打开相应的串口端口,设置通讯参数(如波特率、数据位、停止位等),可以使用相关API函数进行数据的发送和接收。 例如,通过使用C/C++的读取或写入文件的API函数来读取或写入串口数据,可以实现串口的数据发送和接收操作。可以通过`CreateFile()`函数来打开串口设备,通过`ReadFile()`和`WriteFile()`函数来读取和写入数据。 在进行C/C++串口通讯编程时,需要注意一些细节,比如在读取数据时需要保证数据的完整性,可以使用缓冲区来存储接收到的数据。另外,还需考虑相关的错误处理和异常情况,以确保程序的可靠性。 总之,C/C++控制台串口通讯编程是一种利用C/C++编程语言,在控制台环境下通过串口与外部设备进行数据传输的编程过程。通过合理使用相关的API函数和语言特性,可以实现串口通讯的功能,满足不同场景对数据传输的需求。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值