找回密码
 立即注册
查看: 229|回复: 0

Unreal C++ 串口发送数据

[复制链接]
发表于 2022-7-17 07:44 | 显示全部楼层 |阅读模式
本文具体操作的录屏视频:https://www.bilibili.com/video/BV14C4y1a7gP/
在之前文章的基础上,继续增加串口功能。
https://blog.csdn.net/chenkaizhao/article/details/106635753
1.新建串口脚本
1.1新建C++脚本,继承Actor类,命名SerialUtls
1.2在SerialUtls.h申明函数和变量

~ASerialUtls();
public:
bool InitPort(UINT portNo = 2, UINT baud = CBR_9600, char parity = ‘N’,
UINT databits = 8, UINT stopsbits = 1, DWORD dwCommEvents = EV_RXCHAR);
bool WriteData(unsigned char* pData, unsigned int length);
private:
bool openPort(UINT portNo);
void ClosePort();
private:
/** 串口句柄 */
HANDLE m_hComm;
1.3增加头文件
#include “Windows/AllowWindowsPlatformTypes.h”
#include “Windows/PreWindowsApi.h”
#include <windows.h> //冲突头文件
#include “Windows/PostWindowsApi.h”
#include “Windows/HideWindowsPlatformTypes.h”
1.4在SerialUtls.cpp定义函数
  1. ASerialUtls::~ASerialUtls()
  2. {
  3.         ClosePort();
  4. }
  5. bool ASerialUtls::InitPort(UINT portNo, UINT baud, char parity, UINT databits, UINT stopsbits, DWORD dwCommEvents)
  6. {
  7.          /** 临时变量,将制定参数转化为字符串形式,以构造DCB结构 */
  8.     char szDCBparam[50];
  9.     sprintf_s(szDCBparam, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopsbits);
  10.     //** DEBUG
  11.     FString tempString(szDCBparam);
  12.     if (GEngine)
  13.     {
  14.         GEngine->AddOnScreenDebugMessage(1, 5.f, FColor::Red, tempString);
  15.     }
  16.     else
  17.     {
  18.         UE_LOG(LogTemp, Warning, TEXT("baud=%d parity=%c data=%d stop=%d"), baud, parity, databits, stopsbits);
  19.     }
  20.     /** 打开指定串口,该函数内部已经有临界区保护,上面请不要加保护 */
  21.     if (!openPort(portNo))
  22.     {
  23.         return false;
  24.     }
  25.     /** 是否有错误发生 */
  26.     BOOL bIsSuccess = true;
  27.     /** 设置串口的超时时间,均设为0,表示不使用超时限制 */
  28.     COMMTIMEOUTS  CommTimeouts;
  29.     CommTimeouts.ReadIntervalTimeout = 0;
  30.     CommTimeouts.ReadTotalTimeoutMultiplier = 0;
  31.     CommTimeouts.ReadTotalTimeoutConstant = 0;
  32.     CommTimeouts.WriteTotalTimeoutMultiplier = 0;
  33.     CommTimeouts.WriteTotalTimeoutConstant = 0;
  34.     if (bIsSuccess)
  35.     {
  36.         bIsSuccess = SetCommTimeouts(m_hComm, &CommTimeouts);
  37.     }
  38.     DCB  dcb;
  39.     if (bIsSuccess)
  40.     {
  41.         // 将ANSI字符串转换为UNICODE字符串
  42.         DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, szDCBparam, -1, NULL, 0);
  43.         wchar_t* pwText = new wchar_t[dwNum];
  44.         if (!MultiByteToWideChar(CP_ACP, 0, szDCBparam, -1, pwText, dwNum))
  45.         {
  46.             bIsSuccess = true;
  47.         }
  48.         /** 获取当前串口配置参数,并且构造串口DCB参数 */
  49.         bIsSuccess = GetCommState(m_hComm, &dcb) && BuildCommDCB(pwText, &dcb);
  50.         /** 开启RTS flow控制 */
  51.         dcb.fRtsControl = RTS_CONTROL_ENABLE;
  52.         /** 释放内存空间 */
  53.         delete[] pwText;
  54.     }
  55.     if (bIsSuccess)
  56.     {
  57.         /** 使用DCB参数配置串口状态 */
  58.         bIsSuccess = SetCommState(m_hComm, &dcb);
  59.     }
  60.     /**  清空串口缓冲区 */
  61.     PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
  62.     return bIsSuccess;
  63. }
  64. bool ASerialUtls::openPort(UINT portNo)
  65. {
  66.     /** 把串口的编号转换为设备名 */
  67.     char szPort[50];
  68.     sprintf_s(szPort, "COM%d", portNo);
  69.     /** 打开指定的串口 */
  70.     m_hComm = CreateFileA(szPort,                       /** 设备名,COM1,COM2等 */
  71.         GENERIC_READ | GENERIC_WRITE,  /** 访问模式,可同时读写 */
  72.         0,                             /** 共享模式,0表示不共享 */
  73.         NULL,                           /** 安全性设置,一般使用NULL */
  74.         OPEN_EXISTING,                  /** 该参数表示设备必须存在,否则创建失败 */
  75.         0,
  76.         0);
  77.     /** 如果打开失败,释放资源并返回 */
  78.     if (m_hComm == INVALID_HANDLE_VALUE)
  79.     {
  80.         return false;
  81.     }
  82.     return true;
  83. }
  84. void ASerialUtls::ClosePort()
  85. {
  86.     /** 如果有串口被打开,关闭它 */
  87.     if (m_hComm != INVALID_HANDLE_VALUE)
  88.     {
  89.         CloseHandle(m_hComm);
  90.         m_hComm = INVALID_HANDLE_VALUE;
  91.     }
  92. }
  93. bool ASerialUtls::WriteData(unsigned char* pData, unsigned int length)
  94. {
  95.     BOOL   bResult = true;
  96.     DWORD  BytesToSend = 0;
  97.     if (m_hComm == INVALID_HANDLE_VALUE)
  98.     {
  99.         FString msg("failure!");
  100.         if (GEngine)
  101.         {
  102.             GEngine->AddOnScreenDebugMessage(2, 5.f, FColor::Red, msg);
  103.         }
  104.         return false;
  105.     }
  106.     /** 向缓冲区写入指定量的数据 */
  107.     bResult = WriteFile(m_hComm, pData, length, &BytesToSend, NULL);
  108.     if (!bResult)
  109.     {
  110.         DWORD dwError = GetLastError();
  111.         /** 清空串口缓冲区 */
  112.         PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_RXABORT);
  113.         //** LeaveCriticalSection(&m_csCommunicationSync);
  114.         return false;
  115.     }
  116.     UE_LOG(LogTemp, Warning, TEXT("pData=%s length=%d"), pData, length);
  117.     return true;
  118. }
复制代码
1.5在ASerialUtls()增加
m_hComm = INVALID_HANDLE_VALUE;
1.6在BeginPlay()增加
InitPort(3, CBR_9600, ‘N’, 8U, 1U, EV_RXCHAR);
1.7在Tick(float DeltaTime)增加
unsigned char outString[] = “F88F0280808000002000”;
WriteData(outString, 21);
1.8保存,build solution。回到unreal,将脚本拖入。
2.程序调试
2.1打开VSPD,增加虚拟串口COM2和COM3
2.2打开串口调试助手,选择COM2(因为Unreal的程序是COM3),选择和Unreal程序相应的串口设置,打开串口
2.3回到Unreal,点击Play,可以看到串口调试助手接收到相应的信息。**
参考资料:
[1] https://blog.csdn.net/zhuxiaoyang2000/article/details/52096597
[2] https://blog.csdn.net/o0pk2008/article/details/103135421?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-5-1 07:10 , Processed in 0.133094 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表