一.类内容
对于main.cpp文件,是常见的QT生成UI界面的程序。
对于头文件中的widget类部分,成员函数有
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_comboBox_BoTeLv_currentIndexChanged(const QString &arg1);
void on_comboBox_DataBit_currentIndexChanged(const QString &arg1);
void on_comboBox_Port_currentIndexChanged(const QString &arg1);
void on_comboBox_JiaoYanBit_currentIndexChanged(const QString &arg1);
void on_comboBox_StopBit_currentIndexChanged(const QString &arg1);
void on_BTN_OpenPLC_clicked();
void on_BTN_ClosePLC_clicked();
void on_BTN_Write_clicked();
void on_radioButton_XianQuan_clicked();
void on_radioButton_JiCunQI_clicked();
void on_BTN_Read_clicked();
private:
Ui::Widget *ui;
modbus_t *plc;//libmodbus自带的,不透明数据类型
};
二.public成员函数
析构函数释放了ui的指针内存
Widget::~Widget()
{
delete ui;
}
对于构造函数,ui->setupUi(this)不讨论。后面代码以注释形式展示
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())//用于遍历输入对象的系统可用串行端口
{
QSerialPort serial;//定义一个端口
serial.setPort(info);//将serial和info设置在一起
if(serial.open(QIODevice::ReadWrite))//如果串口以读写方式成功打开
{
ui->comboBox_Port->addItem(serial.portName());//向串口号comboBox组建添加端口名信息
serial.close();//关闭设备,重置错误字符串
}
ui->comboBox_BoTeLv->addItem("4800");//向波特率组件添加4800
ui->comboBox_BoTeLv->addItem("9600");//向波特率组件添加9600
ui->comboBox_BoTeLv->addItem("19200");//向波特率组件添加19200
ui->comboBox_BoTeLv->addItem("115200");//向波特率组件添加115200
ui->comboBox_BoTeLv->setCurrentText("9600");//波特率组件默认设置9600
ui->comboBox_DataBit->addItem("6");//数据位组件添加6
ui->comboBox_DataBit->addItem("7");//数据位组件添加7
ui->comboBox_DataBit->addItem("8");//数据位组件添加8
ui->comboBox_DataBit->setCurrentText("8");//数据位组件默认设置为8
ui->comboBox_JiaoYanBit->addItem("O");//校验位组件添加O
ui->comboBox_JiaoYanBit->addItem("E");//校验位组件添加E
ui->comboBox_JiaoYanBit->addItem("N");//校验位组件添加N
ui->comboBox_JiaoYanBit->setCurrentText("N");//校验位组件默认设置为N
ui->comboBox_StopBit->addItem("0");//停止位组件添加0
ui->comboBox_StopBit->addItem("1");//停止位组件添加1
ui->comboBox_StopBit->setCurrentText("1");//停止位组件默认设置为1
}
对于其它几个响应槽函数,则有
void Widget::on_comboBox_BoTeLv_currentIndexChanged(const QString &arg1)//改变波特率组件的文字内容
{
qDebug() << ui->comboBox_BoTeLv->currentText();//将波特率组件内容设置为输入内容
}
对于void Widget::on_BTN_OpenPLC_clicked(),即打开串口,有
void Widget::on_BTN_OpenPLC_clicked()//打开串口槽函数
{
QString Port = ui->comboBox_Port->currentText();//定义一个port字符串并赋值为comboBox_Port组件当前文本
int BoTeLv = ui->comboBox_BoTeLv->currentText().toInt();//将波特率转化为的数字赋值给int
QString JiaoYanBit = ui->comboBox_JiaoYanBit->currentText();//定义一个JiaoYanBit字符串并赋值为comboBox_JiaoYanBit组件当前文本
int DataBit = ui->comboBox_DataBit->currentText().toInt();//将数字位转化为的数字赋值给int
int StopBit = ui->comboBox_StopBit->currentText().toInt();//将停止位转化为的数字赋值给int
int SheBeiDiZhi = ui->lineEdit_SheBeiDiZhi->text().toInt();//将设备地址转化为数字赋值给int
const char *port = Port.toLatin1().constData();//将字节数组传递给char*以qbytearray形式返回字符串的拉丁文-1表示形式。
if(JiaoYanBit == "O")
{
plc = modbus_new_rtu(port, BoTeLv, 'O', DataBit, StopBit);//生成一个modbus_t *结构体指针返回给PLC变量并执行相关RTU模型通信配置,采用奇数校验
}
else if(JiaoYanBit == "E")
{
plc = modbus_new_rtu(port, BoTeLv, 'E', DataBit, StopBit);//同上,采用偶数校验
}
else if(JiaoYanBit == "N")
{
plc = modbus_new_rtu(port, BoTeLv, 'N', DataBit, StopBit);//同上,无奇偶校验
}
qDebug() << Port;//输出端口号
qDebug() << QString::number(BoTeLv, 10);//将BoTeLv变量转化为10进制
qDebug() << JiaoYanBit;//输出校验位
qDebug() << QString::number(DataBit, 10);//将DataBit变量转化为10进制
qDebug() << QString::number(StopBit, 10);//将StopBit变量转化为10进制
plc = modbus_new_rtu(port, BoTeLv, 'N', DataBit, StopBit);生成一个modbus_t *结构体指针返回给PLC变量并执行相关RTU模型通信配置,采用无奇偶校验
modbus_set_slave(plc, SheBeiDiZhi);//设置从机的设备地址
qDebug() << QString::number(SheBeiDiZhi, 10);//将SheBeiDiZhi变量转化为10进制
int plccount = modbus_connect(plc);//与PLC变量建立连接
struct timeval time;//实例化一个timeval的结构体
time.tv_sec = 0;//0s
time.tv_usec = 1000000;//1000000us
modbus_set_response_timeout(plc, (int)&time.tv_sec, (int)&time.tv_usec);//设置响应时间
if(plccount == 0)
{
qDebug() << "连接PLC成功";//输出连接PLC成功
}
else
{
qDebug() << "连接PLC失败";//输出连接PLC失败
}
}
对于qDebug函数,使用数据流输出需要加入头文件#include<QDebug>,将字符串当做传参的话不需要加入相关头文件。
对于void Widget::on_BTN_ClosePLC_clicked()函数
void Widget::on_BTN_ClosePLC_clicked()
{
modbus_close(plc);//关闭跟plc变量的连接
modbus_free(plc);//释放modbus环境
}
有两个函数是QDebug,调用radioButton组件不管。对于on_BTN_Write_clicked()函数:
void Widget::on_BTN_Write_clicked()
{
int Adress = ui->lineEdit_JiCunQiDIZhiWrite->text().toInt();//将写寄存器地址赋值给adress
int ShuZhi = ui->lineEdit_JiCunQiShuZhi->text().toInt();//将写寄存器数值赋值给ShuZhi
if(ui->radioButton_XianQuan->isChecked() == true)//如果线圈的radiobutton被按下
{
qDebug() << "写入线圈";
modbus_write_bit(plc, Adress, ShuZhi);//强制单线圈
}
else//如果寄存器的radiobutton被按下
{
qDebug() << "写入寄存器";
modbus_write_register(plc, Adress, ShuZhi);//强制单寄存器
}
}
对于on_BTN_Read_clicked()函数:
void Widget::on_BTN_Read_clicked()
{
uint16_t read_reg[255] = {0};//定义一个unsigned short数组
uint8_t read_reg_bit[255] = {0};//定义一个unsigned char数组
int Adress = ui->lineEdit_JiCunQiDIZhiRead->text().toInt();//将读寄存器地址赋值给Adress
int Count = ui->lineEdit_Count->text().toInt();/将读寄存器数量赋值给Count
if(ui->radioButton_XianQuan->isChecked() == true)//线圈radiobutton是否被按下
{
qDebug() << "读取线圈";
for (int i = 0; i < Count; i++)
{
modbus_read_bits(plc, Adress, Count, read_reg_bit);//读取线圈状态
qDebug() << read_reg_bit[i];//输出线圈状态
}
}
else//如果寄存器被按下
{
qDebug() << "读取寄存器";
for (int i = 0; i < Count; i++)
{
modbus_read_registers(plc, Adress, Count, read_reg);//读取保存寄存器
qDebug() << read_reg[i];//输出寄存器内容
}
}
}