前面几周跟着野火的教程从0到1实现了RT-Thread的内核,对RT-Thread的调度机制和线程、定时器的底层实现有了总体的了解。后面还需进一步对齐实现细节进行探索,但大致先了解其框架,后面再进行细致的了解。在学习新知识时,最重要的是思维模式的转变。先了解其大致框架,再深入去了解细节。有些人(就是我,后来太痛苦终于悟了)学一个新知识,刚上来就从头到尾一个字一个字仔细看,生怕错过什么重要的内容,搞不懂关键点就立马停下来去查,一查发现哇!解释内容这么多,看解释的时候又发现有不懂得地方,又停下来去查,如此一环套一环,何时是个头。而且这样学习的结果就是学一个新知识很快就会筋疲力尽,觉得自己什么都不懂,自信心受到打击,从而陷入对自己的深深怀疑之中,最后很可能放弃学习(这种学习方式就像C语言中函数的递归调用,一层套一层,层层套娃,很容易导致栈空间不够用,最后造成程序崩溃。在陈正冲老师的《C语言深度剖析》中,就建议尽量不要使用递归,如果要使用一定要注意递归调用的深度和对应使用的栈空间)!其实你想想看,这些知识是前人付出多少心血才总结出来的,哪可能会让你一上来就搞得门儿清?除非你天赋异禀异于常人。因此在学习新知识的时候,先了解其大概,不求甚解,遇到了问题先保持疑问,带着疑问继续学下去。动手做起来再说,做的好不好,完不完美那是另一回事,先做,在做的过程中逐渐完善。有些人总是思前想后觉得要考虑的周到,完美再去做,这也没错,但是你考虑的就会和实际情况一模一样吗?在做中学习,诸葛亮舌战群儒说笔下虽有千言,而心中实无一策。我们也要做到不能心中虽有千言,而手上丝毫不动。很多问题其实在你学习后面的知识的过程中就自然而然的解决了。还记得去年学习Linux,对Linux的驱动开发、应用开发学的是一知半解,云里雾里。那时还在学习RT-Thread,学了一段时间Linux之后回过头再看RT-Thread发现好多在学习RT-Thread的疑问自然懂了。这就是当你接触了一个高等级的知识后,再回过头去看低等级的知识时发现就豁然开朗了。

比如在深入学习STM32时,你就会发现main函数并不是上电就开始运行的第一个函数,在main函数之前,在startup_xxx.S文件中(基于执行效率的考虑,使用汇编语言编写),系统做了好多事情,如完成堆和栈的内存分配等,最后在跳转到用户main函数运行。假使这个时候你发现汇编语言好像你什么都不会,对ARM的架构也不是很了解,然后买了本汇编语言和ARM-Cortex内核权威指南吭哧吭哧的开始读,希望能先解决掉这两个不懂得内容,你就会发现你看的时候实际上会碰到更多不懂得知识。假使你真的坚持住了,学完了这两本书,肯定你的知识层次会提高很多,但同时和你一块的人早都跑远了。因此,在实际学习新知识时,先了解个大概,后面再去进行细节的完善,当你有一个整个框架的时候再将细节逐渐补齐就会发现是水到渠成。

学习嵌入式的知识更要学会嵌入式的知识过于庞杂,硬件、协议、软件,这每一个都是大部头,如果心里没有规划,遇到什么都想去搞明白、研究透彻,那学来学去就忘记自己究竟想学什么了。确定自己学习的主线,先将该主线补齐,再去深入研究该主线上的分支。

当设计一个产品时,需要使用单片机还是Linux取决于硬件成本和软件成本,而不是一味的根据个人喜好去选择高性能的或套件更完善的,嵌入式中没有最好的,只有最合适的(此处可以参照清华大学曾鸣老师的《嵌入式ARM微控制器》,该课程逻辑清晰,值得反复刷)。因此,既要学会使用MCU跑裸机或RTOS用于一些低端的设备,也要学会Linux用于要求较高的场合。

在上层软件对底层硬件的操作上,单片机和Linux的实现没有太大的区别:

  1. 根据原理图确定是哪个引脚,需要配置该引脚为输入?输出?或交由外设控制?
  2. 查看芯片手册中实现具体功能需要使用到的寄存器
  3. 软件实现操作逻辑,实现既定功能(最终会落实到对寄存器的操作)

在单片机程序中没有程序分层的概念,应用程序和驱动程序混着写,至少没有明确的界限,很可能一个人就包揽了从硬件设计、模块调试(针对各模块进行驱动程序开发,如开发SPI、I2C器件的通讯程序,对外留出调用接口)、功能实现(应用程序开发,即使用接口对外围器件进行操作,程序实现各个功能模块的相互配合,从而实现既定功能)的全部内容,一般小公司都这么干,讲究全能型,什么活都能干,不需要有规范的标准,反正能搞出来,能以最短的时间实现既定的功能需求就是最好的。

Linux程序中驱动程序和应用程序进行了分层,驱动程序访问寄存器,应用程序只能通过驱动程序实现对寄存器的访问,而不能直接去操作寄存器。为什么要设计成应用分层有以下原因?

  • 保证程序运行的安全性

Linux系统比较复杂,庞大,因此其中应用程序很多。如果在软件程序中开发对底层寄存器的访问,那软件的设计不良可能会导致程序运行崩溃。因此在Linux系统中,将对底层寄存器访问的重要工作交给驱动程序去完成(系统认为驱动程序比较靠谱,只相信驱动程序的话,一般驱动程序开发需要即懂硬件又懂软件,从而才能设计出可靠的驱动程序,一般该工作由驱动工程师完成)

  • 保证应用程序的可移植性

驱动程序是和底层硬件直接打交道的,因此驱动程序和硬件之间是强相关的。在A款芯片上开发的驱动程序想在B款芯片上面使用就要修改,因此只要硬件有改动,就需要检查驱动程序是否也需要针对硬件的改动作出修改。而软件程序是和驱动程序打交道的,具体点来说是和驱动程序的调用接口打交道的。只要驱动程序提供的调用接口不变,底层硬件如何改变,应用程序是不会care的,也是不需要作任何修改的。这样做的好处就是,在需要将A款芯片上的程序移植到B款芯片上的时候,只需要根据硬件的变化修改驱动程序,应用程序不需要修改。

  • 程序分层易于团队协作

不像单片机程序,Linux项目一般规模比较大,一个人很难全套都搞定,因此就需要分工协作。将程序分为驱动程序和应用程序有利于团队协作,具体点就是做应用程序的只需关心如何实现业务逻辑,做驱动程序的只需要关心如何能提供对硬件操作的接口。举例假如要做一个人脸识别项目,有擅长做图像处理的,只要能给到他图像,他就能进行图像分析,具体你这个图像是用什么拍的,他是不关心的。而不同摄像头的硬件操作可能是存在差异的,因此使用哪款硬件,驱动工程师就需要针对硬件进行驱动程序的更改。

前面对RT-Thread的内核通过从0到1的实现已经有了大概的认识,接下来学习RT-Thread的设备驱动框架,和Linux的驱动树进行类比,其实RT-Thread的很多设计思想和具体实现都有借鉴Linux的设计,好的东西当然大家都要借鉴!因此,学习RT-Thread设备驱动框架又会促进对Linux的设备树的理解。白岩松说过,学习就是这样一个相互作用的过程,当你还不知道你学的知识有什么用的时候,坚持学就完事了。你不知道有什么用是因为你读的书还太少,当你读的书多了,学的知识多了,这些点才会被连起来,到时候就不是零零散散,而会成势。

RT-Thread的设备管理框架如上图所示,可以将以上分为应用层、驱动层、硬件层。RT-Thread的设计思想借鉴了Linux的应用层和驱动层设计理念,因此其设备框架和Linux非常相似,也许以后RT-Thread会引入设备树?

【应用层】应用层只需关心业务逻辑,而不需要关心底层硬件

【驱动层】对应用层提供接口使其可以间接的使用硬件,从而搭建起了应用层和硬件层之间的桥梁,驱动层未实现的硬件驱动应用层无法调用。

【硬件层】具体的硬件,可配置其内部的寄存器实现硬件功能的定制

可以这样去理解,【硬件层】是一堆原材料,【驱动层】是一个工匠,他可以将这些原材料打造成各种各样的工具,【应用层】是人,他只能使用工匠打造好的工具而不能直接去使用原材料。

应用层通过驱动层实现对硬件层设备的访问,驱动层程序的升级更改并不会影响应用层大程序。以此可以实现驱动层程序和应用层程序的低耦合,可独立进行开发。

要使用一个设备,要首先将其注册到I/O设备管理器中,让系统知道其的存在。设备被创建之后需要实现其对硬件的操作方法。根据设备功能的不同,可以选择实现部分操作方法或全部操作方法。

当设备被注册到I/O设备管理器之后,用户应用程序通过I/O设备管理器的接口来访问硬件设备。具体映射关系如下:

应用程序需要对硬件进行操作时可以按照如下步骤:

  1. 查找设备rt_device_t rt_device_find(const char* name);。根据设备名称(字符串)在I/O设备管理器中查找该设备,找到之后返回该设备的句柄(指针)。因此注册设备时需注意不同的设备名称不能重复
  2. 初始化设备rt_err_t rt_device_init(rt_device_t dev);。若该设备已经在之前被初始化成功,调用该接口将不会重复再对设备进行初始化
  3. 打开设备rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);。打开设备时,系统会检查该设备是否已经被初始化,未被初始化的系统会自动调用初始化接口对设备进行初始化
  4. 读设备rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos,void* buffer, rt_size_t size);

或写设备rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer, rt_size_t size);或控制设备rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);。

5、关闭设备rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);。打开设备和关闭设备一般需成对使用,因为打开设备会对打开设备次数加1,关闭设备会对打开的设备次数减1。如果不成对使用,则很可能设备并不会被完全关闭。例如调用了2次打开设备后调用1次关闭设备,实际上此时设备并未被关闭,仍是处于打开状态,只有当设备打开次数减为0时才会真正关闭设备。

需要注意的是,只有官方提供的BSP包才可以使用ENV工具进行配置。RT-Thread官方已经对主流芯片和开发板进行BSP包支持,因此在实际的项目使用中,我们可以先找自己项目使用的芯片对应的BSP包,再使用ENV工具对内核和功能组件进行配置,使用ENV下载软件包,生成MDK项目工程,在此基础之上进行项目开发。

ENV工具是针对全功能版本的RT-Thread源码进行配置的工具,因此不适用于使用RT-Thread Nano的版本。ENV工具常用的命令也没有几条,用几遍就记住了,记不住搜一下就出来了。

当使用ENV工具在配置工程后重新创建工程时,会发现调试选项会恢复成默认的。针对此问题,在《嵌入式实时操作系统 RT-Thread设计与实现》P193有说明,可以双击打开BSP中的template.uvprojx工程,直接修改其中的调试选项,如此使用Scons命令生成的新工程也会包含对模板文件中的修改。

RTT学习--制作BSP2https://blog.csdn.net/weixin_42381351/article/details/91127709

参考如上这篇文章将RT-Thread完整版移植到STM32F105芯片上。

RT-Thread设备框架学习感悟相关推荐

  1. 使用RT Thread设备框架封装一个I2C设备——DS3231

    使用RT Thread设备框架封装一个I2C设备--DS3231 前言 ENV配置 I2C测试 将ds3231封装成一个字符设备 结语 前言 学习rt thread的I2C的时候,恰巧手上的板子留了d ...

  2. xpt 2046的触摸屏 rt thread设备驱动框架

    1 基于rtt 开发触摸屏驱动 准备使用rtt 框架 , 驱动xpt 2046的触摸屏, 翻阅大量资料发现, 大部分文章强调的是时序图, 而且很多代码要么直接操作寄存器, 要么是io 口模拟, 只能用 ...

  3. 基于GD32F103C8T6添加RT Thread nano设备框架并添加串口设备(以控制台console( uart0 )为例)

    最近没事琢磨了一下使用设备框架的问题.因为将串口注册到设备框架可以应用十分丰富的软件包. 于是就整理了一下手上的工程,重新将工程梳理了一遍. 像这样是十分清爽了,其中RTOS是操作系统源代码 并且学习 ...

  4. rt thread studio使用QBOOT和片外flash实现OTA升级

    我们这里要使用单片机外部flash作为OTA的下载分区,外部flash硬件连接关系 PB3-->SPI3_CLK PB4-->SPI3_MISO PB5-->SPI3_MOSI PE ...

  5. Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32

    1.前言     [2014年4月重写该博文]     经过若干时间的努力终于搞定了STM32+LwIP和yeelink平台的数据互通,在学习的过程中大部分时间花在以太网协议栈学习上,但是在RT Th ...

  6. RT Thread之 Uart2 操作

    官网连接:https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/uar ...

  7. Android 框架学习4:一次读懂热门图片框架 Picasso 源码及流程

    Android 框架学习1:EventBus 3.0 的特点与如何使用 Android 框架学习2:源码分析 EventBus 3.0 如何实现事件总线 Android 框架学习3:我从 EventB ...

  8. stm32f407单片机rt thread 片外spi flash OTA升级配置示例

    参考地址https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/ 第一步,生成Boot ...

  9. 【安卓Framework学习】Wifi框架学习之wifi状态机

    系列文章目录 [安卓Framework学习]Wifi框架学习之核心类. [安卓Framework学习]Wifi框架学习之开启与关闭流程. [安卓Framework学习]Wifi框架学习之连接与断开流程 ...

最新文章

  1. 如果是能简单解决的问题,就不用想得太复杂了
  2. android 手机跑分,安兔兔安卓手机跑分性能榜公布:第一名实至名归?
  3. 营销推广中心设计(一)营销架构与策略
  4. 爬虫实战:过年你被催婚啦吗?爬取相亲网站,看看当下年轻小姐姐的择偶观。
  5. 【转】Castle Windsor之组件注册
  6. .NET 深度指南:Colors
  7. 论文浅尝 - EMNLP2020 | ConceptBert:视觉问题回答的概念感知表示
  8. 高并发场景下的缓存 + 数据库双写不一致问题分析与解决方案设计
  9. 计算机协会小游戏,网页闯关小游戏闯关记录(一)ISA TEST
  10. go 依赖注入 哪个好_go与java的依赖注入实现的一些差异
  11. ftp4j的android应用
  12. SqlServer 存贮过程操作类
  13. 抖音时钟js css,JS+CSS3实现时钟效果(抖音)
  14. 安装Android Studio遇到的几个困难和解决办法
  15. 从“游击队”到“正规军”:虾神成长史
  16. android启动过程中cpu降频,android省电开发之cpu降频
  17. SpringCloud禁用Eureka自我保护模式
  18. 3ds max中的对象绕局部坐标系旋转的动画
  19. 【ML】经典降维算法 t-SNE
  20. 使用 Excel 和 Math.Net 进行曲线拟合和数据预测

热门文章

  1. pycharm创建django项目linux部署
  2. centos下resin4启动一会儿自动关闭处理
  3. java.lang.NoSuchMethodError: org.springframework.beans.MutablePropertyValues.add
  4. Android 获取光线强弱,开启闪光灯,关闭闪光灯
  5. vscode vetur 不想标签属性老是转行 配置
  6. npm i依赖版本兼容问题处理
  7. java搭建tcp客户端_【Java学习笔记】TCP客户端/服务器端
  8. python中参数传递_python中参数传递
  9. Java StringBuffer
  10. 计算机网络重要机制(一)可靠数据传输