VC API串口编程问题 附加详细注释的源码和图片
各位高手,我初学VC串口编程,遇到我不能解决的问题,已经阻碍我还几天了,无助之下到此论坛发求助贴,我现在技术有限,以后技术提高了我想尽量帮助别人。但现在需要被高手帮助。以下是我在VC++2005上用纯API编程,不涉及MFC,不涉及串口控件,无对话框,仅有一个按钮和一些监控文字输出,程序尽量简化了,通过COM1口发送任意RS232数据都成功了,就是接收不到数据。我用单片机发出各种数据都可被串口助手(选COM1口,设置正确)正确显示,但我编这个程序就是接收不到数据,调用ReadFile(hComm,&receive,10,&BytesRead,&m_ov)后开单片机连续发送串口数据,发现receive中数据无变化。
以下是源程序,只需在完全空白的VC++工程的源文件下新建一个空白的C文件,然后复制以下代码到上面,直接编译即可。
#include<windows.h>//包含基本数据类型定义
#include<stdlib.h> //数学函数库
#include<string.h> //数学函数库
#include<stdio.h>//输入输出库
#define ID_MYBUT 50//定义按钮事件标识
HWND hwnd;//主窗口句柄
HDC hdc;//设备环境句柄
int number0=2,number=0,number2=0,number3=0,number4=0,number5=0,number6=0,number7=0;//监控标志数,多无用处
int times=0;//记录了WM_PAINT被执行的次数
char dialogue1='m';//无用监控标志
char m_szWriteBuffer='a';//写串口的写入字符
bool open;
char receive;//读串口是数据放到这里
HANDLE hComm;
OVERLAPPED m_ov;
COMSTAT comstat;
DWORD m_dwCommEvents;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);//窗口函数说明
void ReceiveChar();//读串口的函数
BOOL Openport();//开串口的函数
BOOL setupdcb(int);//设置串口参数的函数
BOOL setuptimeout(DWORD,DWORD,DWORD,DWORD,DWORD);//设置超时的函数
BOOL WriteChar(DWORD);//写串口的函数
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) // 入口函数
{
MSG Msg; //MSG为消息结构体变量类型 Message为变量名,可为Msg
WNDCLASS wndclass;
char lpszClassName[]="位图";
char lpszTitle[]="LTL Programe";
wndclass.style=0;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=lpszClassName;
if(!RegisterClass(&wndclass))
{
MessageBeep(0);
return FALSE;
}
hwnd=CreateWindow
(
lpszClassName,//窗口实例的标题名
lpszTitle,//窗口的风格
WS_OVERLAPPEDWINDOW,//
0,//窗口左上角坐标为默认值
0,//
800,//窗口的高和宽为默认值
400,
NULL,//此窗口无父窗口
NULL,//此窗口无主菜单
hInstance,//创建此窗口应用程序的当前句柄
NULL//不使用该值
);
ShowWindow(hwnd,nCmdShow);//显示窗口
UpdateWindow(hwnd);//绘制用户区
while(GetMessage(&Msg,0,0,0))//消息循环
//后两个参数为0不过滤消息
{//GetMessage是从消息队列中提取一条消息,并将消息放到MSG结构体
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)//窗口函数说明
{
PAINTSTRUCT ps;
char str[30]="";
switch(message)//处理消息
{
case WM_CREATE:
hdc=GetDC(hwnd);//获取设备环境句柄
SetTimer(hwnd,1,200,NULL);
//创建按钮////////////////////////////////////////////////
HWND butt;
butt=CreateWindow(
"BUTTON", // predefined class
"OK", // button text
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // styles
20, // starting x position
10, // starting y position
100, // button width
30, // button height
hwnd, // parent window
(HMENU) ID_MYBUT, // No menu
(HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
NULL); // pointer not needed
//////////////////////////////////////////////////////////
break;
case WM_TIMER:
InvalidateRect(hwnd,NULL,FALSE);//刷新用户区,并序发送WM_PAINT消息
break;
case WM_COMMAND://处理按钮消息
switch(LOWORD(wParam))
{
case ID_MYBUT://点击按钮后打开串口并初始化
open=Openport();//打开串口COM1
if(open) number=999;//如果打开成功显示999
else number=111;
if(setupdcb(9600))
{
number2=1;
}
if(setuptimeout(10,0,20,0,0))
{
number3=1;
}
SetupComm(hComm,1024,1024);
SetCommMask(hComm,EV_RXCHAR);//当有字符串在inbuf中时产生这个事件
PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);//清空串口缓冲区
InvalidateRect(hwnd,NULL,TRUE);//刷新用户区,并序发送WM_PAINT消息
break;
}
case WM_PAINT://处理绘图消息
hdc=BeginPaint(hwnd,&ps);
if(number==999) {
ReceiveChar();
PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);//清空串口缓冲区
times++;
//WriteChar(1);
}
/////////监控字符输出////////////////////////
hdc=GetDC(hwnd);
SetTextColor(hdc,RGB(0,0,0));
sprintf(str,"num=%d",number);
TextOut(hdc,166,11,str,strlen(str));
sprintf(str,"times=%d",times);
TextOut(hdc,166,61,str,strlen(str));
sprintf(str,"setupDCB= %d",number2);
TextOut(hdc,250,11,str,strlen(str));
sprintf(str,"setupTIMEout= %d",number3);
TextOut(hdc,400,11,str,strlen(str));
sprintf(str,"Receive=%c",receive);
TextOut(hdc,400,51,str,strlen(str));
ReleaseDC(hwnd,hdc);
////////////////////////////////////////////
EndPaint(hwnd,&ps);//释放设备环境句柄
break;
case WM_DESTROY://消除窗口时由DestroyWindow函数发出此消息
KillTimer(hwnd,1);//删除定时器
CloseHandle(hComm);//关闭串口
PostQuitMessage(0);//向应用程序发出WM_QUIT消息,请求退出
break;
default://对未定义的消息提供默认处理
return(DefWindowProc(hwnd,message,wParam,lParam));
}return 0;
}
BOOL Openport()
{
hComm=CreateFile("COM1",//串口号
GENERIC_READ|GENERIC_WRITE,//允许读写
0,//通讯设备必须以独占方式打开
0,//无安全属性
OPEN_EXISTING,//通讯设备已存在
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//异步IO
NULL);//通讯设备不能用模板打开
if(hComm==INVALID_HANDLE_VALUE)
{
CloseHandle(hComm);//关闭串口
return FALSE;
}
else
return true;
}
BOOL setupdcb(int rate_arg)
{
DCB dcb;
memset(&dcb,0,sizeof(dcb));
if(!GetCommState(hComm,&dcb))
return FALSE;
dcb.DCBlength=sizeof(dcb);//DCB结构体大小
//*---------SERIAL Port Config-----------*/
dcb.BaudRate=9600;//波特率
dcb.Parity=NOPARITY;//奇偶校验
dcb.fParity=0;//是否进行奇偶校验
dcb.ByteSize=8;//数据宽度
dcb.fOutxCtsFlow=0;//CTX线上硬件握手
dcb.fOutxDsrFlow=0;//DSR线上硬件握手
dcb.fDtrControl=DTR_CONTROL_DISABLE;//DTR控制
dcb.fDsrSensitivity=0;
dcb.fRtsControl=RTS_CONTROL_DISABLE;
dcb.fOutX=0;//是否使用XON/XOFF协议
dcb.fInX=0;//是否使用XON/XOFF协议
//*---------misc parameters-----------*/
dcb.fErrorChar=0;
dcb.fBinary=1;//是否是二进制
dcb.fNull=0;
dcb.fAbortOnError=0;
dcb.wReserved=0;
dcb.XonLim=0;//设置XON字符发送前inbuf中允许的最小字节数
dcb.XonChar=0x13;//设置表示XON字符的字符,一般是采用0x11
dcb.XoffChar=0x19;//设置表示XOFF字符的字符,一般采用0x13
dcb.EvtChar=0;
dcb.StopBits=TWOSTOPBITS;//设定停止位为2位
SetCommState(hComm,&dcb);
return true;
}
BOOL setuptimeout(DWORD ReadInterval,DWORD ReadTotalMultiplier,DWORD ReadTotalconstant,DWORD WriteTotalMultiplier,DWORD WriteTotalconstant)
{
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout=ReadInterval;//以毫秒为单位指定通信线上两个字符到达之间的最大时间
timeouts.ReadTotalTimeoutConstant=ReadTotalconstant;//以毫秒为单位指定一个常数,用于计算读操作的总限时时间
timeouts.ReadTotalTimeoutMultiplier=ReadTotalMultiplier;//为0则读操作立即返回已接受到的字符
timeouts.WriteTotalTimeoutConstant=WriteTotalconstant;//与ReadTotalTimeoutConstant相似
timeouts.WriteTotalTimeoutMultiplier=WriteTotalMultiplier;//与ReadTotalTimeoutMultiplier相似
if(!SetCommTimeouts(hComm,&timeouts))//如果设置超时成功
return false;
else
return true;
}
//不好使得读函数
void ReceiveChar()
{
DWORD dwError=0;
DWORD BytesRead=0;
BOOL dataread;
ClearCommError(hComm,&dwError,&comstat);//清除以前的错误并读串口现在的状态
ReadFile(hComm,&receive,1,&BytesRead,&m_ov);//单片机连续发送数据,理应受到数据送至字符串变量receive,然后通过主程序输出到窗口上。
//单片机发送的数据波特率为9600,无奇偶校验,停止位2位,串口助手能显示接收到的数据。
if(GetLastError()==ERROR_IO_PENDING)//查询读写FALSE的详细结果
WaitForSingleObject(m_ov.hEvent,100);
}
//以下为写串口函数,该函数没问题,只是读函数有问题,我在主程序中注释掉写函数了。
BOOL WriteChar(DWORD m_nToSend)
{
BOOL bWrite=TRUE;
BOOL bResult=TRUE;
DWORD BytesSent=0;
HANDLE m_hWriteEvent;
ResetEvent(m_hWriteEvent);
if(bWrite)
{
m_ov.Offset=0;//OVERLAPPED结构体
m_ov.OffsetHigh=0;
//Clean buffer
bResult=WriteFile(hComm,//串口句柄
&m_szWriteBuffer,//待写入数据的首地址
m_nToSend,//待写入数据的字节长度
&BytesSent,//函数返回的实际写入串口的数据数量的地址
&m_ov);//m_ov重叠I/O结构的指针
if(!bResult)//如果写串口不成功
{
number7=2;
DWORD dwError=GetLastError();//获取不成功的详细信息
switch(dwError)
{
case ERROR_IO_PENDING://写串口未完成函数就返回
{
number7=3;
BytesSent=0;//
bWrite=FALSE;
break;
}
default:
{//all other error codes
number7=4;
break;
}
}
}
else number7=1;
}//end if(bWrite)
if(!bWrite)//写串口未完时的操作
{
bWrite=TRUE;
bResult=GetOverlappedResult(hComm,////调用GetOv..函数等待写串口完成
&m_ov,//
&BytesSent,//
TRUE);
number7=5;
//等待OVERLAPPED结构的hEvent事件,若规定了读写超时,超时则自动结束等待,否则一直等待
if(!bResult)
{
number7=6;
number5=1;
}
}//end if(!bWrite)
if(BytesSent!=m_nToSend)//如果实际写入串口字节数不等于要写入的字节数,则报错
{
number6=1;
}
return true;
}
希望高人能解答!