1.2 嵌入式系统的学习困惑、知识体系及学习建议
1.2.1 嵌入式系统的学习困惑
关于嵌入式系统的学习方法,因学习经历、学习环境、学习目的、已有的知识基础等不同,可能在学习顺序、内容选择、实践方式等方面有所不同。但是,应该明确哪些是必备的基础知识,哪些应该先学,哪些应该后学;哪些必须通过实践才能获得的;哪些是与具体芯片无关的知识,哪些是与具体芯片或开发环境相关的知识。
嵌入式系统初学者应该选择一个具体MCU作为蓝本,期望通过学习实践,获得嵌入式系统知识体系的通用知识,其基本原则是:入门时间较快、硬件成本较少,软硬件资料规范、知识要素较多,学习难度较低。
由于微处理器与微控制器的种类繁多,也可能由于不同公司、不同机构给出了一些误导性宣传,特别是我国芯片制造技术的落后及其他相关情况,使人们对微控制器及应用处理器的发展在认识与理解上存在差异,因此使一些初学者有些困惑,下面对此进行简要分析。
(1)嵌入式系统学习困惑之一——选择入门芯片:是微控制器还是应用处理器?在了解嵌入式系统分为微控制器与应用处理器两大类之后,入门芯片选择的困惑表述为:选微控制器,还是应用处理器作为入门芯片?从性能角度来看,与应用处理器相比,微控制器工作频率低、计算性能弱、稳定性高、可靠性强。从使用操作系统角度来看,与应用处理器相比,开发微控制器程序一般使用RTOS,也可以不使用操作系统;而开发应用处理器程序,一般使用非实时操作系统。从知识要素角度来看,与应用处理器相比,开发微控制器程序一般需要了解底层硬件;而开发应用处理器终端程序,一般是在厂家提供的驱动基础上基于操作系统开发,更像开发一般PC软件。从这段分析可以看出,要想成为一名知识结构合理且比较全面的嵌入式系统工程师,应该选择一个较典型的微控制器作为入门芯片,且从不带操作系统(No Operating System,NOS)学起,由浅入深,逐步推进。
关于学习芯片的选择,还有一个困惑是系统的工作频率。初学者认为选择工作频率高的芯片进行入门学习会更先进,实际上,工作频率高可能给他们带来学习过程中的更多困难。
实际嵌入式系统设计不是追求芯片计算速度、工作频率、操作系统等因素,而是追求稳定可靠、维护、升级、功耗、价格等指标。
(2)嵌入式系统学习困惑之二——选择操作系统:NOS、RTOS或EOS。操作系统选择的困惑表述为:开始学习时,是选择无操作系统(NOS)、实时操作系统(RTOS),还是选择一般嵌入式操作系统(EOS)?学习嵌入式系统的目的是为了开发嵌入式应用产品,许多人想学习嵌入式系统,却不知道从何学起,具体目标也不明确。于是,看了一些培训广告,或上网以“嵌入式系统”为关键词进行查询,开始“学习起来”。这样难以对嵌入式产品的开发过程有一个全面了解。针对许多初学者选择“某嵌入式操作系统+某处理器”的嵌入式系统入门学习模式,本书认为是不合适的。本书的建议是:首先把嵌入式系统软件与硬件基础打好,再根据实际应用需要,选择一种实时操作系统(RTOS)进行实践。初学者必须明确认识到,RTOS是开发某些嵌入式产品的辅助工具,是手段,不是目的。况且一些小型、微型嵌入式产品并不需要RTOS。所以,一开始就学习RTOS,并不符合“由浅入深、循序渐进”的学习规律。
另外一个问题是选择RTOS,还是选择EOS?面向测控领域的一般选择RTOS,如mbedOS、MQXLite、FreeRTOS、μCOS-Ⅲ和μCLinux等。本书建议选择mbedOS,而RTOS种类繁多,实际使用哪种RTOS,一般需要工作单位确定。一般基础阶段主要学习RTOS的基本原理,以及在RTOS之上的软件开发方法,而不是学习如何设计RTOS。面向平板电脑、智能手机、电视机顶盒、企业网络设备编程领域一般选择EOS,如Android、Linux等,也可根据实际需要进行学习。
对于嵌入式操作系统,一定不要一开始就学,这样会走很多弯路,也会使初学者对嵌入式系统感到畏惧。实际上,众多MCU嵌入式应用,并不一定需要操作系统或只需一个小型RTOS,也可以根据实际项目需要再学习特定的RTOS。一定不要被一些嵌入式实时操作系统培训班宣传所误导,而忽视实际嵌入式系统软件硬件基础知识的学习。不论如何,以开发实际嵌入式产品为目标的初学者,不要把过多的精力花在设计或移植RTOS、EOS上。正如很多人使用Windows操作系统,而设计Windows操作系统的只有Microsoft。许多人“研究”Linux,但从来没有使用它开发过真正的嵌入式产品,人的精力是有限的,学习必须有所选择。有的初学者,学了很长时间的嵌入式操作系统移植,而不进行实际嵌入式系统产品的开发,到了最后,做不出一个稳定的嵌入式系统的小产品,偏离了学习目标,甚至放弃了嵌入式系统领域。
(3)嵌入式系统学习困惑之三——硬件与软件:如何平衡?以MCU为核心的嵌入式技术的知识体系必须通过具体的MCU来体现、实践与训练。但是,选择任何型号的MCU,其芯片相关的知识只占知识体系的20%左右,80%左右是通用知识。但是这80%的通用知识,必须通过具体的实践才能进行,所以学习嵌入式技术要选择一个系列的MCU。那么嵌入式系统中的硬件与软件两大部分,它们之间的关系如何呢?
有些学者,仅从电子角度认识嵌入式系统,认为“嵌入式系统=MCU硬件系统+小程序”。这些学者大多具有良好的电子技术基础知识。实际情况是,早期MCU内部RAM小、程序存储器外接,需要外扩各种I/O,还没有现在USB、嵌入式以太网等较复杂的接口,因此,程序占总设计量小于50%,使人们认为嵌入式系统(MCU)是“电子系统”,以硬件为主、程序为辅。但是,随着MCU制造技术的发展,不仅MCU内部RAM越来越大,而且Flash进入MCU内部改变了传统的嵌入式系统开发与调试方式,固件程序可以被更方便地调试与在线升级,许多情况与开发PC程序的难易程度相差无几,只不过开发环境与运行环境不是同一载体而已。这些情况使得嵌入式系统的软硬件设计方法发生了根本变化,特别是因软件危机而发展起来的软件工程学科对嵌入式系统软件的发展产生了重要影响,从而产生了嵌入式系统软件工程。
有些学者,仅从软件开发的角度认识嵌入式系统,甚至有的仅从嵌入式操作系统认识嵌入式系统。这些学者大多具有良好的计算机软件开发基础知识,认为硬件是生产厂商的事,没有认识到嵌入式系统产品的软件与硬件均是需要开发者设计的。本书作者常常接到一些关于嵌入式产品稳定性的咨询电话,发现大多数是由于软件开发者对底层硬件的基本原理不理解造成的。特别是有些功能软件开发者,过分依赖于底层硬件的驱动软件设计完美,自己对底层驱动原理又知之甚少。实际上,一些功能软件开发者,名义上是在做嵌入式软件,但仅仅是使用嵌入式编辑、编译环境与下载工具而已,本质与开发通用PC软件没有区别。而底层硬件驱动软件的开发,若不全面考虑高层功能软件对底层硬件的可能调用,也会使得封装或参数设计得不合理或不完备,导致高层功能软件的调用困难。从这段描述可以看出,若把一个嵌入式系统的开发孤立地分为硬件设计、底层硬件驱动软件设计、高层功能软件设计,一旦出现问题,就可能难以定位。实际上,嵌入式系统设计是一个软件、硬件协同设计工程,不能像通用计算机那样,软件、硬件完全分开来设计,要在一个大的框架内协调工作。在一些小型公司,需求分析、硬件设计、底层驱动、软件设计、产品测试等过程可能是由同一个团队完成的,这就需要团队成员对软件、硬件及产品需求有充分认识,才能协作开发好。
面对学习嵌入式系统是以软件为主还是以硬件为主,或者如何选择切入点、如何在软件与硬件之间取得一些平衡的困惑,本书的建议是:要想成为一名真正的嵌入式系统设计师,在初学阶段,必须掌握嵌入式系统的硬件与软件基础知识。以下是从事嵌入式系统设计二十多年的一个美国学者John Catsoulis在Designing Embedded Hardware中关于这个问题的总结:嵌入式系统与硬件紧密相关,是软件与硬件的综合体,没有对硬件的理解就不可能编写好嵌入式软件,同样没有对软件的理解也不可能设计好嵌入式硬件。
充分理解嵌入式系统软件与硬件的相互依存关系,对嵌入式系统的学习有良好的促进作用。一方面,既不能只重视硬件,而忽视编程结构、编程规范、软件工程的要求、操作系统等知识的积累;另一方面,也不能仅从计算机软件角度,把通用计算机学习过程中的概念与方法生搬硬套到嵌入式系统的学习实践中,忽视嵌入式系统与通用计算机的差异。在嵌入式系统学习与实践的初始阶段,应该充分了解嵌入式系统的特点,根据自身已有的知识结构,制订适合自身情况的学习计划。学习过程,可以通过具体应用系统为实践载体,但不能拘泥于具体系统,应该有一定的抽象与归纳。例如,有的初学者开发一个实际控制系统,没有使用实时操作系统,但不要认为实时操作系统不需要学习,要注意知识学习的先后顺序与时间点的把握。又如,有的初学者以一个带有实时操作系统的样例为蓝本进行学习,但不要认为,任何嵌入式系统都需要使用实时操作系统,甚至把一个十分简单的实际系统加上一个不必要的实时操作系统。因此,片面认识嵌入式系统,可能导致学习困惑。应该根据实际项目需要,锻炼自己分析实际问题、解决实际问题的能力。这是一个较长期的需要静下心来的学习与实践过程,不能期望通过短期培训完成整体知识体系的建立,应该重视自身实践,全面地理解与掌握嵌入式系统的知识体系。
1.2.2 嵌入式系统的知识体系
按由浅入深、由简到繁的学习规律,嵌入式学习的入门应该选择微控制器,而不是应用处理器,应通过对微控制器基本原理与应用的学习,逐步掌握嵌入式系统的软件与硬件基础,然后在此基础上进行嵌入式系统其他方面知识的学习。
本节主要阐述以MCU为核心的嵌入式技术基础与实践。要完成一个以MCU为核心的嵌入式系统应用产品设计,需要有硬件、软件及行业领域的相关知识。硬件主要有MCU的硬件最小系统、输入/输出外围电路、人机接口设计;软件设计有固化软件的设计,也可能含PC软件的设计。行业知识需要通过协作、交流与总结获得。
概括地说,学习以MCU为核心的嵌入式系统,需要以下软硬件基础知识与实践训练,即以MCU为核心的嵌入式系统的基本知识体系如下。
(1)掌握硬件最小系统与软件最小系统框架。硬件最小系统是包括电源、晶振、复位、写入调试器接口等可使内部程序得以运行的、规范的、可复用的核心构件系统。软件最小系统框架是一个能够点亮发光二极管的,甚至带有串口调试构件的,包含工程规范完整要素的可移植与可复用的工程模板。
(2)掌握常用基本输出的概念、知识要素、构件使用方法及设计方法,如通用I/O(GPIO)、模数转换(A/D)、数模转换(D/A)、定时器模块等。
(3)掌握若干嵌入式通信的概念、知识要素、构件使用方法及设计方法,如串行通信接口(UART)、串行外设接口(SPI)、集成电路互联总线(I2C)、CAN、USB、嵌入式以太网、无线射频通信等。
(4)掌握常用应用模块的构件设计方法及数据处理方法,如显示模块(LED、LCD、触摸屏等)、控制模块(控制各种设备,包括PWM等控制技术),以及图形、图像、语音、视频等处理或识别等。
(5)掌握一门实时操作系统RTOS的基本用法与基本原理。实时操作系统RTOS既可以作为软件辅助开发工具,也可以作为一个知识要素。可以选择一种实时操作系统RTOS(如mbedOS、MQXLite、μC/OS等)进行学习,在没有明确目的的情况下,选择几种同时学习。如果掌握一种,在确有必要使用另一种RTOS时再学习,也可触类旁通。
(6)掌握嵌入式软硬件的基本调试方法,如断点调试、打桩调试、printf调试方法等。在嵌入式调试过程中,特别要注意确保在正确硬件环境下调试未知软件,在正确软件环境下调试未知硬件。
这里给出的是基础知识要素,关键在于如何学习,是使用他人做好的驱动程序,还是自己完全掌握知识要素,从底层开始设计驱动程序,同时熟练掌握驱动程序的使用,这体现在不同层面的人才培养中。而应用中的软硬件设计及测试等都必须遵循嵌入式软件工程的方法、原理与基本原则。所以,嵌入式软件工程也是嵌入式系统知识体系的有机组成部分,只不过它融于具体项目的开发过程之中。
若是主要学习应用处理器类的嵌入式应用,也应该在了解MCU知识体系的基础上,选择一种嵌入式操作系统(如Android、Linux等)进行学习实践。目前,APP开发也是嵌入式应用的一个重要组成部分,可选择一种APP开发进行实践(如Android APP、iOS APP等)。
与此同时,在PC上,利用面向对象编程语言进行测试程序、网络监听程序、Web应用程序的开发及对数据库的基本了解与应用,也应逐步纳入嵌入式应用的知识体系中。此外,理工科的公共基础科目也是学习嵌入式系统的基础。
1.2.3 基础阶段的学习建议
十多年来,笔者逐步探索与应用构件封装原则,把硬件相关的部分封装底层构件,统一接口,努力使高层程序与芯片无关,可以在各种芯片应用系统移植与复用,试图降低学习难度。学习的关键就变成了解底层构件的设计方法,掌握底层构件的使用方式,并在此基础上进行嵌入式系统设计与应用开发,这也是本科学生应该掌握的基本知识。对于专科类学生,虽然可以直接使用底层构件进行应用编程,但也需了解知识要素的抽取方法与底层构件的基本设计过程。对于看似庞大的嵌入式系统知识体系,可以使用“电子札记”的方式进行知识积累和查漏补缺,任何具有一定理工科基础的学生,通过一段时间的学习与实践,都能学好嵌入式系统。
下面针对嵌入式系统的学习困惑,从嵌入式系统的知识体系角度,对广大渴望学习嵌入式系统的学子提出以下基础阶段的学习建议。
(1)遵循“先易后难、由浅入深”的原则,打好软硬件基础。跟随本书,充分利用本书提供的软硬件资源及辅助视频材料,逐步实验与实践;充分理解硬件基本原理,掌握功能模块的知识要素、底层驱动构件的使用方法,以及一两个底层驱动构件的设计过程与方法;熟练掌握在底层驱动构件基础上利用C语言编程实践,理解学习嵌入式系统必须勤于实践。关于汇编语言问题,随着MCU对C语言编译的优化支持,可以只了解几个必需的汇编语句,但必须通过第一个程序理解芯片初始化过程、中断机制、程序存储情况等区别于PC程序的内容;最好认真理解一个真正的汇编实例。另外,为了测试的需要,最好掌握一门面向对象的编程高级语言(如C#),本书附带的网上教学资源中给出了C#的快速入门方法与实例。
(2)充分理解知识要素、掌握底层驱动构件的使用方法。本书对GPIO、UART、定时器、PWM、AD、DA、Flash在线编程等模块,首先阐述其通用知识要素,随后给出其底层驱动构件的基本内容。期望读者在充分理解通用知识要素的基础上,学会底层驱动构件的使用方法。有关知识要素涉及硬件基本原理,以及对底层驱动接口函数功能及参数的理解,需反复阅读、实践,查找资料,并分析、概括及积累。对于硬件,只要在深入理解MCU的硬件最小系统的基础上,对上述各硬件模块逐个实验理解、逐步实践,再通过自己动手完成一个实际小系统,就可以基本掌握底层硬件基础。同时,这个过程也是软硬件结合学习的基本过程。
(3)基本掌握底层驱动构件的设计方法。对本科以上读者,至少掌握GPIO构件的设计过程与设计方法(第4章)、UART构件的设计过程与设计方法(第6章),透彻理解构件化开发方法与底层驱动构件封装规范(第5章)。从而对底层驱动构件有较好的理解与把握。这是一份细致、静心的任务,只有力戒浮躁,才能理解其要义。书中的底层驱动构件吸取了软件工程的基本原理,学习时注意基本规范。
(4)掌握单步跟踪调试、打桩调试、printf输出调试等调试手段。在初学阶段,充分利用单步跟踪调试了解与硬件交互的寄存器值的变化,理解MCU软件干预硬件的方式。单步跟踪调试也用于底层驱动构件设计阶段,不进入子函数内部执行的单步跟踪调试,可用于整体功能跟踪。打桩调试主要用于编程过程中的功能确认。一般编写几条语句后,即可进行打桩,调试观察。通过串口printf输出信息在PC屏幕显示,是嵌入式软件开发中重要的调试跟踪手段,与PC编程中的printf功能类似,只是嵌入式开发printf输出是通过串口输出到PC屏幕,需要用串口调试工具显示,PC编程中的printf直接将结果显示在PC屏幕上。
(5)日积月累、勤学好问,充分利用本书及相关资源。学习嵌入式切忌急功近利,需要日积月累、循序渐进,充分掌握与应用“电子札记”方法。同时,又要勤学好问,下真功夫、细功夫。人工智能学科里有无教师指导学习模式与有教师指导学习模式,无教师指导学习模式比有教师指导学习模式复杂许多。因此,要多请教良师,少走弯路。此外,本书提供了大量经过打磨的、比较规范的软硬件资源,充分利用这些资源,可以更上一层楼。
以上建议,仅供参考。当然,以上只是基础阶段的学习建议,要成为良好的嵌入式系统设计师,还需要注重理论学习与实践、通用知识与芯片相关知识、硬件知识与软件知识的平衡。要在理解软件工程基本原理的基础上,理解硬件构件与软件构件等基本概念,必须在实际项目中锻炼,并不断学习与积累经验。