說到嵌入式的實時系統,大家首先想到的是不是 聞名遐邇的 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:
-
按方向下鍵不能看到下一條歷史記錄.
-
現在暫時不能發送 帶有\n 的字符串,也不能發送 HEX
-
如果光標在字符中間的時候按下了回車,那么接收到的消息是會從光標處開始插入
發送字符給單片機的時候,是發送最后一行的字符.文本太長會自動換行顯示,但是仍然是一行.
以上的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;
如果按下了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;
如果按下了方向上鍵,不上移光標,然后判斷是不是最后一個的輸入記錄,如果是,直接在光標位置處插入上一次發送的文本,如果不是最后一個歷史記錄,刪除當前歷史的歷史記錄語句,插入更加前面一條歷史語句.
如果刪除時發現已經刪除到最后一行的開始,則刪除無效.

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 }
恩,邏輯上還是比較簡單的.每個人都可以做到.
然而,為了能用上好(裝)用(逼)的 shell 串口,我們就要去移植一個rt-thread系統嗎? NO NO NO.小編也想到這個問題,於是乎,自己編寫了一個.c.h 文件,只需一個聲明,輸入字符串進入執行函數,就會自動調用你想要調用的函數.具體請期待明日更新哦.
RTOS [1] Real Time Operating System 實時操作系統,. 名稱是根據操作系統的工作特性而言的,實時是指物理進程的真實時間. 摘自百度百科 [RTOS] 且RTOS多為搶占式操作系統.
為了能夠更好的交流,小編悄摸的申請了一個公眾號: 奔跑的程序猿 ,感興趣的可以關注一波.