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

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

目录

  • 使用window API开发一个具有字符串收发功能的串口助手
    • 开发环境
    • 串口设备相关的API
    • 步骤
    • 实现代码
    • 收发测试图

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

开发环境

  • Visual Studio 2015

串口设备相关的API

  • CreateFile
    参数详情见:CreateFileA function (fileapi.h) - Win32 apps | Microsoft Learn

  • SetCommState
    参数详情见:SetCommState function (winbase.h) - Win32 apps | Microsoft Learn

  • GetCommState
    参数详情见:GetCommState function (winbase.h) - Win32 apps | Microsoft Learn

  • ReadFile
    参数详情见:ReadFile (Compact 2013) | Microsoft Learn

  • WriteFile
    参数详情见:WriteFile (Compact 2013) | Microsoft Learn

  • PurgeComm
    参数详情见:PurgeComm (Compact 2013) | Microsoft Learn

  • CloseHandle
    参数详情见:CloseHandle (Compact 2013) | Microsoft Learn


// 函数原型 
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串口上位机软件)

图片资源加载失败

Posted By veis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/445874.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL | 第四篇】区分SQL语句的书写和执行顺序

文章目录 4.区分SQL语句的书写和执行顺序4.1书写顺序4.2执行顺序4.3总结4.4扩充&#xff1a;辨别having与where的异同&#xff1f;4.5聚合查询 4.区分SQL语句的书写和执行顺序 注意&#xff1a;SQL 语句的书写顺序与执行顺序不是一致的 4.1书写顺序 SELECT <字段名> …

Nwatch在stm32上的移植

目录 Nwatch在stm32上的移植前言实验目的移植game1_task任务相关代码片段结果本文中使用的工程 Nwatch在stm32上的移植 本文目标&#xff1a;Nwatch在stm32上的移植 按照本文的描述&#xff0c;应该可以跑通实验并举一反三。 先决条件&#xff1a;装有编译和集成的开发环境&…

不允许你不知道Python作用域

在Python中&#xff0c;变量的作用域限制非常重要。根据作用域分类&#xff0c;有局部、全局、函数和内建作用域。无作用域限制的变量可以在分支语句和循环中定义&#xff0c;并在外部直接访问。不同的作用域决定了变量的可访问范围&#xff0c;访问权限取决于变量的位置。 1.…

力扣中档题:旋转链表

思路&#xff1a;将链表数据放到数组中&#xff0c;将数组旋转&#xff0c;然后再赋值给链表 struct ListNode* rotateRight(struct ListNode* head, int k) {if(headNULL){return NULL;}int count0;struct ListNode*goodhead;while(good){count;goodgood->next;}int round…

解锁网络数据:入门级IP代理使用教程

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

10 vector的使用

文档介绍 文档介绍 1.vector是表示可变大小数组的容器 2.就像数组一样&#xff0c;vecotr也采用的连续存储空间来存储元素&#xff0c;也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;大小是可以动态改变的&#xff…

【Web】浅聊Java反序列化之C3P0——URLClassLoader利用

目录 前言 C3P0介绍 回归本源——序列化的条件 利用链 利用链分析 入口——PoolBackedDataSourceBase#readObject 拨云见日——PoolBackedDataSourceBase#writeObject 综合分析 EXP 前言 这条链最让我眼前一亮的就是对Serializable接口的有无进行了一个玩&#xff0c…

权限管理系统-0.2.0

三、菜单管理接口 3.1 创建SysMenu类及相关类 首先创建sys_menu表&#xff1a; CREATE TABLE sys_menu (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,parent_id bigint(20) NOT NULL DEFAULT 0 COMMENT 所属上级,name varchar(20) NOT NULL DEFAULT COMMENT 名称,…

【脚本玩漆黑的魅影】寂雨镇全自动练级

文章目录 原理全部代码 原理 老样子。 治疗路径&#xff0c;练级路径。 def zhi_liao(): # 去治疗walk(RIGHT)walk(RIGHT)press(UP, 0.4)for i in [1, 2, 3, 4]:press(A)for i in [1, 2, 3, 4]:press(B)press(DOWN, 0.4)press(LEFT) def chu_qu(): # 右逛c.press(B)press(…

力扣同类题:重排链表

很明显做过一次 class Solution { public:void reorderList(ListNode* head) {if(!head||!head->next)return;ListNode *fasthead,*lowhead;ListNode *prenullptr,*curnullptr,*nextnullptr;while(fast->next!nullptr){fastfast->next;if(fast->next)fastfast->…

风控规则决策树可视化(升级版)

上一篇我们介绍了如何通过交叉表来生成规则&#xff0c;本篇我们来介绍一种可以生成多规则的方法&#xff0c;决策树。除了做模型以外&#xff0c;也可以用来挖掘规则&#xff0c;原理是一样的。 下面通过sklearn的决策树方法来实现风控规则的发现&#xff0c;同时分享一种可以…

【联邦学习综述:概念、技术】

出自——联邦学习综述&#xff1a;概念、技术、应用与挑战。梁天恺 1*&#xff0c;曾 碧 2&#xff0c;陈 光 1 从两个方面保护隐私数据 硬件层面 可 信 执 行 环 境 &#xff08;Trusted Execution Environment&#xff0c;TEE&#xff09;边 缘 计 算&#xff08;Edge Com…

电动车窗开关中MOS管的应用解析

随着科技的不断发展&#xff0c;电动车窗系统已经成为现代汽车中不可或缺的一部分。而MOS&#xff08;金属氧化物半导体&#xff09;管的应用&#xff0c;为电动车窗开关注入了新的活力&#xff0c;极大地提高了其使用寿命和安全性。 一、MOS的优越性能 MOS管以其卓越的开关…

磁盘无法访问?别慌,这里有解决之道!

电脑中&#xff0c;那块储存着重要文件与数据的磁盘&#xff0c;突然之间无法访问&#xff0c;是不是让你感到惊慌失措&#xff1f;面对这样的突发状况&#xff0c;很多人可能会感到手足无措。但别担心&#xff0c;本文将为你解析磁盘无法访问的原因&#xff0c;并提供实用的数…

小文件问题及GlusterFS的瓶颈

01海量小文件存储的挑战 为了解决海量小文件的存储问题&#xff0c;必须采用分布式存储&#xff0c;目前分布式存储主要采用两种架构&#xff1a;集中式元数据管理架构和去中心化架构。 (1)集中式元数据架构&#xff1a; 典型的集中式元数据架构的分布式存储有GFS&#xff0…

代码讲解:如何把3D数据转换成旋转的视频?

目录 3D数据集下载 读取binvox文件 使用matplotlib创建图 动画效果 完整代码 3D数据集下载 这里以shapenet数据集为例&#xff0c;可以访问外网的可以去直接申请下载&#xff1b;我也准备了一个备份在百度网盘的数据集&#xff0c;可以参考&#xff1a; ShapeNet简介和下…

Leetcode 54. 螺旋矩阵

题目描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a; 输入&a…

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现

Linux文件系列: 深入理解缓冲区和C标准库的简易模拟实现 一.缓冲区的概念和作用二.一个样例三.理解样例1.样例解释2.什么是刷新? 四.简易模拟实现C标准库1.我们要实现的大致框架2.mylib.h的实现1.文件结构体的定义2.myfopen等等函数的声明3.完整mylib.h代码 3.myfopen函数的实…

备战蓝桥杯Day25 - 二叉搜索树

一、基本概念 二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;又称为二叉查找树或二叉排序树&#xff0c;是一种具有特定性质的二叉树。 定义&#xff1a;二叉搜索树可以是一棵空树&#xff0c;也可以是具有以下特性的非空二叉树&#xff1a; 若其左子树不…

MAC OS 14.2.1 ASP.NET Core 调试遇到的端口占用的问题

一、问题描述 在调试 ASP.NET Core 项目时&#xff0c;遇到一个很奇怪的问题&#xff0c;不管项目是否已经运行&#xff0c;使用 Postman 测试接口时&#xff0c;都返回 403 Forbidden。重启电脑&#xff0c;刚开始还好好的&#xff0c;过一会儿就返回 403 Forbidden。 二、问…