利用电脑串口进行控制
cpp
// UartStickDlg.cpp: 实现文件
//
#include "stdafx.h"
#include "UartStick.h"
#include "UartStickDlg.h"
#include "afxdialogex.h"
// CUartStickDlg 对话框
CUartStickDlg::CUartStickDlg(CWnd* pParent /*=nullptr*/)
: CDialog(IDD_UARTSTICK_DIALOG, pParent)
, m_strComPort(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CUartStickDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_strComPort);
}
BEGIN_MESSAGE_MAP(CUartStickDlg, CDialog)
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_BN_CLICKED(IDC_B_UP, &CUartStickDlg::OnBnClickedBUp)
ON_BN_CLICKED(IDC_B_DN, &CUartStickDlg::OnBnClickedBDn)
ON_BN_CLICKED(IDC_B_LEFT, &CUartStickDlg::OnBnClickedBLeft)
ON_BN_CLICKED(IDC_B_RIGHT, &CUartStickDlg::OnBnClickedBRight)
ON_BN_CLICKED(IDC_B_B, &CUartStickDlg::OnBnClickedBB)
ON_BN_CLICKED(IDC_B_A, &CUartStickDlg::OnBnClickedBA)
ON_BN_CLICKED(IDC_B_OPEN, &CUartStickDlg::OnBnClickedBOpen)
ON_BN_CLICKED(IDC_B_SELECT, &CUartStickDlg::OnBnClickedBSelect)
ON_BN_CLICKED(IDC_B_START, &CUartStickDlg::OnBnClickedBStart)
END_MESSAGE_MAP()
// CUartStickDlg 消息处理程序
BOOL CUartStickDlg::OnInitDialog()
{
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CUartStickDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
DoKeyDownOrUp(nChar, TRUE);
}
void CUartStickDlg::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
DoKeyDownOrUp(nChar, FALSE);
}
BOOL CUartStickDlg::PreTranslateMessage(MSG * pMsg)
{
bool bFilter = false;
if (pMsg->message == WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case 'W':
case 'A':
case 'S':
case 'D':
case 'J':
case 'K':
case 'G':
case 'H':
bFilter = TRUE;
DoKeyDownOrUp(pMsg->wParam, TRUE);
}
if (bFilter)
return TRUE;
}
else if (pMsg->message == WM_KEYUP)// 处理WM_KEYUP消息
{
switch (pMsg->wParam)
{
case 'W':
case 'A':
case 'S':
case 'D':
case 'J':
case 'K':
case 'G':
case 'H':
bFilter = TRUE;
DoKeyDownOrUp(pMsg->wParam, FALSE);
}
if (bFilter)
return TRUE;
}
return FALSE;
}
void CUartStickDlg::OnBnClickedBUp()
{
UINT n = 'W';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBDn()
{
UINT n = 'S';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBLeft()
{
UINT n = 'A';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBRight()
{
UINT n = 'D';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBB()
{
UINT n = 'J';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBA()
{
UINT n = 'K';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBSelect()
{
UINT n = 'G';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
void CUartStickDlg::OnBnClickedBStart()
{
UINT n = 'H';
DoKeyDownOrUp(n, TRUE);
::Sleep(100);
DoKeyDownOrUp(n, FALSE);
}
DWORD __stdcall CUartStickDlg::__RecvThread(void * lpp)
{
CUartStickDlg* pThis = (CUartStickDlg*)lpp;
if (pThis)
{
pThis->RecvThread();
}
return 0;
}
void CUartStickDlg::RecvThread()
{
char buffer[12560] = {};
DWORD bytesRead;
OVERLAPPED ovlp = {};
ovlp.hEvent = CreateEvent(0, TRUE, FALSE, NULL);
while (true) {
if (m_hSerial != INVALID_HANDLE_VALUE /*&& WaitCommEvent(m_hSerial, NULL, NULL)*/) {
//与发送之间进行锁定
//CAutoLock lock(&m_lockRW);
BOOL bRead = ReadFile(m_hSerial, buffer, sizeof(buffer) - 1, &bytesRead, &ovlp);
if (!bRead && GetLastError() == ERROR_IO_PENDING) {
// 等待读取完成
WaitForSingleObject(ovlp.hEvent, INFINITE);
GetOverlappedResult(m_hSerial, &ovlp, &bytesRead, FALSE);
bRead = TRUE;
}
if (bRead && bytesRead > 0) {
buffer[bytesRead] = '\0';
// 打印ESP32发送的调试信息
printf("\n[ESP32]%s", buffer);
}
ResetEvent(ovlp.hEvent);
}
Sleep(10);
}
}
void CUartStickDlg::SendThread()
{
OVERLAPPED ovlp = {};
ovlp.hEvent = CreateEvent(0, TRUE, FALSE, NULL);
while (true) {
uint8_t currentState = (uint8_t)m_Kstate;
// 只在状态变化时发送,如果方向键按下也需发送
if (currentState/* || currentState != previousState || direct_key_down(currentState)*/) {
previousState = currentState;
// 构建数据包
uint8_t packet[] = { START_BYTE, currentState, currentState };
DWORD bytesWritten;
if (m_hSerial != INVALID_HANDLE_VALUE)
{
//与发送之间进行锁定
//CAutoLock lock(&m_lockRW);
BOOL bWr=WriteFile(m_hSerial, packet, sizeof(packet), &bytesWritten, &ovlp);
if (!bWr && GetLastError() == ERROR_IO_PENDING) {
// 等待读取完成
WaitForSingleObject(ovlp.hEvent, INFINITE);
GetOverlappedResult(m_hSerial, &ovlp, &bytesWritten, FALSE);
bWr = TRUE;
}
ResetEvent(ovlp.hEvent);
}
}
Sleep(25); // 控制发送频率 40次/s
}
}
DWORD __stdcall CUartStickDlg::__SendThread(void * lpp)
{
CUartStickDlg* pThis = (CUartStickDlg*)lpp;
if (pThis)
{
pThis->SendThread();
}
return 0;
}
bool direct_key_down(uint8_t st)
{
if (st&(uint8_t)CONTROLLER::Up ||
st & (uint8_t)CONTROLLER::Down ||
st & (uint8_t)CONTROLLER::Left ||
st & (uint8_t)CONTROLLER::Right
)
{
return true;
}
return false;
}
// 打开串口
bool CUartStickDlg::OpenSerialPort(CString portName, int baudRate) {
CString Full = L"\\\\.\\" + portName;
m_hSerial = CreateFileW(Full,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED,
NULL);
if (m_hSerial == INVALID_HANDLE_VALUE) {
return false;
}
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(m_hSerial, &dcbSerialParams)) {
CloseHandle(m_hSerial);
m_hSerial = INVALID_HANDLE_VALUE;
return false;
}
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(m_hSerial, &dcbSerialParams)) {
CloseHandle(m_hSerial);
m_hSerial = INVALID_HANDLE_VALUE;
return false;
}
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(m_hSerial, &timeouts)) {
CloseHandle(m_hSerial);
m_hSerial = INVALID_HANDLE_VALUE;
return false;
}
return true;
}
void CUartStickDlg::OnBnClickedBOpen()
{
if (m_hRecv)
return;
//打开串口
UpdateData(TRUE);
//打开串口
redo:
DWORD dwTick = GetTickCount();
if (!OpenSerialPort(m_strComPort, 115200))
{
if (GetTickCount() - dwTick < 10000)
{
Sleep(1);
goto redo;
}
MessageBox(L"错误: 无法打开串口");
return;
}
if (!AllocConsole()) {
AfxMessageBox(L"控制台窗口创建失败!");
return;
}
// 2. 重定向标准输入输出
FILE* pFile = nullptr;
freopen_s(&pFile, "CONOUT$", "w", stdout);
freopen_s(&pFile, "CONOUT$", "w", stderr);
freopen_s(&pFile, "CONIN$", "r", stdin);
// 3. 设置控制台标题
SetConsoleTitle(L"UartStick对话框控制台输出");
printf("使用printf输出测试\n");
//收发线程
m_hRecv = CreateThread(0, 0, __RecvThread, this, 0, 0);
m_hSend = CreateThread(0, 0, __SendThread, this, 0, 0);
}
__declspec(noinline) CONTROLLER _key_down_up(CONTROLLER kstate, CONTROLLER flagm, bool bDownOrUp)
{
if (bDownOrUp)
kstate = (CONTROLLER)((uint8_t)kstate | (uint8_t)flagm);
else
kstate = (CONTROLLER)((uint8_t)kstate &(~(uint8_t)flagm));
return kstate;
}
void CUartStickDlg::DoKeyDownOrUp(UINT nChar, BOOL bDownOrUp)
{
switch (nChar)
{
case 'W':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::Up, bDownOrUp);
break;
case 'S':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::Down, bDownOrUp);
break;
case 'A':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::Left, bDownOrUp);
break;
case 'D':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::Right, bDownOrUp);
break;
case 'J':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::B, bDownOrUp);
break;
case 'K':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::A, bDownOrUp);
break;
case 'G':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::Select, bDownOrUp);
break;
case 'H':
m_Kstate = _key_down_up(m_Kstate, CONTROLLER::Start, bDownOrUp);
break;
default:
break;
}
//发送状态
CString strKeyStl;
strKeyStl.Format(L"[KeySt]=0x%02X\n", m_Kstate);
OutputDebugStringW(strKeyStl);
}