1.完整Demo code

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

#define BUFFER_SIZE 256
// 全局变量,存储串口句柄
HANDLE hSerial;
HANDLE hReadThread;
BOOL threadRunning = FALSE;

// 初始化串口
int initialize_serial_port(const char* port_name) {
    // 打开串口
    hSerial = CreateFile(
        port_name,                  // 串口号,例如 "COM3"
        GENERIC_READ | GENERIC_WRITE, // 读写权限
        0,                       // 共享模式,0表示独占
        NULL,                    // 安全属性
        OPEN_EXISTING,           // 打开已存在的设备
        FILE_ATTRIBUTE_NORMAL,   // 文件属性
        NULL                     // 模板文件句柄
    );

    if (hSerial == INVALID_HANDLE_VALUE) {
        printf("Error opening serial port\n");
        return 1;
    }

    // 配置串口参数
    DCB dcbSerialParams = {0};

    if (!GetCommState(hSerial, &dcbSerialParams)) {
        printf("Error getting serial port state\n");
        CloseHandle(hSerial);
        return 1;
    }

    dcbSerialParams.BaudRate = CBR_9600;  // 波特率
    dcbSerialParams.ByteSize = 8;         // 数据位
    dcbSerialParams.StopBits = ONESTOPBIT;// 停止位
    dcbSerialParams.Parity = NOPARITY;    // 校验位

    if (!SetCommState(hSerial, &dcbSerialParams)) {
        printf("Error setting serial port state\n");
        CloseHandle(hSerial);
        return 1;
    }

    // 设置超时
    COMMTIMEOUTS timeouts = {0};

    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;

    if (!SetCommTimeouts(hSerial, &timeouts)) {
        printf("Error setting timeouts\n");
        CloseHandle(hSerial);
        return 1;
    }

    printf("Serial port initialized successfully\n");
    return 0;
}

// 关闭串口
void close_serial_port() {
    if (hSerial != INVALID_HANDLE_VALUE) {
        CloseHandle(hSerial);
        printf("Serial port closed\n");
    }
}

// 写数据到串口
int write_to_serial_port(const char* data) {
    DWORD bytesWritten;

    if (!WriteFile(hSerial, data, strlen(data), &bytesWritten, NULL)) {
        printf("Error writing to serial port\n");
        return 1;
    }

    printf("Sent: %s\n", data);
    return 0;
}

// 从串口读取数据
int read_from_serial_port(char* buffer, int buffer_size) {
    DWORD bytesRead;

    if (!ReadFile(hSerial, buffer, buffer_size - 1, &bytesRead, NULL)) {
        printf("Error reading from serial port\n");
        return 1;
    }

    buffer[bytesRead] = '\0'; // 添加字符串结束符
    printf("Received: %s\n", buffer);
    return 0;
}

// 读取线程函数
DWORD WINAPI SerialReadThread(LPVOID lpParam)
{
    OVERLAPPED ov = {0};
    char buffer[BUFFER_SIZE];
    DWORD bytesRead;

    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (ov.hEvent == NULL)
    {
        ErrorHandler(TEXT("CreateEvent"));
        return 1;
    }

    printf("Serial read thread started.\n");

    while (threadRunning)
    {
        if (!ReadFile(hCom, buffer, BUFFER_SIZE - 1, &bytesRead, &ov))
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
            	printf("Error reading from serial port\n");
                break;
            }
            // 等待读取完成
            WaitForSingleObject(ov.hEvent, INFINITE);
            GetOverlappedResult(hCom, &ov, &bytesRead, FALSE);
        }

        if (bytesRead > 0)
        {
            buffer[bytesRead] = '\0'; // 确保字符串终止
            printf("Received %d bytes: ", bytesRead);
            
            // 打印十六进制格式
            for (DWORD i = 0; i < bytesRead; i++)
            {
                printf("%02X ", (unsigned char)buffer[i]);
            }
            printf("\n");
            
            // 也可以打印ASCII格式
            // printf("Data: %s\n", buffer);
            
            // 也可以解析数据并根据数类型分发给不同的队列到task中处理
        }
    }

    CloseHandle(ov.hEvent);
    printf("Serial read thread exiting.\n");
    return 0;
}

// 主函数
int main() {
    const char* port_name = "COM3"; // 串口号
    char buffer[256];

    // 初始化串口
    if (initialize_serial_port(port_name) {
        return 1;
    }

    // 发送数据
    if (write_to_serial_port("Hello, Serial Port!")) {
        close_serial_port();
        return 1;
    }

	/*
    // 接收数据
    if (read_from_serial_port(buffer, sizeof(buffer))) {
        close_serial_port();
        return 1;
    }
    */
    // 创建并启动读取线程
    threadRunning = TRUE;
    hReadThread = CreateThread(
        NULL,                   // 默认安全属性
        0,                      // 默认堆栈大小
        SerialReadThread,       // 线程函数
        NULL,                   // 无参数
        0,                      // 默认创建标志
        NULL);                  // 不需要线程ID

    if (hReadThread == NULL)
    {
        close_serial_port();
        return 1;
    }

    printf("Press Enter to exit...\n");
    getchar(); // 等待用户输入以退出

    // 清理
    threadRunning = FALSE;
    
    // 等待线程结束
    WaitForSingleObject(hReadThread, 2000);
    
    CloseHandle(hReadThread);
   	// 关闭串口
    close_serial_port();

    printf("Program exited.\n");
    return 0;
}

2.代码说明

  1. initialize_serial_port 函数

    • 负责打开串口并配置串口参数(波特率、数据位、停止位、校验位等)。
    • 参数 port_name 是串口号,例如 "COM3"
    • 返回 0 表示成功,1 表示失败。
  2. close_serial_port 函数

    • 负责关闭串口。
    • 如果串口句柄有效,则调用 CloseHandle 关闭串口。
  3. write_to_serial_port 函数

    • 负责向串口发送数据。
    • 参数 data 是要发送的字符串。
    • 返回 0 表示成功,1 表示失败。
  4. read_from_serial_port 函数

    • 负责从串口读取数据。
    • 参数 buffer 是用于存储读取数据的缓冲区,buffer_size 是缓冲区大小。
    • 返回 0 表示成功,1 表示失败。
  5. SerialReadThread 函数

    • 用于处理串口读取的数据
    • 可以根据不同类型的数据分发给不同的task
  6. 主函数

    • 调用上述函数完成串口初始化、发送数据、接收数据和关闭串口的操作。

3.使用方法

  1. 修改 port_name 为实际的串口号(例如 "COM3")。
  2. 编译并运行程序。
  3. 程序会发送 "Hello, Serial Port!" 到串口,并尝试从串口读取数据。

4.其他参考案例

  1. windows c编写串口通信
  2. 串口通信(Win32, C++)
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐