本文來源電子發(fā)燒友社區(qū),作者:劉建華, 帖子地址:https://bbs.elecfans.com/jishu_2309556_1_1.html
【話外】經(jīng)過大伙的一個星期的努力,疫情得到控制,核酸檢測社會面清零。今天,單位的領(lǐng)導(dǎo)熱情的用鮮花迎接我們凱旋而歸。
到家后立馬投入到這個帖子的收尾工作,因為今天是最后一天提交作品。話不多說繼續(xù)我的工作。
前面已經(jīng)實現(xiàn)的界面的制作,今天完結(jié)伺服電機的控制。
1、生成電機控制指令,電機的指令是通過modbus(RTU 模式)來控制驅(qū)動器的。主機可以通過 modbus 的讀寫寄存器功能來設(shè)置驅(qū)動器參數(shù)和控制運行。這里只用到了功能碼為 0x3(讀寄存器)、0x6(寫寄存器)這兩個指令。指令格式如下:
2、這里需要用到CRC16的較驗。具體的函數(shù)如下:
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];//第一個數(shù)據(jù)幀異或
for(n=0; n<8; n++){//因為是quint8是8位數(shù)據(jù),所以循環(huán)8次
if(Crc & 1){//移出位為1,就進行異或
Crc >>= 1;
Crc ^= 0xA001;
}else//為0繼續(xù)移出
Crc >>= 1;
}
m--;//下一個數(shù)據(jù)幀
x++;
}
x = Crc>>8;//拿到高8位
Crc <<= 8;//剩下低8位
Crc &= 0xff00;//低位清0
Crc |= x;//實現(xiàn)高低位位置互換
return Crc;
}
3、有了CRC16的較驗后,組裝設(shè)置使能電機命令如下:
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("關(guān)閉電機");
}
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、組裝設(shè)置電機目標(biāo)速度,輸入框在設(shè)計時規(guī)定,只能輸入整數(shù),在獲取目標(biāo)速度時,電機的最高轉(zhuǎn)速為3000轉(zhuǎn),所以如果設(shè)置值高于3000,也只設(shè)置3000轉(zhuǎn)。具體函數(shù)如下:
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、獲取實時的電機速度。獲取電機實時速度,設(shè)置了一個定時器,每一秒向電機發(fā)送讀取電機的指令:01 03 00 10 00 01 85 cf。串口接收數(shù)據(jù)時,判斷前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()
{
/* 接收緩沖區(qū)中讀取數(shù)據(jù) */
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()));
}
這里還有另外一個技巧,就是要設(shè)置一個標(biāo)志,只能是串口打開成功,才能啟用定時器。
6、組裝好電機、控制器后,開發(fā)板后,成功的實現(xiàn)了對電機的實時控制與監(jiān)控。
【總結(jié)】經(jīng)過了差不多兩個多月的學(xué)習(xí)試用,雖然寫出了多篇帖子,學(xué)習(xí)到了不少東西,但是對這塊開發(fā)板的了解還是只在皮毛。如果有時間,還會繼續(xù)了解這塊優(yōu)秀的開發(fā)板,爭取寫出更好的作品。
附工程源碼
*附件:myserial.zip
控制電機視頻,詳見作者原帖子內(nèi)容
-
飛凌
+關(guān)注
關(guān)注
0文章
134瀏覽量
16135
發(fā)布評論請先 登錄
相關(guān)推薦
評論