各位,由于编程需要,现在要将在VC++下编写的串口程序改写在qt平台下,但是本人对Qt串口通信着实不熟悉,鼓捣了几天还是没有成功,因此在此向各位大侠请教。
主要就是从传感器获取数据,十六进制的数据包,例如:
55 AA 5A f3 07 00 00 00 01 05 59
55是包头
07后面的00 00 00 01 05是数据块。59是校验和,也就是数据块之和。
不停的发送,而程序这边设置的每隔200ms接收一次,当然要保证数据的完整性,然后再解析成十进制的数据发送到绘图界面。大致就是这样一个功能.
下面是VC源代码:
comm.h
#pragma once
#include <iostream>
#include <fstream>
using namespace std;
#define FORMAT setiosflags(ios::fixed) << setiosflags(ios::left) << setw(19)
typedef struct _CMD_BAG1
{
byte byHead[3]; // 包头:0x55、0xAA、0x5A
byte byCode; // 命令码:0x00(采集数据);0x01(停止采集)
unsigned short usLength; // 包长:包头和数据块的字节数,即3+4
byte byData[4]; // 数据块
byte byChkUnit; // 校验和
}CMD_BAG1; // 命令长度为11 Bytes
typedef struct _CMD_BAG2
{
byte byHead[3];
byte byData[8];
}CMD_BAG2; // 命令长度为11 Bytes
typedef union _COMM_BAG
{
CMD_BAG1 CmdBag1;
CMD_BAG2 CmdBag2;
byte byData[11]; // 用sizeof获取变量类型的大小时与编译器的对齐方式有关,此处sizeof(CMD_BAG)=12,故需减1
}COMM_BAG;
class CComm
{
public:
CComm(void);
~CComm(void);
bool Init(void);
static DWORD WINAPI ReadPortThread(LPVOID lpParameter);
void ReadRecvData(void);
void SearchBagHead(byte lbyData);
void ReceiveCmdInBag(byte byRecvChar);
void handleSampData(void);
ULONG ObtainTotalWatt(void);
public:
HANDLE m_hComm;
HANDLE m_hCommRecvThread;
bool bIsHeadArrived;
ULONG ulRecvDataCnt;
COMM_BAG CommInData;
ofstream flPowerPara;
ULONG ulSampDataArrayCnt;
ULONG ulTotalWatt;
};
extern CComm MyComm;
comm.cpp
#include "StdAfx.h"
#include "Comm.h"
CComm MyComm;
CComm::CComm(void)
{
m_hComm = INVALID_HANDLE_VALUE;
m_hCommRecvThread = NULL;
ulTotalWatt = 0;
}
CComm::~CComm(void)
{
if (flPowerPara.is_open())
{
flPowerPara.close();
//CloseHandle(flPowerPara);
}
if (m_hComm != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hComm);
}
}
// 初始化可用串口,打开数据采集线程和数据文件,成功则返回true,失败则返回false
bool CComm::Init(void)
{
CString lcString;
byte i;
for (i=0; i<8; ++i)
{ // 最多搜索八个串口单元
lcString.Format(_T("COM%d:"), i+1);
m_hComm = CreateFile(lcString, // 文件名
GENERIC_READ | GENERIC_WRITE, // 允许读和写
0, // 独占方式
NULL,
OPEN_EXISTING, // 打开端口而不是创建
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 重叠方式
NULL
);
if (m_hComm != INVALID_HANDLE_VALUE)
{ // 串口已打开
DCB dcb;
GetCommState(m_hComm, &dcb); // 获取串口状态并保存在dcb中
dcb.BaudRate = 9600; // 波特率为9600
dcb.ByteSize = 8; // 端口使用的数据为8bits
dcb.Parity = NOPARITY; // 无奇偶校验
dcb.StopBits = ONESTOPBIT; // 1bit停止位
dcb.fBinary = true; // 二进制方式
dcb.fParity = false; // 不允许奇偶校验
dcb.DCBlength = sizeof(DCB);
if (SetCommState(m_hComm, &dcb))
{
COMMTIMEOUTS CommTimeouts; // 用于超时设置
GetCommTimeouts(m_hComm, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0; // 读时间系数
CommTimeouts.ReadTotalTimeoutConstant = 0; // 读时间常数
CommTimeouts.WriteTotalTimeoutMultiplier = 50; // 写时间系数
CommTimeouts.WriteTotalTimeoutConstant = 100; // 写时间常数
if (SetCommTimeouts(m_hComm, &CommTimeouts))
{
SetupComm(m_hComm, 1024, 1024); // 设置输入输出缓冲区
SetCommMask(m_hComm, EV_RXCHAR); // 通信事件(接收到一个字符,并放入输入缓冲区)
PurgeComm(m_hComm, PURGE_TXABORT | PURGE_RXABORT
| PURGE_TXCLEAR | PURGE_RXCLEAR); // 终止所有正在进行的字符输入/出操作和清除串口输入/出缓冲区
if (!flPowerPara.is_open())
{
ulSampDataArrayCnt = 0; // 采集数据清零
//flPowerPara.open(_T("C:\\PowerPara.txt")); // 打开数据采集文件
flPowerPara.open(_T("\\NAND FLASH\\PM\\PowerPara.txt")); // 打开数据采集文件
}
if (NULL == m_hCommRecvThread)
{
m_hCommRecvThread = CreateThread(NULL, 0, ReadPortThread,
NULL, 0, NULL); // 开启串口接收数据线程
}
}
}
printf("COM%d打开成功!", i+1);
return true;
}
}
return false;
}
DWORD WINAPI CComm::ReadPortThread(LPVOID lpParameter)
{
while (true)
{
MyComm.ReadRecvData();
}
return 0;
}
// 采集数据
void CComm::ReadRecvData(void)
{
byte lbyData;
DWORD evtMask;
byte * readBuf = NULL; // 读取的字节
DWORD actualReadLen = 0; // 实际读取的字节数
DWORD willReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
if (WaitCommEvent(m_hComm, &evtMask, 0))
{
if (evtMask & EV_RXCHAR)
{ // 串口收到字符
ClearCommError(m_hComm, &dwReadErrors, &cmState);
willReadLen = cmState.cbInQue;
if (willReadLen <= 0)
{
return;
}
readBuf = new BYTE[willReadLen];
ReadFile(m_hComm, readBuf, willReadLen, &actualReadLen, 0);
if (actualReadLen > 0)
{ // 串口已接收字符
byte *buf = readBuf;
for (ULONG i=0; i<actualReadLen; ++i, ++buf)
{
lbyData = *buf; // 获取指针所指地址的值
if (!bIsHeadArrived)
{ // 包头尚未到达,搜索包头
SearchBagHead(lbyData);
}
else
{ // 命令包尚未到达,搜索命令包
if (ulRecvDataCnt > 8)
{
bIsHeadArrived = false;
}
else
{
ReceiveCmdInBag(lbyData);
}
}
}
}
}
}
if (readBuf != NULL)
{
delete readBuf;
readBuf = NULL;
}
}
// 搜索包头
void CComm::SearchBagHead(byte lbyData)
{
CommInData.CmdBag1.byHead[0] = CommInData.CmdBag1.byHead[1]; // 移动包头缓冲区
CommInData.CmdBag1.byHead[1] = CommInData.CmdBag1.byHead[2];
CommInData.CmdBag1.byHead[2] = lbyData;
if ((CommInData.CmdBag1.byHead[0] == 0x55) && (CommInData.CmdBag1.byHead[1] == 0xaa) && (CommInData.CmdBag1.byHead[2] == 0x5a))
{
bIsHeadArrived = true; // 设置包头到达标志
ulRecvDataCnt = 0; // 复位接收数据计数器
}
}
// 获取采集数据
void CComm::ReceiveCmdInBag(byte byRecvChar)
{
byte lbyChekSum;
CommInData.CmdBag2.byData[ulRecvDataCnt] = byRecvChar; // 数据移入缓冲区
if (ulRecvDataCnt > 2)
{
if (CommInData.CmdBag1.usLength == ulRecvDataCnt)
{ // 包长接收完毕
bIsHeadArrived = false; // 包头到达标志复位,允许下次包头接收
lbyChekSum = 0;
for (byte i=0; i<ulRecvDataCnt+3; i++)
{
lbyChekSum += CommInData.byData; // 计算校验和
}
if (lbyChekSum == CommInData.CmdBag2.byData[ulRecvDataCnt])
{ // 接收正确
handleSampData(); // 处理采集数据
}
}
}
++ulRecvDataCnt;
}
// 解析数据
void CComm::handleSampData(void)
{
CString lcsChar, lcsString;
ULONG lulData;
lulData = (ULONG)CommInData.CmdBag1.byData[0]*1000 + (ULONG)CommInData.CmdBag1.byData[1]*100
+ (ULONG)CommInData.CmdBag1.byData[2]*10 + (ULONG)CommInData.CmdBag1.byData[3];
}