串口通信代碼

一、串口通信涉及的主要函數:
Windows處理串口和其他通信設備都是作爲文件處理的,基本步驟爲打開串口->初始化串口->數據讀寫->關閉串口;
1>打開串口:
CreateFile(串口名、訪問權限、共享模式、安全屬性、指定文件不存在或者存在的操作、屬性和標誌位、句柄)
2>初始化串口: 獲取串口參數、設置串口參數、設置緩衝區大小、清空緩衝區
GetCommState(句柄、指向設備控制塊DCB)
SetCommState(句柄、DCB)
SetupComm(句柄、接收緩衝區大小、發送緩衝區大小)
PurgeComm(句柄、發送緩衝區/接收緩衝區清空)
3>數據讀寫:
ReadFile(句柄、可選參數、字節數、實際讀取字節數、結構體指針)
WriteFile(句柄、可選參數、字節數、實際讀取字節數、結構體指針)
4>關閉串口:
CloseHandle(句柄)

二、本文編程實現說明:
讀數據是在打開串口之後,開啓一個線程讀取數據,與寫數據同步進行;
讀數據也可以直接調用類的方法來實現(即serial.GetData());
串口號(COM2),波特率(每秒傳送多少位pbs);
在沒有串口的電腦上實現,除了需要下述代碼,還需要下載虛擬串口和串口調試助手,以方便驗證;

三、編碼實現:
MainpulateCom.cpp

#include"stdafx.h"
#include <windows.h>
#include "Serial.h"
#include <string.h>
#include<tchar.h>
#pragma comment(lib,"User32.lib")

int main()
{
    CSerial serial;
    serial.OpenSerialPort(_T("COM2:"), 9600, 8, 1);  //打開串口後,自動接收數據

    //向串口發送數據
    char* data = "This is a example\n";
    int ret = 1;
    while (ret != IDNO) 
    {
        serial.SendData(data, strlen(data));
        ret = MessageBox(NULL, _T(""), _T("是否向串口發送數據"), MB_YESNO); //YES繼續發送一條數據,NO不發送,退出
    }

    //從串口讀取數據
    //serial.GetData();
    return 0;
}

Serial.h

#pragma once

#include <windows.h>

class CSerial
{
public:
    CSerial(void);
    ~CSerial(void);

    //打開串口
    BOOL OpenSerialPort(TCHAR* port, UINT baud_rate, BYTE date_bits, BYTE stop_bit, BYTE parity = NOPARITY);

    //發送數據
    BOOL SendData(char* data, int len);

    //接收數據
    BOOL GetData();
public:
    HANDLE m_hComm;//串口句柄
};

Serial.cpp

#include "StdAfx.h"
#include "Serial.h"
#include"WinUser.h"
#include <process.h>

typedef unsigned(__stdcall *PTHREAD_START) (void *);

CSerial::CSerial(void)
{
    m_hComm = INVALID_HANDLE_VALUE;
}

CSerial::~CSerial(void)
{
    if (m_hComm != INVALID_HANDLE_VALUE) {
        CloseHandle(m_hComm);
    }
}

//*********************************************************************************************
//* 功能: 讀串口線程回調函數
//* 描述: 收到數據後,簡單的顯示出來
//* 函數: PurgeComm;ReadFile
//*********************************************************************************************
DWORD WINAPI CommProc(LPVOID lpParam)
{
    CSerial* pSerial = (CSerial*)lpParam;

    //清空串口
    PurgeComm(pSerial->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

    char buf[512];
    DWORD dwRead;
    while (pSerial->m_hComm != INVALID_HANDLE_VALUE) {
        BOOL bReadOK = ReadFile(pSerial->m_hComm, buf, 512, &dwRead, NULL);
        if (bReadOK && (dwRead > 0))
        {
            buf[dwRead] = '\0';
            MessageBoxA(NULL, buf, "串口收到數據", MB_OK);
        }
    }
    return 0;
}

BOOL CSerial::GetData()
{
    if (m_hComm == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, _T("串口未打開"), _T("提示"), MB_OK);
        return FALSE;
    }

    //清空串口
    PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

    char buf[512] = {0};
    DWORD dwRead;
    while (m_hComm != INVALID_HANDLE_VALUE)
    {
        BOOL bReadOK = ReadFile(m_hComm, buf, 512, &dwRead, NULL);
        if (bReadOK && (dwRead > 0))
        {
            buf[dwRead] = '\0';
            MessageBoxA(NULL, buf, "串口收到數據", MB_OK);
            ////清空串口
            //PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);
        }
    }
    return 0;
}

/*******************************************************************************************
* 功能     :  打開串口
* port     :    串口號, 如_T("COM2:")
* baud_rate:    波特率
* date_bits:    數據位(有效範圍4~8)
* stop_bit :    停止位
* parity   :    奇偶校驗。默認爲無校驗。NOPARITY 0; ODDPARITY 1;EVENPARITY 2;MARKPARITY 3;SPACEPARITY 4
*函數    :    CreateFile;SetCommState;SetCommMask;SetupComm;CommTimeOuts
********************************************************************************************/
BOOL CSerial::OpenSerialPort(TCHAR* port, UINT baud_rate, BYTE date_bits, BYTE stop_bit, BYTE parity) 
{
    //獨佔方式打開串口(串口名,訪問權限,共享,安全屬性,文件存在或不存在操作,屬性和標誌位,句柄)
    m_hComm = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

    TCHAR err[512];

    if (m_hComm == INVALID_HANDLE_VALUE)
    {
        _stprintf(err, _T("打開串口%s 失敗,請查看該串口是否已被佔用"), port);
        MessageBox(NULL, err, _T("提示"), MB_OK);
        return FALSE;
    }

    //MessageBox(NULL,_T("打開成功"),_T("提示"),MB_OK);

    //獲取串口默認配置(設備控制塊DCB)
    DCB dcb;
    if (!GetCommState(m_hComm, &dcb)) 
    {
        MessageBox(NULL, _T("獲取串口當前屬性參數失敗"), _T("提示"), MB_OK);
    }

    //配置串口參數
    dcb.BaudRate = baud_rate;   //波特率
    dcb.fBinary = TRUE;         //二進制模式。必須爲TRUE
    dcb.ByteSize = date_bits;   //數據位。範圍4-8
    dcb.StopBits = ONESTOPBIT;  //停止位

    if (parity == NOPARITY) {
        dcb.fParity = FALSE;    //奇偶校驗。無奇偶校驗
        dcb.Parity = parity;    //校驗模式。無奇偶校驗
    }
    else 
    {
        dcb.fParity = TRUE;     //奇偶校驗。
        dcb.Parity = parity;    //校驗模式。無奇偶校驗
    }

    dcb.fOutxCtsFlow = FALSE;   //CTS線上的硬件握手
    dcb.fOutxDsrFlow = FALSE;   //DST線上的硬件握手
    dcb.fDtrControl = DTR_CONTROL_ENABLE; //DTR控制
    dcb.fDsrSensitivity = FALSE;
    dcb.fTXContinueOnXoff = FALSE;//
    dcb.fOutX = FALSE;          //是否使用XON/XOFF協議
    dcb.fInX = FALSE;           //是否使用XON/XOFF協議
    dcb.fErrorChar = FALSE;     //是否使用發送錯誤協議
    dcb.fNull = FALSE;          //停用null stripping
    dcb.fRtsControl = RTS_CONTROL_ENABLE;//
    dcb.fAbortOnError = FALSE;  //串口發送錯誤,並不終止串口讀寫

    //設置串口參數
    if (!SetCommState(m_hComm, &dcb)) 
    {
        MessageBox(NULL, _T("設置串口參數失敗"), _T("提示"), MB_OK);
        return FALSE;
    }

    //設置串口事件
    SetCommMask(m_hComm, EV_RXCHAR); //在緩存中有字符時產生事件
    SetupComm(m_hComm, 16384, 16384);

    //設置串口讀寫時間
    COMMTIMEOUTS CommTimeOuts;
    GetCommTimeouts(m_hComm, &CommTimeOuts);
    CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
    CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
    CommTimeOuts.ReadTotalTimeoutConstant = 0;
    CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
    CommTimeOuts.WriteTotalTimeoutConstant = 1000;

    if (!SetCommTimeouts(m_hComm, &CommTimeOuts)) 
    {
        MessageBox(NULL, _T("設置串口時間失敗"), _T("提示"), MB_OK);
        return FALSE;   //創建線程,讀取數據
    }

    HANDLE hReadCommThread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START)CommProc, (LPVOID) this, 0, NULL);

    return TRUE;
}

/********************************************************************************************
* 功能    :   通過串口發送一條數據
* 函數      : PurgeComm;WriteFile
********************************************************************************************/
BOOL CSerial::SendData(char* data, int len) 
{
    if (m_hComm == INVALID_HANDLE_VALUE) 
    {
        MessageBox(NULL, _T("串口未打開"), _T("提示"), MB_OK);
        return FALSE;
    }

    //清空串口
    PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

    //寫串口
    DWORD dwWrite = 0;
    DWORD dwRet = WriteFile(m_hComm, data, len, &dwWrite, NULL);

    //清空串口
    PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

    if (!dwRet) {
        MessageBox(NULL, _T("發送數據失敗"), _T("提示"), MB_OK);
        return FALSE;
    }
    return TRUE;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章