前言
最近学习需要用到电脑获取数据传输给单片机,但奈何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给电脑
结束
这个只是我简单的一个学习程序,没办法和站内其他大佬相比,但是胜在简单,不过效率太低了