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                  // 使用符号表,需要打开,默认打开#endif

4.在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= 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线程优先级低的其他线程永远得不到调用。

 

 

 

《路漫漫其修远兮,吾将上下而求索。———屈原》


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部