关于Linux

这篇文章来自网络。

 

由于很多人总问这个问题,所以这里做一个总结文档供大家参考。这里必须先说明,以下的步骤都是针对Linux系统的,并不面向WinCE。也许你会注意到,现在做嵌入式的人中,做linux研究的人远比做WinCE的人多,很多产家提供的资料也是以linux为主。我一直很难理解,其实WinCE的界面比linux的界面好看多了,使用起来也很方便,更为重要的是,WinCE的开发和Windows下的开发基本一样,学起来简单得多,但是学linux或者使用linux做嵌入式的人就是远比WinCE多。在和很多工作的人交流时我了解到,他们公司从没考虑使用WinCE,因为成本高,都是使用linux进行开发。我读研究生的的实验室中也没有使用WinCE的,大都研究linux,也有少部分项目使用vxwork,但是就没有听说过使用WinCE的,原因就是开源!当然现在WinCE6.0听说也开源,不过在成本和资源上linux已经有了无人能挡的优势。与此相对应的是,越来越多的电子厂商已经开始使用linux开发产品。举个例子,Google近期开发的智能手机操作系统Android其实就是使用linux-2.6.23内核进行改进得到的。

第一,学习基本的裸机编程。
对于学硬件的人而言,必须先对硬件的基本使用方法有感性的认识,更必须深刻认识该硬件的控制方式,如果一开始就学linux系统、学移植那么只会马上就陷入一个很深的漩涡。我在刚刚开始学ARM的时候是选择ARM7(主意是当时ARM9还很贵),学ARM7的时候还是保持着学51单片机的思维,使用ADS去编程,第一个实验就是控制led。学过一段时间ARM的人都会笑这样很笨,实际上也不是,我倒是觉得有这个过程会好很多,因为无论做多复杂的系统最终都会落实到这些最底层的硬件控制,因此对这些硬件的控制有了感性的认识就好很多了
学习裸机的编程的同时要好好理解这个硬件的构架、控制原理,这些我称他为理解硬件。所谓的理解硬件就是说,理解这个硬件是怎么组织这么多资源的,这些资源又是怎么由cpu、由编程进行控制的。比如说,s3c2410中有AD转换器,有GPIO(通用IO口),还有nandflash控制器,这些东西都有一些寄存器来控制,这些寄存器都有一个地址,那么这些地址是什么意思?又怎么通过寄存器来控制这些外围设备的运转?还有,norflash内部的每一个单元在这个芯片的内存中都有一个相应的地址单元,那么这些地址与刚刚说的寄存器地址又有什么关系?他们是一样的吗?而与norflash相对应的nandflash内部的储存单元并不是线性排放的,那么s3c2410怎么将nandflash的地址映射在内存空间上进行使用?或者简单地说应该怎么用nandflash?再有,使用ADS进对ARM9行编程时都需要使用到一个初始化的汇编文件,这个文件究竟有什么用?他里面的代码是什么意思?不要这个可以吗?
诸如此类都是对硬件的理解,理解了这些东西就对硬件有很深的理解了,这对以后更深一步的学习将有很大的帮助,如果跳过这一步,我相信越往后学越会觉得迷茫,越觉得这写东西深不可测。因为,你的根基没打好。
不过先声明一下,本人并没有使用ADS对ARM9进行编程,我是学完ARM7后直接就使用ARM9学linux系统的,因此涉及使用ADS对ARM9进行编程的问题我很难回答^_^,自己去研究研究吧。
对于这部分不久将提供一份教程,这个教程中的例程并不是我为我们所代理的板子写的,是我在我们学院实验室拿的,英培特为他们自己 的实验箱写的,不过很有借鉴意义,可以作为一份有价值的参考。

第二,使用linux系统进行一些基本的实验。
在买一套板子的时候一般会提供一些linux的试验例程,好好做一段时间这个吧,这个过程也是很有意义的,也是为进一步的学习积累感性认识,你能想象一个从没有使用过linux系统的人能学好linux的编程吗?好好按照手册上的例程做一做里面的实验,虽然有点娃娃学走路,有点弱智,但是我想很多高手都会经历这个过程。
在这方面我们深蓝科技目前没有计划提供相应的例程,主要是开发板的提供商会提供很丰富的例程,我们不做重复工作,只提供他们没有的、最有价值的东西给大家。

第三,研究完整的linux系统的的运行过程。
所谓完整的linux系统包括哪些部分呢?
三部分:bootloader、linux kernel(linux内核)、rootfile(根文件系统)。
那么这3部分是怎么相互协作来构成这个系统的呢?各自有什么用呢?三者有什么联系?怎么联系?系统的执行流程又是怎么样的呢?搞清楚这个问题你对整个系统的运行就很清楚了,对于下一步制作这个linux系统就打下了另一个重要的根基。介绍这方面的资料网上可以挖掘到几吨,自己好好研究吧。

第四,开始做系统移植。
上面说到完整的linux有3部分,而且你也知道了他们之间的关系和作用,那么现在你要做的便是自己动手学会制作这些东西。
当然我不可能叫你编写这些代码,这不实现。事实上这个3者都能在网下载到相应的源代码,但是这个源代码不可能下载编译后就能在你的系统上运行,需要很多的修改,直到他能运行在你的板子上,这个修改的过程就叫移植。在进行移植的过程中你要学的东西很多,要懂的相关知识也很多,等你完成了这个过程你会发现你已经算是一个初出茅庐的高手了。
在这个过程中如果你很有研究精神的话你必然会想到看源代码。很多书介绍你怎么阅读linux源代码,我不提倡无目的地去看linux源代码,用许三多的话说,这没有意义。等你在做移植的时候你觉得你必须去看源代码时再去找基本好书看看,这里我推荐一本好书倪继利的《linux内核的分析与编程》,这是一本针对linux-2.6.11内核的书,说得很深,建议先提高自己的C语言编程水平再去看。
至于每个部分的移植网上也可以找到好多吨的资料,自己研究研究吧,不过要提醒的是,很多介绍自己经验的东西都或多或少有所保留,你按照他说的去做总有一些问题,但是他不会告诉你怎么解决,这时就要靠自己,如果自己都靠不住就找我一起研究研究吧,我也不能保证能解决你的问题,因为我未必遇到过你的问题,不过我相信能给你一点建议,也许有助你解决问题。
这一步的最终目的是,从源代码的官方主页上(都是外国的,悲哀)下载标准的源代码包,然后进行修改,最终运行在板子上。
盗用阿基米德的一句话:"给我一根网线,我能将linux搞定"。

第五,研究linux驱动程序的编写。
移植系统并不是最终的目的,最终的目的是开发产品,做项目,这些都要进行驱动程序的开发。
Linux的驱动程序可以说是五花八门,linux2.4和linux2.6的编写有相当大的区别,就是同为linux2.6但是不同版本间的驱动程序也有区别,因此编写linux的驱动程序变都不是那么容易的事情,对于最新版本的驱动程序的编写甚至还没有足够的参考资料。那么我的建议就是使用、移植一个不算很新的版本内核,这样到时学驱动的编程就有足够的资料了。
这部分的推荐书籍可以参考另一篇文章《推荐几本学习嵌入式linux的书籍》。

第六,研究应用程序的编写。
做作品做项目除了编写驱动程序,最后还要编写应用程序。现在的趋势是图形应用程序的开发,而图形应用程序中用得最多的还是qt/e函数库。我一直就使用这个函数库来开发自己的应用程序,不过我希望你能使用国产的MiniGUI函数库。盗用周杰伦的广告词就是"支持国产,支持MiniGUI"。MiniGUI的编程比较相似Windows下的VC编程,比较容易上手,效果应该说是相当不错的,我曾使用过来开发ARM7的程序。不过MiniGUI最大的不好就是没有像qtopia这样的图形操作平台,这大大限制了他的推广,我曾经幻想过与北京飞漫公司(就是MiniGUI的版权拥有者)合作使用MiniGUI函数库开发像qtopia这样的图形操作平台,不过由于水平有限这只能是幻想了,呵呵。
完成这一步你基本就学完了嵌入式linux的全部内容了。

还有一个小小的经验想和大家分享。我在学习嵌入式linux的过程中很少问人,客观原因是身边的老师、同学师兄都没有这方面的高手,主观原因是我不喜欢问人,喜欢自己研究解决问题。这样做有个好处,就是可以提高自己解决问题的能力,因为做这些东西总有很多问题你难以理解,别人也没有这方面的经验,也不是所有问题都有人给你答案,这时必须要自己解决问题,这样,个人的解决问题能力就显得非常关键了。因此我的建议就是一般的问题到网上搜索一下,确实找不到答案了就问问高手,还是不行了就自己去研究,不要一味去等别人帮你解决问题。
记住,问题是学习的最好机会。

嵌入式linux入门学习规划2009-11-14 07:26不知以后能否搞嵌入式,看到文章不错,贴来以后看看

ARM+LINUX路线,主攻嵌入式Linux操作系统及其上应用软件开发目标:
(1) 掌握主流嵌入式微处理器的结构与原理(初步定为arm9)
(2) 必须掌握一个嵌入式操作系统 (初步定为uclinux或linux,版本待定)
(3) 必须熟悉嵌入式软件开发流程并至少做一个嵌入式软件项目。
从事嵌入式软件开发的好处是:
(1)目前国内外这方面的人都很稀缺。这一领域入门门槛较高,所以非专业IT人员很难切入这一领域;另一方面,是因为这一领域较新,目前发展太快,大多数人无条件接触。
(2)与企业计算等应用软件不同,嵌入式领域人才的工作强度通常低一些(但收入不低)。
(3)哪天若想创业,搞自已的产品,嵌入式不像应用软件那样容易被盗版。硬件设计一般都是请其它公司给订做(这叫"贴牌":OEM),都是通用的硬件,我们只管设计软件就变成自己的产品了。
(4)兴趣所在,这是最主要的。
从事嵌入式软件开发的缺点是:
(1)入门起点较高,所用到的技术往往都有一定难度,若软硬件基础不好,特别是操作系统级软件功底不深,则可能不适于此行。
(2)这方面的企业数量要远少于企业计算类企业。
(3)有少数公司经常要硕士以上的人搞嵌入式,主要是基于嵌入式的难度。但大多数公司也并无此要求,只要有经验即可。
(4)平台依托强,换平台比较辛苦。
兴趣的由来:
1、成功观念不同,不虚度此生,就是我的成功。
2、喜欢思考,挑战逻辑思维。
3、喜欢C
C是一种能发挥思维极限的语言。关于C的精神的一些方面可以被概述成短句如下:
相信程序员。
不要阻止程序员做那些需要去做的。
保持语言短小精干。
一种方法做一个操作。
使得它运行的够快,尽管它并不能保证将是可移植的。
4、喜欢底层开发,讨厌vb类开发工具(并不是说vb不好)。
5、发展前景好,适合创业,不想自己要死了的时候还是一个工程师。
方法步骤:
1、基础知识:
目的:能看懂硬件工作原理,但重点在嵌入式软件,特别是操作系统级软件,那将是我的优势。
科目:数字电路、计算机组成原理、嵌入式微处理器结构。
汇编语言、C/C++、编译原理、离散数学。
数据结构和算法、操作系统、软件工程、网络、数据库。
方法:虽科目众多,但都是较简单的基础,且大部分已掌握。不一定全学,可根据需要选修。
主攻书籍:the c++ programming language(一直没时间读)、数据结构-C2。

2、学习linux:
目的:深入掌握linux系统。
方法:使用linux-〉linxu系统编程开发-〉驱动开发和分析linux内核。先看深,那主讲原理。看几遍后,看情景分析,对照深看,两本交叉,深是纲,情是目。剖析则是0.11版,适合学习。最后深入代码。
主攻书籍:linux内核完全剖析、unix环境高级编程、深入理解linux内核、情景分析和源代。
3、学习嵌入式linux:
目的:掌握嵌入式处理器其及系统。
方法:(1)嵌入式微处理器结构与应用:直接arm原理及汇编即可,不要重复x86。
(2)嵌入式操作系统类:ucOS/II简单,开源,可供入门。而后深入研究uClinux。
(3)必须有块开发板(arm9以上),有条件可参加培训(进步快,能认识些朋友)。
主攻书籍:毛德操的《嵌入式系统》及其他arm9手册与arm汇编指令等。

4、深入学习:
A、数字图像压缩技术:主要是应掌握MPEG、mp3等编解码算法和技术。
B、通信协议及编程技术:TCP/IP协议、802.11,Bluetooth,GPRS、GSM、CDMA等。
C、网络与信息安全技术:如加密技术,数字证书CA等。
D、DSP技术:Digital Signal Process,DSP处理器通过硬件实现数字信号处理算法。
说明:太多细节未说明,可根据实际情况调整。重点在于1、3,不必完全按照顺序作。对于学习c++,理由是c++不只是一种语言,一种工具,她还是一 种艺术,一种文化,一种哲学理念、但不是拿来炫耀得东西。对于linux内核,学习编程,读一些优秀代码也是有必要的。
注意: 要学会举一反多,有强大的基础,很多东西简单看看就能会。想成为合格的程序员,前提是必须熟练至少一种编程语言,并具有良好的逻辑思维。一定要理论结合实践。
不要一味钻研技术,虽然挤出时间是很难做到的,但还是要留点余地去完善其他的爱好,比如宇宙,素描、机械、管理,心理学、游戏、科幻电影。还有一些不愿意做但必须要做的!
技术是通过编程编程在编程编出来的。永远不要梦想一步登天,不要做浮躁的人,不要觉得路途漫上。而是要编程编程在编程,完了在编程,在编程!等机会来了在创业(不要相信有奇迹发生,盲目创业很难成功,即便成功了发展空间也不一定很大)。

嵌入式书籍推荐
Linux基础
1、《Linux与Unix Shell 编程指南》
C语言基础
1、《C Primer Plus,5th Edition》【美】Stephen Prata着
2、《The C Programming Language, 2nd Edition》【美】Brian W. Kernighan David M. Rithie(K & R)着
3、《Advanced Programming in the UNIX Environment,2nd Edition》(APUE)
4、《嵌入式Linux应用程序开发详解》
Linux内核
1、《深入理解Linux内核》(第三版)
2、《Linux内核源代码情景分析》毛德操 胡希明著
研发方向
1、《UNIX Network Programming》(UNP)
2、《TCP/IP详解》
3、《Linux内核编程》
4、《Linux设备驱动开发》(LDD) 
5、《Linux高级程序设计》 杨宗德著
硬件基础
1、《ARM体系结构与编程》杜春雷着
2、S3C2410 Datasheet
英语基础
1、《计算机与通信专业英语》
系统教程
1、《嵌入式系统--体系结构、编程与设计》
2、《嵌入式系统--采用公开源代码和StrongARM/Xscale处理器》毛德操 胡希明着
3、《Building Embedded Linux Systems》   
4、《嵌入式ARM系统原理与实例开发》 杨宗德著
理论基础
1、《算法导论》
2、《数据结构(C语言版)》
3、《计算机组织与体系结构?性能分析》
4、《深入理解计算机系统》【美】Randal E. Bryant David O''Hallaron着
5、《操作系统:精髓与设计原理》
6、《编译原理》
7、《数据通信与计算机网络》
8、《数据压缩原理与应用》

C语言书籍推荐
1. The C programming language 《C程序设计语言》
2. Pointers on C 《C和指针》
3. C traps and pitfalls 《C陷阱与缺陷》
4. Expert C Lanuage 《专家C编程》
5. Writing Clean Code -----Microsoft Techiniques for Developing Bug-free C Programs
《编程精粹--Microsoft 编写优质无错C程序秘诀》
6. Programming Embedded Systems in C and C++ 《嵌入式系统编程》
7.《C语言嵌入式系统编程修炼》
8.《高质量C++/C编程指南》林锐
尽可能多的编码,要学好C,不能只注重C本身。算法,架构方式等都很重要


今天我来帮大家讲讲按键驱动,虽然文章的注解我是在网上的找,但他的注解表达了很清楚,所以就在这里引用一下。

开发平台:RED HAT LINUX 9(Linux 2.4.18)

开发板:micro2440(友善之臂)(Linux 2.6.13)

交叉编译工具:arm-linux-gcc-3.4.1

 

--------------------------------------------------------------------------------

/*micro2440_buttons.c*/

/*按键驱动程序*/

/*micro2440所用到的按键资源*/

/**************************************************/

/* 按键 对应的IO寄存器 对应的中断引脚*/

/* K1 GPG0 EINT8 */

/* K2 GPG3 EINT11 */

/* K3 GPG5 EINT13 */

/* K4 GPG6 EINT14 */

/* K5 GPG7 EINT15 */

/* K6 GPG11 EINT19 */

/**************************************************/

/*要搞清楚谁是输入*/

/*在这里,按键控制对应的中断引脚,从而控制对应的IO寄存器*/

/*相当于信息从外面输入*/

/*我们要做的是根据对应的输入信息,来采取相应的响应动作*/

/*这就达到了中断响应的目的*/

/*其核心就是要检测*/

/*那么,该如何去检测呢?*/

/*通过什么来检测呢?*/

/*如何得知一个设备究竟用到哪些资源呢?*/

/*这是个非常重要的问题*/

/*我想应该看具体的电路原理图*/

/*只有看图,才能了解具体的电路连接情况*/

/*从而得知设备所需的硬件资源*/

/*厂商的原理图通常给的都比较详细*/

/*引用的头文件*/

#include <linux/module.h> /*模块有关的*/

#include <linux/kernel.h> /*内核有关的*/

#include <linux/fs.h> /*文件系统有关的*/

#include <linux/init.h> /*init*/

#include <linux/delay.h> /*delay*/

#include <linux/poll.h> /*poll*/

#include <asm/irq.h> /*中断*/

#include <linux/interrupt.h> /*linux中断*/

#include <asm/uaccess.h> /*uaccess*/

#include <asm/arch/regs-gpio.h> /*寄存器设置*/

#include <asm/hardware.h> /*hardware*/

/*定义宏*/

#define BUTTON_MAJOR 221 /*主设备号,本来是232,我改为221*/

#define DEVICE_NAME "buttons_my" /*设备名,本来是buttons,我加上了_my*/

/*定义按钮中断的描述结构体*/

/*由它把按钮中断的信息综合起来*/

/*各个成员表示什么意思?*/

struct button_irq_desc

{

int irq; /*中断号*/

/*中断号唯一表示一个中断*/

int pin; /*中断控制的寄存器*/

/*该寄存器的值由中断引脚设置*/

/*我们希望从该寄存器读出控制信息*/

int pin_setting; /*中断的引脚*/

/*该引脚的电平由按键来控制*/

/*从而最终我们由按键控制了寄存器的值*/

int number; /*编号*/

char *name; /*名称*/

};

/*指定6个按键的信息*/

static struct button_irq_desc button_irqs [] =

{

{IRQ_EINT8,S3C2410_GPG0,S3C2410_GPG0_EINT8,0,"KEY1"}, /*K1*/

{IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG3_EINT11,1,"KEY2"}, /*K2*/

{IRQ_EINT13,S3C2410_GPG5,S3C2410_GPG5_EINT13,2,"KEY3"}, /*K3*/

{IRQ_EINT14,S3C2410_GPG6,S3C2410_GPG6_EINT14,3,"KEY4"}, /*K4*/

{IRQ_EINT15,S3C2410_GPG7,S3C2410_GPG7_EINT15,4,"KEY5"}, /*K5*/

{IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG11_EINT19,5,"KEY6"}, /*K6*/

}

/*这样,资源就组织起来了*/

/*事实上,在这里我们不仅组织起了硬件资源*/

/*我们也把一定的软件资源也糅合进去了*/

/*像中断号*/

/*key_values数组*/

/*存放各个按键在发生中断情况下的值*/

/*volatile是什么意思呢?*/

/*这个数组是我们存放按键操作结果的,因此非常重要*/

static volatile int key_values [] = {0,0,0,0,0,0};

/*宏DECLARE_WAIT_QUEUE_HEAD(),是干什么的呢?*/

/*该宏应该是创建了一个等待队列*/

/*等待队列,是进程调度的一种重要方法*/

/*等待队列也很有意思,button_waitq,表示按键等待的队列*/

/*就是说,按键一按下,就会激活其等待队列里的进程,来做相应的处理*/

/*因此,按键的等待队列,或者说中断所设置的等待队列,*/

/*是中断处理中非常重要的资源,它大大扩展了中断处理的能力*/

static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /*button_waitq是什么呢?*/

/*应该是等待队列的名称*/

/*key_values数组中是否有数据的标志,0表示无数据可读,1表示有数据可读*/

static volatile int ev_press = 0; /*初始为0*/

/*中断服务程序buttons_interrupt()的申明*/

/*即当检测到有中断时,就会执行该中断服务程序*/

/*那么如何检测到有中断发生呢?*/

/*并且中断发生了,知道发生了什么样的中断呢?*/

/*中断有很多种,该中断服务程序究竟该服务于哪一个中断呢?*/

/*显然,要把中断号与中断服务程序联结起来,构成一个整体*/

/*这个工作可以在open函数里做*/

/*参数irq---中断号*/

/*中断服务程序应该是与中断号一一对应的*/

/*对应于某个中断号的中断一发生,就会调用该中断号对应的服务程序*/

/*那么,检测中断的发生,就成了先决条件*/

/*参数dev_id ---具体是哪一个按钮*/

static irqreturn_t buttons_interrupt(int irq,void *dev_id);

/*mini2440_buttons_open()函数申明*/

/*驱动函数open调用的具体函数*/

/*由open函数具体实现硬件的初始化工作*/

/*以及软件的初始化工作*/

/*为我们的键盘设备的运行创造好环境*/

static int mini2440_buttons_open(struct inode *inode,struct file *file);

/*mini2440_buttons_close()函数的申明*/

/*release调用的具体函数*/

/*设备软件环境的拆卸*/

/*具体就是中断的释放工作*/

/*因为中断资源,也是系统宝贵的资源,所以不用的时候,要释放*/

static int mini2440_buttons_close(struct inode *inode,struct file *file);

/*mini2440_buttons_read()函数的申明*/

/*read调用的具体函数*/

/*由它读取键盘输入的结果*/

/*实质上就是读取key_values数组的值*/

/*它完成了键盘作为输入设备的核心功能*/

/*数组是否可读,要根据标志位ev_press来判断*/

/*如果数组可读,则读取数据到用户buffer中*/

/*如果数组不可读,则进程进入等待队列,等待到数组可读为止*/

/*等待队列机制,是中断管理中常用到的机制*/

/*因为有些进程经常需要等待某一事件的发生*/

static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp);

/*注意__user,指的是用户空间*/

/*即要把键盘的输入结果读取到用户空间去*/

/*mini2440_buttons_poll()函数的申明*/

/*poll调用的具体函数*/

/*poll实质上是select的调用函数*/

/*如果有按键数据,则select会立刻返回*/

/*如果没有按键数据,则等待*/

/*实质上这是键盘等待输入的机制*/

static unsigned int mini2440_buttons_poll(struct file *file,struct poll_table_struct *wait);


/*file_operations结构体*/

/*驱动函数的设置*/

/*分别将前面的驱动函数设置进来*/

static struct file_operations mini2440_buttons_fops =

{

.owner = THIS_MODULE,

.open = mini2440_buttons_open, /*open()*/

.release = mini2440_buttons_close, /*release()*/

.read = mini2440_buttons_read, /*read()*/

.poll = mini2440_buttons_poll /*poll()*/

};

/*mini2440_buttons_init()函数的申明*/

/*module_init调用的具体函数*/

/*模块创建时的初始化函数*/

/*主要做的工作是注册设备和创建设备*/

/*而具体的硬件初始化工作,它可以不做*/

/*而把它留给fops里的函数来做*/

static int __init mini2440_buttons_init(void);

/*mini2440_buttons_exit()函数的申明*/

/*模块卸载时的扫尾工作*/

/*主要是设备的卸载工作*/

static void __exit mini2440_buttons_exit(void);

/*模块创建时的入口点*/

module_init(mini2440_buttons_init);

/*模块卸载时的入口点*/

module_exit(mini2440_buttons_exit);

/*驱动程序的一些信息*/

MODULE_AUTHOR("http://www.arm9.net"); /*驱动程序的作者*/

MODULE_DESCRIPTION("S3C2410/S3C2440 BUTTON Driver"); /*描述信息*/

MODULE_LICENSE("GPL"); /*遵循的协议*/

/********************************************************************/

/*********************下面是前面申明函数的实现***********************/

/********************************************************************/

/**********************mini2440_buttons_init()***********************/

static int __init mini2440_buttons_init(void)

{

int ret; /*设备注册的返回值*/

/*注册设备驱动程序*/

/*设备号,设备名,和驱动函数*/

ret = register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&mini2440_buttons_fops);

/*对注册失败的处理*/

if(ret < 0)

{

printk(DEVICE_NAME " can't register major number/n");

return ret;

}

/*创建设备*/

/*devfs_mk_cdev()函数是内核态的设备创建函数*/

/*而mknod是用户态的设备创建函数*/

devfs_mk_cdev(MKDEV(BUTTON_MAJOR,0),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);

printk(DEVICE_NAME " initialized/n");

return 0;

}

/******************mini2440_buttons_exit()****************************/

static void __exit mini2440_buttons_exit(void)

{

/*移除设备*/

devfs_remove(DEVICE_NAME);

/*注消设备驱动*/

unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);

}

/*****************mini2440_buttons_open()******************************/

static int mini2440_buttons_open(struct inode *inode,struct file *file)

{

int i; /*循环变量,因为有6个按钮*/

int err; /*中断注册函数的返回值*/

/*对每个按钮分别处理,用for循环来做*/

/*具体地是要联结寄存器和相应的引脚*/

/*联结中断号和相应的中断服务程序*/

/*这一步类似于前面所说的驱动的注册*/

/*我们可以成功称作中断的注册*/

for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++)

{

/*寄存器与中断引脚的联结*/

s3c2410_gpio_cfgpin(button_irqs[i].pin,button_irqs[i].pin_setting);

/*中断的注册*/

/*request_irq()函数*/

/*要注意其输入参数*/

/*&button_irqs[i]是该中断享有的资源*/

/*会被传入buttons_interrupt,进行处理*/

err = request_irq(button_irqs[i].irq,buttons_interrupt,NULL,button_irqs[i].name,(void *)&button_irqs[i]);

/*中断类型的设置*/

/*set_irq_type()函数*/

/*IRQT_BOTHEDGE的中断类型代表什么样的中断呢?*/

/*有几个非常重要的问题*/

/*中断注册后,并设置好其中断类型之后,当有中断发生时,*/

/*即按下某个按钮时,系统能够自动检测到有中断发生吗?*/

/*检测到有中断发生,它能够自动辨别是几号中断吗?*/

/*知道了是几号中断,那么它能自动调用其中断服务程序吗?*/

/*对这几个问题的解答,够成了linux系统中断处理机制的核心*/

set_irq_type(button_irqs[i].irq,IRQT_BOTHEDGE);

/*注册失败的处理*/

if(err)

break; /*跳出循环*/

}

/*若有一个按钮中断注册失败*/

/*则还需把前面注册成功的中断给拆了*/

if(err)

{

i--; /*回到前面一个按钮的处理*/

for(;i >=0; i--) /*依此拆除*/

{

/*使中断不起作用*/

disable_irq(button_irqs[i].irq);

/*释放中断资源*/

free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);

}

return -EBUSY; /*中断注册没成功的最终的返回值*/

}

return 0; /*正常返回*/

}

/**************************buttons_interrupt()*****************************/

/*此中断服务程序,在每中断一次,就要对key_values数组设一下值*/

/*并对数组可读标志位ev_press设一下值*/

/*并唤醒在等待队列里的进程*/

/*这是中断处理经常要做的事情*/

/*在这里,等待队列button_waitq里经常等待的进程是数组的读取进程*/

/*就是说,读取进程在没有读到数据的时候就一直在等待,等待按键的输入*/

/*读取进程在等待,并不代表所有进程在等待,其它进程该干啥干啥去*/

static irqreturn_t buttons_interrupt(int irq,void *dev_id)

{

/*button_irq_desc结构体变量*/

/*对传入的资源进行处理*/

struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

/*获取寄存器的值*/

/*这一步至关重要*/

/*s3c2410_gpio_getpin()函数直接获取寄存器的值*/

/*要注意,按一下按钮,会发生两次中断*/

/*即按下是一次中断,放开又是一次中断*/

int up = s3c2410_gpio_getpin(button_irqs->pin);

/*通过电路原理图,可以知道没按下的时候,中断引脚应该是高电平*/

/*从而寄存器的值应该是1*/

/*变量取up也是有意义的,表示默认状态是弹起的状态*/

/*当按下按钮的状态下,寄存器的值就应该是0*/

/*下面对up的值进行处理*/

/*即是要把数据经过一定的变换存入key_values数组中*/

if(up) /*如果是弹起的状态*/

/*那么就要在key_values数组的相应位存入很大的一个值*/

/*同时又要能从值里辨别出是哪个按键*/

key_values[button_irqs->number] = (button_irqs->number + 1) + 0x80;

/*比如K1键开启的状态下,key_values[0]被置为(0+1)+0x80,即为129*/

else /*如果按键是闭合的状态*/

/*那么就要在key_values数组的相应位存入一个很小的数*/

/*同时又要能从值中辨别出是哪个键*/

key_values[button_irqs->number] = (button_irqs->number + 1);

/*比如K1键闭合,则key_values[0]被置为(0+1),即为1*/

/*对数组可读标志位进行设置*/

ev_press = 1; /*表示数组已经可读了*/

/*唤醒休眠的进程?*/

/*button_waitq队列里存放有相应的处理进程*/

/*如读取数组的值的进程*/

/*要注意wake_up_interruptible()这些函数的用法*/

wake_up_interruptible(&button_waitq);

/*返回*/

return IRQ_RETVAL(IRQ_HANDLED); /*?*/

}

/**********************mini2440_buttons_close()*****************************/

static int mini2440_buttons_close(struct inode *inode,struct file *file)

{

int i; /*循环变量,要操作好几个按键*/

/*for循环,对各个按键依此释放中断*/

for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++)

{

/*使中断失效*/

disable_irq(button_irqs[i].irq);

/*释放资源*/

free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);

}

/*返回*/

return 0;

}

/**********************mini2440_buttons_read()***************************/

/*要注意,该read函数,只读取一次中断的值,而不是连续地读入*/

/*要做到连续地读入,则需要做一个循环,不断地调用该read函数,但那不是驱动程序里该做的事情*/

static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)

{

unsigned long err; /*copy_to_user()函数的返回值*/

/*如果key_values 数组里没有值,则会此进程会休眠*/

/*一直到中断来临之后,中断服务程序会唤醒此休眠进程从而继续读取值*/

/*key_values数组里有没有值,是靠ev_press标志位来判断的*/

/*有值,就是1,无值,就是0*/

/*进程等待队列的机制,是进程调度的一种方法*/

if(!ev_press) /*标志位为0,即无数据时*/

{

if(filp->f_flags & O_NONBLOCK) /*??*/

return -EAGAIN;

else /*进程休眠,放进button_waitq等待队列*/

/*这里,把ev_press标志位设成了休眠进程的标志位了?*/

/*这是为了便于利用poll_wait函数*/

/*也就是利于select函数*/

wait_event_interruptible(button_waitq,ev_press);

/*在中断处理函数中,此进程会被唤醒*/

/*唤醒前,ev_press 已被置1了*/

/*唤醒后的执行点从这里开始*/

}

/*下面就是标志位为1,即有数据可读的的处理情况*/

/*那就开始往用户空间读数据呗*/

err = copy_to_user(buff,(const void *)key_values,min(sizeof(key_values),count));

/*copy_to_user()函数的使用*/

/*对key_values数组清零*/

memset((void *)key_values,0,sizeof(key_values));

/*对标志位置0*/

/*表示读取过了*/

ev_press = 0;

/*对err的处理*/

if(err) /*读取错误*/

return -EFAULT;

else /*读取正确*/

/*则返回读取到的字节数*/

return min(sizeof(key_values),count);

}

/************************mini2440_buttons_poll()***********************/

static unsigned int mini2440_buttons_poll(struct file *file,struct poll_table_struct *wait)

{

unsigned int mask = 0; /* */

/*poll_wait()函数*/

/*会监测进程队列button_waitq里的进程*/

/*例如,如果mini2440_button_read所在的进程的标志位ev_press置为1了*/

/*那么就不会再等待了*/

/*这实质上就是select函数的运行机制*/

poll_wait(file,&button_waitq,wait);

if(ev_press)

mask |= POLLIN | POLLRDNORM; /*??*/

return mask;

}

 

--------------------------------------------------------------------------------

/*按键测试程序*/

#include <stdio.h> /*标准输入输出头文件*/

#include <stdlib.h> /*标准库*/

#include <unistd.h> /*一些宏的定义在这里*/

#include <sys/ioctl.h> /*设备的控制*/

#include <sys/types.h> /*定义了一些类型*/

#include <sys/stat.h> /*状态*/

#include <fcntl.h> /*文件控制*/

#include <sys/select.h> /*选择?*/

#include <sys/time.h> /*时间方面的函数*/

#include <errno.h> /*有关错误方面的宏*/

/*主函数入口*/

int main(void)
{
int i; /*键盘输出时用到的循环变量*/

int buttons_fd; /*buttons设备号*/

int key_value[4]; /*四个按键的取值*/

/*打开键盘设备文件*/

buttons_fd = open("/dev/buttons",0); /*以0方式打开*/

/*打开出错处理*/

if(buttons_fd < 0) /*打开出错就会返回一个负值*/
{
perror("open device buttons"); /*perror函数?*/

exit(1); /*返回1*/
}

/*for无限循环,等待用户输入*/
/*这是很典型的程序执行方式*/

for(;;)
{
fd_set rds; /*fd_set是types.h中定义的类型,实质上是int型*/
/*rds用来存储设备号*/

int ret; /*for循环内定义的局部变量ret*/

FD_ZERO(&rds); /*rds初始化*/
/*FD_ZERO是哪里定义的呢?*/

FD_SET(buttons_fd,&rds); /*将buttons设备号赋给rds*/
/*FD_SET是哪里定义的呢?*/

/*使用系统调用select检查是否能够从/dev/buttons设备读取数据*/
/*select函数是干什么的呢?*/

ret = select(buttons_fd + 1,&rds,NULL,NULL,NULL);
/*返回值ret*/
/*返回值的具体意义是什么呢?*/

/*对ret的处理*/

if(ret < 0) /*当ret小于0*/
{
perror("select");
exit(1);
}

if(ret == 0) /*当ret等于0*/
{
printf("Timeout./n");
}
else /*能够读到数据*/
if(FD_ISSET(buttons_fd,&rds)) /*??*/
{
/*读取键盘驱动发出的数据*/
/*key_value和键盘驱动中定义一致*/

int ret = read(buttons_fd,key_value,sizeof(key_value)); /*注意此处的ret和前面的ret有何不同*/
/*注意键盘设备读取的特点*/

/*对ret的处理*/
if(ret != sizeof(key_value)) /*没有接收够*/
{
if(errno != EAGAIN) /*???*/
perror("read buttons/n");
continue;
}
else /*正确接收,则打印到标准终端*/
{
for(i = 0;i < 4;i++) /*最开始定义的循环变量i*/
printf("K%d %s, key value = 0x%02x/n",i,(key_value[i] & 0x80) ? "released" : key_value[i] ? "pressed down" : "",key_value[i]);
/*这一连串的输出,要注意格式*/
}
}
}

/*关闭设备*/

close(buttons_fd);

return 0; /*主函数返回*/
}

 

一、引言
  Linux本身为分时操作系统,其系统目标为较好的平均响应时间和较高的吞吐量,而实时系统则主要考虑任务的按时完成、尽量减少进程运行的不可预测性等。但与商业嵌入式操作系统相比Linux遵循GPL,具有源代码开放、定制方便、支持广泛的计算机硬件等优点,所以,近年来嵌入式Linux成为嵌入式系统方向上的一个研究热点。本文首先分析了实时系统的特点和Linux内核在实时应用方面的不足,然后针对影响操作系统实时性能的若干方面进行研究,提出解决方案,最后总结全文。
  二、实时系统的分类
  实时系统最重要的特点就是实时性,即系统的正确性不仅仅依赖于计算的逻辑结果的正确性,还取决于输出结果时间的及时性。从这个角度看,实时系统是"一个能够在指定或者确定的时间内完成系统功能和对外部环境做出响应的系统"。按对实时性能要求的程度,实时系统可分为两类:
  (1) 硬实时系统:要求可确定性强,具有明确的实时约束,在某个限定的时刻之前不能完成任务将造成灾难性的后果。
  (2) 软实时系统:也对时间敏感,但偶尔发生不能满足严格实时要求的情况也是允许的。
  三、Linux在实时方面存在的不足
  Linux虽然符合POSIX1003.1b关于实时扩展部分的标准,例如:支持SCHED_FIFO和SCHED_RR实时调度策略,锁内存机制(memorylocking),实时信号等功能,但是由于其最初的设计目标为通用分时操作系统,因此作为一个实时操作系统,Linux仍然存在如下缺陷:
  (1) Linux的内核本身是非抢占的。Linux下分用户态和核心态两种模式,当进程运行在用户态时,可被优先级更高的进程抢占,但当它进入核心态时,其他用户态进程优先级再高也不能抢占它。
(2) Linux虽然给实时进程提供了较高的优先级,但是没有加入时间限制。例如:完成的最后期限、应在多长时间内完成、执行周期等等。同时,其他大量的非实时进程也可能对实时进程造成阻塞,无法确保实时进程的响应时间。
  (3) 时钟粒度粗糙。时钟管理是操作系统的脉搏,任务的执行和中止在很多情况下都是由时钟直接或间接唤起的,它还是进程调度的重要依据。Linux的周期模式定时器频率仅为100Hz,远不能满足实时应用的要求。
  四、改进内核实时性的分析与研究
  从中断软件模拟、可抢占式内核体系结构、实时任务的调度策略这三个方面对嵌入式Linux内核进行研究,并给出了相应的提高实时性的方法。
  1. 响应时间的分析及解决方法
  任务的响应时间被定义为一个事件的发生和任务响应这一事件开始执行之间的间隔时间,通常有以下几个因素影响任务的响应时间。
  (1) 中断分配时间IDT(interrupt dispatch time):当一个中断产生时,在调用中断处理程序占用CPU以前,操作系统用来保存所有的寄存器中的内容和系统中其他的关于这一任务状态的时间。
  (2) 中断服务时间:IST(interrupt service time):中断服务程序用来从硬件设备读取信息或从操作系统收集信息所用的时间。
  (3) 内核抢占时间KPT(kernelpreemptiontime):在操作系统意欲抢占当前进程与抢占实际上发生之间的时间间隔。
  (4) 调度延迟SD(scheduledelay):调度程序用来调度另一个线程投入运行的时间。
  (5) 进程切换时间CST(contestswitchingtime):当前线程用来保存寄存器和系统状态的时间与将要运行的线程恢复寄存器中的内容和系统状态的时间总和。
  (6) 系统调用返回时间RST(returnfromsystemcall):处于内核态的线程在它返回用户态之前检查一些状态所用的时间。
 以上这些时间中,SD、CST和RST总是固定不变的,如果Linux内核设计得当的话,IDT、IST和KPT可以有效的减少。在实时应用的环境中,若干个中断同时发生的情况是完全可能存在的。这时任务的响应时间最多将包含N(IDT+IST),N为中断数。
  中断软件模拟被用来解决多个中断同时发生的情形。当一个硬件中断发生时,系统只是简单的在时间表中报告这一时间的发生,然后立即将CPU的控制权返回给操作系统,完全略过了查中断向量表并执行相应的中断服务程序。系统在Linux内核之前截获了所有应中断信号,并根据当前实时任务的需要,由软中断模拟机制处理或挂起该中断(例如:IBMPC中的8259中断控制器)。
  采用这个方法,可以减少当多个中断同时发生时任务的响应时间,最长的延迟时间为N*IST',其中N为中断数。在这里之所以是IST',而不是IST,是因为采用软中断软件模拟的方法使得在IST时间段内只执行一些简单的操作。
  2. 抢占式内核体系结构的设计
  为了解决Linux实现硬实时的最大障碍,使Linux内核成为完全可被抢占实时内核,典型的实现方案是双核结构。使用实时核来运行实时任务,Linux内核来运行非实时任务。例如:对于实时数据采样分析而言,利用实时内核运行一个实时任务来完成数据采集,另一个实时任务完成数据分析和控制输出功能;同时利用Linux内核上运行的界面来进行数据显示。如图1所示。

  图1 双内核结构
  在Linux内核和硬件之间加个小的实时核,由它管理中断,提供一些必要的功能,如底层任务创建、中断服务程序,并且为底层任务、ISR和Linux进程之间进行通信排队;而Linux内核本身则成为优先级最低的Idletask。
对实时性要求强的应用编写成实时任务,在实时内核上直接运行。Linux内核可以被优先级更高的实时任务抢占。对于Linux内核的修改主要集中在三方面:(1) 在Linux内核中影响实时性的地方增加控制点,使内核在控制点可以被抢占,减少内核抢占延迟;(2) 将执行时间较长的系统划分为几个甚至是十几个较小的块分别执行,使实时任务随时中断非实时任务;(3) 根据实际需要,增加部分功能。
  随着嵌入式应用的深入,特别是在数字通信和网络中的应用,多核结构的处理器也陆续上市。如:Motorola公司研发的MPC8260PowerQUICC||融合了两个CPU-嵌入式PowerPC内核和通信处理模块(CPM);Infineon公司推出的TC10GP和增强型TC1130都是三核(TriCore)结构的微处理器,这些处理器的产生对于Linux应用中的实时性都大有帮助。
  3. 实时调度的算法研究
  常用的实时调度算法有:基于优先级的调度算法(priority-drivenscheduling,PD);基于时间驱动的调度算法(time-drivenscheduling,TD);基于比例共享的调度算法(share-drivensched2uling,SD)。基于优先级的调度算法 调度器以优先级作为寻求下一个任务执行的依据。可分为如下两种类型:
  (1) 静态优先级调度算法:该算法给系统中所有进程都静态的分配一个优先级。静态优先级的分配可以根据应用的属性来进行,例如任务的周期、用户优先级或者其他预先确定的策略。RM(RateMonotonic)是一种典型的静态优先级调度算法,它根据任务执行周期的长短来决定调度优先级,执行周期小的任务具有较高的优先级。
  (2) 动态优先级调度算法:这种算法根据任务的资源需求来动态的分配任务的优先级。EDF(earliestdeadlinefirst)算法是一种典型的动态优先级调度算法,该算法根据就绪队列中各个任务的截止期限来分配优先级,具有最近截止期限的任的优先级最高。
基于时间驱动的调度算法
  该算法本质上是一种设计时就确定下来的离线的静态调度方法。在系统的设计阶段,在明确系统中所有处理的情况下,对于各个任务的开始、切换以及结束时间等事先组出明确的安排和设计。
  基于比例共享的调度算法
  这是一种越来越受到关注的实时调度模式,基于GPS(generalprocessorscheduling)的算法,其基本思想就是按照一定的权重(CPU使用的比例)对一组需要调度的任务进行调度,使其执行时间与权重完全成正比。可以通过两种方法来实现比例共享调度算法:(1)是调节各个就绪进程出现在当前调度队列队首的频率,并调度队首的进程执行;(2)是逐次调度就绪队列中的各个进程投入运行,但根据分配的权重调节分配给每个进程的运行时间片。比例共享算法包括轮转法、公平共享法、公平队列法和彩票调度法等几类。
  每一种调度策略都有自己的优越性和不足。在这里我们提出了一种宏观调度结构,通过设计和构造多属性和多调度器的选择机制,使三种实时调度策略的应用都得到支持,相对于只对单种调度策略提供支持的方案,拓展了系统的可使用范围。宏观调度结构如图2所示。

  图2 宏观调度结构
  我们给每一个实时任务定义了4个调度属性:priority(优先级:限制该任务比相关联的其他任务的优先权)、starttime(起始时间:任务开始执行时间)、finishtime(截止时间:任务停止时间)和budget(预设值:任务允许执行时间),不同属性的数据对应不同的调度策略。宏观调度结构分为两个模块:属性分配模块和调度器选择模块。属性分配模块给每一个实时任务分配多个属性值,并通过其中的一两个属性值决定哪个属性优先,这样调度器选择模块就可以根据属性的优先级别选择不同的调度器。例如:如果优先级属性优先,则调度器就变成了一个纯粹的PD调度器;如果截止时间优先,那么调度器就作为EDF调度器来工作。
  实验时采用Pentium-||400处理器,128MB内存,运行环境Linux2.0.35(以RED-Linux0.5为补丁),以RM调度策略为例,分别测量每一次系统请求消耗的时间。数据整理如下:宏观调度结构下属性分配模块消耗的时间大部分不到40Ls,平均约35Ls,调度器选择模块平均消耗时间约85Ls,消耗时间总计为118Ls,约占0.118%的CPU时间;单一调度策略的情况平均消耗时间约为25Ls,约占0.025%的CPU时间。宏观调度结构的延迟时间为传统调度方式的5倍,对于大多数的嵌入式系统来讲内核的灵活性和可配置性比调度的延时更为重要,而宏观结构和单一调度结构的CPU可用时间分别为99.88%和99.97%,差别极小,符合嵌入式系统实时性要求。
  五、结论与展望
Linux虽然为分时操作系统,但由于其功能强大、源代码开放以及可移植性强等优势,已成为日益流行的嵌入式实时操作系统的解决方案。本文从软中断模拟技术、可抢占式内核和实时调度策略三个方面给出了改善系统实时性能的方法,并提出了通过采用宏观调度结构实现的混合调度,拓展了实时系统的应用范围。Linux实时性能的逐步完善,必将大大促进嵌入式Linux在工业控制、后PC时代信息电器等领域的广泛应用,应用的需要也会进一步促进大量新型控制算法的

 

 

 

 


一、从基础开始
  常常有些朋友在Linux论坛问一些问题,不过,其中大多数的问题都是很基的。例如:为什么我使用一个命令的时候,系统告诉我找不到该目录,我要如何限制使用者的权限等问题,这些问题其实都不是很难的,只要了解了Linux的基础之后,应该就可以很轻易的解决掉这方面的问题。而有些朋友们常常一接触Linux就是希望构架网站,根本没有想到要先了解一下Linux的基础。这是相当困难的。

  二、Linux命令是必须学习

  虽然Linux桌面应用发展很快,但是命令在Linux中依然有很强的生命力。Linux是一个命令行组成的操作系统,精髓在命令行,无论图形界面发展到什么水平这个原理是不会变的,Linux命令有许多强大的功能:从简单的磁盘操作、文件存取、到进行复杂的多媒体图象和流媒体文件的制作。举一个例子:Linux的常用命令find,察看man文档,初学者一定会觉得太复杂而不原意用,但是你一旦学会就爱不释手.它的功能实在太强了,在配合exec参数或者通过管道重定向到xargs命令和grep命令,可以完成非常复杂的操作,如果同样的操作用图形界面的工具来完成,恐怕要多花十几陪的时间。

  不同版本的Linux命令数量不一样,这里笔者把它们中比较重要的和使用频率最多的命令,按照它们在系统中的作用分成几个部分介绍给大家,通过这些基础命令的学习我们可以进一步理解Linux系统:

  安装和登录命令:login、shutdown、halt、reboot、mount、umount、chsh

  文件处理命令:file、mkdir、grep、dd、find、mv、ls、diff、cat、ln

  系统管理相关命令:df、top、free、quota、at、lp、adduser、groupaddkill、crontab、tar、unzip、gunzip、last

  网络操作命令:ifconfig、ip、ping、netstat、telnet、ftp、route、rloginrcp、finger、mail、nslookup

  系统安全相关命令:passwd、su、umask、chgrp、chmod、chown、chattr、sudo、pswho

  三、选择一本好的工具书

  工具书对于学习者而言是相当重要的。一本错误观念的工具书却会让新手整个误入歧途。目前国内关于Linux的书籍有很多不过精品的不多。

  四、选择一个适合你的Linux发行版本

  目前全球有超过一百多个Linux发行版本,在国内也能找到十几个常见版本。如何选择请根据你的需求和能力,RedhatLinux和DebianLinux是网络管理员的理想选择。对于英语不是很好的读者红旗 Linux、中标Linux这些中文版本比较适合。现在一些Linux网站有一些Linux版本的免费下载,这里要说的是并不适合Linux初学者。

  五、养成在命令行下工作

  一定要养成在命令行下工作的习惯,要知道X-window只是运行在命令行模式下的一个应用程序。在命令行下学习虽然一开始进度较慢,但是熟悉后,您未来的学习之路将是以指数增加的方式增长的。从网管员来说,命令行实际上就是规则,它总是有效的,同时也是灵活的。即使是通过一条缓慢的调制解调器线路,它也能操纵几千公里以外的远程系统。

  六、选择一个适合你的Linux社区

  随着Linux应用的扩展,出现了不少Linux社区。有一些非常优秀的社区往往是Linux高手的舞台,如果在探讨高级技巧的论坛张贴非常初级的问题经常会没有结果。建议选择一些适于初学者的Linux社区。

  七、勤于实践

  要增加自己Linux的技能,只有通过实践来实现了。所以,赶快找一部计算机,赶快安装一个Linux发行版本,然后进入精彩的Linux世界,相信对于你自己的Linux能力必然大有斩获。对Linux命令熟悉后,你可以开始搭建一个小的Linux网络,这是最好的实践方法。Linux是网络的代名词,Linux网络服务功能非常强大,不论是邮件服务器、Web服务器、DNS服务器等都非常完善。当然你不需搭建所有服务,可以慢慢来。自己多动手,不要非等着别人帮你解决问题。

  八、如何得到联机帮助

  和私有操作系统不同,各个Linux的发行版本的技术支持时间都较短,这对于Linux初学者是往往不够的。其实当你安装了一个完整的Linux系统后其中已经包含了一个强大的帮助,只是可能你还没有发现和使用它们的技巧。

  1.主流Linux发行版都自带非常详细的文档(包括手册页和FAQ),从系统安装到系统安全,针对不同层次的人的详尽文档,仔细阅读文档后40%问题都可在此解决。

  2.查阅经典工具书和Howto,特别是Howto是全球数以万计的Linux、Unix的经验总结非常有参考价值通常40%的问题同样可以解决。

  九、在Linux论坛获取帮助

  如果上面的措施没有解决问题,此时你就需要Linux社区的帮助了。 Linux的使用者一般都是专业人士,他们有着很好的电脑背景且愿意协助他人,Linux高手更具有鼓励新手的文化精神。如何在Linux社区获得帮助,需要说明的是你要有周全的思考,准备好你的问题,不要草率的发问,否则只会得到到草率的回答或者根本得不到任何答案。越表现出在寻求帮助前为解决问题付出的努力,你越能得到实质性的帮助。最好先搜寻一下论坛是否有您需要的文章。这样可以获得事半功倍的效果。

  下面笔者在论坛看到的一个好问题: "安装红旗4.0后,系统紫光输入法自带的双拼方案和我的习惯不一样,如何自定义双拼方案解决?谢谢?"这个问题很简练,笔者五分钟后就给出了解决方法: "首先备份原文件到其他目录,然后删掉/usr/local/unispim/unispimsp.ksc,编辑 /usr/local/unispim/unispimsp.ini,最后重启动计算机,生成新的unispimsp.ksc。"另外得到回复后如果问题解决,向帮助过你的人发个说明,让他们知道问题是怎样解决的,这种补充有助于他人在邮件列表/新闻组/论坛中搜索对你有过帮助的完整解决方案,这可能对他们也很有用。

  下面看看一个让人无法回答的问题:"救命各位高手,向你们请教一些问题:如何在Linux下配制HTTP、FTP、Samba、DNS、DHCP、Sendmail服务器,谢谢"这样的问题我想即使Linux高手也很难快速准确精练的回答你。

  你需要提供精确有效的信息。这并不是要求你简单的把成吨的出错代码或者数据完全转储摘录到你的提问中。如果你有庞大而复杂的测试条件,尽量把它剪裁得越小越好。可能你会遇到这种情况,对于一个问题会出现不同内容回答,这时你需要通过实践来验证。另外把这个问题放在其他Linux社区请求帮助也是一种选择。如果得不到答案,请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答案罢了。这时换一个社区是不错的选择。

  另外发问的时候一定要注意到某些礼节。因为Linux社区是一个松散的组织、也不承担回复每个帖子的义务。它不是技术支持。

  十、用Unix思维学习Linux

  Linux是参照Unix思想设计的,理解掌握Linux必须按照Unix思维来进行。思想性的转变比暂时性的技术提高更有用,因为他能帮助你加快学习速度。

  十一、学习专业英文

  如果你想深入学习Linux,看不懂因为文档实在是太难了。写的最好的、最全面的文档都是英语写的,最先发布的技术信息也都是用英语写的。即便是非英语国家的人发布技术文档,也都首先翻译成英语在国际学术杂志和网络上发表。安装一个新的软件时先看README,再看INSTALL然后看FAQ,最后才动手安装,这样遇到问题就知道为什么。如果说明文档不看,结果出了问题再去论坛来找答案反而浪费时间。

 

你可能感兴趣的:(关于Linux)