使用RT-Thread的一个很有用的组件-finsh
Finsh的基本使用
event set
suspend thread
-------- ---------- --------------
通过 list_event() 则可以查看当前系统中使用的 event,event 字段 表示事件的名称,set 字段表示事件的值,suspend thread 字段表示等在 这个事件上的线程数目。
dummy
-- dummy variable for Finsh
0, 0x00000000
Finsh>>
按照上面命令的描述,先 list_thread() 下,查看当前系统中运行的 所有线程
\|/
- RT - Thread Operating System
/ | \ 1.1.0 build Aug 17 2012
具体请参见《Realtouch 开发板使用手册》
实验原理及程序结构
对于用户来讲,Finsh 组件有三个主要功能 获取系统运行时信息,如各种 RT-Thread 内核对象的动态信息。 能够对任意寄存器和内存地址进行读写操作 能够直接在 shell 中调用系统函数,访问系统变量
实验设计
list_mempool -- list memory pool in system
list_timer
-- list timer in system
list_device
-- list device in system
list
-- list all symbol in system
--Variable List:
2006 - 2012 Copyright by rt-thread team
thread1 working...
在 RT-Thread Nano 上添加控制台与 FinSH
本片文档分为两部分:第一部分是实现UART 控制台,该部分只需要实现两个数即可完成UART 控制台打印功能。
第二部分是实现移植FinSH 组件,实现在控制台输入命令调试系统,该部分实现基于第一部分,只需要添加FinSH 组件源码并再对接一个系统函数即可实现。
下面将对这两部分进行说明。
在 Nano 上添加 UART 控制台在RT-Thread Nano 上添加UART 控制台打印功能后,就可以在代码中使用RT-Thread 提供的打印函数rt_kprintf() 进行信息打印,从而获取自定义的打印信息,方便定位代码bug 或者获取系统当前运行状态等。
实现控制台打印(需要确认rtconfig.h 中已使及对接一个系统输出字符的函数,本小节将详细说明。
实现串口初始化使用串口对接控制台的打印,首先需要初始化串口,如引脚、波特率等。
uart_init() 需要在 board.c 中2static int uart_init(void);示例代码:如下是基于 HAL 库的STM32F103 串口驱动,完成添加控制台的示例代码,仅做参考。
1static UART_HandleTypeDef UartHandle;2static int uart_init(void)3{4 /* 初始化串口参数,如波特率、停止位等等 */5 UartHandle.Instance = USART1;6 UartHandle.Init.BaudRate = 115200;7 UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;8 UartHandle.Init.Mode = UART_MODE_TX_RX;9 UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;10 UartHandle.Init.WordLength = UART_WORDLENGTH_8B;11 UartHandle.Init.StopBits = UART_STOPBITS_1;12 UartHandle.Init.Parity = UART_PARITY_NONE;1314 /* 初始化串口引脚等 */15 if (HAL_UART_Init(&UartHandle) != HAL_OK)16 {17 while(1);18 }1920 return 0;21}22INIT_BOARD_EXPORT(uart_init);1/* board.c */2void rt_hw_board_init(void)3{4 ....5 uart_init(); // 在 rt_hw_board_init 函数中调用串口初始化函数6 ....7}实现 rt_hw_console_output实现 finsh 组件输出一个字符,即在该函数中实现 uart 输出字符:1/* 实现 2:输出一个字符,系统函数,函数名不可更改*/2void rt_hw_console_output(const char *str);示例代码:如下是基于STM32F103 HAL 串口驱动对接的rt_hw_console_output() 函数,实现控制台字符输出,示例仅做参考。
RTT4-RTThread使用Shell finsh及TC测试框架
使用RT-Thread 1.0.2 (或者打开任何一个RTThread工程)部分引自Prife的《RT_Thread的测试框架使用及分析》,仔细阅读后作了修订。
/prife/article/details/74870381.Finsh组件配置在例程源代码中,系统配置已经完毕,首先是修改了rtconfig.h 文件,将使用Finsh组件的宏打开其次将Finsh 组件的源文件加入到工程中编译2.连接串口下载程序后,连接好串口1,打开SecureCRT.exe,设置波特率115200,后连接。
开发板上电后,显示:输入list()后回车,list()命令的作用就是将系统中支持的所有shell命令都打印出来,也可以按TAB键。
有点类似与其他系统中的help命令。
有了这些命令和描述信息,我们就可以深入内核,查看它们的信息。
当前系统中运行的线程信息。
敲入list_thread(),回车。
当前系统实际运行时所有线程信息。
当前系统中运行着10个线程。
线程的名称,优先级,运行状态,堆栈地址,堆栈大小,最大使用堆栈,剩余运行tick 时间,错误信息都一览无遗,呵呵,是不是很方便。
其实,Finsh 的更强大功能还等着你挖掘呢.4.一个最简单的测试用例(不使用TestCase 框架)在application.c中的最后添加如下代码int testfunc(void){rt_kprintf("hello, rt-thread!\n");return 0;}#include <finsh.h>FINSH_FUNCTION_EXPORT(testfunc, just a test function);重新编译工程,启动串口工具输入命令list() 或者按Tab键多出一行。
接下来,在finsh上输入t 然后按下Tab键,finsh会自动地为我们补全testfunc,然后我们手动输入()后回车,可以看到如下运行效果:finsh />testfunc()hello, rt-thread!0, 0x00000000finsh />注:finsh跟linux下的shell很像,都具有tab键自动补全的功能,但是又有些不同,finsh的命令是C语言风格的,命令即函数调用语句。
rtthread多线程写法
rtthread多线程写法一、引言RT-Thread是一种广泛使用的实时操作系统,它支持多线程编程,使得开发者能够充分利用多核处理器的能力,提高系统的性能和稳定性。
本文将介绍RT-Thread多线程的编写方法,包括线程的创建、同步、通信等关键技术。
二、线程创建RT-Thread支持多种线程创建方式,包括手动创建、自动创建和共享内存创建。
手动创建适用于简单的应用场景,自动创建适用于复杂的应用场景,而共享内存创建适用于需要跨进程或跨线程通信的情况。
在创建线程时,需要指定线程的优先级、堆栈大小等参数,并为其分配必要的资源。
三、线程同步多线程编程中,线程同步是至关重要的一环。
RT-Thread提供了多种同步机制,包括互斥锁、信号量、条件变量等。
互斥锁用于保护共享资源的访问,避免出现竞态条件;信号量用于控制线程的执行流程,实现线程间的通信;条件变量用于实现线程间的异步通信,提高系统的响应速度。
在使用这些同步机制时,需要注意避免死锁、饥饿等问题。
四、线程通信线程通信是多线程编程中的另一个重要问题。
RT-Thread提供了消息队列、事件通知等机制来实现线程间的通信。
消息队列用于在多个线程之间传递数据,事件通知用于在特定条件下触发某个线程的行为。
在实现线程通信时,需要考虑到通信的效率、可靠性和安全性,避免出现数据丢失、重复接收等问题。
五、代码示例下面是一个简单的RT-Thread多线程示例代码:```c++#include <rtthread.h>// 定义互斥锁rt_mutex_t mutex;// 定义信号量,初始值为1,表示只有一个线程可以执行以下代码块rt_sem_t sem;void thread_func(void* arg){// 锁定互斥锁rt_mutex_lock(&mutex);// 释放信号量,表示有线程进入了等待队列rt_sem_release(&sem);// 执行需要同步的代码块rt_sem_take(&sem, RT_WAITING_FOREVER);// 解锁互斥锁rt_mutex_unlock(&mutex);}int main(){// 创建线程1,参数为线程函数和传递的参数rt_thread_t tid1 = rt_thread_create("tid1", thread_func, NULL, 2048, 5, 3);if (tid1 == RT_NULL) {rt_kprintf("Failed to create thread1\n");return -1;}// 创建线程2,参数为线程函数和传递的参数rt_thread_t tid2 = rt_thread_create("tid2", thread_func, NULL, 2048, 5, 3);if (tid2 == RT_NULL) {rt_kprintf("Failed to create thread2\n");return -1;}// 启动线程1和线程2rt_thread_startup(tid1);rt_thread_startup(tid2);// 等待所有线程退出完成rt_thread_join(tid1);rt_thread_join(tid2);// 销毁线程资源并释放内存空间rt_thread_delete(tid1);rt_thread_delete(tid2);return 0;}```这个示例代码创建了两个线程,并使用互斥锁和信号量实现了简单的同步和通信。
rtthread龙芯移植技术文档
面向对象的特征主要包括:
封装,隐藏内部实现
继承,复用现有代码
多态,改写对象行为
采象的特征。
2.1.1封装
封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
structparent_class *parent_ptr;/*父类指针*/
obj_ptr = &obj;
/*取父指针*/
parent_ptr = (structparent_class*) &obj;
/*可通过转换过类型的父类指针访问相应的属性*/
parent_ptr->a= 1;
parent_ptr->b= 5;
1.3轻型IP协议栈
LwIP是瑞士计算机科学院(Swedish Institute of Computer Science)的Adam Dunkels等开发的一套用于嵌入式系统的开放源代码TCP/IP协议栈,它在包含完整的TCP协议实现基础上实现了小型的资源占用,因此它十分适合于使用到嵌入式设备中,RT-Thread采用LwIP做为默认的TCP/IP协议栈,同时根据小型设备的特点对其进行再优化,体积相对进一步减小,RAM占用缩小到5kB附近(依据上层应用使用情况会有浮动)。
1.1.2任务同步机制
系统支持信号量、互斥锁作为线程间同步机制。互斥锁采用优先级继存方式以解决优先级翻转问题。信号量的释放动作可安全用于中断服务例程中。同步机制支持线程按优先级等待或按先进先出方式获取信号量或互斥锁。
干货扒一扒RT-Thread内核对象管理器设计思路
干货扒一扒RT-Thread内核对象管理器设计思路RT-Tread内核架构RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统,基本属性之一是支持多任务,允许多个任务同时运行并不意味着处理器在同一时刻真地执行了多个任务。
其内核架构如下图所示:RT-Thread 内核及底层结构对于各部分的功能,这里不做展开描述。
RT-Tread内核吸引我的方面:•代码优雅、可读性非常高•体积小巧、代码类Linux风格,可裁剪•社区活跃,国人自主开发,用户越来越多•优秀的设计,对于面向对象设计思想可以说是非常优秀的实践•主要定位于物联网应用,各种组件丰富,融合的也很好•........所以如果是RTOS应用或者开发从业者,面对这么优秀且比较容易深入学习的内核,如果不去好好读读,实在有点可惜。
要去体会RT-Thread对象设计思想,从其对内核对象object的管理入手,不失为一个非常好的切入点。
什么是RT-Thread内核对象管理?RT-Thread 采用内核对象管理系统来访问/ 管理所有内核对象,内核对象包含了内核中绝大部分设施,这些内核对象既可以是静态分配的静态对象,也可以是从系统内存堆中分配的动态对象。
通过这种内核对象的设计方式,RT-Thread 做到了不依赖于具体的内存分配方式,系统的灵活性得到极大的提高。
RT-Thread 内核对象包括:线程,信号量,互斥量,事件,邮箱,消息队列和定时器,内存池,设备驱动等。
对象容器中包含了每类内核对象的信息,包括对象类型,大小等。
对象容器给每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上,如图RT-Thread 的内核对象容器及链表如下图所示:RT-Thread 的内核对象容器及链表参考自:/document/site/programming-manual/basic/basic/#_7这个集中管理的内核对象容器在内存的开销方面代价很小,但却具有高度的灵活性,从设计的角度看其代码也非常利于扩展,增加新的内核对象类别,以及对于相应的内核对象功能的裁剪适配。
十余年历史的国产RTOS,从RT
十余年历史的国产RTOS,从RT现在是一个快节奏的时代,技术领域也是如此。
近些年,IoT备受资本青睐,各种新技术新方案层出不穷,质量也参差不齐,这边唱罢那边登台,以至于有些技术还未被人熟知,就被淹没在长河中了。
客观的说,RTOS领域玩家众多,仅笔者短短的从业时间,国产RTOS就听闻了五、六款之多。
RT-Thread作为一个有十余年历史的国产RTOS,经历了长时间的考验和用户的青睐,目前发展趋势蒸蒸日上,也即将发布RT-Thread 3.0,其中必然有值得我们思考和学习的地方,我们也可以从中汲取到不少宝贵的经验。
软件工程管理 软件工程管理对于软件研发是十分重要的,甚至可以说是开发过程的基石。
公司中有高水平的嵌入式软件程序员,也有刚入职的实习生,水平难免参差不齐,当共同协作开发一个项目时,如何彼此协调也是一个难题。
时至今日,很多公司仍然在使用落后的代码管理方式。
有些甚至使用把代码压缩成一个个的压缩包来做版本管理。
同事之间的协作依靠互相发送文件,每次接收到同事的新文件首先要花半天时间解决编译error,甚至还要在本地对同事的代码进行修改,这样,软件基本处在半失控的状态,某次改动产生问题,就要从浩瀚的压缩包海洋里挑选一个,进行版本回退。
在开发一个大项目的时候,这种情况下甚至会出现人数越多,开发难度和周期越大的情况。
而RT-Thread,提供了一个教科书级的范例。
RT-Thread由13000多个文件构成,支持各类设备和芯片近70款,从代码量和组织方式上来说,是一个相当庞大的软件工程。
在近十年的时间里,至少有将近100个开发者参与到了RT-Thread的开发中,使得RT-Thread稳步迭代,而这也是有一定的维护难。
RT-Thread学习之对FLASH进行分区管理
FLASH分区管理是怎么一回事呢?我们可以以个人电脑来做类比,我们的电脑通常都分有很多个盘符:这些都是我们硬盘的分区,我这里装了两块硬盘,512GB的机械硬盘+128GB的固态硬盘,共分C~H六个分区,我这里的C盘和H盘是固态硬盘,其它盘符是机械硬盘:分区是为了方便我们对我们的资料进行管理,各个分区互不影响,比如格式化某个分区只会删除这个分区的内容而不会影响其它分区及整个硬盘等。
同样的,在我们的STM32上也是可以进行分区管理的,这篇笔记我们来使用RT-Thread的FAL软件包来对我STM32片内FLASH及片外FLASH的分区管理。
FAL软件包介绍FAL (Flash Abstraction Layer) Flash 抽象层,是 RT-Thread 的一个软件包,是对 Flash 及基于 Flash的分区进行管理、操作的抽象层,对上层统一了 Flash 及分区操作的 API ,并具有以下特性:• 支持静态可配置的分区表,并可关联多个 Flash 设备;• 分区表支持自动装载。
避免在多固件项目,分区表被多次定义的问题;• 代码精简,对操作系统无依赖,可运行于裸机平台,比如对资源有一定要求的 bootloader;• 统一的操作接口。
保证了文件系统、 OTA、 NVM 等对 Flash 有一定依赖的组件,底层 Flash 驱动的可重用性;• 自带基于 Finsh/MSH 的测试命令,可以通过 Shell 按字节寻址的方式操作(读写擦) Flash 或分区,方便开发者进行调试、测试;FAL软件包使用本笔记主要对潘多拉开发板的FAL例程进行一次梳理,所以部分表述来自于教程文档。
我们这个实验建立如下分区表:1、移植接口文件说明FAL软件包的目录如下,其中samples文件夹下为移植接口文件:其中fal_cfg.h 为fal 配置文件(Flash 设备配置和分区表配置):fal 是 Flash 抽象层,要操作 Flash 设备必然要将 Flash 的读、写、擦接口对接到 fal 抽象层中。
rt-thread 事件集的使用方法
一、什么是rt-thread事件集?rt-thread是一个开源的嵌入式实时操作系统,具有高度灵活性和可扩展性。
事件集是rt-thread提供的一种事件管理机制,用于实现任务之间的同步和通信。
二、事件集的创建和初始化1. 创建事件集在rt-thread中创建事件集非常简单,只需调用相应的API即可。
示例代码如下:```c/* 定义事件集变量 */static rt_event_t ev;/* 在m本人n函数中创建事件集 */int m本人n(){/* 创建事件集 */rt_event_init(ev, "event", RT_IPC_FLAG_FIFO);/* 其他代码 */}```2. 初始化事件集rt-thread的事件集初始化函数为rt_event_init,其原型为:```crt_err_t rt_event_init(rt_event_t event, const char *name,rt_uint8_t flags);```其中,event为事件集指针,name为事件集的名称,flags为事件集的标志位。
三、事件集的使用方法1. 设置事件标志位使用rt_event_send函数可以设置事件集的指定标志位,示例代码如下:```crt_uint32_t set = 0x01; // 要设置的标志位rt_event_send(ev, set);```2. 清除事件标志位使用rt_event_recv函数可以清除事件集的指定标志位,示例代码如下:```crt_uint32_t clear = 0x01; // 要清除的标志位rt_event_recv(ev, clear, RT_EVENT_AND_CLEAR, set, RT_W本人TING_FOREVER);```3. 等待事件集标志位使用rt_event_recv函数可以等待事件集的指定标志位,示例代码如下:```crt_uint32_t w本人t = 0x01; // 要等待的标志位rt_event_recv(ev, w本人t, RT_EVENT_AND, set, RT_W本人TING_FOREVER);```四、事件集的优势和适用场景事件集是一种轻量级的事件管理机制,具有以下优势:- 灵活性高:可以灵活地设置、清除和等待事件标志位,便于实现复杂的任务同步和通信。
f1c200s rtthread sdk说明
一、RT-Thread SDK的概述RT-Thread是一个实时操作系统,具有精简、高效的特点,能够在资源有限的嵌入式系统中运行。
RT-Thread SDK是基于RT-Thread实时操作系统的开发套件,提供了丰富的示例代码、文档和工具,帮助开发者快速搭建和开发嵌入式系统。
二、RT-Thread SDK的特点1. 开源免费:RT-Thread SDK完全开源,同时免费提供给开发者使用和修改。
2. 轻量级:RT-Thread SDK采用模块化设计,能够根据具体需求选择合适的模块,减小系统的占用空间。
3. 易用性:RT-Thread SDK提供了丰富的示例代码和文档,帮助开发者快速上手,快速搭建和开发嵌入式系统。
三、RT-Thread SDK的组成部分RT-Thread SDK包含了以下重要的组成部分:1. RT-Thread内核:RT-Thread是一个轻量级的实时操作系统内核,提供了丰富的系统服务和功能模块,包括任务调度、内存管理、设备驱动、网络通信等。
2. 驱动程序:RT-Thread SDK提供了多种设备驱动程序,包括串行通信、网络、存储设备等,方便开发者在嵌入式系统中使用各种外设。
3. 中间件:RT-Thread SDK还包含了多种中间件,例如文件系统、GUI图形界面库、网络协议栈等,帮助开发者快速实现各种功能。
4. 示例代码:RT-Thread SDK提供了丰富的示例代码,覆盖了各种常见的应用场景,方便开发者参考和使用。
四、RT-Thread SDK的应用领域RT-Thread SDK适用于各种嵌入式系统的开发,包括但不限于以下领域:1. 工业控制:RT-Thread SDK提供了丰富的通信协议栈和设备驱动程序,能够满足工业控制系统的需求。
2. 智能家居:RT-Thread SDK提供了GUI图形界面库和网络通信功能,能够快速实现智能家居设备的控制和监控。
3. 汽车电子:RT-Thread SDK支持多种外设和通信协议,能够应用于汽车电子系统的开发。
RT-Thread进阶之网络框架
RT-Thread进阶之网络框架展开全文1、网卡组件(netdev)netdev 组件主要作用是解决设备多网卡连接时网络连接问题,用于统一管理各个网卡信息与网络连接状态,并且提供统一的网卡调试命令接口。
其主要功能特点如下所示:•抽象网卡概念,每个网络连接设备可注册唯一网卡。
•提供多种网络连接信息查询,方便用户实时获取当前网卡网络状态;•建立网卡列表和默认网卡,可用于网络连接的切换;•提供多种网卡操作接口(设置IP、DNS 服务器地址,设置网卡状态等);•统一管理网卡调试命令(ping、ifconfig、netstat、dns 等命令);网卡概念:网卡概念介绍之前先了解协议栈相关概念,协议栈是指网络中各层协议的总和,每种协议栈反映了不同的网络数据交互方式,RT-Thread 系统中目前支持三种协议栈类型:lwIP 协议栈、AT Socket 协议栈、WIZnet TCP/IP硬件协议栈。
每种协议栈对应一种协议簇类型(family),上述协议栈分别对应的协议簇类型为:AF_INET、AF_AT、AF_WIZ。
网卡的初始化和注册建立在协议簇类型上,所以每种网卡对应唯一的协议簇类型。
Socket 套接字描述符的创建建立在netdev 网卡基础上,所以每个创建的Socket 对应唯一的网卡。
协议簇、网卡和socket 之间关系如下图所示:1.1 netdev数据结构每个网卡对应唯一的网卡结构体对象,其中包含该网卡的主要信息和实时状态,用于后面网卡信息的获取和设置。
网卡状态:•up/down:底层网卡初始化完成之后置为 up 状态,用于判断网卡开启还是禁用。
•link_up/link_down:用于判断网卡设备是否具有有效的链路连接,连接后可以与其他网络设备进行通信。
该状态一般由网卡底层驱动设置。
•internet_up/internet_down:用于判断设备是否连接到因特网,接入后可以与外网设备进行通信。
RT-Thread用户手册
6.7
线程相关接口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 5 5 5 6 9 9 14 18 20 21 22 27 28 29 29 29 29 31 31 34 43 43 43 44 46 47 47 i
5 内核对象模型 5.1 C语言的对象化模型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 内核对象模型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 线程调度与管理 6.1 实时系统的需求 6.2 线程调度器 . . . 6.3 线程控制块 . . . 6.4 线程状态 . . . . 6.5 空闲线程 . . . . 6.6 调度器相关接口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
RTThreadRTOS应用之二——使用finsh组件
RT Thread RTOS应用之二——使用finsh组件RT Thread RTOS应用之二——使用finsh shell系统实验描述:开启RTT 的finsh组件;向finsh中添加用户函数;利用finsh观察RTT个线程的运行状态;通过finsh调用用户函数。
实验讲解开始:“每个线程栈应该设定多大最合适,”,“当前到底启动了哪几个线程,”“我的程序没有正常运行,到底是哪个线程出现了问题,”,“我想要随时获得任意变量的数值应该怎么办,”,“我想要在程序运行中,人为插入一些操作应该如何实现,”。
这些问题都是使用RTOS的人经常会碰到的,这些问题在传统的OS中并不好解决,需要用户自行设计解决方法。
而在RT Thread中却非常容易解决。
原因就在于他的finsh shell系统。
RT-Thread的shell系统——finsh,提供了一套供用户在命令行操作的接口,主要用于调试、查看系统信息。
finsh被设计成一个不同于传统命令行的C语言表达式解释器:由于很多嵌入式系统都是采用C语言来编写,finsh正是采用了这种系统软件开发人员都会的语法形式,把C 语言表达式变成了命令行的风格。
它能够解析执行大部分C语言的表达式,也能够使用类似于C语言的函数调用方式访问系统中的函数及全局变量,此外它也能够通过命令行方式创建变量——引自《RT-Thread实时操作系统编程指南》。
移植finsh系统移植finsh系统非常简单,只需要将rtt文件夹中的components文件夹下的finsh文件夹中的文件添加进入MDK。
结果如图:之后,在MDK中包含finsh的文件路径,以保证可以检测到全部finsh相关的头文件,如下图所示:开启finsh系统在RTT中启用finsh系统非常容易,只需要在rtconfig.h头文件中,定义 /* SECTION: finsh, a C-Express shell */ #define RT_USING_FINSH /* Using symbol table */#define FINSH_USING_SYMTAB#define FINSH_USING_DESCRIPTION 这三个宏。
极致简单:RT-Thread Nano 全新体验
小而美的物联网操作系统
◆ 步骤1:安装 Nano pack ◆ 步骤2:添加 Nano pack 到工程(配置工程、生成工程) ◆ 步骤3:实现系统时钟与 OS Tick ◆ 步骤4:编写第一个 led 应用
小而美的物联网操作系统
◆ 步骤1:添加 Nano 源码到工程 ◆ 步骤2:添加 board.c / rtconfig.h 到工程 ◆ 步骤3:实现系统时钟与 OS Tick (已实现) ◆ 步骤4:编写第一个 led 应用
板级移植 board.c
⚫ 配置系统时钟:时钟 与 OS Tick ⚫ 实现外设初始化:如 MMU、Cache、GPIO、
UART 等 ⚫ 初始化内存堆,实现内存堆管理
小而美的物联网操作系统
◆ 步骤1:安装 Nano pack ◆ 步骤2:添加 Nano pack 到工程 ◆ 步骤3:实现系统时钟与 OS Tick (已实现) ◆ 步骤4:编写第一个 led 应用
rt_coLeabharlann ponents_init() $Super$$main()
main()
rt_hw_context_switch_to
小而美的物联网操作系统
rt-thread nano
【源码文件夹】
bsp
【示例代码】
components
【FinSH 组件】
include
【头文件】
libcpu
【CPU 移植文件】
◆ 设备驱动框架 ◆ 组件 ◆ 软件包
内核
软件包 组件 内核
小而美的物联网操作系统
简单 小巧
易于 使用
易于 下载
易于 移植
简单小巧
01
支持极简化配置
易于下载
04使用 RT-Thread 提高嵌入式软件“调试”效率
使用RT-Thread 提高嵌入式软件“调试”效率朱天龙(Armink)工具思维用户尽可能只接触上层,繁琐的底层工作交给RTT 、交给工具去完成降低使用门槛繁琐的工作交给工具以后,我们能把精力聚焦在更有技术含量的工作加速开发过程多思考重复性的工作内容,如果可以尽量交给工具去完成减少重复工作工具干活的速度和质量比我们可能更高,使用工具也能提高工作效率提高工作效率人类和其他动物的最大区别:使用工具和制造工具RTT 已提供数十种开发、调试工具开发工具:ENV构建系统:SCons基于python 简单易用,支持自动生成工程配置系统:menuconfig图形化的配置界面软件包平台:package目前软件包数量接近100模拟器:qemuPC 端开发,无需连接真机,Code any where编码VS调试20%80%代码编写根据设计要求,编写实现代码。
该阶段主要以软件框架搭建、模块开发为主。
主要用的ENV 工具。
代码调试检查代码运行结果,查找软件出错原因,调整修改软件代码保证符合功能性要求。
该阶段需要通过各种调试工具,获取软件硬件运行状态,分析、定位问题原因。
用到的工具也比较多。
高效调试工具Shell组件: Finsh/MSH最受开发者欢迎的调试接口shell 人机交互接口,拉近与程序之间距离方便执行调试、测试代码快速查看调试结果状态,传统模式通常是:按键+ 指示灯简单易用,只需额外增加一行代码用户基本无需增加过多调试代码,即可将函数注册为命令,非常方便使用广泛,兼容Linux 常用命令几乎所有组件均已集成Finsh/MSH 测试命令,并且与linux 常见命令风格一致:ps, ifconfig, ls为什么需要日志组件好记性不如烂笔头记录功能作为日志的最主要功能,保证了系统即便死机瘫痪,我们也能还原问题现场需要获取更多系统信息定位问题通常需要不同维度的信息,比如:时间戳,当前线程等等系统并行运行,如何了解运行流程使用操作系统后,多线程并行运行,有需要知道产品运行时序或整体流程有些环境不支持仿真器调试还有些用户场景下无法使用仿真器,此时只能使用日志调试工具日志组件:ulog1 2 3 4超轻量级1K ROM,0.2K RAM资源占用小,非常适合嵌入式平台。
RT-Thread--线程管理
RT-Thread--线程管理线程管理的功能特点RT-Thread系统中线程是调度的最⼩单位;线程分为:系统线程和⽤户线程,系统线程是由 RT-Thread 内核创建的线程,⽤户线程是由应⽤程序创建的线程,这两类线程都会从内核对象容器中分配线程对象,当线程被删除时,也会被从对象容器中删除RT-Thread 的线程调度器是抢占式的,主要的⼯作就是从就绪线程列表中查找最⾼优先级线程,保证最⾼优先级的线程能够被运⾏,最⾼优先级的任务⼀旦就绪,总能得到 CPU 的使⽤权。
当调度器调度线程切换时,先将当前线程上下⽂保存起来,当再切回到这个线程时,线程调度器将该线程的上下⽂信息恢复。
线程的⼯作机制线程控制块线程控制块由结构体 struct rt_thread 表⽰,线程控制块是操作系统⽤于管理线程的⼀个数据结构,它会存放线程的⼀些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之间连接⽤的链表结构,线程等待事件集合等/*** Thread structure*/struct rt_thread{/* rt object */char name[RT_NAME_MAX]; /**< the name of thread */rt_uint8_t type; /**< type of object */rt_uint8_t flags; /**< thread's flags */#ifdef RT_USING_MODULEvoid *module_id; /**< id of application module */#endifrt_list_t list; /**< the object list */rt_list_t tlist; /**< the thread list *//* stack point and entry */void *sp; /**< stack point */void *entry; /**< entry */void *parameter; /**< parameter */void *stack_addr; /**< stack address */rt_uint32_t stack_size; /**< stack size *//* error code */rt_err_t error; /**< error code */rt_uint8_t stat; /**< thread status *//* priority */rt_uint8_t current_priority; /**< current priority */rt_uint8_t init_priority; /**< initialized priority */#if RT_THREAD_PRIORITY_MAX > 32rt_uint8_t number;rt_uint8_t high_mask;#endifrt_uint32_t number_mask;#if defined(RT_USING_EVENT)/* thread event */rt_uint32_t event_set;rt_uint8_t event_info;#endif#if defined(RT_USING_SIGNALS)rt_sigset_t sig_pending; /**< the pending signals */rt_sigset_t sig_mask; /**< the mask bits of signal */void *sig_ret; /**< the return stack pointer from signal */rt_sighandler_t *sig_vectors; /**< vectors of signal handler */void *si_list; /**< the signal infor list */#endifrt_ubase_t init_tick; /**< thread's initialized tick */rt_ubase_t remaining_tick; /**< remaining tick */struct rt_timer thread_timer; /**< built-in thread timer */void (*cleanup)(struct rt_thread *tid); /**< cleanup function when thread exit *//* light weight process if present */#ifdef RT_USING_LWPvoid *lwp;#endifrt_uint32_t user_data; /**< private user data beyond this thread */};typedef struct rt_thread *rt_thread_t;nit_priority 是线程创建时指定的线程优先级,在线程运⾏过程当中是不会被改变的(除⾮⽤户执⾏线程控制函数进⾏⼿动调整线程优先级);cleanup 会在线程退出时,被空闲线程回调⼀次以执⾏⽤户设置的清理现场等⼯作;user_data 可由⽤户挂接⼀些数据信息到线程控制块中,以提供类似线程私有数据的实现。
RT-Thread内核对象控制块详解
RT-Thread内核对象控制块详解背景•学习RT-Thread,除了基础的应用,应该花点时间,研究下底层内核的实现方法。
•RT-Thread内核,整体代码量不大,很适合研究,后期,打算在这个基础上,开发一些软件包。
•之前了解了一点数据结构的知识,主要为结构体、链表。
不过感觉没有真正的使用起来。
•程序 = 数据结构+算法。
•万事开头难,先从最基本的概念开始。
内核对象控制块•对象(object)结构体•对象可以派生具体的对象导火索•今天,想仔细看看RT-Thread 的内核的对象,基本上都是结构体,看看结构体的大小,占用RAM的大小。
•单片机的程序,短小精悍是每个嵌入式软件工程师追求的,实现相同功能,占用最少资源,意味着硬件成本会进一步降低。
•编写一个函数,打印一下rt_object 等对象的结构体占用的内存(RAM)大小。
void print_kernel_object_size(void){struct rt_object obj;rt_kprintf("struct rt_object size=%d\\n", sizeof(obj));rt_kprintf("rt_list_t size=%d\\n", sizeof(rt_list_t));rt_kprintf("struct rt_ti mer size=%d\\n", sizeof(struct rt_timer)); rt_kprintf("struct rt_thre ad size=%d\\n", sizeof(structrt_thread));rt_kprintf("struct rt_ipc_object size=%d\\n", sizeof(structrt_ipc_object));rt_kprintf("struct rt_semaphore size=%d\\n", sizeof(structrt_semaphore));rt_kprintf("struct rt_mu te x size=%d\\n", sizeof(struct rt_mutex)); rt_kprintf("struct rt_event size=%d\\n", sizeof(struct rt_event)); rt_kprintf("struct rt_mailbox size=%d\\n", sizeof(structrt_mailbox));rt_kprintf("struct rt_messagequeue size=%d\\n", sizeof(structrt_messagequeue));rt_kprintf("struct rt_mempool size=%d\\n", sizeof(structrt_mempool));rt_kprintf("struct rt_device size=%d\\n", sizeof(structrt_device));rt_kprintf("struct rt_device_graphic_info size=%d\\n",sizeof(struct rt_device_graphic_info));}MSH_CMD_EXPORT(print_kernel_object_size, print_kernel_object_size);//导出命令•运行效果msh / >priprint_kernel_object_sizemsh / >print_kernel_object_sizestruct rt_object size=20rt_list_t size=8struct rt_timer size=44struct rt_thread size=128struct rt_ipc_object size=28struct rt_semaphore size=32struct rt_mutex size=36struct rt_event size=32struct rt_mailbox size=48struct rt_messagequeue size=60struct rt_mempool size=52struct rt_device size=80struct rt_device_graphic_info size=12•struct rt_object size=20,说明:RT_NAME_MAX为8时,内核对象大小为:20字节(8+ (4)+8 = 20)•初步分析,rt_uint8_t type,rt_uint8_t flag,因为内存对齐,占用了2+2=4个字节。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
rt_kprintf("input : %d \r\n",input); rt_kprintf("fun_a done.\r\n"); } FINSH_FUNCTION_EXPORT(fun_a, fun_a desc);
#endif
//初始化 FINSH 线程 //设置 FINSH 使用的输入输出设备为 "uart1"
在以前,FINSH 需要自己实现输入和输出,现改进为使用 RT-Thread 的设备管理框架来实现 输入输出,这样可以很方便地使用"uart2"来操作 Finsh,甚至是网络,类似于 telnet. 极大地增强了灵活性,
finsh>> fun_a(9) finsh>> fun_b(10) finsh>> int fun_val = 20 finsh>> fun_a(fun_val) finsh>> fun_b(++fun_val) finsh>> fun_a(fun_val *2)
Finsh 使用秘籍: 1.finsh>>状态下按 TAB 有惊喜. 2.输入 fun 再按 TAB 依然有惊喜.(可以输入 list 再按 TAB 测试下) 3.执行一个函数退出后再按上,下键可浏览历史.
//定义使用 RT-Thread 的设备管理
#define RT_USING_UART1
//使用 UART1 在 /src/usart.c 中有用到.
2. 取消原来的简单串口输出程序 把原来 board.c 中的 rt_hw_console_init(); 函数取消掉,换成 usart 中的 rt_hw_usart_init(); RT-Thread 中的 rt_kprinf() 也可以使用设备来输出,只需要
/* enter interrupt */ rt_interrupt_enter(); rt_hw_serial_isr(&uart1_device);
/* leave interrupt */ rt_interrupt_leave(); }
第四步: 写一个简单应用来使用 Finsh
因为原来 app.c 中有两个线程,都有使用 rt_kprintf 来打印信息,因 console 和 finsh 现都使用 "uart1",这两个线程打印的信息可能会影响观察,我们sart.c 把每个串口注册成设备.因 STM32 有多个串口,所以,根据需要来使用.
1.rtconfig.h 打开使用 RT-Thread 的设备管理
/* SECTION: Device System */
/* Using Device System */
#define RT_USING_DEVICE
使用 finsh
本例程和目标 CPU 配置无关,已把芯片内部 SRAM 容量配置为 20KB,C8T6~ZET6 通用. 除使用 USART1 外不使用其它外设.
Finsh 是一个很有用的调试-交互组件,使用 Finsh 可以查看所有线程,信号量,设备等信息. 是调试系统的得力肋手,下面介绍下如何使用 finsh.
后记:
因为需要导出一些符号给 finsh shell 使用,也就是那些函数名,变量名. 而这些函数名和变量名统一的放在两个 section 中,这样 finsh shell 能够自动的到这两个段中寻找. 而因为上面的 fun_a() fun_b() 并没有在别处被引用,因此在链接时可能被链接程序自动移除掉. 所以需要添加如下图链接选项让链接器保留这些段.
"--keep __fsym_* --keep __vsym_*" 详 细 请 看 FINSH_FUNCTION_EXPORT 的 实 现
3.添加 USART1 中断服务程序,在前面我们仅实现输出,通过查询方式,没有使用中断。
#include <rtthread.h> void USART1_IRQHandler(void) {
extern struct rt_device uart1_device; extern void rt_hw_serial_isr(struct rt_device *device);
所以,在下面,我们还需要实现这个 "uart1"设备.
第三步: 实现统一的设备管理
在 base_kernel 例程中,为了使例程变成简单,我们实现了一个最简单的通过查询方式的串口 输出程序.缺点很明显:没有灵活性,性能也只能做来做演示.
RT-Thread 提供了一个完整的设备管理方案,可以把不同类型的外设都按统一的接口进行 操作,通过设备名称就可以找到设备,然后就可以直接访问了.
void fun_b(int input) {
rt_kprintf("input : %d \r\n",input); rt_kprintf("fun_b done.\r\n"); } FINSH_FUNCTION_EXPORT(fun_b, fun_b desc); //同上
这样,当我们在 finsh 中执行 fun_a() 时,就会运行 fun_a 这个函数(注意加回车).
然后需要在初始化 RT-Thread 时把 Finsh 也一并初始化.
/* init application */ rt_application_init();
#ifdef RT_USING_FINSH /* init finsh */ finsh_system_init(); finsh_set_device("uart1");
第一步: 添加 Finsh 源文件
本例程基于 base_kernel 例程修改 既然要使用 Finsh,首先是添加 Finsh 的全部源文件.见:rt-thread/finsh.
然后更新头文件搜索路径:
第二步: 配置使用 Finsh 并初始化 Finsh.
作为 RT-Thread 的一个组件,要使用 Finsh,需要在 rtconfig.h 中开启使用 Finsh.
rt_console_set_device("uart1"); 就可以让 rt_kprinf() 通过"uart1"来输出,原来的 rt_hw_console_output() 也可以取消掉. 因为设置 rt_kprinf() 通过设备来输出后,就不会再通过 rt_hw_console_output() 来输出数 据了.
因为 STM32 的各型号外设兼容性极高,所以 RT-Thread 为 STM32 的 USART 提供了一个通用 框架.
rt-thread/stm32/serial.c rt-thread/stm32/serial.h 之所以写一个框架是因为 STM32 有多达 5 个串口.这样是为了提高程序的重用性.
/* SECTION: finsh, a C-Express shell */
#define RT_USING_FINSH
//定义使用 FINSH
/* Using symbol table */
#define FINSH_USING_SYMTAB
#define FINSH_USING_DESCRIPTION