赞
踩
一、串口通信的基本原理
串口的本质功能是作为 CPU 和串行设备间的编码转换器。当数据从 CPU 经过串行端口发送出去时,字节数据转换为串行的位(bit);在接收数据时,串行的位被转换为字节数据。应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。典型地,串口用于 ASCII 码字符的传输。通信使用3根线完成:地线,发送数据线,接收数据线。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配:
(1)波特率是一个衡量通信速度的参数,它表示每秒钟传送的 bit 的个数;
(2)数据位是衡量通信中实际数据位的参数,当计算机发送一个信息包,标准的值是 5,7 和 8 位。如何设置取决于你的需求;
(3)停止位用于表示单个包的最后一位,典型的值为 1,1.5和 2 位,停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会;
(4)奇偶校验位是串口通信中一种简单的检错方式,有四种检错方式——偶、奇、高和低,也可以没有校验位。
二、C++代码实现
1、头文件“SerialPort.h”
- #ifndef _CSerialPort_H
- #define _CSerialPort_H
- using namespace std;
-
- class CSerialPort
- {
- public:
- CSerialPort();
- ~CSerialPort();
-
- // 打开串口,成功返回true,失败返回false
- // portname(串口名): 在Windows下是"COM1""COM2"等,在Linux下是"/dev/ttyS1"等
- // baudrate(波特率): 9600、19200、38400、43000、56000、57600、115200
- // parity(校验位): 0为无校验,1为奇校验,2为偶校验,3为标记校验
- // databit(数据位): 4-8,通常为8位
- // stopbit(停止位): 1为1位停止位,2为2位停止位,3为1.5位停止位
- // synchronizable(同步、异步): 0为异步,1为同步
- bool open(const char* portname, int baudrate = 115200, char parity = 0, char databit = 8, char stopbit = 1, char synchronizeflag = 0);
-
- //关闭串口,参数待定
- void close();
-
- //发送数据或写数据,成功返回发送数据长度,失败返回0
- int send(string dat);
-
- //接受数据或读数据,成功返回读取实际数据的长度,失败返回0
- string receive();
-
- private:
- int pHandle[16];
- char synchronizeflag;
- };
-
- #endif
2、cpp文件“SerialPort.cpp”
- #include "stdafx.h"
- #include "SerialPort.h"
- #include <WinSock2.h>
-
- using namespace std;
-
- CSerialPort::CSerialPort()
- {
-
- }
-
- CSerialPort::~CSerialPort()
- {
-
- }
-
- bool CSerialPort::open(const char* portname, int baudrate, char parity, char databit, char stopbit, 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 p;
- memset(&p, 0, sizeof(p));
- p.DCBlength = sizeof(p);
- p.BaudRate = baudrate; // 波特率
- p.ByteSize = databit; // 数据位
-
- switch (parity) //校验位
- {
- case 0:
- p.Parity = NOPARITY; //无校验
- break;
- case 1:
- p.Parity = ODDPARITY; //奇校验
- break;
- case 2:
- p.Parity = EVENPARITY; //偶校验
- break;
- case 3:
- p.Parity = MARKPARITY; //标记校验
- break;
- }
-
- switch (stopbit) //停止位
- {
- case 1:
- p.StopBits = ONESTOPBIT; //1位停止位
- break;
- case 2:
- p.StopBits = TWOSTOPBITS; //2位停止位
- break;
- case 3:
- p.StopBits = ONE5STOPBITS; //1.5位停止位
- break;
- }
-
- if (!SetCommState(hCom, &p))
- {
- // 设置参数失败
- 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 CSerialPort::close()
- {
- HANDLE hCom = *(HANDLE*)pHandle;
- CloseHandle(hCom);
- }
-
- int CSerialPort::send(string dat)
- {
- HANDLE hCom = *(HANDLE*)pHandle;
-
- if (this->synchronizeflag)
- {
- // 同步方式
- DWORD dwBytesWrite = dat.length(); //成功写入的数据字节数
- BOOL bWriteStat = WriteFile(hCom, //串口句柄
- (char*)dat.c_str(), //数据首地址
- dwBytesWrite, //要发送的数据字节数
- &dwBytesWrite, //DWORD*,用来接收返回成功发送的数据字节数
- NULL); //NULL为同步发送,OVERLAPPED*为异步发送
- if (!bWriteStat)
- {
- return 0;
- }
- return dwBytesWrite;
- }
- else
- {
- //异步方式
- DWORD dwBytesWrite = dat.length(); //成功写入的数据字节数
- 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, //串口句柄
- (char*)dat.c_str(), //数据首地址
- 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;
- }
- }
-
- string CSerialPort::receive()
- {
- HANDLE hCom = *(HANDLE*)pHandle;
- string rec_str = "";
- char buf[1024];
- if (this->synchronizeflag)
- {
- //同步方式
- DWORD wCount = 1024; //成功读取的数据字节数
- BOOL bReadStat = ReadFile(hCom, //串口句柄
- buf, //数据首地址
- wCount, //要读取的数据最大字节数
- &wCount, //DWORD*,用来接收返回成功读取的数据字节数
- NULL); //NULL为同步发送,OVERLAPPED*为异步发送
- for (int i = 0; i < 1024; i++)
- {
- if (buf[i] != -52)
- rec_str += buf[i];
- else
- break;
- }
- return rec_str;
- }
- else
- {
- //异步方式
- DWORD wCount = 1024; //成功读取的数据字节数
- 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
- //std::cout << comStat.cbInQue << std::endl;
- 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;
- }
- }
- for (int i = 0; i<1024; i++)
- {
- if (buf[i] != -52)
- rec_str += buf[i];
- else
- break;
- }
- return rec_str;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。