其实一直有人问我嵌入式怎么学,今天跟大家讲讲我的理解。因为嵌入式是一个泛的概念,可能很多人认为嵌入式就是嵌入式Linux。但是其实并不仅仅只有Linux, 像STM32,51单片机也属于这个范畴之内的,它们有的也可以跑协议栈,跑ucos等系统。所以其实嵌入式是有很多方向的,选择一个方向,做好,做精,都是有前途的。接下来,跟大家探讨一下嵌入式的一些方向,和如何去学习。我以前也是摸索着过来的,没人告诉我如何学习,也没有学习线路,所以走了很多弯路。所以希望这篇文章可以帮助到一些正在学习的人,当然这些内容可能有主观的东西,欢迎大家一起探讨吧。如下仅讨论软件方面_。 以下内容对牛人不适用。
单片机开发在这个市场上的需求还是很大,因为制造业公司还是很多,单片机更多用在工业控制,机械控制等上面,当然也会涉及物联网。单片机有8位,16位,32位的,一般8位用得比较多的就是51单片机和STM8,32位用得比较多的就是STM32,还有NXP的芯片,比如K60,K22等。一般学完51和STM32之后,找个单片机的工作应该是没什么问题了。单片机的门槛其实并不高,但是做好也不容易就是了,可能因为门槛问题,导致薪资上面并不会特别高(能力牛逼者例外)。
以前很多人问我“Linux应用到底在做什么?”。其实应用就是在做功能,在操作系统中,因为分层的原因,把应用和驱动区分开,也是为了方便开发分工。因为单片机中基本都是驱动和功能混在一个程序中,所以转到Linux开发中,突然被细分了,就会不清楚应用到底是干啥的。Linux应用使用到的编程语言基本就是C和C++了。所以Linux应用开发一定要掌握好C语言,大学课本中的C语言只是入门,像多线程,多进程,网络通信,还有一些其他的库都没讲到。Linux应用在市场需求上还是很多的,基本有涉及Linux开发的,都需要,它的岗位需求会比驱动多。比如做网络设备,做路由,做POS机, 做楼宇对讲等等。薪资上大家可以参考各个地区招聘网站,相对来说,一般会比单片机高。
Linux驱动开发是难度最高的,因为它涉及的方面比较多。你必须要会看原理图,datasheet,要了解许多驱动框架,然后还要能写一些应用来调试驱动。驱动入门时间是比较长的,这一块的工作机会在芯片原厂比较多,虽然一些公司也会需要,但是大部分是移植调试,对接原厂工程师等工作。驱动工程师要求高,所以薪资还是很不错的。
上面是基本的三大方向,其实还有一些像FPGA或DSP等,但是因为这些的机会并不多,所以我们并不过多探讨。还有像Android,它是基于Linux的,所以它算是Linux的深入,我们不把它单独列出。
认真学习C语言,认真学习C语言, 认真学习C语言, 重要的事说三遍。C语言在嵌入式中是重中之重,它就是你上手嵌入式的工具。大学考试不考的,在工作中却经常用到。函数指针,结构体,枚举,文件操作,共同体,宏等相关知识都是非常常用的。不仅是ANSI C, 还有GUN C,所以学起来可不轻松哦。
推荐书籍:
《C Primer Plus》
《C程序设计语言》
虽然现在51单片机用得越来越少,但在一些要求不高的项目中还是会被使用。个人觉得学习51是在学习一些基础知识,对于后面学习其他芯片会有帮助。比如理解寄存器是什么,如何去看电路图,学习一些协议(I2C, SPI, 串口等),学习看datasheet,这些对于后面的学习会有很大帮助。
推荐书籍:
《新概念51单片机C语言教程》
建议:
买块开发板学习,把里面的例子都码一遍,基本就OK了。
STM32属于ARM系列的芯片,STM32在这个市场上用得特别多的,有各种各样的系列(L0, F0, F1, F4等)。基本都大同小异,学习一种之后,其他的基本分分钟就能上手,因为现在官方基本都封装了库,我们只需要对结构体进行配置,然后调用接口函数就可以了。它有着丰富的外设资源,运行速度也比51快很多。我们一般就是学习它的外设资源( SPI, I2C, 定时器, 看门狗等),在这个过程中还会接触很多传感器。学完这些,找个单片机的工作应该没啥问题了。如果要深入STM32, 还可以学习UCOS, FreeRTOS等实时操作系统, 这些对你以后深入理解操作系统会有很大帮助。
推荐教程:
正点原子,野火
建议:
买块开发板玩玩,虽然有点小贵,但是学习嘛。野火和正点原子的书和教程都不错。一定要自己码一遍,写了才能更有感觉,才能激发兴趣。还有就是要多看官方手册,官方手册才是最好的教程。(英语越练越好)
总结:
把上面的搞明白之后,基本能胜任单片机开发了,以后换其他平台的芯片也都差不多,比如TI或NXP,国产的新唐之类的,都是大同小异。
做Linux应用肯定要在Linux环境下开发啊,所以熟悉Linux的基本操作是应该的。装个Ubuntu系统,在上面练习shell命令,把基本的命令练熟练了。可以顺便把shell脚本学习一下,刚开始可以只练习命令即可。
基本shell命令: ls cd cp rm touch mkdir echo cat mv ln chmod man等。
推荐书籍:
《Linux命令行与shell脚本编程大全》
注:书很厚,很详细,可当工具书查阅.
推荐网站:
https://www.runoob.com/linux/linux-command-manual.html
建议:
很多嵌入式开发的书籍,刚开始的章节也会讲一些基本的命令,那里面的已经够用了,如果以后有需要了解更多命令,可以再临时查。命令不是去背,而是多练,熟悉了自然就记住了。
上面提到的C语言主要是基本的语法,在Linux下我们要涉及的就更多了。包括文件IO, 多进程控制,多进程通信,多线程编程,网络编程等。掌握这些就基本算入门了,后面要深入,可以去接触一些第三方库,比如ffmpeg,log4c, openssl等。这些一般跟你所处的行业有关,比如ffmpeg一般是音视频相关的。
推荐书籍:
《嵌入式Linux应用程序开发标准教程》
《Linux C编程实战》
《Linux/UNIX系统编程手册》
建议:
在学习这个的过程中,除了直接在命令行上使用gcc编译,还建议学习使用Makefile来进行编译。刚开始手写一些简单的Makefile来编译源码,慢慢的就可以直接使用AutoTools和Cmake了,这两个工具是用来生成Makefile的 ,对于大项目管理会更加方便(刚开始不建议使用)。
Qt就是图形化编程,它是一些基于C++写的图形化库。它是跨平台的,所以写完的代码,只要在不同的编译器下编译,就能在不同的平台下运行。因为它是C++写的,所以要进行Qt开发需要有C++的语言基础。Qt不仅在嵌入式用得很多,现在很多PC软件也使用Qt写的,比如VirtualBox。
推荐书籍:
《C++ Primer Plus》
《Qt5 开发实战》
《Qt Creator快速入门》
《Qt Quick 核心编程》
视频教程:
https://www.bilibili.com/video/av50849127?from=search&seid=1349644639656479463
建议:
Qt学习的难点可能是C++语言本身,所以学好C++后学习Qt就很轻松了,因为Qt Creator可以很轻松的拖出图形化界面,然后Qt也帮我们封装很了接口,所以Qt上手很快。
Linux驱动的学习一般是建立在前面的基础上的。当然,学驱动也不需要你应用写得很牛逼,但是基本的应用还是要会写的,这样才能方便你调试驱动。接下来大致讲一下,学习的顺序。
裸板程序其实跟单片机程序没啥区别,都是直接操作寄存器。那为什么要还要学这块内容呢,其实是为了后面打个基础,因为Linux驱动就是Linux驱动框架加上操作寄存器。而且这个阶段对我们查看电路图和datasheet也会有很大帮助。
Uboot其实是属于系统层的,但是目前行业中大家都是分为底层和应用层,所以这些系统层的一般也归为底层,所以驱动工程师一般也需要做这块。Uboot的主要目标是去引导内核,当然Uboot上也会有属于自己的驱动程序(这里的驱动和内核驱动是不一样的,是独立的)。学习的过程,除了照着别人的教程一步一步移植外,还可以自己找一个其他版本的Uboot,然后自己慢慢移植,会很有趣。
内核移植和Uboot移植差不多,都是基于具体芯片架构做移植。现在的内核越来越完善,并且芯片原厂也一直在向内核提交自己的代码,所以慢慢的,非原厂工程师对这块的移植越来越少。但是还是希望学习的过程中能自己找一个版本来进行移植,边查资料边移植,会学到很多东西。建议有时间和精力的,可以深入学习Linux内核,会对写驱动与很大帮助。
根文件系统比较简单,嵌入式根文件系统一般都是使用busybox,一般就是配置,编译,制作,打包。它也是属于系统的。
字符设备是最基本的,像RTC,音频,LCD都是字符设备。可不是仅仅按键,LED,虽然我们学习时都喜欢从它们开始,那是因为它们简单,不会涉及很多设备本身的知识。这样我们在学时会更注重在驱动框架本身的学习。在学习字符设备驱动的过程中,除了基本的open、read、write、ioctl、close外,还要学习并发(原子量,自旋锁,互斥体等),阻塞和非阻塞I/O, 异步通知和异步I/O等等,最后还有一个很重要的就是中断。这些东西随便拧一个出来,都能学很久。像并发,阻塞,异步I/O这些在其他的设备驱动中也一样会用到,所以在这个阶段一定要好好学的。
可能很多人学完字符设备驱动后,会马上继续学块设备和网络设备驱动。但我觉得这个时候去学这些是比较容易受打击的。并且我认为应该先把一种摸透,然后再去理解更复杂的,这样会提升信心,对学习更有帮助。
这里说的驱动架构是"总线设备驱动"模型。一般掌握platform,spi,i2c等总线。platform是一种虚拟总线,一般控制器都是用这种总线,还有像LED,按键这种不是挂接在具体总线上的,也是用platform。这个模型的目的是为了将硬件部分分离,让驱动可以复用。
这过程中我们可以将上面的字符设备驱动改为使用"总线设备驱动"模型。到此,我们基本可以应付很多传感器驱动了。
块设备一般就是存储设备,比如磁盘,MMC,FLASH等。Linux定义了大量结构体和函数接口来让我们填充调用。网络设备也是一样,Linux封装了net_device结构体,然后让我们填充注册。大量的驱动都是这样,Linux系统屏蔽了很多细节,让我们专注于设备的控制和读写。比如RTC,LCD等,我们只需要去使用rtc_device结构体就可以去注册一个RTC设备。现在的网络设备一般拆分成MAC+PHY的结构,就是主芯片有MAC控制器,然后外挂PHY芯片。像最早的DM9000是将MAC和PHY集中在一起。
Linux内部有很多驱动子系统,比如前面说的RTC,Linux提供了RTC核心层,再比如LCD,提供了FrameBuffer等等。还有鼠标,键盘等输入(Input)子系统。每一种驱动都能啃很久,以后可能还会接触Wifi,蓝牙,USB等等。这些东西不单单需要驱动相关知识,还需要很多协议和接口相关的知识,它们的复杂之处就在于此。这些复杂的驱动等需要的时候,或者有时间的时候再慢慢深入研究。
为什么将设备树放最后,因为你不用设备树也可以,但是自从设备树出现之后,基本上大家都在使用。所以它已经成为驱动工程师的必备技能了。Linux推出这个东西,肯定是经过深思熟虑的,我们要顺应潮流。
Linux的更新是非常快的,很多东西在迭代,所以我们也要经常关注。驱动架构也在更新,你会经常发现很多结构体在不同版本下是不同的。
推荐书籍:
《LINUX设备驱动程序》
《嵌入式Linux应用开发完全手册》
《Linux设备驱动开发详解–基于最新的Linux4.0内核》
建议:
买块板子学习,之前可能大家推荐三星的2440,但是这款慢慢的在停产,所以现在更推荐三星210或4412,还有NXP的IMX6。这些芯片性能好,以后还可以用来学Android。
嵌入式软件可以深入的东西还有很多,包括算法,数据结构,设计模式等等。上面探讨的是关于学习的路线和方向,并不是教程之类的,只是在告诉大家如何去学习,具体的学习内容,需要大家去找资料,找教程。
因为上面都是个人经验,如有错误或遗漏,欢迎指出!或者有更好的建议,也欢迎探讨,后期会对其进行完善。
更多精彩文章,欢迎关注"嵌入式软件开发交流"