使用Windows API实现一个简单的串口助手

目录

使用window API开发一个具有字符串收发功能的串口助手

开发环境

  • Visual Studio 2015

串口设备相关的API

// 函数原型 
HANDLE WINAPI CreateFile(
  _In_      LPCTSTR lpFileName,
  _In_      DWORD dwDesiredAccess,
  _In_      DWORD dwShareMode,
  _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  _In_      DWORD dwCreationDisposition,
  _In_      DWORD dwFlagsAndAttributes,
  _In_opt_  HANDLE hTemplateFile
);

BOOL WINAPI SetCommState(
  _In_  HANDLE hFile,
  _In_  LPDCB lpDCB
);

BOOL WINAPI GetCommState(
  _In_     HANDLE hFile,
  _Inout_  LPDCB lpDCB
);

BOOL ReadFile(
  HANDLE hFile,
  LPVOID lpBuffer,
  DWORD nNumberOfBytesToRead,
  LPDWORD lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);

BOOL WriteFile( 
  HANDLE hFile, 
  LPCVOID lpBuffer, 
  DWORD nNumberOfBytesToWrite, 
  LPDWORD lpNumberOfBytesWritten, 
  LPOVERLAPPED lpOverlapped
);

BOOL PurgeComm(
  HANDLE hFile,
  DWORD dwFlags
);

BOOL CloseHandle(
  HANDLE hObject
);

步骤

  1. 创建一个设备句柄
  2. 创建一个设备文件
  3. 配置串口参数
  4. 创建读写线程
  5. 对设备文件进行读写
  6. 退出线程后关闭设备文件

实现代码

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>

HANDLE hCom; // 句柄,用于初始化串口

DWORD WINAPI ThreadWrite(LPVOID lpParameter)
{
	char outputData[100] = { 0x00 }; // 输出数据缓存

	if (hCom == INVALID_HANDLE_VALUE)
	{
		puts("打开串口失败");
		return 0;
	}

	DWORD strLength = 0;
	while (1)
	{
		for (int i = 0; i < 100; i++)
		{
			outputData[i] = 0;
		}
		fgets(outputData, 100, stdin); // 从控制台输入字符串
		strLength = strlen(outputData);
		printf("发送了%d个字节\r\n", strLength); // 打印字符串长度
		WriteFile(hCom, outputData, strLength, &strLength, NULL); // 串口发送字符串
		fflush(stdout);
		PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR); // 清空缓冲区
		Sleep(100);
	}
	return 0;
}

DWORD WINAPI ThreadRead(LPVOID lpParameter)
{
        // INVALID_HANDLE_VALUE表示出错,会设置GetLastError
	if (hCom == INVALID_HANDLE_VALUE)   
	{
	        puts("打开串口失败");
		return 0;
	}
	char getputData[100] = { 0x00 }; // 输入数据缓存
	// 利用错误信息来获取进入串口缓冲区数据的字节数
	DWORD dwErrors; // 错误信息
	COMSTAT Rcs; // COMSTAT结构通信设备的当前信息
	int Len = 0;
	DWORD length = 100; //用来接收读取的字节数
	while (1)
	{
		for (int i = 0; i < 100; i++)
		{
			getputData[i] = 0;
		}

		ClearCommError(hCom, &dwErrors, &Rcs); // 获取读缓冲区数据长度
		Len = Rcs.cbInQue;
		ReadFile(hCom, getputData, Len, &length, NULL);  // 获取字符串
		PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);  // 清空缓冲区
		if (Len > 0)
		{
			printf("接收的数据为:%s\r\n", getputData);
			fflush(stdout);
		}
		Sleep(100);
	}
	return 0;
}

int main()
{
	// 初始化串口
	TCHAR *com_name = (TCHAR *)malloc(10 * sizeof(TCHAR));
	do
	{
		printf("请输入需要打开的串口号(示例:COM2):");
		scanf("%s",com_name);
		getchar();
		hCom = CreateFile(com_name, GENERIC_READ | GENERIC_WRITE, 
                        0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hCom == INVALID_HANDLE_VALUE)
			printf("串口号不存在,请重新输入!\n");
		else
			break;
	} while (1);
	free(com_name);

	// 获取和设置串口参数
	DCB myDCB;
	myDCB.BaudRate = 115200;       // 波特率
	myDCB.Parity = NOPARITY;     // 校验位
	myDCB.ByteSize = 8;          // 数据位
	myDCB.StopBits = ONESTOPBIT; // 停止位
	SetCommState(hCom, &myDCB);  // 设置串口参数
	printf("baud rate is %d\n", (int)myDCB.BaudRate);

	// 线程创建
	HANDLE HRead, HWrite;
	HWrite = CreateThread(NULL, 0, ThreadWrite, NULL, 0, NULL);
	HRead = CreateThread(NULL, 0, ThreadRead, NULL, 0, NULL);

	while (1);

	CloseHandle(HRead);
	CloseHandle(HWrite);
        CloseHandle(hCom);
	return 0;
}

收发测试图

  • 备注(左边为自己开发的串口软件,右边为正点原子团队开发的XCOM V2.0串口上位机软件)

使用Windows API实现一个简单的串口助手