【话外】经过大伙的一个星期的努力,疫情得到控制,核酸检测社会面清零。今天,单位的领导热情的用鲜花迎接我们凯旋而归。
到家后立马投入到这个帖子的收尾工作,因为今天是最后一天提交作品。话不多说继续我的工作。
前面已经实现的界面的制作,今天完结伺服电机的控制。
1、生成电机控制指令,电机的指令是通过modbus(RTU 模式)来控制驱动器的。主机可以通过 modbus 的读写寄存器功能来设置驱动器参数和控制运行。这里只用到了功能码为 0x3(读寄存器)、0x6(写寄存器)这两个指令。指令格式如下:
2、这里需要用到CRC16的较验。具体的函数如下:
quint16 MainWindow::CalcCRC16(quint8 *SC_Buffer, quint8 SC_Amount)
{
quint16 Crc;
quint8 n, m, x;
Crc= 0xFFFF;
m= SC_Amount;
x= 0;
while(m>0){
Crc ^= SC_Buffer[x];
for(n=0; n<8; n++){
if(Crc & 1){
Crc >>= 1;
Crc ^= 0xA001;
}else
Crc >>= 1;
}
m--;
x++;
}
x = Crc>>8;
Crc <<= 8;
Crc &= 0xff00;
Crc |= x;
return Crc;
}
3、有了CRC16的较验后,组装设置使能电机命令如下:
void MainWindow::on_openMotorBut_clicked()
{
QByteArray data;
data.resize(8);
quint8 crc[8];
quint8 n;
ui->textBrowser->insertPlainText("start clicked!\n");
if(ui->openMotorBut->text() == "启动电机")
{
crc[0] = 0x01;
crc[1] = 0x06;
crc[2] = 0x00;
crc[3] = 0x00;
crc[4] = 0x00;
crc[5] = 0x01;
quint16 reCrc;
reCrc = CalcCRC16(crc,6);
crc[6] = reCrc>>8;
crc[7] = reCrc & 0xff;
for(n=0;n<8;n++){
data[n] = crc[n];
}
serialPort->write(data);
ui->openMotorBut->setText("关闭电机");
}
else {
crc[0] = 0x01;
crc[1] = 0x06;
crc[2] = 0x00;
crc[3] = 0x00;
crc[4] = 0x00;
crc[5] = 0x01;
quint16 reCrc;
reCrc = CalcCRC16(crc,6);
crc[6] = reCrc>>8;
crc[7] = reCrc & 0xff;
ui->openMotorBut->setText("启动电机");
}
}
4、组装设置电机目标速度,输入框在设计时规定,只能输入整数,在获取目标速度时,电机的最高转速为3000转,所以如果设置值高于3000,也只设置3000转。具体函数如下:
void MainWindow::on_setSpeedBut_clicked()
{
QByteArray data;
data.resize(8);
quint8 crc[8];
quint8 n;
quint16 speed_val;
ui->textBrowser->insertPlainText("set speed!\n");
//speed set 01 06 00 02 05 DC 2A C3
speed_val = ui->editSetSpeed->text().toInt();
if (speed_val>3000)
{
speed_val = 3000;
}
crc[0] = 0x01;
crc[1] = 0x06;
crc[2] = 0x00;
crc[3] = 0x02;
crc[4] = speed_val>>8;
crc[5] = speed_val & 0xff;
quint16 reCrc;
reCrc = CalcCRC16(crc,6);
crc[6] = reCrc>>8;
crc[7] = reCrc & 0xff;
for(n=0;n<8;n++){
data[n] = crc[n];
}
serialPort->write(data);
ui->textBrowser->setText("set speed val");
}
5、获取实时的电机速度。获取电机实时速度,设置了一个定时器,每一秒向电机发送读取电机的指令:01 03 00 10 00 01 85 cf。串口接收数据时,判断前3位是否为收到的速度的指令,如果是就更新LCDNUMBER。具体指令如下:
void MainWindow::read_speed()
{
QByteArray data;
quint8 n;
quint8 crc[8] = {0x01, 0x03, 0x00, 0x10, 0x00, 0x01, 0x85, 0xcf};
for(n=0;n<8;n++){
data[n] = crc[n];
}
serialPort->write(data);
}
void MainWindow::serialPortReadyRead()
{
quint16 speed;
QByteArray buf = serialPort->readAll();
if(buf[0] == 0x01 && buf[1] == 0x03 && buf[2] == 0x02)
{
speed = buf[3]<<8 | buf[4];
speed = speed/10;
ui->lcdNumber->display(QString::number(speed));
}
ui->textBrowser->insertPlainText(QString(buf.toHex()));
}
这里还有另外一个技巧,就是要设置一个标志,只能是串口打开成功,才能启用定时器。
6、组装好电机、控制器后,开发板后,成功的实现了对电机的实时控制与监控。
【总结】经过了差不多两个多月的学习试用,虽然写出了多篇帖子,学习到了不少东西,但是对这块开发板的了解还是只在皮毛。如果有时间,还会继续了解这块优秀的开发板,争取写出更好的作品。
附工程源码
*附件:myserial.zip