嵌入式操作系统课程设计实验报告

华中科技大学

嵌入式操作系统课程设计实验报告

 

院    系:     计算机科学与技术学院

专    业:           物联网       

班    级:           1102        

姓    名:           吴斌        

           报告时间:        20##-06-25    

计算机科学与技术学院

                            目 录

1.课程设计目的…………………………………………………………3

2.课程设计环境搭建……………………………………………………3

3.内容一:熟悉和理解Linux编程环境

   (1)内容要求……………………………………………………………………4

    (2)计过程及实现………………………………………………………………4

4.内容三:掌握添加设备驱动程序的方法

   (1) 内容要求 …………………………………………………………………7

   (2) 设计过程及实现 …………………………………………………………7

5.课设感想 ………………………………………………………………………12

 

 

 

 

实验内容

1 .课程设计目的

(1)掌握Linux操作系统的使用方法;

(2)了解Linux系统内核代码结构;

(3)掌握实例操作系统的实现方法。

2 .课程设计环境搭建

(1)安装linux

(2)更改root登录:

    在现阶段Ubuntu的系统中,是不允许直接以root身份登录系统的,但是在做课设的过程中,需要大量的使用root权限来进行命令的操作。如果以普通用户登录ubuntu,会连编辑一个文件都非常周折。为此,我找到了一种修改系统文件,以达到直接使用root身份登录的方法:

    ◎开始的时候,只能以普通用户登录,用Ctrl+Alt+T打开终端:

    初始化/修改root密码

           sudo passwd root       

    用vi编辑器修改这个文件:

           sudo vi /etc/lightdm/lightdm.conf

    在文件最后加入这么一行代码:

           greeter-show-manual-login=true

    然后保存退出,sudo reboot 重启系统。之后就可以输入root用户登录。

(3)在添加系统调用中用到的其他内核包:

    ◎下载和当前实验环境最为接近的系统版本(这点很重要)

       使用apt-get install linux-source-3.0.0 命令,

    ◎下载结果是linux-source-3.0.0.tar.bz2

    ◎解压命令:tar –xjvf linux-source-3.0.0.tar.bz2 –C /usr/src

    ◎解压后,在/usr/src目录下得到内核文件夹linux-source-3.0.0

(4)在调用linux图形库时需要安装GTK环境:

    ◎安装gcc/g++/gdb/make 等基本编程工具
           apt-get install build-essential

    Tip:如果提示由于依赖项不能安装,需要使用apt的强化版aptitude,这个工具可以自动分析软件包依赖,系统一般不自带,需要先安装,具体过程是:

           apt-get install aptitude

           aptitude install build-essential

    aptitude这个工具很强大,对于解决软件包安装时的依赖问题很有帮助。

    ◎安装 libgtk2.0-dev libglib2.0-dev 等开发相关的库文件:

           apt-get install gnome-core-devel

    ◎安装GTK核心组件:
           apt-get install libgtk2.0-dev

       这个安装完成后,GTK环境就基本搭建成功,网上有些教程说要安装其他配置文件,经我亲测,发现只要安装libgtk2.0-dev这个包就能搞定。

3.熟悉和理解Linux编程环境

(1)实验内容:实现三个进程之间的并发程序:

(2)计过程及实现:这里需要用到课程实验时的fork( )程序以及GTK的图形显示。

  ①基本fork()程序,调用显三个进程的结构如下:

   #include <stdio.h>

   #include <unistd.h>

   #include <sys/types.h>

   #include <sys/wait.h>

   void main(int argc,char argv[]){

   pid_t p1,p2,p3;

   pid_t t1,t2,t3;

   int status;

  if ((p1=fork()) == 0){/*创建第一个子进程*/

    execv("./pa",argv);

  }

  else if ((p2=fork()) == 0) {/*创建第二个子进程*/

    execv("./pb",argv);

  }

  else if((p3=fork()) == 0){/*创建第三个子进程*/

    execv("./pc",argv);    

  }

  else{

  t1=waitpid(p1,&status,0);

  t2=waitpid(p2,&status,0);

  t3=waitpid(p3,&status,0);

  }

  }

②调用GTK显示窗体函数模块的结构:

    void show(int argc,char *argv[ ],char *title )  {

    gtk_init (&argc, &argv);                  //初始化工具包并且获取命令行参数;

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL); //创建新的窗口;

       //设定窗口的位置;

    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

   //监听窗口的destroy事件;

g_signal_connect (G_OBJECT (window),

                     "destroy", G_CALLBACK (destroy_progress), NULL);

    gtk_window_set_title (GTK_WINDOW (window), title);//用来设定更改窗口标题;

    gtk_container_set_border_width (GTK_CONTAINER (window), 20);//设定宽度;

       //使用gtk_vbox_new函数建立纵向组装盒;

       //为了显示构件,必须将构件放入组装盒中,并将组装盒放在窗口内;

    vbox = gtk_vbox_new (FALSE, 10);

    gtk_container_set_border_width (GTK_CONTAINER (vbox), 100);//设定宽度;

    gtk_container_add (GTK_CONTAINER (window), vbox);

    gtk_widget_show (vbox);

  

       //使用gtk_box_pack_start函数将构件放到组装盒中;

    sprintf (id_char, "%s ,My ID:%d", title,getpid ());            //显示PID号

    label = gtk_label_new (id_char);

    gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 10);

    gtk_widget_show (label);

   

    sprintf (id_char, "父进程ID:%d", getppid ());                 //显示PPID号

    label = gtk_label_new (id_char);

    gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 10);

    gtk_widget_show (label);

    button = gtk_button_new_with_label ("close");                  //关闭窗口按钮

   

   //信号登记函数,监听按钮的clicked事件。

   //当窗口clicked时, gtk_widget_destroy 就会被调用。

       //而 gtk_widget_destroy 函数又调用 gtk_main_quit() 结束程序运行。

    g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), window);

    gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 10);

    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);

    gtk_widget_grab_default (button);

       //函数显示窗口中的组件

    gtk_widget_show (button);

    gtk_widget_show (window);

       //准备将窗口和所有的组件显示在屏幕上,函数必须在GTK程序的最后调用.

    gtk_main ();

}

  ③编译代码main.c,运行;

    编译命令为:gcc -o a main.c `pkg-config --cflags --libs gtk+-2.0`

    程序运行结果如下图3-3所示:

4.内容三:掌握添加设备驱动程序的方法

1 内容要求

(1)采用模块方法,添加一个新的设备驱动程序。

(2)要求添加字符设备的驱动。

(3)编写一个应用程序,测试添加的驱动程序

2 设计过程及实现

(1)Linux内核中的设备驱动程序是一组常驻内存的具有特权的共享库,是低级硬件处理例程。对用户程序而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件,用户程序可以象对其它文件一样对此设备文件进行操作。

    Linux支持3种设备:字符设备、块设备和网络设备。

    设备由一个主设备号和一个次设备号标识。主设备号唯一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引。次设备号仅由设备驱动程序解释,一般用于识别在若干可能的硬件设备中,I/O请求所涉及到的那个设备。

    一个典型的驱动程序,大体上可以分为这么几个部分:

    ①注册设备:

    在系统初启,或者模块加载时候,必须将设备登记到相应的设备数组,并返回设备的主设备号;

    ②定义功能函数:

    对于每一个驱动函数来说,都有一些和此设备密切相关的功能函数。以最常用的块设备或者字符设备来说,都存在着诸如 open()、read()这一类的操作。当系统调用这些调用时,将自动的使用驱动函数中特定的模块。来实现具体的操作;

    ③卸载设备:

    在不用这个设备时,可以将它卸载,主要是从/proc 中取消这个设备的特殊文件。 

(2)编写Makefile文件如下:

# If KERNELRELEASE is defined, we've been invoked from the

# kernel build system and can use its language.

ifeq ($(KERNELRELEASE),)

    # Assume the source tree is where the running kernel was built

    # You should set KERNELDIR in the environment if it's elsewhere

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build

    # The current directory is passed to sub-makes as argument

    PWD := $(shell pwd)

modules:

  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:

  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:

  rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else

    # called from kernel build system: just declare what our modules are

    obj-m := devDrv.o

endif

      调用Makefile文件之后,其具体过程如下:

      ①KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义,所以make将读取执行else之后的内容;

      ②如果make的目标是clean,直接执行clean操作,然后结束。

    ③当make的目标为all时,-C $(KDIR)指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile。

      ④当从内核源码目录返回时,KERNELRELEASE已被定义,内核的build程序Kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。     ⑤else之前的内容为kbuild语法的语句,指明模块源码中各文件的依赖关系,以及要生成的目标模块名

(3)编写设备功能函数:(devDrv.mod.c)

      函数框架如下所示:

#include <linux/module.h>

#include <linux/vermagic.h>

#include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

__visible struct module __this_module

__attribute__((section(".gnu.linkonce.this_module"))) = {

    .name = KBUILD_MODNAME,

    .init = init_module,

#ifdef CONFIG_MODULE_UNLOAD

    .exit = cleanup_module,

#endif

    .arch = MODULE_ARCH_INIT,

};

static const struct modversion_info ____versions[]

__used

__attribute__((section("__versions"))) = {

    { 0x59caa4c3, __VMLINUX_SYMBOL_STR(module_layout) },

    { 0x6bc3fbc0, __VMLINUX_SYMBOL_STR(__unregister_chrdev) },

    { 0xbb2c2e33, __VMLINUX_SYMBOL_STR(__register_chrdev) },

    { 0x839fb39, __VMLINUX_SYMBOL_STR(try_module_get) },

    { 0x4f8b5ddb, __VMLINUX_SYMBOL_STR(_copy_to_user) },

    { 0x4f6b400b, __VMLINUX_SYMBOL_STR(_copy_from_user) },

    { 0x6d9da20b, __VMLINUX_SYMBOL_STR(module_put) },

    { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) },

    { 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) },

};

static const char __module_depends[]

__used

__attribute__((section(".modinfo"))) =

"depends=";

MODULE_INFO(srcversion, "EC04EE455AF92F2C3E445E0");

(4)设备加载,安装过程如下:

      ①进入Makefile文件和devDrv.mod.c文件所在目录,清除make产生的残留文件。命令为:

           make  clean

    ②删除先前可能加载过的模块,命令为:

           rmmod  /dev/devDrv  

      ③卸载设备:

           rm  /dev/devDrv

      ④编译设备文件,产生模块文件

           make

      ⑤加载模块

           sudo insmod  devDrv.ko

     ⑥ 查询设备号

           cat /proc/devices

     截图:

     

      ⑦加载设备,分配设别号

            sudo mknod /dev/test c 250 0

      ⑧更改用户对设备的操作权限为可读、可写

            sudo chmod 666 /dev/test

(5)测试结果:

       执行sa文件

       

运行test这个设备

输入123451234512345后的结果

5.课设感想

课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。这对我们这些学习有关网络以及计算机专业的学生来说既是一种挑战,又是一个难得的机会。通过这次嵌入式的课程设计让我们对linux系统有了更深的了解和应用。

实验一,这次是我的一次使用gtk这个编程环境,所以刚开始我上网查询了很多也学习了很多,终于在同学的帮助下,完成了相关代码的编写。

实验三,总体上来说,相对比较简单,编程简单,代码容易写。但是拿到题目的时候,却无从下手,不知道是干什么用的,怎么处理。通过在网上查阅相应资料,跟同学讨论,明白了编写字符设备驱动程序,其实格式是固定的,只需要写几个简单函数就可以了。 

一开始,不是很明白每个函数的作用,从网上下载的代码,看的也不是很明白,运行那些代码,发现可以正确运行。 

后来,经过仔细分析,研究,知道了每个函数的功能,就按照模板,编写自己的字符设备驱动程序。并且取得了成功。

相关推荐