QT Creator学习记录二上位机和下位机网口UDP通信
UI界面图
1. 工程文件及头文件添加代码
工程文件xxx.pro中添加:
-
#网口通信
-
QT = network
头文件xxx.h中添加:
-
//UDP
-
-
2. 接收数据
(1) uSocket初始化
-
MainWindow::MainWindow(QWidget *parent)
-
: QMainWindow(parent)
-
, ui(new Ui::MainWindow)
-
{
-
ui->setupUi(this);
-
-
-
/* UDP -注意逻辑- */
-
//创建QUdpSocket对象
-
uSocket = new QUdpSocket(this);
-
//绑定本地IP和端口号,IPLocal与PortLocal为自定义的全局变量
-
uSocket->bind(QHostAddress(IPLocal),PortLocal);
-
//默认关闭
-
uSocket->close();
-
//收到数据时,会触发readyRead()信号,自定义readPendingDatagrams()进行读取数据
-
connect(uSocket,&QUdpSocket::readyRead, this,&MainWindow::UDP_DataReceived);
-
-
}
-
/* UDP网口 ↓*/
-
//默认本地端口号
-
quint16 PortLocal =8089;
-
//默认本地IP地址
-
QString IPLocal ="192.168.10.200";
QT官方文档:bind函数的定义和所需参数, 咱直接传个IP地址和端口号就行
-
// ### Qt6: make the first one virtual
-
bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform);
-
bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform);
问题记录:关于QUdpSocket数据类型的 bind () 与 close () 与 open ()
之前将IP与端口号绑定后,正常接收数据,关闭网口再打开发现收不到数据了😂
后面发现UDP关闭后,再打开需要重新绑定,即便uSocket对象一直存在。
另外open的时候注意,记得写open方式,QT官方文档:
virtual bool open(OpenMode mode);
-
public:
-
enum OpenModeFlag {
-
NotOpen = 0x0000,
-
ReadOnly = 0x0001,
-
WriteOnly = 0x0002,
-
ReadWrite = ReadOnly | WriteOnly,
-
Append = 0x0004,
-
Truncate = 0x0008,
-
Text = 0x0010,
-
Unbuffered = 0x0020
-
};
-
Q_DECLARE_FLAGS(OpenMode, OpenModeFlag)
而且,记得传参数时加上QIODevice:: (我之前没加,一直尝试,不知道哪出了问题,坑。)
uSocket->open(QIODevice::ReadWrite);
结论:close后open要重新bind
(2)UDP接收数据
-
//UDP接收
-
void MainWindow::UDP_DataReceived(){
-
-
-
//while循环中读取数据,只要有数据,就一直读取并处理。
-
while (uSocket->hasPendingDatagrams()) {
-
-
QNetworkDatagram datagram = uSocket->receiveDatagram();
-
UDP_DataHex.append(datagram.data().toHex());
-
-
//报文头判断,true则继续,false则将数据丢弃
-
if(UDP_DataHex.at(0)=='f'||UDP_DataHex.at(1)=='f'){
-
count =1;
-
//qDebug()<<"UDP test count:"<< count;
-
if(count==10){
-
-
DataRecevied_Hex=UDP_DataHex;
-
//数据模拟(连通单片机时应注释掉)
-
DataRecevied_Hex="ffb27f02d9022600e114";
-
-
//校验位判断,true则输出,false则将数据丢弃
-
if(Parity_DataReceived()){
-
ui->IPDestination->setText(datagram.senderAddress().toString());
-
ui->PortDestination->setText(QString::number(datagram.senderPort()));
-
ui->UDP_DataReceived->append(Line75Percent TimeStamp() DataFactory(DataRecevied_Hex));
-
-
//AngleCurrent();
-
-
}else{}
-
//UDP_DataHex数据输出后,清空内容,并将计数器归零
-
count=0;
-
UDP_DataHex="";
-
}else{}
-
}else{
-
//UDP_DataHex头两个字符不是ff,则清空内容,并将计数器归零
-
count=0;
-
UDP_DataHex="";
-
}
-
-
}
-
-
}
-
3. 接收数据校验
将接受到的数据进行校验和,如何最后接收到的数据最后两位与计算后所得相同,返回true。
-
bool MainWindow::Parity_DataReceived(){
-
-
bool judge;
-
-
//校验位计算与转换
-
int ache=0;
-
//↓除去校验位本身的长度
-
for(int i=0;i<DataRecevied_Hex.size()-2; i =2){
-
-
ache = HexToDec(DataRecevied_Hex.at(i)).toInt()*16 HexToDec(DataRecevied_Hex.at(i 1)).toInt();
-
//qDebug() << "test"<< ache;
-
-
}
-
QString Parity =QString::number(ache, 16);
-
-
if(Parity.size()==1){
-
Parity.prepend("000");
-
}
-
else if(Parity.size()==2){
-
Parity.prepend("00");
-
}
-
else if(Parity.size()==3){
-
Parity.prepend("0");
-
}
-
-
Parity.remove(0,2);
-
QString str =DataRecevied_Hex.at(18);
-
str.append(DataRecevied_Hex.at(19));
-
if(Parity==str){
-
qDebug() << "校验成功,校验位为:" << Parity;
-
return judge = true;
-
}else{
-
ui->UDP_DataReceived->append("<font color=\"#B22222\">数据校验失败,接收校验位为:" str " 应为:" Parity);
-
qDebug() << "校验失败,数据校验位为:" << str << "计算校验位为:" << Parity;
-
return judge = false;
-
}
-
}
4. UDP数据发送
-
-
//最终数据发送[判断是 串口发送 or UDP发送]
-
void MainWindow::SendMode(){
-
-
QByteArray dataByte =QByteArray::fromHex(DataSend_Hex.toLatin1());
-
-
//发送方式判断
-
if(serial->isOpen()){
-
//串口写入
-
qDebug() << "串口发送数据:"<< dataByte;
-
serial->write(dataByte);
-
ui->Serial_DataSend->append(Line75Percent TimeStamp() "<font color=\"#05BDFF\">" DataFactory(DataSend_Hex));
-
}else if(uSocket->isOpen()){
-
qDebug() << "UDP发送数据:";
-
-
//读取用户输入的IP地址与端口号
-
QString IPDestination = ui->IPDestination->text();
-
quint16 PortDestination = ui->PortDestination->text().toInt();
-
-
qDebug() << "IPDestination:"<<IPDestination;
-
qDebug() << "PortDestination:"<<PortDestination;
-
-
//发送数据
-
uSocket->writeDatagram(dataByte,QHostAddress(IPDestination),PortDestination);
-
-
//控件增加
-
ui->UDP_DataSend->append(Line75Percent TimeStamp() "<font color=\"#05BDFF\">" DataFactory(DataSend_Hex));
-
}else{
-
qDebug() << "请打开串口或UDP";
-
}
-
-
};
数据发送用的函数QT官方文档:
qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port);
writeDatagram(数据,QHostAddress(IP地址),端口)
5. 控件QLineEdit输入限制
实际应用时,应该限制用户所输入的内容(如只能输入IP地址):
(1)方法一:正则表达式
首先这种方法点号是不驻留的,其次输入时无法跳过点号完全删除其他数字
例如255.123.255.255,是没办法直接删除123的,必须将后面内容全部删除,才能更改123
ui->IPLocal->setValidator(new QRegExpValidator(QRegExp("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b")));
(2)方法二: setInputMask函数
ui->IPLocal->setInputMask("000.000.000.000; ");
官方文档内容:
void setInputMask(const QString &inputMask);
其中"000.000.000.000; "的含义就是限制IP地址输入,这种方法点号会驻留就如UI界面中显示的一样,无法删除,但不存在方法一的问题。
6. 用户更改IP地址
首先判断输入是否为空,不为空再判断IP地址格式是否正确
-
//本地IP地址与端口号更改
-
void MainWindow::on_UDP_IPChange_clicked(){
-
-
if(ui->IPLocal->text()!=""&&IsIP(ui->IPLocal->text())){
-
IPLocal = ui->IPLocal->text();
-
}
-
if(ui->PortLocal->text()!=""){
-
PortLocal = ui->PortLocal->text().toInt();
-
}
-
uSocket->close();
-
uSocket->bind(QHostAddress(IPLocal),PortLocal);
-
uSocket->open(QIODevice::ReadWrite);
-
qDebug() <<"IP地址更改test:" IPLocal " " PortLocal;
-
};
-
QRegExp为QT的正则表达式,我直接趴下来的,具体表达式的含义可以自行查阅。
-
//是否为IP地址判断
-
bool MainWindow::IsIP(QString currentIP)
-
{
-
QRegExp rxp("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b");
-
if(!rxp.exactMatch(currentIP))
-
{
-
QMessageBox::information(this, tr("错误"), tr("IP地址错误"));
-
return false;
-
}
-
return true;
-
}
7. 总结
相比串口通信,UDP参数不多,主要就四个,本机IP、本机端口、目标IP、目标端口。
经过串口的各种数据转换洗礼,这里反而轻松不少,只是要注意UDP接收数据容易出现问题,要想办法验证数据头和校验位。(其实保险起见,串口也应该验证一下的,(╯▔皿▔)╯再说吧)
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfcfjj
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13