国产精品久久久久永久免费看,大地资源网更新免费播放视频,国产成人久久av免费,成人欧美一区二区三区黑人免费,丁香五月天综合缴情网

  • 方案介紹
  • 附件下載
  • 相關推薦
申請入駐 產(chǎn)業(yè)圖譜

Windows下串口編程與單片機串口設備通信(win32-API)

9小時前
150
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

更多詳細資料請聯(lián)系.docx

共1個文件

一、前言

串行通信接口,通常簡稱為“串口”,是一種數(shù)據(jù)傳輸方式,其中信息以連續(xù)的比特流形式發(fā)送,每個比特在不同的時間點被傳輸。這與并行通信形成對比,在并行通信中,多個比特同時通過多個線路傳輸。串口通信因其簡單的硬件需求和廣泛的應用場景而受到青睞,尤其是在遠程通信、設備控制、數(shù)據(jù)采集等領域。

image-20240715144416067

image-20240715144518138

串口通信在現(xiàn)代技術中的應用場景極為廣泛,從個人電腦連接外設(如鼠標、鍵盤)到工業(yè)自動化系統(tǒng)中的傳感器網(wǎng)絡,從移動設備的數(shù)據(jù)同步到實驗室設備的控制,都能見到其身影。在嵌入式系統(tǒng)開發(fā)中,單片機與PC機或其他設備之間的通信經(jīng)常采用串口,因為其易于實現(xiàn)且成本低廉。

在Windows環(huán)境下使用C語言進行串口編程,主要涉及到對Windows API函數(shù)的調(diào)用。Windows提供了豐富的API用于串口通信,包括CreateFileSetupComm、PurgeComm、SetCommState、SetCommTimeouts、ReadFileWriteFile等,這些函數(shù)分別用于打開串口、設置串口參數(shù)、讀寫串口數(shù)據(jù)以及控制串口的輸入輸出緩沖區(qū)等。

下面示例,展示如何使用C語言和Windows API打開指定的串口并進行通信:

#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hComm;
    DCB dcbSerialParams = {0};
    COMMTIMEOUTS timeouts;

    // 打開串口
    hComm = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hComm == INVALID_HANDLE_VALUE) {
        printf("無法打開串口。n");
        return -1;
    }

    // 設置串口參數(shù)
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    GetCommState(hComm, &dcbSerialParams);
    dcbSerialParams.BaudRate = CBR_9600;       // 設置波特率
    dcbSerialParams.ByteSize = 8;             // 設置字節(jié)大小
    dcbSerialParams.StopBits = ONESTOPBIT;    // 設置停止位
    dcbSerialParams.Parity   = NOPARITY;      // 設置校驗位
    SetCommState(hComm, &dcbSerialParams);

    // 設置超時時間
    timeouts.ReadIntervalTimeout         = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier  = 0;
    timeouts.ReadTotalTimeoutConstant    = 500;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant   = 500;
    SetCommTimeouts(hComm, &timeouts);

    // 發(fā)送數(shù)據(jù)
    char data[] = "Hello from PC!";
    DWORD dwWritten;
    WriteFile(hComm, data, strlen(data), &dwWritten, NULL);

    // 接收數(shù)據(jù)
    char buffer[256];
    DWORD dwRead;
    ReadFile(hComm, buffer, sizeof(buffer), &dwRead, NULL);
    buffer[dwRead] = '?'; // 確保字符串以空字符結尾
    printf("Received: %sn", buffer);

    // 關閉串口
    CloseHandle(hComm);
    return 0;
}

這段代碼展示了如何打開一個串口(例如COM3),設置其通信參數(shù),然后向串口發(fā)送數(shù)據(jù),并從串口接收數(shù)據(jù)。通過這樣的程序設計,可以實現(xiàn)PC機與單片機或其他串口設備之間的雙向通信,為數(shù)據(jù)交換、設備控制等應用提供基礎。

串口通信是連接不同設備之間的一種基本而強大的手段,尤其在嵌入式系統(tǒng)領域。掌握Windows環(huán)境下的串口編程,對于從事相關領域的開發(fā)者來說至關重要。

二、實操代碼

2.1 串口編程的函數(shù)詳解

在Windows環(huán)境下進行串口編程時,主要依賴于Windows API中的一系列函數(shù)。這些函數(shù)允許你控制串口的打開、配置、讀寫操作以及錯誤處理。下面是幾個關鍵函數(shù)的詳細說明,包括它們的功能、參數(shù)含義和用法:

1. CreateFile

功能:打開或創(chuàng)建一個指定的設備或文件。

語法

HANDLE CreateFile(
  LPCWSTR lpFileName,       // 指定文件名或設備名
  DWORD dwDesiredAccess,    // 請求的訪問類型
  DWORD dwShareMode,        // 共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全屬性
  DWORD dwCreationDisposition, // 創(chuàng)建或打開的處置
  DWORD dwFlagsAndAttributes, // 文件屬性
  HANDLE hTemplateFile      // 模板文件句柄
);

用法

  • 通常用于打開串口設備,如CreateFile(TEXT("COM1"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

2. CloseHandle

功能:關閉一個已打開的設備或文件句柄。

語法

BOOL CloseHandle(
  HANDLE hObject // 要關閉的句柄
);

用法

  • 在完成串口操作后調(diào)用以釋放資源,如CloseHandle(hComm);

3. GetCommState

功能:獲取串口當前的通信狀態(tài)。

語法

BOOL GetCommState(
  HANDLE hFile,     // 串口句柄
  LPDCB lpDCB       // 指向DCB結構體的指針
);

用法

  • 用于獲取串口的當前配置,如波特率、數(shù)據(jù)位數(shù)等。

4. SetCommState

功能:設置串口的通信狀態(tài)。

語法

BOOL SetCommState(
  HANDLE hFile,     // 串口句柄
  LPDCB lpDCB       // 指向DCB結構體的指針
);

用法

  • 用于設置串口的配置參數(shù),如波特率、數(shù)據(jù)位、停止位和奇偶校驗。

5. PurgeComm

功能:清除串口的輸入輸出緩沖區(qū)。

語法

BOOL PurgeComm(
  HANDLE hFile,     // 串口句柄
  DWORD dwMask      // 指定要清除的緩沖區(qū)
);

用法

  • 用于清除串口的輸入或輸出緩沖區(qū),避免數(shù)據(jù)殘留。

6. ReadFile

功能:從串口讀取數(shù)據(jù)。

語法

BOOL ReadFile(
  HANDLE hFile,         // 串口句柄
  LPVOID lpBuffer,      // 數(shù)據(jù)緩沖區(qū)
  DWORD nNumberOfBytesToRead, // 要讀取的字節(jié)數(shù)
  LPDWORD lpNumberOfBytesRead, // 實際讀取的字節(jié)數(shù)
  LPOVERLAPPED lpOverlapped    // 異步讀取時的重疊結構
);

用法

  • 用于從串口讀取數(shù)據(jù)到緩沖區(qū)中。

7. WriteFile

功能:向串口寫入數(shù)據(jù)。

語法

BOOL WriteFile(
  HANDLE hFile,         // 串口句柄
  LPCVOID lpBuffer,     // 數(shù)據(jù)緩沖區(qū)
  DWORD nNumberOfBytesToWrite, // 要寫入的字節(jié)數(shù)
  LPDWORD lpNumberOfBytesWritten, // 實際寫入的字節(jié)數(shù)
  LPOVERLAPPED lpOverlapped      // 異步寫入時的重疊結構
);

用法

  • 用于向串口發(fā)送數(shù)據(jù)。

8. SetCommTimeouts

功能:設置串口的超時值。

語法

BOOL SetCommTimeouts(
  HANDLE hFile,     // 串口句柄
  LPCOMMTIMEOUTS lpCommTimeouts // 指向COMMTIMEOUTS結構體的指針
);

用法

  • 用于設置讀寫操作的超時時間,防止無限期等待。

9. GetLastError

功能:獲取上一次調(diào)用失敗的錯誤代碼。

語法

DWORD GetLastError(void);

用法

  • 當API函數(shù)調(diào)用失敗時,可以調(diào)用此函數(shù)獲取具體的錯誤代碼,幫助診斷問題。

以上函數(shù)是進行串口編程時最常用的,它們共同提供了串口設備的完整控制能力。在實際編程中,你需要根據(jù)具體的應用需求選擇合適的函數(shù)組合,以實現(xiàn)串口的高效穩(wěn)定通信。

2.2 掃描當前系統(tǒng)可用串口端口

在Windows環(huán)境下,使用C語言來枚舉所有可用的串口,可以通過調(diào)用Windows API函數(shù)來實現(xiàn)。

以下代碼,會打印出系統(tǒng)上所有可用的串口名稱:

#include <windows.h>
#include <stdio.h>
#include <string.h>

// 定義一個結構體存儲串口信息
typedef struct _SERIAL_INFO {
    DWORD dwSize;
    HANDLE hFile;
    DWORD dwDeviceType;
    DWORD dwReserved;
    DWORD dwProviderSubType;
    DWORD dwServiceCharacteristics;
    DWORD dwVendorGuidData;
    DWORD dwDriverVersion;
    DWORD dwDriverDate;
    DWORD dwHardwareIndex;
    DWORD dwConfigFlags;
    DWORD dwNumParameters;
    DWORD dwNumProperties;
} SERIAL_INFO;

// 定義一個結構體存儲串口屬性
typedef struct _SERIAL_PROPERTY_KEY {
    DWORD dwPropertyKey;
    DWORD dwPropertyType;
    DWORD dwReserved;
} SERIAL_PROPERTY_KEY;

int main() {
    DWORD dwSize = 0;
    DWORD dwRetVal = 0;
    HANDLE hComm = NULL;
    SERIAL_INFO SerialInfo;
    SERIAL_PROPERTY_KEY SerialPropKey;
    TCHAR szPortName[MAX_PATH];
    DWORD dwBufferSize = 0;
    DWORD dwBytesReturned = 0;
    DWORD dwError = 0;

    // 獲取所需的SERIAL_INFO結構體大小
    dwRetVal = QueryDosDevice(NULL, NULL, 0);
    if (dwRetVal == 0) {
        dwSize = GetLastError();
        SerialInfo.dwSize = dwSize;
    } else {
        printf("QueryDosDevice failed with error: %ldn", GetLastError());
        return -1;
    }

    // 枚舉所有的串口
    for (int i = 1; i <= 256; i++) {
        wsprintf(szPortName, TEXT("COM%d"), i);
        dwRetVal = QueryDosDevice(szPortName, NULL, 0);
        if (dwRetVal != 0) {
            continue; // 如果返回非零,則跳過,表示端口不存在或不可用
        }
        dwError = GetLastError();
        if (dwError != ERROR_INSUFFICIENT_BUFFER) {
            continue; // 如果錯誤不是緩沖區(qū)不足,則跳過
        }

        // 如果是緩沖區(qū)不足,則獲取正確的緩沖區(qū)大小
        dwBufferSize = dwError;
        if (dwBufferSize > 0) {
            SerialInfo.dwSize = dwBufferSize;
            dwRetVal = QueryDosDevice(szPortName, (LPTSTR)&SerialInfo, dwBufferSize);
            if (dwRetVal != 0) {
                // 成功獲取串口信息,嘗試打開串口
                hComm = CreateFile(szPortName,
                                   GENERIC_READ | GENERIC_WRITE,
                                   0, NULL,
                                   OPEN_EXISTING,
                                   FILE_ATTRIBUTE_NORMAL,
                                   NULL);
                if (hComm != INVALID_HANDLE_VALUE) {
                    // 打印可用的串口號
                    wprintf(L"Found COM port: %sn", szPortName);
                    // 清理資源
                    CloseHandle(hComm);
                }
            }
        }
    }

    return 0;
}

這個代碼片段會遍歷從COM1到COM256的所有可能的串口號,嘗試打開每一個串口,如果成功打開,則表明該串口是可用的,并將串口號打印出來。

2.3 創(chuàng)建串口程序與單片機進行數(shù)據(jù)互發(fā)通信

下面是一個使用C語言在Windows環(huán)境下進行串口編程的例子,演示了如何與單片機進行數(shù)據(jù)互發(fā)通信。

創(chuàng)建一個程序,打開串口,設置波特率為115200,然后接收從單片機發(fā)送來的數(shù)據(jù),將其打印出來,并將同樣的數(shù)據(jù)返回給單片機。

#include <windows.h>
#include <stdio.h>
#include <string.h>

int main() {
    HANDLE hComm;
    DCB dcbSerialParams = {0};
    COMMTIMEOUTS timeouts;

    // 打開串口
    hComm = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (hComm == INVALID_HANDLE_VALUE) {
        printf("無法打開串口。n");
        return -1;
    }

    // 設置串口參數(shù)
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hComm, &dcbSerialParams)) {
        printf("無法獲取串口狀態(tài)。n");
        CloseHandle(hComm);
        return -1;
    }

    dcbSerialParams.BaudRate = CBR_115200;       // 設置波特率為115200
    dcbSerialParams.ByteSize = 8;               // 設置數(shù)據(jù)位為8位
    dcbSerialParams.StopBits = ONESTOPBIT;      // 設置停止位為1位
    dcbSerialParams.Parity = NOPARITY;          // 設置無校驗位

    if (!SetCommState(hComm, &dcbSerialParams)) {
        printf("無法設置串口參數(shù)。n");
        CloseHandle(hComm);
        return -1;
    }

    // 設置超時時間
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 500;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 500;
    if (!SetCommTimeouts(hComm, &timeouts)) {
        printf("無法設置串口超時時間。n");
        CloseHandle(hComm);
        return -1;
    }

    // 循環(huán)讀取和回顯數(shù)據(jù)
    char buffer[256];
    DWORD dwRead, dwWritten;

    while (1) {
        memset(buffer, 0, sizeof(buffer));
        if (!ReadFile(hComm, buffer, sizeof(buffer)-1, &dwRead, NULL)) {
            printf("讀取數(shù)據(jù)失敗。n");
            break;
        }

        if (dwRead > 0) {
            printf("接收到: %sn", buffer);
            if (!WriteFile(hComm, buffer, dwRead, &dwWritten, NULL)) {
                printf("寫入數(shù)據(jù)失敗。n");
                break;
            }
        }
    }

    // 清理資源
    CloseHandle(hComm);
    return 0;
}

在這個例子中,使用CreateFile函數(shù)打開串口,然后通過GetCommStateSetCommState函數(shù)設置串口的波特率、數(shù)據(jù)位、停止位和校驗位。接著,使用SetCommTimeouts函數(shù)設置讀寫操作的超時時間,以防在沒有數(shù)據(jù)的情況下無限等待。

接下來,進入一個無限循環(huán),使用ReadFile函數(shù)從串口讀取數(shù)據(jù)。如果讀取成功,將接收到的數(shù)據(jù)打印出來,并使用WriteFile函數(shù)將同樣的數(shù)據(jù)返回到串口,實現(xiàn)回顯功能。

  • 更多詳細資料請聯(lián)系.docx
    下載

相關推薦