本文來源電子發燒友社區,作者:劉建華, 帖子地址:https://bbs.elecfans.com/jishu_2309556_1_1.html
【話外】經過大伙的一個星期的努力,疫情得到控制,核酸檢測社會面清零。今天,單位的領導熱情的用鮮花迎接我們凱旋而歸。
到家后立馬投入到這個帖子的收尾工作,因為今天是最后一天提交作品。話不多說繼續我的工作。
前面已經實現的界面的制作,今天完結伺服電機的控制。
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;//16個1
m= SC_Amount;//拿到長度
x= 0;
while(m>0){
Crc ^= SC_Buffer[x];//第一個數據幀異或
for(n=0; n<8; n++){//因為是quint8是8位數據,所以循環8次
if(Crc & 1){//移出位為1,就進行異或
Crc >>= 1;
Crc ^= 0xA001;
}else//為0繼續移出
Crc >>= 1;
}
m--;//下一個數據幀
x++;
}
x = Crc>>8;//拿到高8位
Crc <<= 8;//剩下低8位
Crc &= 0xff00;//低位清0
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() == "啟動電機")
{
//EN set
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 {
//close
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
控制電機視頻,詳見作者原帖子內容
-
飛凌
+關注
關注
0文章
134瀏覽量
16154
發布評論請先 登錄
相關推薦
評論