第三代软件开发-485通信
关键字:
Qt
、 Qml
、 QSerialPort
、 QSerialPort
、 QThread
项目介绍
重要说明☝
☀该专栏在第三代软开发更新完将涨价
485通信
RS-485 简介
因为咱们项目中有多个设备,所以232无法满足需求,因此使用了485通信,这里不是我的端口不够,而是设备希望的连接是的线越细越好。所以选择了485,这里其实也可以选择CAN,但是485 更简单,是不是。嘿嘿嘿。
RS-232 简介
RS-485 与 RS-232 区别
Qt 中使用485
这里其实在上位机使用来看,没有任何区别,从代码来看,完全看不出来是232 害死 485,我们这里区分就是在BISO修改一下端口的模式就可以了。下面看下代码
/**
* @brief XXXX::initSerialPort
* 初始化串口
*/
void XXXX::initSerialPort()
{
// 重置参数定时器
m_ResetValueTimer = new QTimer;
connect(m_ResetValueTimer,&QTimer::timeout,this,[=](){
setOutputValue(0);
});
// 自动连接定时器
m_AutoConnectTimer = new QTimer;
connect(m_AutoConnectTimer,&QTimer::timeout,this,[=](){
openSeriaPort();
});
connect(this,&XXXX::connectedChanged,this,[=](){
if(!m_connected)
{
m_heartBeatTimer->stop();
m_AutoConnectTimer->start(m_autoConnectDuration);
}
else
m_AutoConnectTimer->stop();
});
// 心跳定时器
m_heartBeatTimer = new QTimer;
m_heartBeatTimer->setTimerType(Qt::PreciseTimer);
connect(m_heartBeatTimer,&QTimer::timeout,this,[=](){
if(m_heartBeatSendFlag)
{
// sendToHandle(CommandHandel::heartBeatHandel);
sendToInterfaceBox(CommandInterfaceBox::heartBeatInterfaceBox);
// sendToInterfaceBox(CommandInterfaceBox::laserClicked);
}
else
{
sendToHandle(CommandHandel::heartBeatHandel);
// sendToInterfaceBox(CommandInterfaceBox::heartBeatInterfaceBox);
}
m_heartBeatSendFlag = !m_heartBeatSendFlag;
});
// 读取定时器
m_readTimer = new QTimer;
m_readTimer->setTimerType(Qt::PreciseTimer);
connect(m_readTimer,&QTimer::timeout,this,&XXXX::readOpticalHandleDate);
m_serialPort = new QSerialPort;
connect(m_serialPort,&QSerialPort::errorOccurred,this,[=](QSerialPort::SerialPortError value){
emit signal_opticalHandleState(value);
if(value > 0)
setConnected(false);});
openSeriaPort();
}
- 首先,先起了一个定时器,看我注释叫做重置参数定时器,这个是做什么的呢,我这里有一个变量A,当我从缓冲器读取到数据,解析后,会把对应的数据赋值给A,那么这个A的值在我下次赋值前就一直是保持不变的了,但是我的需求是1.5秒后需要归零,所以就有了这个定时器,这个定时器在每接收到一次数据后重新计时。这就实现了1.5秒内没有数据清零。
- 后面可以看到又起了一个定时器,这个是自动重连定时器,没错,这个定时器的原理和上面的差不多,因为咱现在的情况是基本是不存在打开485端口失败的情况的,所以这里就需要有一个定时器来检测我们的设备是否在线,同样,在接收到数据后,重置这个定时器,当到达时间后,如果没有数据,那就表示这个设备断开,这里就可以尝试重新连接,并且抛出异常
- 嘿嘿,看到又一个定时器是不是,这个就是我们的心跳定时器,我们按照一定的频率分别给每个设备发送心跳,并等待数据返回。
- 是不是又看到一个定时器,这个定时器是在发送数据后启动的,就是在数据发送多少ms后,去缓冲区读取数据。没错,我没有用readready信号,因为我的数据是边长的,我这里就偷懒处理了。
- 最后一步就是打开串口了
/**
* @brief XXXX::openSeriaPort
* @return
* 打开串口
*/
bool XXXX::openSeriaPort()
{
if(m_serialPort)
{
if(m_serialPort->isOpen())
{
m_serialPort->close();
}
m_serialPort->setPortName(m_serialPortname); //设置串口名称
if(m_serialPort->open(QIODevice::ReadWrite)) //打开串口模式为读写模式
{
m_serialPort->setBaudRate(QSerialPort::Baud115200); //设置串口波特率为115200
m_serialPort->setDataBits(QSerialPort::Data8); //设置串口数据位为8位
m_serialPort->setParity(QSerialPort::NoParity); //设置串口没有校验位
m_serialPort->setStopBits(QSerialPort::OneStop); //设置串口停止位为1位
m_serialPort->setFlowControl(QSerialPort::NoFlowControl); //设置串口流控为无
setConnected(true);
m_heartBeatTimer->start(40);
emit signal_opticalHandleState(0);
return true;
}
else
{
setConnected(false);
emit signal_opticalHandleState(1);
return false;
}
}
return false;
}
这里就没有好解释的,不管你怎么百度, Qt使用串口就这么几步,固定的。
总结一下
这里如果是普通使用或者学术没有问题,放到生产力,会遇到高频数据通信问题,这个我们可以看后面的一篇,使用第三方串口库来尝试解决这个问题。不过也不确定会不会解决,在当下的系统演示阶段是使用Qt 的串口是可以的,但是最终我们还是希望提高数据的通信频率。