Qt 实现串口终端控制台,适配RT-Thread的FinSH控制台功能(提供qt源码)
開發環境:Window 10?64bit
開發工具:IAR Embedded Workbench
硬件:stm32f103c8t6
RT-Thread Nano?版本包含了?FinSH 組件,我們可以在reconfig.h配置使用它,使用之后我們可以在電腦上通過串口終端輸入命令調試系統。這功能用于調試或查看系統信息,在實際開發中可以帶來很多的方便,。效果如下圖:
?
1.基于IAR,進行RT-Thread源碼移植
1.我使用的芯片是stm32f103c8t6,基于IAR移植RT-Thread Nano,點擊下載RT-Thread Nano源碼?。如果你沒有IAR,而是使用KEIL,點擊查看參考鏈接。
2.下載源碼后,在rt-thread-3.1.3\bsp\stm32f103-msh路徑下,打開iar工作空間文件Project.eww,打開后是這樣子的:
Project->Options,General Optons->配置成自己使用的芯片、Debugger->配置調試工具:
?
3.配置rtconfig.h文件,在該文件里加入一下宏:
#define RT_USING_FINSH #define FINSH_USING_HISTORY?開啟后可對 FinSH 組件相關的參數進行配置修改(在rtconfig.h文件結尾的地方):
#if defined (RT_USING_FINSH) // 開關 FinSH 組件#define FINSH_USING_MSH // 使用 FinSH 組件 MSH 模式#define FINSH_USING_MSH_ONLY // 僅使用 MSH 模式#define __FINSH_THREAD_PRIORITY 5 // 設置 FinSH 組件優先級,配置該值后通過下面的公式進行計算#define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)#define FINSH_THREAD_STACK_SIZE 1024 // 設置 FinSH 線程棧大小,范圍 1-4096#define FINSH_HISTORY_LINES 5 // 設置 FinSH 組件記錄歷史命令個數,值范圍 1-32#define FINSH_USING_SYMTAB // 使用符號表,需要打開,默認打開#endif4.在shell.c文件里面找到rt_hw_console_getchar函數:
//修改點:函數返回值,增加清除RXNE標志,去掉delayint rt_hw_console_getchar(void) {int ch = -1;if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE) != RESET){ch = UartHandle.Instance->DR & 0xff;__HAL_UART_CLEAR_FLAG(&UartHandle, UART_FLAG_RXNE);}else{//rt_thread_mdelay(10);}return ch; }5.在shell.c文件里面找到finsh_thread_entry 函數,注釋掉兩個回顯:
/*.........*/else if (ch == 0x44) /* left key */{if (shell->line_curpos){//rt_kprintf("\b");shell->line_curpos --;}continue;}else if (ch == 0x43) /* right key */{if (shell->line_curpos < shell->line_position){//rt_kprintf("%c", shell->line[shell->line_curpos]);shell->line_curpos ++;}continue;}/*.........*/2.基于QT,開發與finsh功能對接的PC終端
1.點擊下載源碼
2.我使用的qt版本是Qt Creator 5.14,如果下載我的源碼由于版本沖突,不能使用的話可以自己新建一個工程,把代碼復制過去;或者去qt官網下載該版本。
3.效果圖:
4.關鍵代碼:
?重寫鍵盤釋放事件函數,通過ev->text()可以獲取鍵盤輸入的字符(包括回退鍵,確認鍵),此外我們還需要獲取方向鍵,方向鍵的使用類似Linux終端,可通過按上鍵來翻閱之前的命令記錄,命令是在MCU里記錄,當按了上鍵時,MCU就會返回上一次輸入的命令,命令記錄的條數最大值設置是在在rtconfig.h文件中的宏FINSH_HISTORY_LINES。
方向鍵需要發送的鍵值是不能直接通過ev->text()獲取到的,所以先通過ev->key(),不同的按鍵發送對應的控制碼,比如“上”鍵,發送的是:0x1b 0x5b 0x41即可。
void MainWindow::keyReleaseEvent(QKeyEvent *ev) {int code = 0xFF;unsigned char controlkey[5]={0x1b,0x5b,0x00};//unsigned int key = ev->key();//qDebug("鍵值:0x%x",ev->key());if(!ui->textEdit->hasFocus()){//判斷光標是否在textEdit控件上return;}/** handle control key* up key : 0x1b 0x5b 0x41* down key: 0x1b 0x5b 0x42* right key:0x1b 0x5b 0x43* left key: 0x1b 0x5b 0x44*/ controlkey[2] = 0x00;switch (ev->key()) {case Qt::Key_Left:controlkey[2] = 0x44;ui->textEdit->moveCursor(QTextCursor::Left);break;case Qt::Key_Right:controlkey[2] = 0x43;ui->textEdit->moveCursor(QTextCursor::Right);break;case Qt::Key_Up:controlkey[2] = 0x41;break;case Qt::Key_Down:controlkey[2] = 0x42;break;default:QString text = ev->text();if(text.size() > 0){code = text.at(0).toLatin1();if((code >= 0) && (code <= 0x7e)){//ASCIIif(code == '\n'||code == '\r'){//回車按鍵按下時,將光標移動到末尾ui->textEdit->moveCursor(QTextCursor::End);}if(port != NULL && port->isOpen()){//發送字符到串口port->write((const char*)&code,1);}}}break;}if(controlkey[2] != 0x00){port->write((const char*)&controlkey[0],3);}//qDebug("0x%x %c",(char)code,(char)code);//QWidget::keyPressEvent(ev); }窗口接收函數,當PC端串口接收到數據就會進入下面的函數,接受到的數據會先保存到MainSerialRecvData數組里,然后再一個一個的追加到顯示輸入控件textEdit上,這里我同了temp數組來過度,如果有更好的辦法可以優化一下;當CP端按下了“backspace”鍵時,MCU會往PC回發‘/b’,那么當PC端接收到‘/b’就要刪除關標后一個字符。
void MainWindow::SerialRecvMsgEvent() {QByteArray MainSerialRecvData;char temp[10]={0};if(port->bytesAvailable()>0){MainSerialRecvData = port->readAll();//qDebug("rec data");int count = MainSerialRecvData.count();for(int i = 0;i<count;i++){//qDebug("0x%x",MainSerialRecvData.at(i));temp[0] = MainSerialRecvData[i];if((temp[0] >= 0) && (temp[0] <= 0x7e)){//ASCIIif(temp[0] == 0x08){// '/b':backspace鍵ui->textEdit->textCursor().deletePreviousChar();//刪除光標后面一個字符}else{ui->textEdit->textCursor().insertText(temp);//把字符顯示到textedit里}//移動滾動條到底部QScrollBar *scrollbar = ui->textEdit->verticalScrollBar();if (scrollbar){scrollbar->setSliderPosition(scrollbar->maximum());}}}}}把qt的源碼下載解壓,就可以直接編譯運行,選擇串口,設置波特率,輸入命令是記得把輸入法切換到英文,否則輸入無效的。?
3.遇到的問題
- 還沒用qt做的終端時,我在PC端用串口助手發送命令到MCU,發現MCU會丟失很多數據,因為MCU端用輪詢的方式從UART里獲取數據,如果處理不及時必然會丟失數據。解決這個問題,一種方法是,可以加長PC端發送兩個字符之間的時間;另一種方法是,MCU端利用中斷接收數據,先把數據發進隊列里面(RT-Thread源碼有隊列功能),然后再while循環里取出隊列里的數據進行處理,這樣就不會丟失UART數據了。
- 在函數rt_hw_console_getchar里,我注釋掉了rt_thread_mdelay(10),因為不注釋掉,按方向鍵是沒用的,因為MCU沒及時處理導致PC端發送的數據丟失了;但是,注釋掉也會導致比finsh線程優先級低的其他線程永遠得不到調用。
?
?
?
《路漫漫其修遠兮,吾將上下而求索。———屈原》
總結
以上是生活随笔為你收集整理的Qt 实现串口终端控制台,适配RT-Thread的FinSH控制台功能(提供qt源码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于stm32、spi协议的Fatfs文
- 下一篇: IAR新建stm32工程,完美移植stm