zoukankan      html  css  js  c++  java
  • BCB 串口调试——CreateFile

    转自网址:http://blog.csdn.net/henhen2002/article/details/4485157

     

    项目(先这么称呼吧)简介,计算机通过串口分别控制4个二极管的亮度。

    上位机部分:只说说我用到的一些函数,和遇到的问题。基本的比如什么是异步通讯啦之类的就不说了

    下边是一些函数:

    函数名  作用

    1. CreateFile 打开串口

    2. GetCommState  检测串口设置

    3. SetCommState 设置串口

      BuilderCommDCB 用字符串中的值来填充设备控制块

      GetCommTimeouts 检测通信超时设置

      SetCommTimeouts 设置通信超时参数

      SetCommMask 设定被监控事件

      WaitCommEvent 等待被监控事件发生

      WaitForMultipleObjects 等待多个被监测对象的结果

    4. WriteFile 发送数据

      ReadFile  接收数据

      GetOverlappedResult 返回最后重叠(异步)操作结果

    5. PurgeComm 清空串口缓冲区,退出所有相关操作

    6. ClearCommError 更新串口状态结构体,并清除所有串口硬件错误

    7. CloseHandle  关闭串行口

    项目只是通过计算机向51发送指令所以连ReadFile()都没用到。省了很多事。。。。。。

    【CreateFile()】

    功能:打开串口设备

    函数原型

      HANDLE CreateFile(

            LPCTSTR lpFileName, // 串口名称字符串;如: "COM1" 或 "COM2"

            DWORD dwDesiredAccess, // 设置读写属性(访问模式 );一般为 GENERIC_READ|GENERIC_WRITE,

            DWORD dwShareMode, // 共享模式;"必须"为 0, 即不能共享

            LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性;一般为NULL

            DWORD dwCreationDistribution, // 创建方式,串口设置必须设置此值; 在这里"必须"为 OPEN_EXISTING

            DWORD dwFlagsAndAttributes, // 文件属性和标志;在这里我们设置成FILE_FLAG_OVERLAPPED ,实现异步I/O关于Overlapped I/O模型,自己上网搜了去理解吧,我自己也说不清楚,懵懂的很。

            HANDLE hTemplateFile // 临时文件的句柄,通常为NULL 

            );

    说明:

    如果调用成功返回文件的句柄,如果调用失败,则函数返回INVALID_HANDLE_VALUE

    【GetCommState()】

    功能:获得串口状态

        BOOL GetCommState(

              HANDLE hFile, // handle of communications device

              LPDCB lpDCB // address of device-control block structure

              );

    【SetCommState()】

    功能:设置串口状态 

        BOOL SetCommState(

                HANDLE hFile, // handle of communications device

                LPDCB lpDCB // address of device-control block structure

                );

    说明:

    在打开通信设备句柄后,常常需要对串行口进行一些初始化工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、每个字符的数据位数、奇偶校验和停止位数等信息。在查询或配置置串行口的属性时,都要用DCB结构来作为缓冲区。

    调用GetCommState函数可以获得串口的配置,该函数把当前配置填充到一个DCB结构中。一般在用CreateFile打开串行口后,可以调用GetCommState函数来获取串行口的初始配置。要修改串行口的配置,应该先修改DCB结构,然后再调用SetCommState函数用指定的DCB结构来设置串行口

    For example:

          DCB dcb;

          memset(&dec,0,sizeof(dcb));

          if(!GetCommState(HComm,&dcb))//获取当前DCB配置

           return FALSE;

          dcb.BaudRate = CBR_9600;//修改数据传输率。。。很多参数可以修改,比如,停止位,有无校验等等

          ............

          if(SetCommState(hComm,&dcb))//设置新参数

          ......    //错误处理

    【WriteFile()】

    功能:来将资料写入Serial port.

    函数原型:

          BOOL WriteFile(

              HANDLE hFile, // handle to file to write to

              LPCVOID lpBuffer, // 写如字符串的首地址

              DWORD nNumberOfBytesToWrite, // 要写如字符的个数

              LPDWORD lpNumberOfBytesWritten, // 实际写入字节数,为一个int型指针

              LPOVERLAPPED lpOverlapped // i/o重构结构,我讲不清楚,sorry

              );

    说明:

       ReadFile函数只要在串行口输入缓冲区中读入指定数量的字符,就算完成操作。

      而WriteFile函数不但要把指定数量的字符拷入到输出缓冲中,而且要等这些字符从串行口送出去后才算完成操作。

    ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。如果GetLastError函数返回ERROR_IO_PENDING,则说明重叠操作还为完成,线程可以等待操作完成。

      有两种等待办法:一种办法是用象WaitForSingleObject这样的等待函数来等待OVERLAPPED结构的hEvent成员,可以规定等待的时间,在等待函数返回后,调用GetOverlappedResult。

      另一种办法是调用GetOverlappedResult函数等待,如果指定该函数的bWait参数为TRUE,

      那么该函数将等待OVERLAPPED结构的hEvent 事件。GetOverlappedResult可以返回一个OVERLAPPED结构来报告包括实际传输字节在内的重叠操作结果。

      如果规定了读/写操作的超时,那么当超过规定时间后,hEvent成员会变成有信号的。因此,在超时发生后,                  WaitForSingleObject和GetOverlappedResult都会结束等待。WaitForSingleObject的dwMilliseconds参数会规定一个等待超时,该函数实际等待的时间是两个超时的最小值。注意GetOverlappedResult不能设置等待的时限,因此如果hEvent成员无信号,则该函数将一直等待下去【注意下】

    【PurgeComm()】

    功能:终止目前正在进行的读或写的动作

    函数原型:

        BOOL PurgeComm(

              HANDLE hFile, // handle of communications resource

              DWORD dwFlags // action to perform

              );

    参数说明:

    HANDLE hFile,//串口名称字符串

    dwFlags 共有四种 flags:

      PURGE_TXABORT: 终止目前正在进行的(背景)写入动作

      PURGE_RXABORT: 终正目前正在进行的(背景)读取动作

      PURGE_TXCLEAR: flush 写入的 buffer

      PURGE_TXCLEAR: flush 读取的 buffer

    调用PurgeComm函数可以终止正在进行的读写操作,该函数还会清除输入或输出缓冲区中的内容。

    【ClearCommError()】

    功能: 从字面上的意思看来, 它是用来清除错误情况用的, 但是实际上它还可以拿来取得目前通讯设备的一些信息.

    函数原型:

        BOOL ClearCommError(

              HANDLE hFile, // handle to communications device

              LPDWORD lpErrors, // pointer to variable to receive error codes

              LPCOMSTAT lpStat // pointer to buffer for communications status

              );

    说明:

     在调用ReadFile和WriteFile之前,线程应该调用ClearCommError函数清除错误标志。

    该函数负责报告指定的错误和设备的当前状态。

    【CloseHandle()】

    功能:关闭串口

    BOOL CloseHandle(HANDLE hObject // handle to object to close)

    //-------------------------------------------------------------------------------- 

    下面是我在bcb里的一些具体实现:

    1.       打开串口

    void __fastcall TForm1::Button1Click(TObject *Sender)

    {

            hCom=CreateFile( "COM2", //文件名

                             GENERIC_READ|GENERIC_WRITE,//访问模式允许读写

                             0, //此项必须是0

                             0,//无安全参数

                             OPEN_EXISTING,//创建方式

                             FILE_FLAG_OVERLAPPED,//异步工作方式

                             0);

            if (hCom==INVALID_HANDLE_VALUE)

            {

                    ShowMessage("Can not open the port !");

                    CloseHandle(hCom);

                    hCom = 0;

                    return;

            }

            else

        {    

          ShowMessage("COM2 open success!");

        }

            Button1->Enabled=false;

            CheckBox1->Enabled=true;

            CheckBox2->Enabled=true;

            CheckBox3->Enabled=true;

            CheckBox4->Enabled=true;

            CheckBox5->Enabled=true;

            if(!GetCommState(hCom,&dcb)) //获得串口设置并用它填充dcb结构体

                    ShowMessage("GetCommState failed");

            if (!SetupComm(hCom,1024,1024)) //设置输入输出缓冲区大小

                    ShowMessage("SetupComm failed");

       //9600,0,N,8,1

            dcb.BaudRate=9600;

            dcb.fParity=0;

            dcb.Parity=NOPARITY;

            dcb.StopBits=ONESTOPBIT;

            dcb.ByteSize=8;

            if(!SetCommState(hCom,&dcb)) //重新配置串口

                  ShowMessage("SetCommState failed");

            SetCommMask(hCom,EV_TXEMPTY); //EV_RXCHAR| 设定被监控事件

            memset(&os,0,sizeof(OVERLAPPED));//将已开辟内存空间 s 的首 n 个字节的值设为值 c,用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化

            os.hEvent=CreateEvent(NULL,true,false,NULL);// 创建一个无名的,不能被继承的,手动复原,初始状态是无信号状态的事件对象

    }


    2.       发送一个字节

    void sendchar(char ch)

    {  DWORD BytesSent=0;

       OverWrite.Offset=0;

       OverWrite.OffsetHigh=0;

       BOOL bResult;

      bResult=WriteFile(hCom,

                &ch,

                1,

                &BytesSent,

                &OverWrite);

          if(bResult) return;

          DWORD dwError=GetLastError();

          if(dwError!=ERROR_IO_PENDING)

          {

              ShowMessage("写字符错误,请确认串口以打开!");

              return;

          }

          if(!GetOverlappedResult(hCom,&OverWrite,&BytesSent,TRUE))

          {

               ShowMessage("写字符错误,请确认串口以打开!");

               return;

          }

        }      

    在与51通讯的过程中,一次有计算机发送两个数据给单片机,第一个是控制二极管亮度的数据,第二个是选择控制哪个二极管的数据。为了简单考虑,每次发送过程调用两次send函数。下面的是发送子程序:

    void send(char channel,int Vdata)

    {    

      PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

          sendchar(char(Vdata));

          PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

          sendchar(channel);

          Sleep(10);

     }

    上位机的程序就这么样了。。。。。

    //------------------------------------------------------------------------- 

    单片机源码:这是根据上位机的程序来写的。写成后生成Hex烧录到单片机中即可

    #include <reg51.h>

    char datax=0;//作为判断接受的数据为控制信号的标志使用

    char receive;

    sbit a=P3^2;

    sbit b=P3^3;

    sbit c=P3^4;

    sbit d=P3^5;

    sbit e=P3^7;

    void initial(void);

    void P3con(char x);

    void delay(short ms);

    void main(void)

    {

    int i; 

    for(i=0;i<5;i++)

      {

        e=0;d=0;c=0;b=0;a=0;P1=0;

        delay(2000);

        a=1;

        b=1;

        c=1;

        d=1;

        e=1;

        P1=0xFF;

        delay(2000);

       

      }

      initial();//串口初始化

      while(1);

    }

    void initial(void)      //初始化子程序

    {

      IP=0x10;//串口中断优先级高

      IE=0x90;//开中断

      TMOD=0x20;//定时器1 工作模式2

      TH1=253;TL1=253;//设置定时器1初值,波特率为9.6k/s

      SCON=0x50;//串行模式1 8bit异步传输

      PCON=0x7f&PCON;//SMOD=0

      TR1=1;//计时器开

    }

    void Sinterrupt(void) interrupt 4 using 3 //串口中断响应程序;

    {

      if(TI) TI=0;

      else if(RI)

      {   

         RI=0;

         receive=SBUF;

         delay(10);

         SBUF=receive;

         //delay(10);

         //while(!TI);

         //TI=0;

        if(datax==0)                

          {

            P1=receive;                

            datax++;

            return;

          }

        if(datax==1)                 

         {

            P3con(receive);

            datax=0; 

            return;

         }

      }

    }

    void P3con(char x)   //dac0809的片选信号

    {

      switch(x)

     {

      case '1': a=1;delay(2);a=0;break;

      case '2': b=1;delay(2);a=0;break;

      case '3': c=1;delay(2);a=0;break;

      case '4': d=1;delay(2);a=0;break;

      case '5': e=1;delay(2);a=0;break;

      default : break;

      }

    }

    void delay(int ms)

    {

      int i,j;

      for (i=0;i<ms;i++)

        for (j=0;j<120;j++)

        {}

    这里就不多说了,基本懂得51c的都能看懂。

    仿真:用的是proteus,串口调试助手,虚拟串口这三个软件。


    这是虚拟串口的软件。


    这个,串口调试助手

    具体怎么用,一摸索就知道了,要说明的是仿真是串口调试助手的“串口”选择“COM3”,protues中串口要选择“COM4”,其他比如波特率之类的设置就不废话了。


     

    下面这个是仿真的截图


     

    另外注意的是,51的rxd接rs232rxd,txd接txd,这里,我十分不明白。。。。


    就这些啦,哈哈,第一次写点东西,想想以后回来自己看看肯定会笑话自己的,不过,没什么,不这样哪有进步~虽然很稚嫩,但是是自己的~要指导的请联系我,感激不尽!

  • 相关阅读:
    SignalR 持久链接 (该功能为手机设备与后台同个用户id进行实现的,仅用signalR学习参考)
    SQL SERVER 分割符转列
    js时间计算加减
    SQL查询历史执行语句
    MSSQL 多行数据串联字符分割单行
    居于HttpWebRequest的HTTP GET/POST请求
    硬件UDP读数AsynUdpClient
    SQL取分组数据的所有第一条数据
    Python 文件的使用
    Python 数据类型
  • 原文地址:https://www.cnblogs.com/gaoquanning/p/3530592.html
Copyright © 2011-2022 走看看