串口开发小小心得
本人新入行,写的也只是很肤浅的自己的一点点理解。欢迎批评指正,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,这里,我十分不明白。。。。
就这些啦,哈哈,第一次写点东西,想想以后回来自己看看肯定会笑话自己的,不过,没什么,不这样哪有进步~虽然很稚嫩,但是是自己的~要指导的请联系我,感激不尽!
瓦靠,图片发不上,反正附件里要用的都有
c代码就比较难了, 不过楼上的可以找一下,我记得我以前看到过,用turboC编的串口程序,带中断的
谢谢楼主
用API实现
呵呵
我以前还用汇编写过,在dos下运行