开发环境: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<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源码)相关推荐

  1. java串口发送十六进制数,本文实例为大家分享了Java实现串口通信的具体代码,供大家参考,具体内容如下1.介绍使用Java实现的串口通信程序,支持十六进制数据的发送与接收。 源码:...

    本文实例为大家分享了Java实现串口通信的具体代码,供大家参考,具体内容如下 1.介绍 使用Java实现的串口通信程序,支持十六进制数据的发送与接收. 源码:SerialPortDemo 效果图如下: ...

  2. 关于 Android 中 TabLayout 下划线适配文字长度解析(附清晰详细的源码解析)

    温故而知新 坚持原创 请多多支持 一.问题背景 假期在做项目的时候,当时遇到了一个需求就是需要使用 TabLayout + ViewPager 来实现一个上部导航栏的动态效果,并且希望下划线的长度等于 ...

  3. Qt之超简单的TCP通信(自定义TCP通信类,含源码+注释)

    文章目录 一.TCP通信示例图 二.TCP使用前的准备 三.自定义TCP通信类的两种方法 四.源码(含注释) TCP Server CTcpServer.h CTcpServer.cpp TCP Cl ...

  4. 【QT学习】QSS样式表实现界面换肤(图文详解+源码)

    文章目录 前言 一.实现效果 二.QSS简介及用法 1.什么是QSS? 2.怎么使用QSS? 三.QSS用法一:单个控件调用setStyleSheet函数 四.QSS用法二:编写单个界面.qss文件的 ...

  5. 控制台五子棋java源代码_两套 五子棋小游戏源码(控制台+JavaSWing)

    [实例简介] [实例截图] [核心代码] 五子棋 ├── 图形 │   ├── java五子棋小程序.doc │   ├── 五子棋 │   │   ├── bin │   │   │   └── c ...

  6. JAVA基础控制台版本演示增删改查项目(带完整源码)

    package com.zking.temp;public class Bb {Bbs[] b=new Bbs[100];/*** 增加的方法*/public void add(Bbs bb) {fo ...

  7. 【Qt学习】Qt自制串口助手程序打包

    Qt自制串口助手 1.做好UI界面 2.实现逻辑功能 3.打包Qt程序到Windows软件 1.做好UI界面 2.实现逻辑功能 部分代码如下: widget.h #ifndef WIDGET_H #d ...

  8. Android Q 基站刷新接口源码分析 适配双卡手机基站刷新逻辑

    目录 一.获取基站信息的两个关键方法 getAllCellInfo调用流程总结 requestCellInfoUpdate 流程总结 问题 二.双卡手机适配 Android Q requestCell ...

  9. java join()源码_Java Thread的join() 之刨根问底

    0.Join() 线程的合并的含义就是 将几个并行线程的线程合并为一个单线程执行,应用场景是 当一个线程必须等待另一个线程执行完毕才能执行时,Thread类提供了join方法来完成这个功能,注意,它不 ...

最新文章

  1. Simics系统模拟器
  2. 好用的Markdown编辑器推荐
  3. html按钮冻结,Vue js按钮冻结dom
  4. java writedouble_Java FSDataOutputStream.writeDouble方法代碼示例
  5. 打造一个全命令行的Android构建系统
  6. PowerDesigner逆向工程从现有数据库生成PDM
  7. 2021高考技能考试成绩查询,2021年临床技能考试成绩出来了!附查询方式
  8. PHP中$_FILES['file']['error']的用法
  9. Java出现The import javax.servlet cannot be resolved 的解决方法
  10. i2c-tools使用及调试
  11. 图像分割与GAN网络
  12. sklearn之线性回归实现—阿里云天池二手车交易价格预测赛
  13. 那些所倚靠的利器记载
  14. python3安装库报错ERROR: Exception: Traceback (most recent call last): File “A:\ProgramData\Anacon
  15. 控制器中接收数据的四种方式
  16. java找不到主类错误的原因_java错误:找不到或无法加载主类的原因与解决方法...
  17. python学习——把Excel的内容自动填写到Word
  18. DNS 服务与邮件服务器应用--配置DNS正向解析与反向解析
  19. Linguistic Sorting and Matching
  20. VLAN和交换机接口模式:access、trunk、hybrid

热门文章

  1. 每个人都该懂点的版本管理技能
  2. Linux c中使用系统时间
  3. linux统计使用最多的10个命令
  4. “2012年度IT博客大赛”获奖感言--梦想、学习、坚持、自信、淡定
  5. 远程桌面连接提示“您的凭据不工作”
  6. sun cluster3.1
  7. 10 个 GitHub 上超火的 CSS 奇技淫巧项目,找到写 CSS 的灵感!
  8. Spring注解@Import详细使用说明
  9. java 反射 Constructor、Method、Field 基本用法
  10. Linux文件系统的组成部分