📄 step2_serial.cpp
字号:
// step2_serial.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; //接收的数据总字节数
// 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("Step2"), //窗口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(...)
EndPaint( hWnd, &ps ); //退出窗口显示操作
return 0;
}
//--------------------------------------------------------------------
// 消息WM_DESTROY的处理函数
//--------------------------------------------------------------------
LRESULT DoDestroyMain( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
PostQuitMessage( 0 );
return 0;
}
//--------------------------------------------------------------------
// 消息WM_RXDATA的处理函数
// 本来应当用回调函数,但有问题,所以用消息处理函数进行测试...
//--------------------------------------------------------------------
LRESULT DoShowRxInfo( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
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 ); //获取窗口外形尺寸
hdc = GetDC( hWnd );
//接收信息显示
DrawText( hdc, SzShowStr, -1, &rect, DT_BOTTOM|DT_LEFT|DT_SINGLELINE );
//另外一个写text函数是ExtTextOut(...)
ReleaseDC( hWnd, hdc );
return 0;
}
//供串口线程调用的处理函数
LRESULT CALLBACK RxDatPro( HWND hWnd, char* pDatBuf, ULONG nLen )
{
HDC hdc;
RECT rect;
int i1;
char cBuf[100];
TCHAR SzShowStr[100];
// 接收数据处理
RxDataTotalLen += nLen; // 累加串口接收数据
pDatBuf[nLen] = 0;
// 生成窗口显示信息
i1 = sprintf( cBuf, "接收长度=%d...%s", RxDataTotalLen, pDatBuf);
mbstowcs( SzShowStr, cBuf, i1 ); //转换成unicode
SzShowStr[i1] = 0; //添加结束符
GetClientRect( hWnd, &rect ); //获取窗口外形尺寸
hdc = GetDC( hWnd );
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 );
ReleaseDC( hWnd, hdc );
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 + -