各位,由于编程需要,现在要将在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];
}