讓串口調試助手像命令行一樣


說到嵌入式的實時系統,大家首先想到的是不是 聞名遐邇的 UCOS 呢? UCOS 簡單,易移植,在關鍵部分移植匯編語言,是入坑 RTOS [1]的不二選擇.接觸了一段時間之后,偶然在網上看到,原子哥(正點原子) 的開源教材里頭也有介紹 RT-Thread OS 系統,然后開始了解和使用Rt-thread. 它的優勢是:商用無風險,不限任務個數,各種協議棧齊全(尤其在 IoT方面),兼容部分POSIX接口(linux接口).

圖片來自網絡截圖侵刪

RT-thread 是一個中國人自己開發的開源的RTOS ,借鑒了linux的部分想法.甚至可以復用linux的驅動接口.同時高度可裁剪和豐富的協議棧.當然現在的菜鳥小編都用不到這些. 可是有一個功能小編可是眼紅的很,那就是它的 串口 shell 功能,讓單片機跟電腦的命令行一樣執行命令.

用過gcc 或者java 的小伙伴都知道,可以直接在命令行敲 gcc *.c 或者javac *.java 就可以直接編譯文件, 這個 gcc javac 就是咱們的*.exe 文件,那么在單片機里,我定義了一個 printcircle (int r);這個函數,那么我們可不可以直接在串口助手里給單片機發信息: printcircle 30 \n 是不是他就可以執行printcirc這個函數並且r = 30 呢?  答案當然是可以的.

rt-thread 中的shell 就可以做到.並且更加完善.但是單片機支持這樣的命令行操作,可是咱們的串口助手並不能像cmd窗口一樣啊.著名的Xcom 串口調試軟件,不支持這個功能.於是我萌生了做一個上位機適配這個shell 的想法.

 

我的想法很簡單,就是做一個窗口盡量讓他像我們的命令行. 但是串口還是需要掃描,檢查串口.所以我在最下面增加了幾個按鈕.同時盡量關聯快捷鍵.盡量做到少操作鼠標.經過幾天的打磨,思考,現在已經有點樣子了.有需要的同學可以移步:

Github: https://github.com/KimAlittleStar/UART_SHELL

程序下載:  https://github.com/KimAlittleStar/UART_SHELL/releases

百度雲:  https://pan.baidu.com/s/12Soblpsm5CUIeg1eEZEp1Q           提取碼:  hyhn

軟件說明:按下回車就是發送消息.方向上鍵是發送消息的歷史記錄.有以下幾個BUG:  

  1. 按方向下鍵不能看到下一條歷史記錄.

  2. 現在暫時不能發送 帶有\n 的字符串,也不能發送 HEX

  3. 如果光標在字符中間的時候按下了回車,那么接收到的消息是會從光標處開始插入

 

發送字符給單片機的時候,是發送最后一行的字符.文本太長會自動換行顯示,但是仍然是一行.

以上的bug我還在修,因為現在是在實習工作,可能修bug 的速度會慢一些.Ps:win10/win7 64bit 實測可用.

接下來是里面的一些具體的邏輯想法:

    首先UI界面布局,這個不贅述,需要注意的就是使用*.ui文件的時候注意將你需要用到的對象的名稱修改掉,不然你可能過了幾天,你就不記得你的變量名那個是哪個了.沒錯我就經歷過.

之后 開啟串口.

void Widget::openprot()
{
    if(activePort->isOpen()) //如果串口打開着就關閉
    {
//        activePort->clear();
        activePort->close();
        ui->pushButton_2->setText("打開串口");
        ui->tLine_message->setText("串口"+ui->cBox_Portlist->currentText()+"已關閉");
    }else{ //關閉着就打開
        activePort->setPortName(ui->cBox_Portlist->currentText());
        if(activePort->open(QIODevice::ReadWrite)== true)
        {
            int a = ui->cBox_Baudlist->currentText().toInt();
            activePort->setBaudRate(a,QSerialPort::AllDirections);//設置波特率和讀寫方向
            activePort->setDataBits(QSerialPort::Data8);      //數據位為8位
            activePort->setFlowControl(QSerialPort::NoFlowControl);//無流控制
            activePort->setParity(QSerialPort::NoParity); //無校驗位
            activePort->setStopBits(QSerialPort::OneStop); //一位停止位
            ui->tLine_message->setText(ui->cBox_Portlist->currentText()+"打開成功");
            connect(activePort,SIGNAL(readyRead()),this,SLOT(receiveInfo()));
            ui->pushButton_2->setText("關閉串口");
            ui->tEdit_shell->setFocus();
        }else {
            ui->tLine_message->setText("打開失敗,檢查串口是否被占用");
            ui->pushButton_2->setText("打開串口");
        }
    }
}

監聽按鍵,如果按鍵按到了 方向上 下 和enter鍵那么就執行相應的操作.同時我 也預留了一個 tab 鍵,為以后自定義關鍵字,做到字符按提示.

 1 if (static_cast<QKeyEvent *>(event)->key() == Qt::Key_Up) {
 2                 QTextCursor tc =  ui->tEdit_shell->textCursor();
 3 
 4                 if(history.size() == 0) return true;//如果沒有歷史記錄,則不操作
 5 
 6                 if(historyNum != history.size())//如果當前不是第一次按上鍵,則要刪除上一次補全的歷史記錄
 7                 {
 8                     if(historyNum == 0)
 9                         tc.movePosition(QTextCursor::Left,QTextCursor::KeepAnchor,history[0].length());
10                     else {
11                         tc.movePosition(QTextCursor::Left,QTextCursor::KeepAnchor,history[historyNum].length());
12                     }
13                     tc.removeSelectedText();
14                 }
15                 if(historyNum == 0)
16                     historyNum = history.size();
17 
18                 ui->tEdit_shell->insertPlainText(history[historyNum-1]); //插入上一個輸入的歷史記錄
19                 qout<<history[historyNum-1]<<"history size "<< history.length();
20                 historyNum--;
21                 qout<<"使用上一個記錄"<<endl;
22 
23                 return true;
View Code

 

如果按下了enter 把最后一行的文本獲取到,用串口發送出去,將發出去的字符寫入一個數組,記錄下來以便提供歷史記錄

 1 if(k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter)
 2             {
 3                 txtcur.movePosition(QTextCursor::End,QTextCursor::MoveAnchor);
 4                 txtcur.movePosition(QTextCursor::StartOfLine,QTextCursor::MoveAnchor);
 5                 txtcur.movePosition(QTextCursor::EndOfLine,QTextCursor::KeepAnchor);
 6                 QString msg = txtcur.selectedText();
 7                 history.append(msg);
 8                 sendText(msg);
 9 
10                 historyNum = history.size();
11                 ui->tEdit_shell->append("");
12                 return true;
View Code

 

如果按下了方向上鍵,不上移光標,然后判斷是不是最后一個的輸入記錄,如果是,直接在光標位置處插入上一次發送的文本,如果不是最后一個歷史記錄,刪除當前歷史的歷史記錄語句,插入更加前面一條歷史語句.

如果刪除時發現已經刪除到最后一行的開始,則刪除無效.

1 if (static_cast<QKeyEvent *>(event)->key() == Qt::Key_Backspace) {
2                 QTextCursor tc = ui->tEdit_shell->textCursor();
3                 int oldposition = tc.position();
4                 tc.movePosition(QTextCursor::StartOfLine);
5                 if((tc.blockNumber()+1) == maxline && oldposition == tc.position())
6                 {
7                     return true;
8                 }
View Code

 

恩,邏輯上還是比較簡單的.每個人都可以做到.

然而,為了能用上好(裝)用(逼)的 shell 串口,我們就要去移植一個rt-thread系統嗎? NO NO NO.小編也想到這個問題,於是乎,自己編寫了一個.c.h 文件,只需一個聲明,輸入字符串進入執行函數,就會自動調用你想要調用的函數.具體請期待明日更新哦.

 

RTOS [1]    Real Time  Operating System  實時操作系統,. 名稱是根據操作系統的工作特性而言的,實時是指物理進程的真實時間.  摘自百度百科 [RTOS]    且RTOS多為搶占式操作系統.

 為了能夠更好的交流,小編悄摸的申請了一個公眾號: 奔跑的程序猿 ,感興趣的可以關注一波. 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM