[WinAPI] 串口读写

2024-05-11 11:08
文章标签 串口 读写 winapi

本文主要是介绍[WinAPI] 串口读写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

HANDLE hComm;
OVERLAPPED m_ov;
COMSTAT comstat;
DWORD    m_dwCommEvents;

//如果在调用CreateFile创建句柄时指
//定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进
//行的操作就应该是重叠的;如果未指定
//重叠标志,则读写操作应该是同步的
//在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从
//而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费
//时的I/O操作在后台进行
bool openport(char *portname)//打开一个串口
{
    hComm = CreateFile(portname,
        GENERIC_READ | GENERIC_WRITE,
        0,
        0,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,    
        0);
    if (hComm == INVALID_HANDLE_VALUE)
        return FALSE;
    else
        return true;
}


bool setupdcb(int rate_arg)
{
    DCB  dcb;
    int rate= rate_arg;
    memset(&dcb,0,sizeof(dcb)); //在一段内存块中填充某个给定的值,是对较大的结构//体或数组进行清零操作的一种最快方法
    if(!GetCommState(hComm,&dcb))//获取当前DCB配置
    {
        return FALSE;
    }
    /* -------------------------------------------------------------------- */
    // set DCB to configure the serial port
    dcb.DCBlength       = sizeof(dcb);
    /* ---------- Serial Port Config ------- */
    dcb.BaudRate        = rate;
    dcb.Parity      = NOPARITY;
    dcb.fParity     = 0;
    dcb.StopBits        = ONESTOPBIT;
    dcb.ByteSize        = 8;
    dcb.fOutxCtsFlow    = 0;
    dcb.fOutxDsrFlow    = 0;
    dcb.fDtrControl     = DTR_CONTROL_DISABLE;
    dcb.fDsrSensitivity = 0;
    dcb.fRtsControl     = RTS_CONTROL_DISABLE;
    dcb.fOutX           = 0;
    dcb.fInX            = 0;
    /* ----------------- misc parameters ----- */
    dcb.fErrorChar      = 0;
    dcb.fBinary         = 1;
    dcb.fNull           = 0;
    dcb.fAbortOnError   = 0;
    dcb.wReserved       = 0;
    dcb.XonLim          = 2;
    dcb.XoffLim         = 4;
    dcb.XonChar         = 0x13;
    dcb.XoffChar        = 0x19;
    dcb.EvtChar         = 0;
    /* -------------------------------------------------------------------- */
    // set DCB
    if(!SetCommState(hComm,&dcb))
    {
        return false;
    }
    else
        return true;
}
//在用readfile和writefile读写串行口时,需要考虑超时问题, 读写串口的超时有两
//种:间隔超时和总超时, 写操作只支持总超时,而读操作两种超时均支持, 如果所有
//写超时参数均为0,那么就不使用写超时。
bool setuptimeout(DWORD ReadInterval,DWORD ReadTotalMultiplier,DWORD ReadTotalconstant,DWORD WriteTotalMultiplier,DWORD WriteTotalconstant)               
{
    COMMTIMEOUTS timeouts;
    timeouts.ReadIntervalTimeout=ReadInterval; //读间隔超时
    timeouts.ReadTotalTimeoutConstant=ReadTotalconstant; //读时间系数
    timeouts.ReadTotalTimeoutMultiplier=ReadTotalMultiplier; //读时间常量
    timeouts.WriteTotalTimeoutConstant=WriteTotalconstant; // 写时间系数
    timeouts.WriteTotalTimeoutMultiplier=WriteTotalMultiplier; //写时间常//量, 总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时间常量
    if(!SetCommTimeouts(hComm, &timeouts))
    {
        return false;
    }
    else
        return true;
}
void ReceiveChar(){
    BOOL  bRead = TRUE;
    BOOL  bResult = TRUE;
    DWORD dwError = 0;
    DWORD BytesRead = 0;
    char RXBuff;
    while(true){
        bResult = ClearCommError(hComm, &dwError, &comstat);
        // 在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误
        if(comstat.cbInQue==0)// COMSTAT结构返回串口状态信息
            //本文只用到了cbInQue成员变量,该成员变量的值代表输入缓冲区的字节数
            continue;
        if(bRead){
            bResult = ReadFile(hComm, // Handle to COMM port串口的句柄
                &RXBuff,// RX Buffer Pointer// 读入的数据存储的地址,即读入的数据将存//储在以该指针的值为首地址的一片内存区
                1,// Read one byte要读入的数据的字节数,
                &BytesRead, // Stores number of bytes read, 指向一个DWORD//数值,该数值返回读操作实际读入的字节数
                &m_ov);           // pointer to the m_ov structure// 重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL
            printf("%c",RXBuff);
            if (!bResult){// 当ReadFile和WriteFile返回FALSE时,不一定就是操作失//败,线程应该调用GetLastError函数分析返回的结果
                switch (dwError = GetLastError()){
                case ERROR_IO_PENDING:
                        bRead = FALSE;
                        break;
                default:break;
                }
            }else{
                bRead = TRUE;
            }
        }  // close if (bRead)
        if (!bRead){
            bRead = TRUE;
            bResult = GetOverlappedResult(hComm,    // Handle to COMM port
                &m_ov,    // Overlapped structure
                &BytesRead,        // Stores number of bytes read
                TRUE);             // Wait flag
        }
    }
}
BOOL WriteChar(BYTE* m_szWriteBuffer,DWORD m_nToSend){
    BOOL bWrite = TRUE;
    BOOL bResult = TRUE;
    DWORD BytesSent = 0;
    HANDLE    m_hWriteEvent;
    ResetEvent(m_hWriteEvent);
    if (bWrite){
        m_ov.Offset = 0;
        m_ov.OffsetHigh = 0;
        // Clear buffer
        bResult = WriteFile(hComm,    // Handle to COMM Port, 串口的句柄
            m_szWriteBuffer,        // Pointer to message buffer in calling finction
                                    // 即以该指针的值为首地址的nNumberOfBytesToWrite
                                    // 个字节的数据将要写入串口的发送数据缓冲区
            m_nToSend,                // Length of message to send, 要写入的数据的字节数
            &BytesSent,                // Where to store the number of bytes sent
                                    // 指向指向一个DWORD数值,该数值返回实际写入的字节数
            &m_ov );                // Overlapped structure
                                    // 重叠操作时,该参数指向一个OVERLAPPED结构,
                                    // 同步操作时,该参数为NULL
        if (!bResult){                // 当ReadFile和WriteFile返回FALSE时,不一定就是操作失
            //败,线程应该调用GetLastError函数分析返回的结果
            DWORD dwError = GetLastError();
            switch (dwError){
            case ERROR_IO_PENDING: //GetLastError函数返回//ERROR_IO_PENDING。这说明重叠操作还未完成
                    // continue to GetOverlappedResults()
                    BytesSent = 0;
                    bWrite = FALSE;
                    break;
            default:break;
            }
        }
    } // end if(bWrite)
    if (!bWrite){
        bWrite = TRUE;
        bResult = GetOverlappedResult(hComm,    // Handle to COMM port
            &m_ov,        // Overlapped structure
            &BytesSent,        // Stores number of bytes sent
            TRUE);             // Wait flag
        
        // deal with the error code
        if (!bResult){
            printf("GetOverlappedResults() in WriteFile()");
        }
    } // end if (!bWrite)
    
    // Verify that the data size send equals what we tried to send
    if (BytesSent != m_nToSend){
        printf("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char*)m_szWriteBuffer));
    }
    return true;
}


void   main(){
    if(openport("com4"))
        printf("open comport success\n");
    if(setupdcb(115200))
        printf("setupDCB success\n");
    if(setuptimeout(0,0,0,0,0)) //如果所有写超时参数均为0,那么就不使用写超时
        printf("setuptimeout success\n");
    PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // 在读写串口之前,还要用PurgeComm()函数清空缓冲区
    //PURGE_TXABORT      中断所有写操作并立即返回,即使写操作还没有完成。
    //PURGE_RXABORT      中断所有读操作并立即返回,即使读操作还没有完成。
    //PURGE_TXCLEAR      清除输出缓冲区
    //PURGE_RXCLEAR      清除输入缓冲区
    //WriteChar("please send data now",20);
    printf("received data:\n");
    ReceiveChar( );
    system("pause");
}

这篇关于[WinAPI] 串口读写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/979364

相关文章

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

关于使用cspreadsheet读写EXCEL表格数据的问题

前几天项目有读写EXCEL表格的需求,我就找了大概有几种,大致分为:COM方法、ODBC方法、OLE方法、纯底层格式分析方法。由于COM方法要求必须安装有OFFICE的EXCEL组件,纯底层格式分析方法又很多功能需要自行去完善,所有最终选择了数据库的方法,用数据库的方法去存取xls格式的数据。网上有一个高手写的CSpreedSheet,看了一下提供的接口,感觉挺好用的。在使用的过程中发现几个

linux 内核提权总结(demo+exp分析) -- 任意读写(四)

hijack_modprobe_path篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     原理同hijack_prctl, 当用户执行错误格式的elf文件时内核调用call_usermod

linux 内核提权总结(demo+exp分析) -- 任意读写(三)

hijack_prctl篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   prctl函数: 用户态函数,可用于定制进程参数,非常适合和内核进行交互 用户态执行prctl函数后触发prctl系统

linux 内核提权总结(demo+exp分析) -- 任意读写(二)

hijack_vdso篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     vdso: 内核实现的一个动态库,存在于内核,然后映射到用户态空间,可由用户态直接调用 内核中的vdso如果被修改

linux 内核提权总结(demo+exp分析) -- 任意读写(一)

cred篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   每个线程在内核中都对应一个线程结构块thread_infothread_info中存在task_struct类型结构体 struct t

安卓开发板_联发科MTK开发评估套件串口调试

串口调试 如果正在进行lk(little kernel ) 或内核开发,USB 串口适配器( USB 转串口 TTL 适配器的简称)对于检查系统启动日志非常有用,特别是在没有图形桌面显示的情况下。 1.选购适配器 常用的许多 USB 转串口的适配器,按芯片来分,有以下几种: CH340PL2303CP2104FT232 一般来说,采用 CH340 芯片的适配器,性能比较稳定,价

Java 文件读写最好是用buffer对于大文件可以加快速度

参考例子: FileReader fileReader = new FileReader(filename);BufferedReader bufferedReader = new BufferedReader(fileReader);List<String> lines = new ArrayList<String>();String line = null;while ((line =