Windwos串口API的简易封装(C++)

本文讲述了作者在使用Windows串口编程过程中遇到的CreateFile打开串口失败问题,通过转换到宽字符版本函数解决了字符问题。并提供了C++代码示例,包括串口初始化、超时设置、数据发送和接收功能,以帮助初学者理解Windows串口编程的基本操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

最近学习需要用到电脑获取数据传输给单片机,但奈何USB难度太高,因此选择使用串口,因为我写单片机较多,所以这个也写的比较单片机,鉴定为玩单片机玩的

windows串口API建议从站内的这些大佬学习Windows使用串口API函数串口编程_windows 串口编程-优快云博客

用createfile 打开串口失败的解决方法_createfile 串口 打不开-优快云博客

遇到的问题

比较普遍的问题就是字符问题

刚开始我是这样子写的,但是一直打开失败,然后我咨询GPT,他给出的说法是

这样子确实是正常了但是过于繁琐,复杂,然后问群友得知有宽字符版的函数

改成如此,就完全正常了!!!

封装程序

SerialPort.h

#ifndef _SERIALPPORT_H_
#define _SERIALPPORT_H_

#include <iostream>
#include <windows.h>
#include<cstdio>
#include<string.h>

class usart {
public:
	HANDLE  h_Com;
	COMMTIMEOUTS TimeOuts;
	DCB		dcb;
	OVERLAPPED wrOverlapped;
	DWORD dwError;

	int init(int COMx, unsigned int Baudrate, unsigned char byte, unsigned char Stopbits, unsigned char Parity);
	void SetupComm_set(int rx, int tx);
	int TimeOuts_init(int ReadInterval, int ReadTotalMultiplier, int ReadTotalConstant, int WriteTotalMultiplier, int WriteTotalConstant);
	int WriteDate(unsigned char* pSendBuf, int len, DWORD* dwSend);
	int ReadDate(unsigned char* pReadBuf, int len, DWORD* dwRead);
	~usart() {
		CloseHandle(h_Com);
	}
};

#endif

SerialPort.c

#include "SerialPort.h"
/*
 *	串口初始化函数
 *	@变量:
 *		COMx:串口号
 *		Baudrate:波特率
 *		byte:数据位 Number of bits/byte, 4-8
 *		Stopbits:停止位 ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS = 1, 1.5, 2
 *		Parity:校验位  NOPARITY,ODDPARITY,EVENPARITY,MARKPARITY,SPACEPARITY =None,Odd,Even,Mark,Space
 */
int usart::init(int COMx, unsigned int Baudrate, unsigned char byte, unsigned char Stopbits, unsigned char Parity)
{
    char *ComName = new char[10];
    if (COMx > 9)
        sprintf_s(ComName, 10, "\\\\.\\COM%d", COMx);
    else
        sprintf_s(ComName, 10, "COM%d", COMx);

    h_Com = CreateFileA(ComName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
    if (h_Com == INVALID_HANDLE_VALUE)
    {
        std::cout << "连接错误\n";
        return 1;
    }
    else
    {
        // 设置串口属性
        GetCommState(h_Com, &dcb); // 串口属性配置
        dcb.BaudRate = Baudrate;
        dcb.ByteSize = byte;
        dcb.StopBits = Stopbits;
        dcb.Parity = Parity;
        if (!SetCommState(h_Com, &dcb))
        {
            CloseHandle(h_Com);
            std::cout << "串口配置失败\n";
            return 2;
        }
        PurgeComm(h_Com, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT); // 清空串口缓冲区

        ZeroMemory(&wrOverlapped, sizeof(wrOverlapped));
        if (wrOverlapped.hEvent != NULL)
        {
            ResetEvent(wrOverlapped.hEvent);
            wrOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        }
    }
    delete[] ComName;
    return 0;
}

/*
*	串口超时设置
*	@变量:
        ReadIntervalTimeout:两字符之间最大的延时,当读取串口数据时,一旦两个字符传输的时间差超过该时间,读取函数将返回现有的数据。设置为0表示该参数不起作用。
*		ReadTotalTimeoutMultiplier:读取每字符间的超时。
*		ReadTotalTimeoutConstant:一次读取串口数据的固定超时。所以在一次读取串口的操作中,其超时为ReadTotalTimeoutMultiplier乘以读取的字节数再加上
*												ReadTotalTimeoutConstant。将ReadIntervalTimeout设置为MAXDWORD,并将ReadTotalTimeoutMultiplier
*												和ReadTotalTimeoutConstant设置为0,表示读取操作将立即返回存放在输入缓冲区的字符。
*		WriteTotalTimeoutMultiplier:写入每字符间的超时。
*		WriteTotalTimeoutConstant:一次写入串口数据的固定超时。所以在一次写入串口的操作中,其超时为WriteTotalTimeoutMultiplier乘以写入的字节数再加上 WriteTotalTimeoutConstant。
*/
int usart::TimeOuts_init(int ReadInterval, int ReadTotalMultiplier, int ReadTotalConstant, int WriteTotalMultiplier, int WriteTotalConstant)
{
    TimeOuts.ReadIntervalTimeout = ReadInterval;
    TimeOuts.ReadTotalTimeoutMultiplier = ReadTotalMultiplier;
    TimeOuts.ReadTotalTimeoutConstant = ReadTotalConstant;
    TimeOuts.WriteTotalTimeoutMultiplier = WriteTotalMultiplier;
    TimeOuts.WriteTotalTimeoutConstant = WriteTotalConstant;
    SetCommTimeouts(h_Com, &TimeOuts);
    return 0;
}
/*
 *	串口缓冲区设置
 *		@变量:
 *			rx:输入缓冲区大小
 *			tx:输出缓冲区大小
 */
void usart::SetupComm_set(int rx, int tx)
{
    SetupComm(h_Com, rx, tx);
}
/*
 *	数据发送
 *	@变量:
 *		pSendBuf:数据缓冲区
 *		len:发送数量
 *		dwSend:发送成功数量
 */
int usart::WriteDate(unsigned char *pSendBuf, int len, DWORD *dwSend)
{
    if (ClearCommError(h_Com, &dwError, NULL))
    {
        PurgeComm(h_Com, PURGE_TXABORT | PURGE_TXCLEAR);
    }
    if (!WriteFile(h_Com, pSendBuf, len, dwSend, &wrOverlapped))
    {
        if (GetLastError() == ERROR_IO_PENDING)
        {
            while (!GetOverlappedResult(h_Com, &wrOverlapped, dwSend, FALSE))
            {
                if (GetLastError() == ERROR_IO_INCOMPLETE)
                {
                    continue;
                }
                else
                {
                    std::cout << "数据发送错误\n";
                    ClearCommError(h_Com, &dwError, NULL);
                    return 1;
                }
            }
        }
    }
    return 0;
}
/*
 *	数据接收
 *	@变量:
 *		pReadBuf:数据缓冲区
 *		len:从USB串口缓冲区中读取数量
 *		dwRead:成功读取数量
 */
int usart::ReadDate(unsigned char *pReadBuf, int len, DWORD *dwRead)
{
    if (ClearCommError(h_Com, &dwError, NULL))
    {
        PurgeComm(h_Com, PURGE_RXABORT | PURGE_RXCLEAR);
    }
    if (!ReadFile(h_Com, pReadBuf, len, dwRead, &wrOverlapped))
    {
        if (dwError = GetLastError() == ERROR_IO_PENDING)
        {
            while (!GetOverlappedResult(h_Com, &wrOverlapped, dwRead, FALSE))
            {
                if (GetLastError() == ERROR_IO_INCOMPLETE)
                {
                    continue;
                }
                else
                {
                    std::cout << "数据接收失败" << std::endl;
                    ClearCommError(h_Com, &dwError, NULL);
                    return 1;
                }
            }
        }
    }
    return 0;
}

使用

主程序

#include <iostream>
#include <windows.h>
#include<cstdio>
#include<string.h>
#include "SERIALPPORT/SerialPort.h"

int main()
{	
	usart husart1;
	DWORD len = 0;
	unsigned char chanshu[21] = "hellohellohellohello";
	unsigned char* readbuf = new unsigned char[20];
	husart1.init(13, 115200, 8, ONESTOPBIT, NOPARITY);
	husart1.SetupComm_set(100, 100);
	husart1.TimeOuts_init(1, 1, 0, 0, 0);
	memset(readbuf, 0, 20);
	while (true)
	{
		husart1.WriteDate(chanshu, 20, &len);
		std::cout << "发送数量" << len<<std::endl;
		Sleep(100);
		husart1.ReadDate(readbuf, 10, &len);
		std::cout << "接收到" << readbuf << std::endl;
		std::cout << "接收数量" << len << std::endl;
		Sleep(100);
	}
	delete[] chanshu;
}

这个程序发送chanshu给单片机,单片机收到确认后发送hello给电脑

结束

这个只是我简单的一个学习程序,没办法和站内其他大佬相比,但是胜在简单,不过效率太低了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值