串口发送数据,测试程序 C

1, main.c 文件

#include "WzSerialPort.h"
#include <stdio.h>
#include <string.h>
#include "conio.h"
#include <WinSock2.h>
#include <windows.h>
/*
* 此程序已与虚拟串口程序联合测试,通过!
*/

WzSerialPort::WzSerialPort()
{

}

WzSerialPort::~WzSerialPort()
{

}

bool WzSerialPort::open(const char* portname,
  int baudrate,
  char parity,
  char databit,
  char stopbit,
  FlowControl fc,
  char synchronizeflag)
{
  this->synchronizeflag = synchronizeflag;
  HANDLE hCom = NULL;
  if (this->synchronizeflag)
  {
	//同步方式
	hCom = CreateFileA(portname, //串口名
	  GENERIC_READ | GENERIC_WRITE, //支持读写
	  0, //独占方式,串口不支持共享
	  NULL,//安全属性指针,默认值为NULL
	  OPEN_EXISTING, //打开现有的串口文件
	  0, //0:同步方式,FILE_FLAG_OVERLAPPED:异步方式
	  NULL);//用于复制文件句柄,默认值为NULL,对串口而言该参数必须置为NULL
  }
  else
  {
	//异步方式
	hCom = CreateFileA(portname, //串口名
	  GENERIC_READ | GENERIC_WRITE, //支持读写
	  0, //独占方式,串口不支持共享
	  NULL,//安全属性指针,默认值为NULL
	  OPEN_EXISTING, //打开现有的串口文件
	  FILE_FLAG_OVERLAPPED, //0:同步方式,FILE_FLAG_OVERLAPPED:异步方式
	  NULL);//用于复制文件句柄,默认值为NULL,对串口而言该参数必须置为NULL
  }

  if (hCom == (HANDLE)-1)
  {
	return false;
  }

  //配置缓冲区大小 
  if (!SetupComm(hCom, 1024, 1024))
  {
	return false;
  }

  // 配置参数 
  DCB dcb;

  if (!GetCommState(hCom, &dcb))
  {
	// 获取参数失败
	return false;
  }

  memset(&dcb, 0, sizeof(dcb));
  dcb.DCBlength = sizeof(dcb);
  dcb.BaudRate = baudrate; // 波特率
  dcb.ByteSize = databit; // 数据位

  switch (parity) //校验位
  {
  case 0:
	dcb.Parity = NOPARITY; //无校验
	break;
  case 1:
	dcb.Parity = ODDPARITY; //奇校验
	break;
  case 2:
	dcb.Parity = EVENPARITY; //偶校验
	break;
  case 3:
	dcb.Parity = MARKPARITY; //标记校验
	break;
  }

  switch (stopbit) //停止位
  {
  case 1:
	dcb.StopBits = ONESTOPBIT; //1位停止位
	break;
  case 2:
	dcb.StopBits = TWOSTOPBITS; //2位停止位
	break;
  case 3:
	dcb.StopBits = ONE5STOPBITS; //1.5位停止位
	break;
  }

  //流控设置
  dcb.fDsrSensitivity = FALSE;
  dcb.fTXContinueOnXoff = FALSE;
  dcb.fRtsControl = RTS_CONTROL_DISABLE;
  dcb.fDtrControl = DTR_CONTROL_ENABLE;

  switch (fc)
  {
	//不流控
  case NoFlowControl:
  {
	dcb.fOutxCtsFlow = FALSE;
	dcb.fOutxDsrFlow = FALSE;
	dcb.fOutX = FALSE;
	dcb.fInX = FALSE;
	break;
  }
  //硬件CtsRts流控
  case CtsRtsFlowControl:
  {
	dcb.fOutxCtsFlow = TRUE;
	dcb.fOutxDsrFlow = FALSE;
	dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
	dcb.fOutX = FALSE;
	dcb.fInX = FALSE;
	break;
  }
  //硬件 CtsDtr流控
  case CtsDtrFlowControl:
  {
	dcb.fOutxCtsFlow = TRUE;
	dcb.fOutxDsrFlow = FALSE;
	dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
	dcb.fOutX = FALSE;
	dcb.fInX = FALSE;
	break;
  }
  //硬件DsrRts流控
  case DsrRtsFlowControl:
  {
	dcb.fOutxCtsFlow = FALSE;
	dcb.fOutxDsrFlow = TRUE;
	dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
	dcb.fOutX = FALSE;
	dcb.fInX = FALSE;
	break;
  }
  //硬件DsrDtr流控
  case DsrDtrFlowControl:
  {
	dcb.fOutxCtsFlow = FALSE;
	dcb.fOutxDsrFlow = TRUE;
	dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
	dcb.fOutX = FALSE;
	dcb.fInX = FALSE;
	break;
  }
  //软件流控
  case XonXoffFlowControl:
  {
	dcb.fOutxCtsFlow = FALSE;
	dcb.fOutxDsrFlow = FALSE;
	dcb.fOutX = TRUE;
	dcb.fInX = TRUE;
	dcb.XonChar = 0x11;
	dcb.XoffChar = 0x13;
	dcb.XoffLim = 100;
	dcb.XonLim = 100;
	break;
  }
  }


  if (!SetCommState(hCom, &dcb))
  {
	// 设置参数失败
	return false;
  }

  //超时处理,单位:毫秒
  //总超时=时间系数×读或写的字符数+时间常量
  COMMTIMEOUTS TimeOuts;
  TimeOuts.ReadIntervalTimeout = 1000; //读间隔超时
  TimeOuts.ReadTotalTimeoutMultiplier = 500; //读时间系数
  TimeOuts.ReadTotalTimeoutConstant = 5000; //读时间常量
  TimeOuts.WriteTotalTimeoutMultiplier = 500; // 写时间系数
  TimeOuts.WriteTotalTimeoutConstant = 2000; //写时间常量
  SetCommTimeouts(hCom, &TimeOuts);

  PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);//清空串口缓冲区

  memcpy(pHandle, &hCom, sizeof(hCom));// 保存句柄

  return true;
}
  void WzSerialPort::close()
  {
	HANDLE hCom = *(HANDLE*)pHandle;
	CloseHandle(hCom);
  }

  int WzSerialPort::send(const void* buf, int len)
  {
	HANDLE hCom = *(HANDLE*)pHandle;

	if (this->synchronizeflag)
	{
	  // 同步方式
	  DWORD dwBytesWrite = len; //成功写入的数据字节数
	  BOOL bWriteStat = WriteFile(hCom, //串口句柄
		buf, //数据首地址
		dwBytesWrite, //要发送的数据字节数
		&dwBytesWrite, //DWORD*,用来接收返回成功发送的数据字节数
		NULL); //NULL为同步发送,OVERLAPPED*为异步发送
	  if (!bWriteStat)
	  {
		return 0;
	  }
	  return dwBytesWrite;
	}
	else
	{
	  //异步方式
	  DWORD dwBytesWrite = len; //成功写入的数据字节数
	  DWORD dwErrorFlags; //错误标志
	  COMSTAT comStat; //通讯状态
	  OVERLAPPED m_osWrite; //异步输入输出结构体

	  //创建一个用于OVERLAPPED的事件处理,不会真正用到,但系统要求这么做
	  memset(&m_osWrite, 0, sizeof(m_osWrite));
	  m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, L"WriteEvent");

	  ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通讯错误,获得设备当前状态
	  BOOL bWriteStat = WriteFile(hCom, //串口句柄
		buf, //数据首地址
		dwBytesWrite, //要发送的数据字节数
		&dwBytesWrite, //DWORD*,用来接收返回成功发送的数据字节数
		&m_osWrite); //NULL为同步发送,OVERLAPPED*为异步发送
	  if (!bWriteStat)
	  {
		if (GetLastError() == ERROR_IO_PENDING) //如果串口正在写入
		{
		  WaitForSingleObject(m_osWrite.hEvent, 1000); //等待写入事件1秒钟
		}
		else
		{
		  ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通讯错误
		  CloseHandle(m_osWrite.hEvent); //关闭并释放hEvent内存
		  return 0;
		}
	  }
	  return dwBytesWrite;
	}
  }

  int WzSerialPort::receive(void* buf, int maxlen)
  {
	HANDLE hCom = *(HANDLE*)pHandle;

	if (this->synchronizeflag)
	{
	  //同步方式
	  DWORD wCount = maxlen; //成功读取的数据字节数
	  BOOL bReadStat = ReadFile(hCom, //串口句柄
		buf, //数据首地址
		wCount, //要读取的数据最大字节数
		&wCount, //DWORD*,用来接收返回成功读取的数据字节数
		NULL); //NULL为同步发送,OVERLAPPED*为异步发送
	  if (!bReadStat)
	  {
		return 0;
	  }
	  return wCount;
	}
	else
	{
	  //异步方式
	  DWORD wCount = maxlen; //成功读取的数据字节数
	  DWORD dwErrorFlags; //错误标志
	  COMSTAT comStat; //通讯状态
	  OVERLAPPED m_osRead; //异步输入输出结构体

	  //创建一个用于OVERLAPPED的事件处理,不会真正用到,但系统要求这么做
	  memset(&m_osRead, 0, sizeof(m_osRead));
	  m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, L"ReadEvent");

	  ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通讯错误,获得设备当前状态
	  if (!comStat.cbInQue)return 0; //如果输入缓冲区字节数为0,则返回false

	  BOOL bReadStat = ReadFile(hCom, //串口句柄
		buf, //数据首地址
		wCount, //要读取的数据最大字节数
		&wCount, //DWORD*,用来接收返回成功读取的数据字节数
		&m_osRead); //NULL为同步发送,OVERLAPPED*为异步发送
	  if (!bReadStat)
	  {
		if (GetLastError() == ERROR_IO_PENDING) //如果串口正在读取中
		{
		  //GetOverlappedResult函数的最后一个参数设为TRUE
		  //函数会一直等待,直到读操作完成或由于错误而返回
		  GetOverlappedResult(hCom, &m_osRead, &wCount, TRUE);
		}
		else
		{
		  ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通讯错误
		  CloseHandle(m_osRead.hEvent); //关闭并释放hEvent的内存
		  return 0;
		}
	  }
	  return wCount;
	}
  }

  int getcounts(char str[])
  {
	int i = 0;
	while (str[i] != '\0') 
	{
	  i++;
	}
	  return i;
  }
  int main(void)
  {
	static int i;
	char ch = 'a';
	WzSerialPort TestA;
	char str[127] = "12";
	printf("正在打开串口...\n");
	(TestA.open("COM3", 9600, 0, 8, 1, TestA.NoFlowControl, 0)) ? (printf("串口打开成功!\n")) : (printf("串口打开失败!\n"));
	printf("请输入字符串:\n");
	printf("输入 \"exit\" , 退出程序! \n");

	while (strcmp(str,"exit")!=0)
	{
	  gets_s(str, 127);	  
	  TestA.send(str, getcounts(str));
	  TestA.send("\r\n", sizeof("\r\n"));
	}
	TestA.close();
  }

2,头文件


#ifndef _WZSERIALPORT_H
#define _WZSERIALPORT_H

/*
	类名:WZSerialPort
	用途:串口读写
	示例:
		参考 main.cpp
*/


class WzSerialPort
{
public:
  enum FlowControl
  {
	NoFlowControl,
	CtsRtsFlowControl,
	CtsDtrFlowControl,
	DsrRtsFlowControl,
	DsrDtrFlowControl,
	XonXoffFlowControl
  };

  WzSerialPort();
  ~WzSerialPort();

  // 打开串口,成功返回true,失败返回false
  // portname(串口名): 在Windows下是"COM1""COM2"等,在Linux下是"/dev/ttyS1"等
  // baudrate(波特率): 9600、19200、38400、43000、56000、57600、115200 
  // parity(校验位): 0为无校验,1为奇校验,2为偶校验,3为标记校验(仅适用于windows)
  // databit(数据位): 4-8(windows),5-8(linux),通常为8位
  // stopbit(停止位): 1为1位停止位,2为2位停止位,3为1.5位停止位
  // synchronizeflag(同步、异步,仅适用与windows): 0为异步,1为同步
  bool open(const char* portname, int baudrate, char parity, char databit, char stopbit, FlowControl fc, char synchronizeflag = 1);

  //关闭串口,参数待定
  void close();

  //发送数据或写数据,成功返回发送数据长度,失败返回0
  int send(const void* buf, int len);

  //接受数据或读数据,成功返回读取实际数据的长度,失败返回0
  int receive(void* buf, int maxlen);

private:
  int pHandle[16];
  char synchronizeflag;
};
#endif

3, 主要文件借用了 博主 SunkingYang 的文章中的内容,如有不合适的,请私信我删除!

4,以上代码 与 vspd 虚拟串口程序 测试通过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值