串口开发小小心得

zhangjingrui   2007-10-15 18:05 楼主
串口开发小小心得

本人新入行,写的也只是很肤浅的自己的一点点理解。欢迎批评指正,qq:15065328.email:zxiki@163.com。msn:zxiki@hotmail.com。如果这些经验能对您有所帮助,我将非常荣幸。欢迎转载(可能抬举自己了),但请把以上文字一并保留。谢谢!








项目(先这么称呼吧)简介,简单的来说就是计算机通过串口分别控制4个二极管的亮度。
上位机部分:只说说我用到的一些函数,和遇到的问题。基本的比如什么是异步通讯啦之类的就不说了,随便网上一搜能找一箩筐!
下边是一些函数:
因为是最简单的应用,所以用到的函数也都是最最简单的一些,都是非常容易理解的。只是通过计算机向51发送指令所以连ReadFile()都没用到。省了很多事。。。。。。
1.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。

2.GetCommState()
功能:获得串口状态
BOOL GetCommState(
HANDLE hFile, // handle of communications device
LPDCB lpDCB // address of device-control block structure
);

3.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;//修改数据传输率。。。。这里还有很多参数可以修改,比如,停止位,有无校验等等,具体参见dcb结构。
............
if(SetCommState(hComm,&dcb))//设置新参数
......    //错误处理
4.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成员无信号,则该函数将一直等待下去

5.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函数可以终止正在进行的读写操作,该函数还会清除输入或输出缓冲区中的内容。

6.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函数清除错误标志。
该函数负责报告指定的错误和设备的当前状态。
7CloseHandle();
功能:关闭串口
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!");
        
        if(!GetCommState(hCom,&dcb)) //获得串口设置并用它填充dcb结构体
                ShowMessage("GetCommState failed");

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

        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));
        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;
  }
  }      
上位机的程序就这么样了。。。。。

单片机源码:这是根据上位机的程序来写的。
写不下那么多了。。。

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

这是虚拟串口的软件。

这个,串口调试助手

具体怎么用,一摸索就知道了,要说明的是仿真是串口调试助手的“串口”选择“COM3”,protues中串口要选择“COM4”,其他比如波特率之类的设置就不废话了。
  
另外注意的是,51的rxd接rs232rxd,txd接txd,这里,我十分不明白。。。。

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


瓦靠,图片发不上,反正附件里要用的都有

回复评论 (13)

顶LZ.
点赞  2007-10-15 19:39
向LZ学习!
正要学BCB

谢谢
点赞  2007-10-15 21:11
有类似的C 代码吗?
点赞  2007-10-16 01:51
c代码就比较难了, 不过楼上的可以找一下,我记得我以前看到过,用turboC编的串口程序,带中断的
点赞  2007-10-21 21:59
呵呵,谢谢大家~
点赞  2007-11-11 20:14
C 也不能难啊

呵呵 代码就更简洁了
点赞  2007-11-12 11:09
有没有汇编的代码啊?
点赞  2007-11-13 11:47
现在谁还用汇编?
谢谢搂主啦
点赞  2007-11-20 11:20
我还是熟悉单片机一点
点赞  2007-12-1 10:47


谢谢搂主

点赞  2007-12-2 23:46
正是我需要的,拜谢楼主,,学学
点赞  2007-12-15 19:37
谢谢楼主
用API实现
呵呵

我以前还用汇编写过,在dos下运行
点赞  2007-12-16 20:55
接分是王道!
点赞  2008-5-1 09:18
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复