⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 step2_serial2.cpp

📁 此为一个在arm的wince操作系统上运行的 串口例子程序.
💻 CPP
字号:
// step2_serial2.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "serial.h"

//--------------------------------------------------------------------
//全局变量
//--------------------------------------------------------------------
const TCHAR szAppName[] = TEXT("HelloCE");
HINSTANCE   hInst;								//程序instance handle
ULONG       RxDataTotalLen;						//接收的数据总字节数

// 窗口操作的公共变量
HDC         hdc;
PAINTSTRUCT ps;


// Message dispatch table for MainWindowProc
const struct decodeUINT MainMessages[] =
{
	{ WM_PAINT,   DoPaintMain },
	{ WM_DESTROY, DoDestroyMain },
	{ WM_RXDATA,  DoShowRxInfo }
};

int WINAPI WinMain(	HINSTANCE hInstance,
					HINSTANCE hPrevInstance,
					LPTSTR    lpCmdLine,
					int       nCmdShow)
{
	MSG msg;
	int rc = 0;
	HWND hwndMain;
	SERIAL_THREAD_PARA SerPara;
	HANDLE hReadThread;
	DCB  SerDCB;
	COMMTIMEOUTS SerTimeouts;

 	// TODO: Place code here.
	// 初始化本程序实例,主要是创建窗口等工作
	hwndMain = InitInstance( hInstance, lpCmdLine, nCmdShow );
	if( hwndMain == 0 ) 
		return 0x10;	// init fail!

	// 初始化串口
	SerPara.hWnd = hwndMain;
	SerPara.hSer = CreateFile( TEXT("COM1:"), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL );
	if( SerPara.hSer == INVALID_HANDLE_VALUE )
	{
		return 0x11;					// 打开串口失败
	}
	SerPara.fnDatPro = RxDatPro;		// 加载回调函数

	// 设置串口通讯参数
	SerDCB.DCBlength = sizeof( DCB );

	// 读取当前DCB
	GetCommState( SerPara.hSer, &SerDCB );

	// 修改相关参数, 如9600bps, 8-N-1
	SerDCB.BaudRate = CBR_9600;			// 波特率 9600
	SerDCB.ByteSize = 8;				// 数据位 8bit
	SerDCB.StopBits = ONESTOPBIT;		// 1个停止位
	SerDCB.Parity = NOPARITY;			// 无校验
	SerDCB.fNull = FALSE;
	SerDCB.fParity = FALSE;
	
	// 再设置回串口驱动
	SetCommState( SerPara.hSer, &SerDCB );

	// 读取当前超时参数结构
	GetCommTimeouts( SerPara.hSer, &SerTimeouts );

	// 修改相关参数...
	SerTimeouts.ReadIntervalTimeout = 0;
	SerTimeouts.ReadTotalTimeoutConstant = 0;
	SerTimeouts.ReadTotalTimeoutMultiplier = 0;
	SerTimeouts.WriteTotalTimeoutConstant = 0;
	SerTimeouts.WriteTotalTimeoutMultiplier = 0;
	// 再设置回串口驱动
	SetCommTimeouts( SerPara.hSer, &SerTimeouts );

	RxDataTotalLen = 0;		//接收到的数据总数清零
		
	// 创建串口接收线程
	hReadThread = CreateThread( NULL, 0, RxThread, (LPVOID)&SerPara, 0, NULL );
	if( hReadThread==NULL )
	{
		return 0x12;    // 创建线程失败
	}

	// 应用程序消息循环
	while( GetMessage( &msg, NULL, 0, 0 ) )
	{
		TranslateMessage( &msg );
		DispatchMessage( &msg );
	}

	//------------------------------------------------------------------------------
	// 进入当前进程推出阶段...
	//------------------------------------------------------------------------------
	TerminateThread( hReadThread, 0 );				// 终止线程
	CloseHandle( SerPara.hSer );					// 关闭串口		
	return TermInstance( hInstance, msg.wParam );	// Instance cleanup
}

//--------------------------------------------------------------------
// Instance Initialization 实例初始化
//--------------------------------------------------------------------
HWND InitInstance( HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow )
{
	WNDCLASS wc;
	HWND     hWnd;

	//注册本应用程序主窗口类
	wc.style = 0;												//窗口风格
	wc.lpfnWndProc = MainWndProc;								//回调函数,系统将调用该函数处理消息
	wc.cbClsExtra = 0;											//Extra class data, a char string 
	wc.cbWndExtra = 0;											//Extra window data, a char string
	wc.hInstance = hInstance;									//本程序handle
	wc.hIcon = NULL;											//Application Icon
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );					//使用缺省光标
	wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpszMenuName = NULL;										//Menu name
	wc.lpszClassName = szAppName;								//窗口类名称

	if( !RegisterClass( &wc ) )
		return 0;												//注册失败,返回0

	//创建主窗口
	hWnd = CreateWindow( szAppName,								//指定窗口类
		                 TEXT("Serial Test"),					//窗口title
						 WS_VISIBLE|WS_CAPTION|WS_SYSMENU,		//窗口风格标志
						 CW_USEDEFAULT,							//x position
						 CW_USEDEFAULT,							//y position
						 CW_USEDEFAULT,							//inital width
						 CW_USEDEFAULT,							//initial height
						 NULL,									//Parent
						 NULL,									//Menu, must be null
						 hInstance,								//本程序handle
						 NULL );								//参数
	if( !IsWindow( hWnd ) )
		return 0;												//创建失败,返回0

	//执行标准显示、更新调用
	ShowWindow( hWnd, nCmdShow );
	UpdateWindow( hWnd );
	return hWnd;
}

//--------------------------------------------------------------------
// 实例终止
//--------------------------------------------------------------------
int  TermInstance( HINSTANCE hInstance, int nMssgParam )
{
	return nMssgParam;
}

//====================================================================
// 主窗口消息处理函数
//--------------------------------------------------------------------

//--------------------------------------------------------------------
// 窗口回调函数MainWndProc
//--------------------------------------------------------------------
LRESULT CALLBACK MainWndProc( HWND hWnd,  UINT wMsg, WPARAM wParam, LPARAM lParam )
{
	int i1, nNum;

	// 用switch更容易理解消息处理的分派,但Douglas建议用循环来搜索消息,以精简代码,当然降低些速度。
	nNum = dim(MainMessages);
	for( i1=0; i1<nNum; i1++ )
	{
		if( wMsg != MainMessages[i1].Code ) continue;
		return MainMessages[i1].Fxn( hWnd, wMsg, wParam, lParam );
	}

	/*
	// 根据不同的消息,执行相应的处理。
	switch( wMsg )
	{
	case WM_PAINT:
		return DoPaintMain( hWnd, wMsg, wParam, lParam );

	case WM_DESTROY:
		return DoDestroyMain( hWnd, wMsg, wParam, lParam );
	}
	*/

	return DefWindowProc( hWnd, wMsg, wParam, lParam );
}


//--------------------------------------------------------------------
// 消息WM_PAINT的处理函数
//--------------------------------------------------------------------
LRESULT DoPaintMain( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
	//PAINTSTRUCT ps;
	//HDC         hdc;
	RECT        rect;

	//获取窗口外形尺寸
	GetClientRect( hWnd, &rect );

	hdc = BeginPaint( hWnd, &ps );		//进入窗口显示操作
	//显示初始化信息
	DrawText( hdc, TEXT("Step2: Serial Test"), -1, &rect, DT_CENTER|DT_VCENTER|DT_SINGLELINE );
	//另外一个写text函数是ExtTextOut(...)
	return 0;
}

//--------------------------------------------------------------------
// 消息WM_DESTROY的处理函数
//--------------------------------------------------------------------
LRESULT DoDestroyMain( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
	EndPaint( hWnd, &ps );				//退出窗口显示操作
	PostQuitMessage( 0 );
	return 0;
}

//--------------------------------------------------------------------
// 消息WM_RXDATA的处理函数
// 本来应当用回调函数,但有问题,所以用消息处理函数进行测试...
//--------------------------------------------------------------------
LRESULT DoShowRxInfo( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
	//PAINTSTRUCT         ps;
	//HDC                 hdc;
	RECT                rect;
	int                 i1;
	char                cBuf[100];
	TCHAR               SzShowStr[100];
	PSERIAL_THREAD_PARA lpSerPara;

	lpSerPara = (PSERIAL_THREAD_PARA)lParam;

	// 接收数据处理
	RxDataTotalLen += lpSerPara->nDatLen;			// 累加串口接收数据
	lpSerPara->DatBuf[lpSerPara->nDatLen] = '\0';
	// 生成窗口显示信息
	i1 = sprintf( cBuf, "Recv=%d ", RxDataTotalLen );
	mbstowcs( SzShowStr, cBuf, i1 );				//转换成unicode
	SzShowStr[i1] = 0;						//添加结束符

	GetClientRect( hWnd, &rect );					//获取窗口外形尺寸
	//接收信息显示
	DrawText( hdc, SzShowStr, -1, &rect, DT_BOTTOM|DT_LEFT|DT_SINGLELINE );
	//另外一个写text函数是ExtTextOut(...)
	return 0;
}

//供串口线程调用的处理函数
LRESULT CALLBACK RxDatPro( HWND hWnd, char* pDatBuf, ULONG nLen )
{
	//PAINTSTRUCT ps;
	//HDC         hdc;
	RECT        rect;
	int         i1;
	char        cBuf[100];
	TCHAR       SzShowStr[100];

	// 接收数据处理
	RxDataTotalLen += nLen;			// 累加串口接收数据
	pDatBuf[nLen] = 0;
	// 生成窗口显示信息
	i1 = sprintf( cBuf, "  Recv=%d...%s", RxDataTotalLen, pDatBuf);
	mbstowcs( SzShowStr, cBuf, i1 );		//转换成unicode
	SzShowStr[i1] = 0;						//添加结束符

	GetClientRect( hWnd, &rect );			//获取窗口外形尺寸
	rect.bottom -= 50;
	rect.top = rect.bottom - 100;
	rect.left += 50;
	rect.right -= 50;
	//显示接收信息
	//DrawText( hdc, SzShowStr, -1, &rect, DT_BOTTOM|DT_LEFT|DT_SINGLELINE );
	ExtTextOut( hdc, rect.left, rect.top, ETO_OPAQUE, &rect, SzShowStr, i1, NULL );
	return 0;
}

/*
//串口线程的输入参数
typedef struct  _SER_THREAD_PARA
{
	HWND	   hWnd;			// 创建串口线程的进程的handler
	HANDLE     hSer;			// 打开的串口handler
	FPRxDatPro fnDatPro;		// 回调函数指针
	char       DatBuf[1500];	// 串口数据接收buffer
	ULONG      nDatLen;			// 接收的数据长度
} SERIAL_THREAD_PARA, *PSERIAL_THREAD_PARA;
*/

DWORD WINAPI RxThread( PVOID pArg )
{
	PSERIAL_THREAD_PARA lpSerPara;
	ULONG               nWillLen;
	DWORD			    dwEvtMask, dwReadError;
	COMSTAT			    cmStat;

	lpSerPara = (PSERIAL_THREAD_PARA)pArg;
	
	if( lpSerPara->hSer == INVALID_HANDLE_VALUE )       
		return 0;
	if( lpSerPara->fnDatPro == NULL )
		return 0;
	if( lpSerPara->DatBuf == NULL )
		return 0;

	// 清收发数据buffer
	PurgeComm( lpSerPara->hSer, PURGE_RXCLEAR|PURGE_TXCLEAR );

	SetCommMask( lpSerPara->hSer, EV_RXCHAR|EV_ERR );
	while( 1 )
	{
		if( WaitCommEvent( lpSerPara->hSer, &dwEvtMask, NULL ) )
		{
			SetCommMask( lpSerPara->hSer, EV_RXCHAR|EV_ERR );
			// get how many data available in receive buffer
			if( dwEvtMask & EV_RXCHAR )
			{
				ClearCommError( lpSerPara->hSer, &dwReadError, &cmStat );	//取接收数据长度信息
				nWillLen = cmStat.cbInQue;
				if( nWillLen <=0 )
					continue;
				ReadFile( lpSerPara->hSer, lpSerPara->DatBuf, nWillLen, &lpSerPara->nDatLen, 0 );
			
				if( lpSerPara->nDatLen>0 )
				{
					// 发送接收到的数据
					WriteFile( lpSerPara->hSer, lpSerPara->DatBuf, lpSerPara->nDatLen, &nWillLen, 0 );
					// 调用回调函数处理接收到的数据(本例中用于窗口显示)
					lpSerPara->fnDatPro( lpSerPara->hWnd, lpSerPara->DatBuf, lpSerPara->nDatLen );

					// 也可以采用发送消息到主窗口代替回调函数...
					//PostMessage( lpSerPara->hWnd, WM_RXDATA, 0, (LPARAM)lpSerPara );
				}
			}
			else if( dwEvtMask & EV_ERR )
			{
				// 清错误标志
				ClearCommError( lpSerPara->hSer, &dwReadError, &cmStat );
			}

		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -