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