6 1 Linux?

Document Sample
6 1 Linux? Powered By Docstoc
					嵌入式系统程序设计

 大连理工大学软件学院
 嵌入式系统工程系
 赖晓晨
Linux库       ★ ★★★



 Linux库概述
 库操作工具
 静态库
 共享库
 动态链接库
一、Linux库概述
 库的概念:库是操作系统或者编译器
 提供的一种目标文件,是可以被多个
 软件项目使用的二进制代码集。
 库是代码重用思想的体现。
 使用库可以节约编程人员大量的时间。
库分类
 静态库,是在执行程序运行前就已经加入到执
  行码中,在物理上成为执行程序的一部分。
 共享库,是在执行程序启动时加载到执行程序
  中,可以被多个执行程序共享使用。
 动态链接库,其实并不是一种真正的库类型,
  应该是一种库的使用技术,应用程序可以在运
  行过程中随时加载和使用库。
库命名约定
 所有库都以lib开头,表示一个库文件;
 文件名以.a结尾的是静态库,以.so结
  尾的是共享库。
共享库库名称约定
 共享库命名规则稍显繁琐,我们来区分一下
  一下命名:
  real name:包含库名、主版本号、次版本号
   以及发布号等字段,它代表文件中包含了库的
   代码,这是库的实体文件。
  soname(shared object name):库文件
   的一个符号链接,一般仅包括库名和主版本号。
  linkername:库文件的符号链接,它仅包含库
   名,一般供编译器使用。
  共享库库名称约定(续)
     看下面的例子:
#ls -l *png*
lrwxrwxrwx 1 root root libpng.so -> libpng12.so
lrwxrwxrwx 1 root root libpng.so.2 -> libpng.so.2.1.0.12
-rw-r--r-- 1 root root libpng.so.2.1.0.12

  在以上信息中:
   libpng.so.2.1.0.12是共享库的实名(realname)
   libpng.so.2是共享库so名(soname)
   libpng.so 则是连接名(linker name),用于编译连
    接。
常用库
   库            头文件         描述
libc.so         无           标准C库
libdb.so        db.h        数据库库
libm.so         math.h      数学库
libpthread.so   pthread.h   多线程库
libz.so         zlib.h      压缩例程库
libvga.so       vga.h       底层图形库
libcom_err.so   com_err.h   出错处理库
libdl.so        dlfcn.h     动态加载库
二、库操作工具
 Linux系统提供很多对库进行操作的工具,
  具体如下:
  nm命令
  ar命令
  ldd命令
  ldconfig命令
1. nm命令
 用途:列出库或目标文件的所有符号。
  查看程序调用什么函数
  查看一个给定的库或者目标文件是否提供了所
   需的函数。
 举例:下图列出了libc.so.6中所有包含sprintf的
 字符串的符号。
nm命令(续)
2. ar命令
 用途:可以建立一个归档文件,通常用来创
  建静态库。


 举例:建立静态库

 ar rc libmy.a file1.o file2.o …
3. ldd命令
 用途:列出为程序正常运行所需要的共享库
  。
 举例:利用ldd命令查看bash所依赖的库
  文件,如下图所示:
ldd命令(续)
4. ldconfig命令
当为系统安装好库文件之后,需要运行
ldconfig命令,其功能是根据
/etc/ld.so.conf中的路径检查库文件,并
为它们创建相应的soname,然后更改
ld.so.cache文件。
ldconfig命令(续)
 应用程序执行时,/lib目录下的程序ld-
  linux.so.X(X是版本号)会首先被运行,
  这就是Linux系统的程序装载器。
 装载器负责检查应用程序需要使用的共享库,
  从ld.so.conf指定的目录中找到这些库并
  加载,然后把加载信息写入缓存文件
  /lib/ld.conf.cache中供其他程序使用,
  以提高系统运行效率。
ldconfig命令(续)
 Linux系统下的一个环境变量:
  $LD_LIBRARY_PATH:是一个由冒号分隔
  的目录清单,包含了运行时的共享库,可以指
  示ld.so到何处搜索没有保存在标准位置的库。
  (对应文件为:/etc/ld.so.conf)
三、静态库
 静态库一般命名为libxxx.a,采用静态编
  译得到的程序文件比较大,因为整个函数库
  都已经被链接到程序中。
 静态库实质是目标文件的集合,采用ar命令
  可以创建静态库。首先编写源文件,然后把
  源文件分别编译为目标文件,注意使用-c选
  项,然后用ar命令把目标文件归档为一个静
  态库文件。
【例6-1】
/*    ch6_1 main.c   */
void hello();             静态库源文件:
void bye();
#include <stdio.h>
int main()
{
      hello();
      bye();
      return 0;
}
【例6-1】(续)
/*    ch6_1 hello.c      */
#include <stdio.h>                    静态库源文件:
void hello ()
{
      printf("hello everybody!\n");
}
/*    ch6_1 bye.c */
#include <stdio.h>
void bye()
{
      printf("goodbye!\n");
}
【例6-1】(续)
四、共享库
 共享库一般命名为libxxx.so,与静态库不
  同,共享库并不会在程序编译时被添加到可
  执行文件中,而是在程序执行时才会被链接,
  因此采用动态编译方式得到的可执行程序文
  件比较小,但是程序的执行依赖于环境,当
  前操作系统中必须存在程序需要的共享库,
  否则程序不能执行。
 编译共享库时要用gcc的-shared和-fPIC
  选项,前者表示编译为共享库,后者表示把
  库文件编译成位置无关代码,否则将来程序
  无法运行。
共享库的生成和使用方法
共享库(续)
用ldd命令检查main程序运行时所需要的
动态库,结果如下图所示:
库依赖关系
五、动态链接库
 打开共享库
 提取函数地址
 关闭共享库
 共享库错误函数
1. 打开共享库
 函数原型: void *dlopen (
    const char *libname, int
  flag);
 功能描述:将libname代表的库装载到
  内存,flag是打开共享库的方式。如果
  函数调用成功,返回库句柄,如果该库已
  经被装载过,则返回同样的句柄,如果调
  用失败,返回NULL。如果要装载的库依
  赖其他库,必须先装载依赖库。
打开共享库(续)
 功能描述:参数中的libname一般是库的绝对路径,
  这样dlopen会直接装载该文件;如果只是指定了库名
  称,在dlopen会按照下面的机制去搜寻:
  根据环境变量LD_LIBRARY_PATH查找;
  根据/etc/ld.so.cache查找;
  依次在/lib和/usr/lib目录查找。
 flag参数表示处理未定义函数的方式
  RTLD_LAZY:暂时不去处理未定义函数,先把库装载到内
   存,等用到没定义的函数再报错
  RTLD_NOW:马上检查是否存在未定义的函数,若存在,
   则dlopen以失败告终。
  RTLD_GLOBL:使共享库定义的符号全局可见。
2. 提取函数地址
 函数原型: void *dlsym(void *handle,
  char *symbol)
 功能描述:在dlopen之后,库被装载到内存。
  dlsym可以获得指定函数(symbol)在内存中的
  位置(指针)。如果找不到指定函数,则dlsym会
  返回NULL值。根据动态链接库操作句柄
  (handle)与符号(symbol),返回符号对应的函
  数的执行代码地址。
3. 关闭共享库
 函数原型为: int dlclose (void
  *handle);
 功能描述:将已经装载的库句柄减一,
  如果句柄减至零,则该库会被卸载。
4. 共享库错误函数
 函数原型: const char
  *dlerror(void);
 功能描述:当动态链接库操作函数
  (dlopen、dlsym、dlclose)执
  行失败时,dlerror可以返回出错信息,
  返回值为NULL时表示操作函数执行成
  功。
【例6-2】
/*     ch6_2 sub.h */
#ifndef SUB_H
                                   源文件
#define SUB_H
int square(int);
#endif
/*     ch6_2 sub.c */
#include <stdio.h>
int square(int a)
{
       printf("the square of the
number is:");
       return a*a;
}
【例6-2】(续)
/* ch6_2main.c */
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "sub.h"
int main()                         声明函数指针,将来用来
{                                    执行希望使用的函数
    void *handle;
    int (*fp)(int);
    char *error;
    int n;
    int result;
    printf("please input a number.\n");
    scanf("%d",&n);
    handle=dlopen("/lib/libmydll.so", RTLD_LAZY);
    if(!handle)
    {
         printf("%s\n",dlerror());
    }                                  打开动态链接库
    fp=dlsym(handle, "square");
    if((error=dlerror())!=NULL)
                                       RTLD_LAZY:
    {                                  只有在使用时才检查错误
         printf("%s\n",error);
         dlclose(handle);
         exit(1);
    }
    printf("now call the function square.\n");
    result = (*fp)(n);
    printf(" %d\n",result);
    dlclose(handle);
    return 0;
}
         handle=dlopen("/lib/libmydll.so", RTLD_LAZY);
    if(!handle)
    {                                   如未成功,handle为
         printf("%s\n",dlerror());
    }                                   NULL,则显示错误信息
    fp=dlsym(handle, "square");
    if((error=dlerror())!=NULL)
    {
         printf("%s\n",error);
         dlclose(handle);
         exit(1);
    }
    printf("now call the function square.\n");
    result = (*fp)(n);
    printf(" %d\n",result);
    dlclose(handle);
    return 0;
}
    handle=dlopen("/lib/libmydll.so", RTLD_LAZY);
    if(!handle)
    {
         printf("%s\n",dlerror());
    }
    fp=dlsym(handle, "square");
    if((error=dlerror())!=NULL)
    {
                                               找到需要的函数
         printf("%s\n",error);
         dlclose(handle);
         exit(1);
    }
    printf("now call the function square.\n");
    result = (*fp)(n);
    printf(" %d\n",result);
    dlclose(handle);
    return 0;
}
    handle=dlopen("/lib/libmydll.so", RTLD_LAZY);
    if(!handle)
    {
         printf("%s\n",dlerror());        如未找到函数,显
    }                                     示error中的错误
    fp=dlsym(handle, "square");
    if((error=dlerror())!=NULL)           信息
    {
         printf("%s\n",error);
         dlclose(handle);
         exit(1);
    }
    printf("now call the function square.\n");
    result = (*fp)(n);
    printf(" %d\n",result);
    dlclose(handle);
    return 0;
}
    handle=dlopen("/lib/libmydll.so", RTLD_LAZY);
    if(!handle)
    {
         printf("%s\n",dlerror());
    }
    fp=dlsym(handle, "square");
    if((error=dlerror())!=NULL)
    {
         printf("%s\n",error);
         dlclose(handle);
         exit(1);                                 用函数指针调用相
    }
    printf("now call the function square.\n");
                                                  应函数
    result = (*fp)(n);
    printf(" %d\n",result);
    dlclose(handle);
    return 0;
}
    handle=dlopen("/lib/libmydll.so", RTLD_LAZY);
    if(!handle)
    {
         printf("%s\n",dlerror());
    }
    fp=dlsym(handle, "square");
    if((error=dlerror())!=NULL)
    {
         printf("%s\n",error);
         dlclose(handle);
         exit(1);
    }
    printf("now call the function square.\n");
    result = (*fp)(n);
    printf(" %d\n",result);
    dlclose(handle);
    return 0;
}                                 关闭库
动态链接库建立步骤
 建立动态链接库
 gcc –shared –fPIC –o libmydll.so sub.c -wall
动态链接库建立步骤
 建立动态链接库
 gcc –shared –fPIC –o libmydll.so sub.c -wall

 移动动态链接库到系统标准库目录
 mv libmydll.so /lib
动态链接库建立步骤
 建立动态链接库
 gcc –shared –fPIC –o libdy2.so k1.c k2.c

 移动动态链接库到系统标准库目录
 mv libdy2.so /lib

 生成可执行文件
 gcc main.c –o main –lmydll -ldl -Wall
动态链接库建立步骤
 建立动态链接库
 gcc –shared –fPIC –o libmydll.so sub.c -wall

 移动动态链接库到系统标准库目录
 mv libdy2.so /lib

 生成可执行文件
 gcc main.c –o main–lmydll2 -ldl -Wall

 执行文件
 ./main
执行结果
嵌入式Linux操作系统
   嵌入式Linux操作系统简介
   启动引导程序vivi
   CRAMFS文件系统
   构建嵌入式Linux系统
一、嵌入式Linux操作系统简介
 嵌入式Linux是以Linux为基础,经过裁剪
  之后适用于嵌入式设备的操作系统,广泛应
  用在移动电话、PDA、媒体播放器、消费
  性电子产品以及航空航天等领域。Linux系
  统具有开源、可裁剪、免费、完全支持
  TCP/IP协议、可移植性好、运行稳定等特
  点,嵌入式Linux继承了这些特性。
嵌入式Linux操作系统简介(续)
 与uClinux系统相同,基本的嵌入式
  Linux操作系统包括三个组成部分:
  Bootloader,负责引导系统;操作系统内
  核,负责管理硬件,为上层软件提供运行环
  境;文件系统,负责管理文件。
Linux内核源码目录树
 arch:包含所有体系结构相关的内核代码,
  可以在其中找到Linux目前支持的所有硬件
  体系结构;
 kernel:包含Linux内核代码。
 drivers:包含设备驱动程序源代码;
 fs:包含文件系统实现代码;
Linux内核源码目录树(续)
 include:包含各种体系结构下编译内核所
  需要的头文件;
 init:包含内核初始化源代码;
 ipc:包含进程间通信源代码;
 mm:包含内存管理源代码;
 net:包括网络相关源代码。
二、启动引导程序vivi
   vivi简介
   vivi的工作过程
   vivi的工作模式
   vivi的命令接口
   vivi命令实现的数据结构
1. vivi简介
 vivi是韩国mizi公司开发的BootLoader,
  其结构简洁,易于扩展,非常适合运行于
  ARM9处理器,支持S3C2410X,被许多
  底层程序员广泛采用。
 vivi的代码包括200多个文件,散布在
  arch、init、lib、drivers和include等
  几个目录中。
2. vivi的工作过程
 vivi执行分为两个阶段:
  主要完成硬件相关部分操作,常用汇编语言编写;完成功能包
   括:硬件初始化;为加载BootLoader的第二部分准备内存
   空间;复制第二部分到RAM中;设置堆栈;跳转到第二阶段
   的入口点。
  完成硬件无关操作,常用C语言编写;完成功能包括:清理内
   存,为系统运行准备空间;初始化硬件定时器,设置GPIO引
   脚功能;建立页表、启动MMU,进行存储器系统初始化;堆
   空间初始化;MTD设备初始化;初始化内核启动参数;初始
   化vivi内置命令;根据终端输入选择进入vivi命令行或者引导
   Linux内核。
3. vivi的工作模式
 vivi支持两种工作模式
  启动加载模式:设备正常运行状态下启动时
   vivi的工作模式,vivi负责把操作系统内核从
   某种非易失性存储器中复制到RAM中,并跳转
   到操作系统内核处开始执行。
  下载模式:系统调试时vivi的工作方式。vivi
   通过目标机的串口连接或者网络连接把操作系
   统内核或者根文件系统映像从宿主机下载到目
   标机内存中。
4. vivi的命令接口
 vivi支持很多种命令。在Windows超级终
  端或Linux的minicom下,进入vivi后,
  按下除回车键之外的任意键,都可以进入到
  vivi提示符,通过vivi命令实现各种操作。
 利用help命令尅查看vivi支持哪些命令,
  在某些命令后面加help可以查看该命令的
  用法。
    5. vivi命令实现的数据结构
     文件vivi/include/command.h中的
      user-command-t是vivi命令实现的核
      心数据结构:

tpyedef struct user-command
{
      const char* name;
      void (*cmdfunc)(int argc, const char **);
      struct user-command* next-cmd;
      const char* helpstr;
}user-command-t;
vivi命令实现的数据结构(续)
 vivi每一个命令都是这个数据结构类型的一
  个实例。user-command-t结构中,
  name代表命令的名称;函数指针
  cmdfunc指向命令的实现代码,第一个参
  数表示命令行参数的个数,第二个参数代表
  命令行中的各个字符串,这两个参数的意义
  类似主函数的参数;next-cmd是同种类
  型的结构指针,用来构建一张单链表;
  helpstr指向此命令的帮助信息。
三、CRAMFS文件系统
 CRAMFS是专门针对闪存设计的只读文件
  系统。它是一种压缩的文件系统,存在于
  Flash中,当系统运行需要某一部分数据时,
  CRAMFS会实时计算该部分数据解压缩后
  的容量,然后从内存中分配相应的空间,将
  其解压缩到内存中。
CRAMFS文件系统(续)
 一个完整的CRAMFS文件系统通常包含以下
  几个目录:
  /linuxrc:启动脚本文件,负责进行系统启动时
   的配置。
  /bin:保存常用命令。
  /sbin:保存系统相关命令,其中最重要的是供内
   核初始化之后执行的/sbin/init程序。
  /etc:保存配置文件。
CRAMFS文件系统(续)
 /lib:保存系统运行所需要的库文件。
 /dev:保存设备驱动程序。
 /usr:保存用户程序和配置文件,可以根据需
  要进行设置。
 /mnt:用于设备安装的目录。
 /proc:内存文件系统,存放代表系统运行状态
  的文件。
  CRAMFS文件系统(续)
   构造CRAMFS时,可以从
    http://sourceforge.net/projects/
    cramfs下载源码包cramfs-1.1.tar.gz,
    然后解压缩、编译生成可执行文件。


# tar zxvf cramfs-1.1.tar.gz
# cd cramfs-1.1
# make
CRAMFS文件系统(续)
 编译之后生成可执行文件mkcramfs,下面是
  mkcramfs的命令格式:
 mkcramfs [-h] [-e edition] [-i file] [-n name]
   dirname outfile
  -h:显示帮助信息。
  -e edition:设置生成的文件系统的版本号。
  -i file:将一个文件映像插入这个文件系统中。
  -n name:设定mkcramfs文件系统的名字。
  dirname:指明需要被压缩的整个目录树。
  outfile:最终输出文件。
四、构建嵌入式Linux系统
 移植BootLoader
 配置编译内核源码
 制作文件系统
1. 移植BootLoader
 准备好vivi源码,修改Makefile文件,指
  定目标体系结构arm,交叉编译工具前缀
  为arm-linux-,注意工具链的路径要设置
  正确;然后按照目标板的实际情况设置vivi
  运行的硬件地址;交叉编译vivi。本阶段依
  次运行:
  $make clean
  $make menuconfig
  $make
2. 配置编译内核源码
 首先修改Makefile文件,把内核运行的目标平台
  改为2410处理器,修改交叉编译器前缀为arm-
  linux-,注意工具链的路径要设置正确;然后按
  照目标板RAM、Flash的实际情况配置硬件地址;
  配置串口,设置正确的波特率。本阶段依次运行:
    $make mrproper
    $make xconfig
    $make dep
    $make clean
    $make zImage
3. 制作文件系统
 首先创建根目录,在其中新建bin、dev、etc、
  usr、lib、sbin等目录;下载BusyBox源码,
  配置、交叉编译和安装BusyBox,注意目标
  平台指定为arm、交叉编译器前缀为arm-
  linux-,注意工具链的路径要设置正确;复制
  需要的C库到文件系统目录树中;编写需要的
  配置文件;上述工作完成之后,使用文件系统
  生成工具mkcramfs来生成文件系统的镜像文
  件。
结果
     把vivi、内
     核和文件
     系统烧写
     到Flash中,
     重新启动
     目标机,
     操作成功
     出现如图
     所示:
嵌入式Linux驱动程序设计
 编写驱动程序
 测试驱动程序
 执行步骤
一、编写驱动程序
       Vcc         Vcc




         R1

              R2         Q1
 PB0


                         1
                              BUZZER
                         2


                   GND


       蜂鸣器
【例6-3】蜂鸣器驱动程序
 蜂鸣器驱动程序,由4个文件组成。分别是
  蜂鸣器驱动程序buzzer_driver.c、编译
  驱动程序使用的Makefile_driver文件、
  测试程序buzzer_test.c以及编译测试程
  序的makefile_test。
/* ch6_3蜂鸣器驱动程序           */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/arch-s3c2410/s3c2410.h>
#define GPB_CTL_BASE io_p2v(0x56000010)
#define S3C2410_GPBCON (GPB_CTL_BASE + 0x0)
#define S3C2410_GPBDAT (GPB_CTL_BASE + 0x4)
struct unit {
u32 *GPB_CON;
u32 *GPB_DAT;
};
static struct unit buzzer_unit = {
.GPB_CON        = (u32 *)S3C2410_GPBCON,
.GPB_DAT        = (u32 *)S3C2410_GPBDAT,
};


ssize_t Buzzer_open(struct inode * inode, struct file *
file)
{
MOD_INC_USE_COUNT;
file->private_data = &buzzer_unit;
return 0;
}
ssize_t Buzzer_release(struct inode * inode, struct file
* file)
{
MOD_DEC_USE_COUNT;
return 0;
}
static void buzzer_set_value(struct unit *unit, u8 val)
{
u32 temp;
if(val==1)
    *unit->GPB_DAT = *unit->GPB_DAT & ~0x1;
else
    *unit->GPB_DAT = *unit->GPB_DAT | 0x1;
}
ssize_t Buzzer_write(struct file * file, const char * buf,
                      size_t count, loff_t * offset)
{
char temp;
int ret;
struct unit *unit = (struct unit *)file->private_data;
ret = copy_from_user(&temp,buf,count);
if(ret!=0)
{
    printk("wrong!\n");
    return -EFAULT;
}
else
    buzzer_set_value(unit, temp);
return ret;
}
struct file_operations Buzzer_Ctl_ops =
{
open: Buzzer_open,
write: Buzzer_write,
release: Buzzer_release,
};


static devfs_handle_t devfs_handle,devfs_buzzer_dir;
static void __init buzzer_init(struct unit *unit)
{
*unit->GPB_CON &= ~0x2;
*unit->GPB_CON |= 0x1;
*unit->GPB_DAT |= 0x1;
}
int __init init_Buzzer(void)
{
int res;
printk("This is my buzzer driver!\n");
devfs_register_chrdev(201, "buzzer",
&Buzzer_Ctl_ops);
devfs_buzzer_dir = devfs_mk_dir(NULL, "buzzer",
NULL);
devfs_handle = devfs_register(devfs_buzzer_dir, "0",
    DEVFS_FL_DEFAULT, 201, 0,S_IFCHR | S_IRUSR |
    S_IWUSR,&Buzzer_Ctl_ops, NULL);
buzzer_init(&buzzer_unit);
printk("Efault =: %d\n",EFAULT);
return 0;
}
static void __exit clean_Buzzer(void)
{
devfs_unregister_chrdev(201,"buzzer");
devfs_unregister(devfs_handle);
devfs_unregister(devfs_buzzer_dir);
}


module_init(init_Buzzer);
module_exit(clean_Buzzer);
MODULE_DESCRIPTION("EduKitIII-2410 buzzer
driver");
MODULE_LICENSE("GPL");
    驱动程序的Makefile脚本
# ch6_3 驱动程序编译Makefile
# Makefile for the kernel i2c driver (Module).
#
WKDIR       = /usr/local/src/edukit-2410
CROSSDIR = /usr
INSTALLDIR     = /home/app
MODDEV      = buzzer.o
MODFILE        = buzzer.c
MODFILE_H =
CROSS=arm-linux-
CC = $(CROSS)gcc
AS = $(CROSS)as
MACRO = -DMODULE -D__KERNEL__ -
DCONFIG_KERNELD
Makefile脚本
ifdef DEBUG
CFLAGS = -g
endif
CFLAGS = -O2 -fomit-frame-pointer
CFLAGS += $(MACRO) -mapcs-32 -march=armv4 -
mtune=arm9tdmi -fno-builtin
INCLUDES = -I$(WKDIR)/kernel/include\
-I$(CROSSDIR)/arm-linux/include \
-I$(CROSSDIR)/lib/gcc-lib/arm-linux/2.95.3/include \
Makefile脚本 $(MODFILE_H) Makefile
$(MODDEV): $(MODFILE)
$(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $<
install: $(MODDEV)
mkdir -p $(INSTALLDIR)
cp --target-dir=$(INSTALLDIR) $(MODDEV)
clean:
-rm -f $(MODDEV)
二、测试驱动程序
 测试程序中,首先打开蜂鸣器设备文件,通
  过write()系统调用,以1秒为间隔,不断
  向蜂鸣器设备中写1和写0,控制蜂鸣器间
  隔发声。测试程序代码如下:
/* ch6_3蜂鸣器测试程序         */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/fcntl.h>


int main(int argc, char** argv)
{
    int fd, on, off;
    int i=0;
    static char *driver = "/dev/buzzer/0";
    on = 1;
    off =0;
    printf("BUZZER test example base on Linux. \n");
    fd = open(driver, O_RDWR);
if(fd <0)
{
    printf("Can't not open %s\n",driver);
    return fd;
}
for(;i<10;i++)
{
    if(i%2==0)
    {
        write(fd, &on, 1);
        printf("Buzzer ON!\n");
        usleep(1000*1000);
    }
else
        {
            write(fd, &off, 1);
            printf("Buzzer OFF!\n");
            usleep(1000*1000);
        }
    }
    printf(" end.\n");
    close(fd);
    return 0;
}
  编译测试程序的Makefile脚本
# ch6_3 测试程序编译Makefile
# Makefile for Linux application test example.
LINUXDIR    = /usr/local/src/edukit-2410/kernel
CROSSDIR = /usr
INSTALLDIR     = /home/app
TESTFILE    = buzzer-test
SRCFILE     = buzzer-test.c
TESTFILE_H=
CROSS=arm-linux-
CC = $(CROSS)gcc
AS = $(CROSS)as
LD = $(CROSS)ld
ifdef DEBUG
  CFLAGS = -g
else
  CFLAGS = -O2 -fomit-frame-pointer
endif
CFLAGS += -mapcs-32 -march=armv4 -mtune=arm9tdmi -
fno-builtin
INCLUDES = -I$(LINUXDIR)/include \
         -I$(CROSSDIR)/arm-linux/include \
         -I$(CROSSDIR)/lib/gcc-lib/arm-
linux/2.95.3/include
CFLAGS +=$(INCLUDES)
CRYPT    = $(CROSSDIR)/arm-linux/lib/crt1.o \
         $(CROSSDIR)/arm-linux/lib/crti.o \
         $(CROSSDIR)/arm-linux/lib/crtn.o
LIBDIR    = -L$(CROSSDIR)/arm-linux/lib/ \
          -L$(CROSSDIR)/lib/gcc-lib/arm-linux/2.95.3
LDFLAGS += $(LIBDIR) -nostartfiles -static
all:   $(TESTFILE)
$(TESTFILE): $(SRCFILE) $(TESTFILE_H) Makefile
   $(CC) $(CFLAGS) -o $@ $@.c
clean:
   rm -f $(TESTFILE)
install: $(TESTFILE)
   mkdir -p $(INSTALLDIR)
   cp --target-dir=$(INSTALLDIR) $(TESTFILE)
   cp led.o $(INSTALLDIR)
三、执行步骤
 1. 用仿真器连接宿主机与目标机,用串口线连
  接宿主机和目标机串口0,用网线连接宿主机
  和目标机的网络端口,配置二者IP地址到同一
  网段,用ping命令检测网络连接是否正常。打
  开windows超级终端或者Linux的
  minicom,运行tftp服务器程序,配置tftp
  服务器默认目录为源文件所在目录。
执行步骤(续)
 2. 安装arm-linux-gcc工具链,交叉编译驱
  动程序源文件,得到驱动模块buzzer.o;交
  叉编译测试程序源文件,得到测试程序
  buzzer-test。
 3. 使用tftp协议下载驱动模块到目标机的
  /tmp目录下。使用insmod命令插入模块,
  此时超级终端会显示“This is my buzzer
  driver!”
执行步骤(续)
 4. 用ls命令显示/dev下文件列表,如下图所
  示,可以看到已经生成buzzer目录,进一步
  观察发现此目录中生成了名为0的设备。下载
  测试程序buzzer-test,修改文件访问权限为
  八进制数766,执行测试程序,可以看到输出
  为交替出现的“Buzzer ON!”和“Buzzer
  OFF! ”,同时听到蜂鸣器以1秒为间隔间断响起
  ,说明驱动程序工作正常。
执行步骤(续)
  直接建立设备文件
   也可以不在/dev下建立buzzer目录,而直接
    建立蜂鸣器的设备文件,方法是删去驱动程序
    的init_Buzzer()函数中以下两行:


devfs_buzzer_dir = devfs_mk_dir(NULL, "buzzer", NULL);
     devfs_handle = devfs_register(devfs_buzzer_dir, "0",
DEVFS_FL_DEFAULT, 201, \
0,S_IFCHR | S_IRUSR | S_IWUSR,&Buzzer_Ctl_ops, NULL);
  直接建立设备文件(续)
   在原位置增加下面这一行:
devfs_handle = devfs_register(NULL, "0", DEVFS_FL_DEFAU
LT, 201, \
0,S_IFCHR | S_IRUSR | S_IWUSR,&Buzzer_Ctl_ops, NULL);
   与此对应的测试程序也要修改,删去
    buzzer_test.c中的如下行:

static char *driver = "/dev/buzzer/0";
   在原位置添加如下行:

static char *driver = "/dev/0";
Framebuffer技术
 Framebuffer是2.2版本Linux内核之后出
  现的一种显示接口,也称为帧缓冲技术。
 Framebuffer缓冲区是内存中的一块区域,
  其中的每个单元按照一维编址,而显示器是按
  照二维编址,要使Framebuffer的每一个单
  元与显示器的每一个点对应起来,需要一个映
  射算法。
Framebuffer与lcd象素关系
 两色图:只有黑白两色,一个象素用一个二
  进制位表示。
  10101010表示黑白相间的8个点
 四色图:用两个二进制位表示一个象素点
  10101010表示颜色值为10,长度为4的一条
   直线
Framebuffer与lcd象素关系(续)
 Framebuffer的大小如下公式所示:

screensize = lcd.x * lcd.y * bit_per_pixel / 8

 例:320×240的黑白屏,需要的
  framebuffer大小为

  screensize = 320 * 240 * 1 / 8 = 9600B
Framebuffer与lcd象素关系(续)
 例:320×240屏,16位色,需要的
  framebuffer大小为

screensize = 320 * 240 * 16 / 8 = 153600B
Framebuffer映射关系
程序   用户空间         内核空间Framebuffer缓冲区        显示屏
                                    0   m            Xmax
                         0                                  0
应
用                                                           n
程    显示
序    缓冲                                                     Ymax
     区在
     应用
                              ...           c位颜色深度
     程序
     中的
     映射     (n×Xmax+m)×c/8
                              ...

                Xmax×Ymax-1
帧缓冲区驱动
 实现帧缓冲区驱动主要基于内核中的两个文件:
  linux/include/linux/fb.h
  linux/drivers/video/fbmem.c
 fb.h中定义了Framebuffer中一些重要的数
  据结构,主要有三个:
  struct fb_var_screeninfo
  struct fb_fix_screeninfo
  struct fb_info
struct fb_var_screeninfo
 记录了帧缓冲设备和指定显示模式的可修改
  信息,包括显示器的分辨率、颜色深度等,
  通常是被用户设置的。该结构在内核中定义
  如下:
struct fb_var_screeninfo
{
    __u32 xres;
    __u32 yres;
    __u32 xres_virtual;
    __u32 yres_virtual;
    __u32 xoffset;
    __u32 yoffset;
    __u32 bits_per_pixel;
    __u32 grayscale;
    struct fb_bitfield red;
    struct fb_bitfield green;
    struct fb_bitfield blue;
    struct fb_bitfield transp;
    __u32 nonstd;
    __u32 activate;
    __u32 height;
    __u32 width;
    __u32 accel_flags;
    __u32 pixclock;
    __u32 left_margin;
    __u32 right_margin;
    __u32 upper_margin;
    __u32 lower_margin;
    __u32 hsync_len;
    __u32 vsync_len;
    __u32 sync;
    __u32 vmode;
    __u32 rotate;
    __u32 reserved[5];
}
struct fb_fix_screeninfo
 定义了图形卡的硬件特性, 是不能改变的,
  用户选定了哪一个图形卡,那么它的硬件特
  性也就定下来了。该数据结构包含了屏幕缓
  冲区的物理地址、长度、显示类型等不可修
  改的信息,用于用户空间的调用。该结构在
  内核中的定义如下:
struct fb_fix_screeninfo
{
    char id[16];
    unsigned long smem_start;
    __u32 smem_len;
    __u32 type;
    __u32 type_aux;
    __u32 visual;
    __u16 xpanstep;
    __u16 yanstep;
    __u16 ywrapstep;
    __u32 line_length;
    unsigned long mmio_start;
    __u32 mmio_len;
    __u32 accel;
    __u16 reserved[3];
    …
    struct fb_ops * fbops;
    struct device *device;
    struct device *dev;
    int class_flag;
    char __iomem *screen_base;
    unsigned long screen_size;
    void *pseudo_palette;
    u32 state;
    void *par;
}
struct fb_info
 定义了当前图形卡Framebuffer 设备的
  独立状态,一个图形卡可能有两个
  Framebuffer, 在这种情况下,就需要
  两个fb_info 结构。该结构在内核中的定
  义如下:
struct fb_info
{
    int node;
    int flags;
    struct fb_var_screeninfo var;
    struct fb_fix_screeninfo fix;
    struct fb_monspecs monspecs;
    struct work_struct queue;
    struct fb_pixmap pixmap;
    struct fb_pixmap sprite;
    struct fb_cmap cmap;
    struct list_head modelist;
    struct fb_videomode *mode;
}
Framebuffer常用操作
 读写操作:读写帧缓冲区。
 映射操作:利用mmap()函数把内核空间的显示缓冲
  区映射到用户空间应用程序自己的虚拟地址空间中,
  使用户应用程序可以通过访问虚拟地址空间实现直接
  写屏。
 I/O控制:ioctl()是设备驱动程序中对设备的I/O通
  道进行管理的函数,可以对设备的一些特性进行控制,
  以及获得显示设备的某些信息,包括一些固定信息,
  例如显示内存大小;还包括与显示模式相关的可变信
  息,例如分辨率、像素结构、每扫描线的字节宽度,
  以及伪彩色模式下的调色板信息等等。
Framebuffer的具体操作流程
 打开/dev /fb 设备文件。
 用ioctl()函数取得当前显示屏幕的参数,
  如屏幕分辨率、每个像素点的比特数。根据
  屏幕参数可计算屏幕缓冲区的大小,将屏幕
  缓冲区映射到用户空间。
 直接读写屏幕缓冲区,进行绘图和图片显示。
基于Framebuffer的图形界面
   画点函数
   画线函数
   文字显示
   位图显示
一、画点函数
 画点函数可以完成在屏幕上的(x,y)坐标
  处绘制一个确定颜色值的点。函数中要完成
  两维屏幕上点的位置到一维编址的内存单元
  的映射,即找到当前点在Frambuffer中
  对应的位置,然后向此位置写入一个代表颜
  色的数值。
    画点函数(续)
     draw_dot()函数完成了在320×240分
      辨率、256色显示器上显示一个点的功能,
      定义如下:

void draw_dot(int x, int y, uint8_t c)//横坐标,纵坐标,颜色值
{
      uint32_t offset;
      uint8_t color = c;
      offset = y * 320 + y;
      fb_memcp((void *)(pFbdev->fb_mem + pFbdev->
      fb_mem_offset + offset), &color, 1)
}
    画点函数(续)
     下面看一下fb_memcpy()函数定义:
void fb_memcpy(void *addr, void *color, size_t len)
{
       memcpy(addr, color, len);
}
     memcpy()函数原型如下:

#include<string.h>
void * memcpy(void *dest, const void *src, size_t n);
二、画线函数
 画点函数是所有绘图函数的基础,画点函数
  的参数有三个:横坐标、纵坐标、颜色值。


void对于16位色图象,可以直接把color值
    setpixel(short x, short y, short color);
 赋到内存相应位置。
画线函数(续)
 画线函数采用Bresenham算法
    【例6-4】
/* ch6_4.c 画线算法1             */
static inline void draw_yline(short x, short y, short dx, short dy, short
xdir)
{
    short dx2=dx+dx;
    short dx2mdy2=dx+dx-dy-dy;
    short error=dx+dx-dy;
    setpixel(x, y, color);
    while(dy--)
    {
    【例6-4】
    if(error>0)
     {
            x+=xdir;
            error+=dx2mdy2;
        }
        else
        {
            error+=dx2;
        }
        y++;
        setpixel(x, y, color);
    }
    return ;
}
void line(short x1, short y1, short x2, short y2)
{
    short dx, dy;
    //令1点的y值小于2点的y值
    if(y1>y2)
    {
          short t=y1;
          y1=y2;
          y2=t;
          t=x1;
          x1=x2;
          x2=t;
    }
void line(short x1, short y1, short x2, short y2)
{   【例6-4】
     short dx, dy;
     //令1点的y值小于2点的y值
     if(y1>y2)
     {
          short t=y1;
          y1=y2;
          y2=t;
          t=x1;
          x1=x2;
          x2=t;
     }
    //求出差值
    dx=x2-x1;
    dy=y2-y1;
    //2点在1点右侧
    else
    {
           dx=-dx;            //令差值总为正
           if(dx>dy)          //直线斜率小
                  draw_xline(x1, y1, dx, dy, -1);
           else           //直线斜率大
                  draw_yline(x1, y1, dx, dy, -1);
    }
}
画线函数(续)
 绘制直线算法2流程图:
                            直线斜率
               Y            大于 ?
                              1           N

           y=Min(y1 , y2)          x=Min(x1 , x2)


             计算 的值
               x                     计算 的值
                                       y


             画点 ,y)
               (x                    画点 ,y)
                                       (x


              y=y+1                   x=x+1


       Y   Y<=Max(y1,y2)         x<=Max(x1,x2)      Y
               N                          N
                            结束
     【例6-4】
/*   ch6_5.c 画线算法2             */
void draw_line(PFBDEV pFbdev, int x1, int y1, int x2, int y2, uint8_t c)
{
     int x, y;
     if((MAX(y1,y2)-MIN(y1,y2)) > (MAX(x1,x2)-MIN(x1,x2)))
     {
          for( y = MIN(y1,y2); y <= MAX(y1,y2); y++ )
          {
                 x = ( x2 - x1 ) * ( y - y1 ) / ( y2 - y1 ) + x1;
                 draw_dot(pFbdev, x, y, c);
          }
     }
    else
    {
        for( x = MIN(x1,x2); x <= MAX(x1,x2); x++ )
        {
               y = ( y2 - y1 ) * ( x - x1 ) / ( x2 - x1 ) + y1;
               draw_dot(pFbdev, x, y, c);
        }
    }
}
三、文字显示
 计算机处理汉字信息的前提条件是对每个汉
  字进行编码,这些编码统称为汉字编码。汉
  字编码主要有国标码、区位码、机内码等。
  国标码:汉字信息处理系统之间或通信系统之
   间传输信息时,对每一个汉字所规定的统一编
   码。
  区位码:将GB2312-80的全部字符集组成一
   个94×94的方阵
文字显示(续)
 机内码:机内码是保存在计算机中或文件中的
  汉字编码,它是十六进制编码。
 汉字字形码:汉字字形码是表示汉字字形的数
  据编码,通常用点阵、矢量函数等方式表示,
  又称为字模。用点阵表示字形时,汉字字形码
  一般指确定汉字字体的点阵代码。字形码是汉
  字的输出形式,随着汉字字形点阵和格式的不
  同,汉字字形码也不同。常用的字形点阵有
  16×16点阵、24×24点阵、48×48点阵等
  等。
文字显示(续)
 汉字机内码、国标码和区位码三者之间的关系为:
  区位码(十进制)的两个字节分别转换为十六进制
  后加20H得到对应的国标码;机内码是汉字交换
  码(国标码)两个字节的最高位分别加1,即汉字
  交换码(国标码)的两个字节分别加80H得到对
  应的机内码;区位码(十进制)的两个字节分别转
  换为十六进制后加A0H得到对应的机内码。
     【例6-6】
/*   ch6_6.c 显示字符、数字、汉字*/
void Lcd_Hz24(PFBDEV pFbdev,UINT16T x0,UINT16T y0,INT8T
*s,uint8_t c)
{
     UINT16T i,j,k,x,y,xx;
     INT8T qm,wm;       //区位码
     long int offset;
     INT8T hzbuf[72],temp[2];
     for(i=0;i<strlen((const char*)s);i++)
     {
if(((INT8T)(*(s+i)))<161)
{
    temp[0]=*(s+i);
    temp[1]='\0';
    offset = temp[0] * 8;
    for(j=0;j<8;j++)
    {
        hzbuf[j] = fontdata_8x8[offset+j];
    }
    for(y=0;y<8;y++)//the height is 8
    {
         for(x=0;x<8;x++)//the length is 8
         {
       k=x%8;
       if(hzbuf[y*1+x/8]&(0x80>>k))
       {
           xx=x0+x+i*8;
           draw_dot(pFbdev,xx,y+y0,c);
       }//end if
     }//end for
    }//end for
}
else
{
    qm=*(s+i)-176;//area code
    wm=*(s+i+1)-161;//location code
    offset=(long int)(qm*94+wm)*72;//the actual location
for(y=0;y<8;y++)//the height is 8
{
    for(x=0;x<8;x++)//the length is 8
    {
           k=x%8;
           if(hzbuf[y*1+x/8]&(0x80>>k))
           {
               xx=x0+x+i*8;
               draw_dot(pFbdev,xx,y+y0,c);
           }//end if
         }//end for
        }//end for
    }
for(j=0;j<72;j++)
{
    //put the codes of the Chinese        charactor into the buffer
    hzbuf[j]=g_auc_hzk24[offset+j];
}
for(y=0;y<24;y++)//the height is 24
{
    for(x=0;x<24;x++)//the length is 24
    {
        k=x%8;
          if(hzbuf[y*3+x/8]&(0x80>>k))
          {
              xx=x0+x+i*12;
              draw_dot(pFbdev,xx,y+y0,c);
          }//end if
        }//end for
       }//end for
       i++;
     }//end else
    }//end for
}
绘制字符串算法
                   找 到 待 绘 制 字 符 内 码



                           是 汉 字 ?
               Y                            N

      计 算 区 码                              找 到 字 符 字 模


      计 算 位 码                                   绘 制 字 形

                                      Y
    找 到 汉 字 字 模                                 绘 制 完 成
                                                     N
      绘 制 字 形
                                           定 位 下 一 字 符

      绘 制 完 成          Y

           N
    定 位 下 一 字 符                      结 束
    四、位图显示
/*   ch6_7.c 位图显示*/
//描述位图头信息的结构体
typedef struct
{
     unsigned char id[2];
     long filesize;
     short reserved[2];
     long headsize;
     long infosize;
     long width;
     long height;
    short planes;
    short bits;
    long biCompression;
    long sizeimage;
    long biXpp;
    long biYpp;
    long biclrused;
    long biclrimportant;
}BMPHEAD;
//图片采用555存储方式时
void color_555_draw_bmp(short x,short y,unsigned short
width,unsigned short height,char *buf)
{
    long i,j,offset;
    unsigned short tmp,red,green,blue;
    //不超出屏幕高度且间隔不超过图象高度
    for(j=y;j<ScreenHeight&&(j-y)<height;j++)
    {
        //不超出屏幕宽度且间隔不超过图象宽度
            for(i=x;i<ScreenWidth&&(i-x)<width;i++)
        {
                offset=(j-y)*width*2+(i-x)*2;   //计算偏移量
                //取得偏移量处的图象数值
                tmp=*(unsigned short*)(buf+offset);
                red=(tmp&0x7c00)<<1;            //分别计算红、绿、蓝分量
                green=(tmp&0x03e0)<<1;
                tmp&=0x001f;
                tmp|=red|green;
                //把颜色值写到缓存
                *(unsigned short*)(screen_ptr+j*240*2+2*i)=tmp;
            }
    }
}
void color_565_draw_bmp(short x,short y,unsigned short
width,unsigned short height,char *buf)
{
    long i,j,offset;
    for(j=y; j<ScreenHeight&&(j-y)<height; j++)
    {
         for(i=x; i<ScreenWidth&&(i-x)<width; i++)
         {
              offset=(j-y)*width*2+(i-x)*2;
              tmp=*(unsigned short*)(buf+offset);
              *(unsignedshort*)(screen_ptr+j*ScreenWidth*2+2*i)
                  =tmp;
         }
    }
}
//这个函数在屏幕的x,y坐标处绘制出文件filename中的bmp文件。
void ShowBMP(char *filename,short x,short y)
{
    //定义相关的变量的信息
    BMPHEAD bmp_inf;
    FILE *fp;
    char Tmp,*buf,*buf1,*buf2,c;
    int width,height;
    int red,green,blue;
    long aver_size,size,i,m,j,k;
    //打开Bmp文件,如果不能打开该文件,则直接退出。
    fp=fopen(filename,"rb");
    if(!fp)
    {
         printf("open file failure! \n")
         return;
    }
//省略最初的2个字节,这两个字节存储的是“BM”这两个字母。
fseek(fp,2L,0);
//读出文件的长度
fread(&bmp_inf.bfSize,4,1,fp);
fseek(fp,22L,0);
//读出BMP图像的宽度和高度。
fread(&bmp_inf.biWidth,4,1,fp);
fread(&bmp_inf.biHeight,4,1,fp);
//在不同的操作系统中要注意字节序的大小端,如果需要,就需要进行调整。
//计算图像文件占用空间的大小
size=bmp_inf.biWidth*bmp_inf.biHeight*2;
//在内存中开辟一块内存空间来存储图像
buf=(char*)malloc(size);
//BMP默认的数据的顺序和实际需要显示的顺序正好相反
//因此需要在这里上下调整一下顺序
    for(i=0;i<(bmp_inf.biHeight>>1);i++)
    {
        for(k=i*bmp_inf.biWidth*2, j=0; j<bmp_inf.biWidth*2;
             j++)
        {
             Tmp=buf[k+j];
             buf[k+j]=buf[size-k-bmp_inf.biWidth*2+j];
             buf[size-k-bmp_inf.biWidth*2+j]=Tmp;
        }
    }
    //16位色的显示有2种制式,分别为555和565。
    //这个要根据该位图是采用555还是565方式来决定如何显示到LCD上。
    color_555_draw_bmp(x,y, bmp_inf.biWidth,bmp_inf.biHeight,buf);
    //color_565_draw_bmp(x,y,bmp_inf.biWidth,bmp_inf.biHeight,buf);
    free(buf);
}
  【例6-8】
/* ch6_8.c 图形系统框架*/
#define INIT       -1
#define ON_CLOSE            0
#define ON_FILE_MENU             1
#define ON_SETTING_MENU              2
#define ON_HELP_MENU 3
#define ON_CLEAR_MENU 4
#define ON_VIEW             5
#define INVALID         6
#define ON_FILE_SHOW            10
#define ON_FILE_CLOSE 11
#define ON_SETTING_SINGLE 20
#define ON_SETTING_COLOR 21
#define RECTANGLE         603
#define ELLIPSE         604
#define FILE_NOW         701
#define SETTING_NOW            702
#define HELP_NOW         703
typedef struct
{
    unsigned short pressure;
    unsigned short x;
    unsigned short y;
} TS_RET_HANDPAD;
char * device = "/dev/touchscreen/0raw";
int screen_tp_fd;
int status=INIT;    //mouse down status
short color_rand=0x0a0a;
int min(int, int);
int get_average_num(int, int, int);
void init_handpad();
void init_graph();
int get_handpad(unsigned short *,unsigned short *);
void main_menu();
int in_which_region(int, int);
void game_over();
void file_menu();
void setting_menu();
void help_menu();
void clear_menu();
void draw(int, int, int);
void file_show_menu();
void setting_single_menu();
void setting_color_menu();


int main()
{
    int x,y,i,j;
    int rec=0;
    init_handpad();
    initgraph();
    clearscreen();
    srand(time(0));
    init_graph();
    if(get_handpad(&x,&y))
     main_menu();
    x=0;
y=0;
while(1)
{
    if(get_handpad(&x,&y))
    {
        rec=in_which_region(x,y);
    }
    if(rec==ON_CLOSE)
        game_over();
    else if(rec==ON_FILE_MENU)
        file_menu();
    else if(rec==ON_SETTING_MENU)
        setting_menu();
    else if(rec==ON_HELP_MENU)
        help_menu();
    else if(rec==ON_CLEAR_MENU)
     clear_menu();
    else if(rec==ON_VIEW)
     draw(x,y,RECTANGLE);
    else if(rec==ON_FILE_SHOW)
     file_show_menu();
    else if(rec==ON_FILE_CLOSE)
     game_over();
    else if(rec==ON_SETTING_SINGLE)
     setting_single_menu();
    else if(rec==ON_SETTING_COLOR)
     setting_color_menu();
    else
     printf("invald input...");
}
    return 0;
}
int min(int x,int y)
{
    return x>y?y:x;
}
int get_average_num(int x,int y,int z)
{
    return (x+y+z)/3;
}
void init_handpad()
{
    screen_tp_fd = open(device, O_RDONLY);
    if (screen_tp_fd == -1)
    {
        printf("Unable to open touch screen");
        exit(0);
    }
}
void init_graph()
{
    rectangle(30,50,200,150);
    textout(50,70,"触摸屏演示系统1.0",0xff00,0x0);
    textout(70,100,"大连理工大学",0x00ff,0x0);
    textout(95,120, "赖晓晨",0xff,0x0);
    textout(50,310,"touch to continue....",0xaaaa,0x0);
}
int get_handpad(unsigned short *x,unsigned short *y)
{
    int i=0,x_sum=0,y_sum=0;
int xa[3],ya[3];
     //take 3 times touchscreen point
     for(i=0;i<3;)
     {
         TS_RET_HANDPAD cBuffer;
         read(screen_tp_fd,&cBuffer,sizeof(TS_RET_HANDPAD));
         if( cBuffer.pressure)
         {
             xa[i] = cBuffer.x;
             ya[i] = cBuffer.y;
             i++;
         }
     }
     *x = get_average_num( xa[0], xa[1], xa[2]);
     *y = get_average_num( ya[0], ya[1], ya[2]);
     return 1;
 }
void main_menu()
{
    clearscreen();
    rectangle(0,1,239,15);    //caption
    rectangle(227,3,237,13); //close
    line(227,3,237,13);
    line(227,12,237,3);
    rectangle(0,15,239,40);    //menu
    line(50,15,50,40);
    line(100,15,100,40);
    line(150,15,150,40);
    line(200,15,200,40);
    textout(10,20,"文件",0xff00,0x0);
    textout(60,20,"设置",0xff00,0x0);
    textout(110,20,"帮助",0xff00,0x0);
    textout(160,20,"还原",0xff00,0x0);
    rectangle(0,15,239,319); //view
    fillrectangle(1,41,238,318,0x0);
}
int in_which_region(int a, int b)
{
    if(status==FILE_NOW && a>=0 && a<=90 && b>=40 && b<= 70)
    {//显示图形
        status=INIT;
        printf("\nin_which_region.........INIT show pic      ");
        return ON_FILE_SHOW;
    }
    if(status==FILE_NOW && a>=0 && a<=90 && b>70 && b<= 100)
    {//关闭
        status=INIT;
        printf("\nin_which_region.........INIT close   ");
    return ON_FILE_CLOSE;
}
    if(status==SETTING_NOW && a>50 && a<=140 && b>=40 && b<=
        70)
    {//单色
        status=INIT;
        printf("\nin_which_region.........INIT   single color   ");
        return ON_SETTING_SINGLE;
    }
    if(status==SETTING_NOW && a>50 && a<=140 && b>=70 && b<=
        100)
    {//彩色
        status=INIT;
        printf("\nin_which_region.........INIT    colorful   ");
        return ON_SETTING_COLOR;
    }
if(a>=227 && a<=237 && b>=3 && b<=13)
{//关闭按钮
    status=INIT;
    printf("\nin_which_region.........INIT   close button   ");
    return ON_CLOSE;
}
else if(a>=0 && a<=50 && b>=15 && b<=40)
{//文件菜单
    status=FILE_NOW;
    printf("\nin_which_region.........FILE_NOW      file main     ");
    return ON_FILE_MENU;
}
else if(a>=51 && a<=100 && b>=15 && b<=40)
{//设置菜单
    status=SETTING_NOW;
printf("\nin_which_region.........INIT      setting main    ");
       return ON_SETTING_MENU;
   }
   else if(a>=101 && a<=150 && b>=15 && b<=40)
   {//帮助菜单
       status=INIT;
       printf("\nin_which_region.........INIT   help main     ");
       return ON_HELP_MENU;
   }
   else if(a>151 && a<=200 && b>=15 && b<40)
   {//还原菜单
       status=INIT;
       printf("\nin_which_region.........INIT   clear main    ");
       return ON_CLEAR_MENU;
   }
    else if(a>=0 && a<=239 && b>40 && b<=319)
    {//视图区
        status=INIT;
        printf("\nin_which_region.........INIT   view region    ");
        return ON_VIEW;
    }
    else
    {//非法点击
        status=INIT;
        printf("\nin_which_region.........INIT   invalid dot   ");
        return INVALID;
    }
}
void game_over()
{
    clearscreen();
    exit(0);
}
void file_menu()
{
    fillrectangle(50,41,140,100,0x0);
    fillrectangle(51,16,99,39,0x0);
    textout(60,20,"设置",0xff00,0x0);
    status=FILE_NOW;
    printf("\nin file_nenu.......FILE_NOW   ");
    rectangle(0,40,90,100);       //edge
    fillrectangle(1,16,49,39,0xaaaa); //menu item
    fillrectangle(1,41,89,99,0xaaaa); //menu poped
    line(0,70,90,70);         //seperator
    textout(10,20,"文件",0x0,0xaaaa); //menu item name with color
    textout(10,50,"显示图片",0x0,0xaaaa);
    textout(10,80,"退出",0x0,0xaaaa);
}
void setting_menu()
{
    fillrectangle(1,41,90,100,0x0);
    fillrectangle(1,16,49,39,0x0);
    textout(10,20,"文件",0xff00,0x0);
    status=SETTING_NOW;
    printf("\nin setting_nenu.......SETTING_NOW   ");
    rectangle(50,40,140,100);         //edge
    fillrectangle(51,16,99,39,0xaaaa); //menu item backgrand
    fillrectangle(51,41,139,99,0xaaaa);
    line(51,70,139,70);
    textout(60,20,"设置",0x0,0xaaaa);
    textout(60,50,"单色",0x0,0xaaaa);
    textout(60,80,"彩色",0x0,0xaaaa);
}
void help_menu()
{
    int i,k=0;
    fillrectangle(1,41,90,100,0x0);
    fillrectangle(1,16,49,39,0x0);
    textout(10,20,"文件",0xff00,0x0);
    fillrectangle(50,41,140,100,0x0);
    fillrectangle(51,16,99,39,0x0);
    textout(60,20,"设置",0xff00,0x0);
    status=HELP_NOW;
    printf("\nin help_menu........HELP_NOW   ");
    fillrectangle(101,16,149,39,0xaaaa); //menu item backgrand
    textout(110,20,"帮助",0x0,0xaaaa);
    fillrectangle(1,41,238,318,0x0);
    rectangle(0,40,239,319);
    rectangle(30,130,210,210);
    rectangle(32,132,208,208);
    fillrectangle(33,133,207,207,0x1111);
    textout(40,140,"触摸屏演示系统1.0",0xf000,0x1111);
    textout(40,160,"赖晓晨",0xfff000,0x1111);
    textout(40,180,"touch to continue.",0xf000,0x1111);
    for(i=0;i<9999;i++)
     k++;
    fillrectangle(101,16,149,39,0x0);
    textout(110,20,"帮助",0xff00,0x0);
}
void clear_menu()
{
    int i,j,k=0;
    status=INIT;
    printf("\nin clear_menu.........INIT   ");
    fillrectangle(151,16,199,39,0xaaaa);
    textout(160,20,"还原",0x0,0xaaaa);
    fillrectangle(1,41,238,318,0x0);
    for(i=0;i<9999;i++)
     k++;
    main_menu();
}
void draw(int x, int y, int sig)
{
    int a, b,x1,y1;
    unsigned short color;
    main_menu();
    a=min(239-x,x-1);
    b=min(319-y,y-40);
    if(sig==RECTANGLE)
    {
        color=rand()%65535;
        x1=rand()%a+1;
        y1=rand()%b+1;
        rectangle(x, y, x+x1, y+y1,rand()%65535);
        fillrectangle(x+1,y+1, x+x1-1, y+y1-1,color|color_rand);
    color=rand()%65535;
    x1=rand()%a+1;
    y1=rand()%b+1;
    rectangle(x-x1, y-y1, x, y,rand()%65535);
    fillrectangle(x-x1+1,y-y1+1, x-1, y-1,color|color_rand);
    color=rand()%65535;
    x1=rand()%a+1;
    y1=rand()%b+1;
    rectangle(x-x1, y, x, y+y1,rand()%65535);
    fillrectangle(x-x1+1,y+1, x-1, y+y1-1,color|color_rand);
    color=rand()%65535;
    x1=rand()%a+1;
    y1=rand()%b+1;
    rectangle(x, y-y1, x+x1, y,rand()%65535);
    fillrectangle(x+1,y-y1+1, x+x1-1, y-1,color|color_rand);
}
    else if(sig==ELLIPSE)
    {
        ellipse(x,y,a,b);
    }
}
void file_show_menu()
{
    status=INIT;
    printf("\nin file_show_menu.........INIT   ");
    fillrectangle(1,41,90,100,0x0);
    fillrectangle(1,16,49,39,0x0);
    textout(10,20,"文件",0xff00,0x0);
    fillrectangle(1,41,239,319,0x0);
    rectangle(0,40,239,319);
    ShowBMP("keyboard.bmp",40,150);
}
void setting_single_menu()
{
    status=INIT;
    printf("\nin setting_single_menu.........INIT    ");
    color_rand=0xffff;
    fillrectangle(50,41,140,100,0x0);
    fillrectangle(51,16,99,39,0x0);
    textout(60,20,"设置",0xff00,0x0);
}
void setting_color_menu()
{
    status=INIT;
    printf("\nin setting_color_menu.........INIT    ");
    color_rand=0x0;
    fillrectangle(50,41,140,100,0x0);
    fillrectangle(51,16,99,39,0x0);
    textout(60,20,"设置",0xff00,0x0);
}
【例6-8】(续)
 上述代码实现了一个基于触摸屏的图形菜单
  程序,代码结构比较简单,下面把其中涉及
  到的各个函数做一个简要介绍:
  init_handpad():触摸屏初始化函数。
  initgrahp():图形界面初始化函数,在其中
   打开Framebuffer设备文件,并把它映射到
   内存中。
  clearscreen():清屏函数。
【例6-8】(续)
 get_handpad():通过函数调用把触摸点坐
  标送至变量x与y,数据采用三次采样求均值的
  方式。
 main_menu():绘制主菜单函数。
 in_which_region():辨别屏幕触摸点的位
  置处在哪些区域,返回值是区域标识。
 game_over():结束程序。
 file_menu():文件菜单响应函数。
 setting_menu():设置菜单响应函数。
【例6-8】(续)
 help_menu():帮助菜单响应函数。
 clear_menu():调用重绘函数,负责重新绘制
  菜单,并清空显示区。
 draw():图形绘制函数,根据设置显示各种图形。
 file_show_menu():显示文件下拉菜单函数。
 setting_single_menu():设置单色显示方式
  函数。
【例6-8】(续)
 setting_color_menu():设置彩色显示方式函
  数。
 min():求最小值函数。
 get_average_num():求平均数函数。
 textout():在屏幕某坐标处显示字符串函数。
 rectangle():绘制矩形函数。
 line():绘制直线函数。
 fillrectangle():填充矩形函数。
 ShowBMP():在屏幕某坐标处显示BMP图形函
  数。
一、MiniGUI简介          ★ ★★★


 MiniGUI诞生于1998年,最初由清华大
  学魏永明主持的一个工控项目,由于当时的
  X Window并不满足时实性的需要,因此
  决定自行设计一套图形用户界面,这就是
  MiniGUI的诞生。
1. MiniGUI的特性           ★ ★★★


 MiniGUI有很多优良的特性。
  内建有很多资源,可提高初始化速度
   位图、图标、和字体等
  提供对常用图形格式的支持
   BMP、GIF、JPEG、PNG等
  有完备的多窗口机制和消息传递机制
2. MiniGUI的结构   ★ ★★★
3. MiniGUI的运行模式(add exp)
                    ★ ★★★


 MiniGUI1.3.*有三种运行模式
  Threads
    支持多线程
  Lite
    支持多进程
  Standalone
    单进程模式
4. MiniGUI和系统平台的关系
二、MiniGUI模拟环境
 由于嵌入式系统运行需要特定硬件环境,这
  给嵌入式开发带来了一定困难,如果能在
  PC机上进行一部分嵌入式开发工作,可以
  提高工作效率。
1. 环境准备
 需要的源码包:
  MiniGUI核心库:libmingui-1.3.3.tar.gz
  MiniGUI资源:mingui-res-1.3.3.tar.gz
  MiniGUI例程:mg-samples-1.3.0.tar.gz
  模拟环境QVFB:qvfb-1.0.tar.gz
 在/opt目录下新建名为linux的目录,把
  上述四个源码包复制到此目录下
2. MiniGUI源码介绍
 libminigui-1.3.3.tar.gz:
   MiniGUI的所有核心文件都在这个库中
 minigui-res-1.3.3.tar.gz:
   包含了所有MiniGUI使用的资源包
 mde-1.3.0.tar.gz:
   包含了MiniGUI的综合演示程序
 ms-samples-1.3.0.tar.gz:
   包含了MiniGUI的配套实例程序包
3. MiniGUI模拟环境构建
 启动Red Hat Linux 9,用root登陆
 建立自己的开发目录

 cd /opt
 mkdir s3c2410
cd s3c2410
  在s3c2410下使用tar命令解压缩
  MiniGUI的所有源码文件
A. 安装libminigui-1.3.3.tar.gz
tar -zxf /opt/linux/libminigui-1.3.3.tar.gz
cd libminigui-1.3.3
./configure
 这里采用缺省的MiniGUI-Thread模式,
  而不是MiniGUI-Lite模式

 make
 make install
B. 安装minigui-res-1.3.3.tar.gz
cd /opt/s3c2410
tar zxf /opt/linux/minigui-res-1.3.3.tar.gz
cd /opt/s3c2410/minigui-res-1.3.3
make install
 检查/usr/local/lib目录是否生成了
  minigui目录
C. 设置环境变量
 Linux系统的库路径环境变量保存在
  /etc/ld.so.conf文件中,为了让链接程
  序能够找到相应的库,需添加
   /usr/local/lib一行

cd /etc
vi ld.so.conf
ldconfig
D. QVFB的安装与设置
cd /opt/s3c2410
tar zxf /opt/linux/qvfb-1.0.tar.gz
cd qvfb-1.0
./configure
make
make install
 安装成功后,修改用户主目录的shell配置文件


cd $HOME
vi .bashrc
D. QVFB的安装与设置(续)
 在这个文件中加入:
export PATH="$PATH:/sbin:/usr/local/arm/2.95.3/bin"
export PATH="$PATH:/usr/local/bin:/usr/local"
 然后执行:
  source .bashrc
E. 安装mg-samples-1.3.0.tar.gz
cd /opt/s3c2410
tar zxf /opt/linux/mg-samples-1.3.0.tar.gz
cd mg-samples-1.30
./configure
make
ls src
 检查是否src目录下有例子程序
F. 修改MiniGUI配置文件
 编辑
   /usr/local/etc/MiniGUI.cfg文件

vi /usr/local/etc/MiniGUI.cfg
 然后把配置文件修改为下页的形式
F. 修改MiniGUI配置文件(续)
[system](此处不能有多余的空格!!!)
# GAL engine
#gal_engine=fbcon
gal_engine=qvfb //这里修改
# IAL engine
#ial_engine=console
ial_engine=qvfb //这里修改 console
mdev=/dev/mouse
mtype=IMPS2
[fbcon]
defaultmode=1024x768-16bpp
[qvfb]
defaultmode=640x480-16bpp //这里修改
display=0
G. 测试
 以上完成了MiniGUI的模拟环境的建立的
  全过程
 qvfb &
 然后对qvfb设置
  选择File->Configure
  在弹出窗口中选中640×480 VGA和16bit
  按下Enter
G. 测试(续)
 运行例程(如helloworld)
cd /opt/s3c2410/mg-samples-1.3.0/src
./helloworld
G. 测试(续)
G. 测试(续)
 注意
  每次执行MiniGUI应用程序前需要先运行
   QVFB
  每次都要对QVFB进行配置
  退出的时候,先结束已经进行的程序,然后右
   键单击QVFB界面,选择结束会话,再关闭
   QVFB窗口即可
G. 测试(续)
三、MiniGUI移植
 需要的工具包
    cross-2.95.3.tar.bz2: 交叉编译工具
    zlib-1.2.3.tar.gz:压缩解压缩库
    libpng-1.0.10rc1.tar.gz:图形库
    freetype-1.3.1.tar.gz:freetype字体
    libminigui-1.3.3.tar.gz:MiniGUI核心
     库
三、MiniGUI移植(续)
 需要的工具包
    mde-1.3.0.tar.tar:MiniGUI例程库
    popt-1.7.tar.gz:选项解析库
    cramfs-1.1.tar.tar:文件系统生成工具
    root.cramfs.tar.bz2:文件系统
A. 安装交叉编译工具
 需要的工具包
  把工具链解压到/usr/local/arm下
mkdir -p /usr/local/arm
cd /usr/local/arm
tar jxf /opt/linux/cross-2.95.3.tar.bz2
B. 安装zlib库
 zlib库的configure脚本不支持交叉编译
  选项
 需要修改gcc为指向arm-linux-gcc的链
  接

cd /usr/bin
mv gcc gcc_back
ln -s /usr/local/arm/2.95.3/bin/arm-linux-gcc ./gcc
B. 安装zlib库(续)
 同理修改链接器

mv ld ld_back
ln -s /usr/local/arm/2.95.3/bin/arm-linux-ld ./ld
 回到/opt/s3c2410目录下

cd /opt/s3c2410
tar zxf /opt/linux/zlib-1.2.3.tar.gz
cd zlib-1.2.3
./configure --prefix=/usr/local/arm/2.95.3/arm-linux --shared
make; make install
B. 安装zlib库(续)
 检查/usr/local/arm/2.95.3/arm-
  linux[include,lib]中是否含有zlib.h等头文件
  和libz.so.1.2.3等库文件
 if没有
   手动复制
 接下来,还要把gcc和ld还原
   (别忘了^_^)
C. 安装png图形库
  cd /opt/s3c2410
  tar zxf /opt/linux/libpng-1.0.10rc1.tar.gz
  cd libpng-1.0.10rc1
 png库不提供交叉编译的有效 configure脚本,
  需要自己准备Makefile

   cp scripts/makefile.linux Makefile

 vi Makefile
  修改如下
[user]# vi Makefile   // 自己动手改
C. 安装png图形库
CC=arm-linux-gcc //修改这里
# where "make install" puts libpng.a, libpng.so*,
png.h and
pngconf.hprefix=/usr/local/arm/2.95.3/arm-
linux   //修改这里
# Where the zlib library and include files are
located#ZLIBLIB=/usr/local/lib#ZLIBINC=/usr/local
/includeZLIBLIB=/usr/local/arm/2.95.3/arm-
linux/lib //修改这里
ZLIBINC=/usr/local/arm/2.95.3/arm-
linux/include //修改这里
C. 安装png图形库(续)
 Make
 Make install
 png图形库准备完毕
D. 安装jpeg图形库
 cd /opt/s3c2410
 tar zxf /opt/linux/jpegsrc.v6b.tar.gz
 cd jpeg-6b
 ./configure --prefix=/usr/local/arm/2.95.3/arm-linux/ --
 host=arm-linux --enable-shared --enable-static
 make

 执行make install需要在arm-linux下
  新建两个目录(见下页)
D. 安装jpeg图形库(续)
mkdir -p /usr/local/arm/2.95.3/arm-linux/man/man1
make install



 jpeg图形库安装完毕
E. 安装TrueType字体库
mkdir -p /opt/s3c2410/libttf/extend
cd /opt/s3c2410
tar zxf /opt/linux/freetype-1.3.1.tar.gz
cd freetype-1.3.1

 jpeg图形库安装完毕
cp ./lib/* ../libttf/
cp ./lib/extend/* ../libttf/extend/
cd /opt/s3c2410/libttf
arm-linux-gcc -c -fPIC -O2 freetype.c
arm-linux-gcc -c -fPIC -O2 -I./extend/*.c
E. 安装TrueType字体库(续)
 把交叉编译得到的目标文件链接为字体共享库


 arm-linux-gcc --shared -o libttf.so *.c
  新建目录/usr/local/arm/2.95.3/arm-
  linux/include/freetype1/freetype
E. 安装TrueType字体库(续)
mkdir -p /usr/local/arm/2.95.3/arm-
linux/include/freetype1/freetype
cp *.h /usr/local/arm/2.95.3/arm-linux/include/freetype1/freetype
cp extend/*.h
/usr/local/arm/2.95.3/armlinux/include/freetype1/freetype
cp libttf.so /usr/local/arm/2.95.3/arm-linux/lib
 修改符号链接
E. 安装TrueType字体库(续)
cd /usr/lib
mv libjpeg.so libjpeg.so_back
ln -s /usr/local/arm/2.95.3/arm-linux/lib/libjpeg.so ./libjpeg.so
mv libpng.so libpng.so_back
ln -s /usr/local/arm/2.95.3/arm-linux/lib/libpng.so ./png.so
mv libttf.so libttf.so_back
ln -s /usr/local/arm/2.95.3/arm-linux/lib/libttf.so ./libttf.so
 完成上面内容后就可以交叉编译libminigui了
F. 交叉编译MiniGUI库文件
cd /opt/s3c2410/libminigui-1.3.3
make menuconfig

 如果没有出错,进行下列配置

 [*] Build MiniGUI-Lite
 [ ] Stand-Alone
 [ ] Use incore (built-in) resource
 [*] Unit of timer is 10ms
F. 交叉编译MiniGUI库文件(续)
[*] Cursor support
[ ] User can move window with mouse
[*] Mouse button can do double click
 如果没有出错,进行下列配置
[*] Build with debugging messages
[ ] Trace messages of MiniGUI
[*] Include symbol name of messages
F. 交叉编译MiniGUI库文件(续)
 在GAL engine Options菜单中
[*] NEWGAL engine on Linux FrameBuffer console
[ ] NEWGAL engine on Qt Virtual FrameBuffer
[ ] NEWGAL engine on eCos LCD interface
[*] Dummy NEWGAL engine
[*] Have console on Linux FrameBuffer
F. 交叉编译MiniGUI库文件(续)
 在IAL engine options菜单中
[ ] EP7211-based board
[ ] ADS Graphics Client
[ ] iPAQ H3600 (also H3800)
[ ] MPC823
[ ] PX255B
[ ] NEC VR4181
[ ] Helio Touch Panel
[ ] MT T800
[*] SMDK2410 Touch Screen
F. 交叉编译MiniGUI库文件(续)
 在IAL engine options菜单中
[ ] uClinux Touch Screen Palm/MC68EZ328
[*] Dummy IAL engine
[*] Native (console) input engine
--- Native IAL engine subdriver options
[ ] PS2 mouse
[ ] IntelligentMouse (IMPS/2) mouse
[ ] MS mouse
[ ] MS3 mouse
[*] GPM daemon
F. 交叉编译MiniGUI库文件(续)
 在Font Options菜单中
[*] Raw bitmap font
[ ] Var bitmap font
[*] Incore font sansserif
[*] Incore font courier
[*] Incore font symbol
[*] Incore font vgas
[*] Qt Prerendered Font
[*] TrueType font
[ ] Adobe Type1 font
F. 交叉编译MiniGUI库文件(续)
 在Image Options菜单中
[*] Includes SaveBitmap-related functions
[ ] PCX file support
[ ] LBM/PBM file support
[ ] TGA file support
[*] GIF file support
[*] JPG file support
[*] PNG file support
F. 交叉编译MiniGUI库文件(续)
 在Input Medthold Option菜单中
[*] IME (GB2312) support
[ ] IME (GB2312) Intelligent Pinyin module
F. 交叉编译MiniGUI库文件(续)
 在Development Environment
  Option菜单中
(Linux) Platform
(arm-linux-gcc) Compiler //注意这里
(glibc) Libc       //注意这里--- Installation options
Path prefix: "/usr/local/arm/2.95.3/arm-linux" //注意这里,我们把库装到
交叉编译器的目录下
--- Additonal Compiler Flags
         CFLAGS: ""
         LDFLAGS: ""
F. 交叉编译MiniGUI库文件(续)
 其他的用缺省选项,修改完毕后选择退出
 观察是否有输出


checking for TT_FreeType_Version in -lttf... yes
checking for jpeg_std_error in -ljpeg... yes
for png_check_sig in -lpng... yes
F. 交叉编译MiniGUI库文件(续)
 还要修改一些东西
cd /opt/s3c2410/libminigui-1.3.3/src
rm -f template.o template.lo
arm-linux-gcc –c –fPIC –O2 template.c
arm-linux-gcc –shared –o template.so *.o
cd /opt/s3c2410/libminigui-1.3.3/ext
rm -f template.o template.lo
arm-linux-gcc –c –fPIC –O2 template.c
arm-linux-gcc –shared –o template.so *.o
F. 交叉编译MiniGUI库文件(续)
 还要修改一些东西
cd /opt/s3c2410/libminigui-1.3.3/src/newga
rm -f yuv_mmx.lo
arm-linux-gcc –c –fPIC –O2 yuv_mmx.c
arm-linux-gcc –shared –o yuv_mmx.so yuv_mmx.o
 接下来

make
make install
G. 安装popt库
 安装方式同上
# cd /opt/s3c2410
# tar zxf popt-1.7.tar.gz
# cd popt-1.7
./configure --prefix=/usr/local/arm/2.95.3/arm-linux/ --host=arm-linux --
#
    接下来
enable-shared --enable-static
# make
# make install
H. 安装mde
 安装方式同上
# cd /opt/s3c2410
# tar zxf mde-1.3.0.tar.gz
# cd mde-1.3.0
 如果MiniGUI支持鼠标或者触摸屏,不需要这一步骤


cd mginit ; vi mginit.c
在 297 行处,把下面代码注释掉
/*************** AboutMiniGUI ();AboutMDE ();**************/
H. 安装mde(续)
 编译
cd /opt/s3c2410/mde-1.3.0
./configure --host=arm-linux
make
I. 制作根文件系统
 解压文件系统到/opt目录下
cd /opt/
tar -jxf /opt/linux/root.cramfs.tar.bz2

 删除/opt/root中的两个符号链接:tmp和var,
  新建两个目录 tmp、var/tmp

cd /opt/root; rm -f tmp var
mkdir tmp
mkdir var/tmp
I. 制作根文件系统(续)
 复制文件到根文件系统中
mkdir -p /opt/root/usr/local/lib/shared/miniguiapps
cd /opt/s3c2410/mde-1.3.0
cp -r -a ./* /opt/root/usr/local/lib/shared/miniguiapps
 进入miniguiapps删除.c, .h, .o, Makefile,
  只保留可执行文件和res下的资源,不要删除
  mginit.rc
I. 制作根文件系统(续)
 复制库及配置文件

mkdir -p /opt/root/usr/local/lib
mkdir -p /opt/root/usr/local/etc
 把编译好的所有库文件从
  /usr/local/arm/2.95.3/arm-linux/lib下复
  制到 /opt/root/usr/local/lib,
  /opt/root/usr/lib和/opt/root/lib下
I. 制作根文件系统(续)
 这些库文件是

libjpeg.so、libjpeg.so.62、libjpeg.so.62.0.0、libmgext-1.3.so.3、
libmgext-1.3.so.3.0.0、libmgext.so
libminigui-1.3.so.3.0.0、libminigui.so、libminigui-1.3.so.3
libpng.so.2、libpng.so.2.1.0.10rc1、libpng.so、libttf.so
libm.so、libm.so.6、libm-2.2.3.so、libz.so、libz.so.1、
libz.so.1.2.3
libpopt.so.0、 libpopt.so、libpopt.so.0.0.0
libvcongui-1.3.so.3、libvcongui-1.3.so.3.0.0、libvcongui.a、
libvcongui.la、libvcongui.so
I. 制作根文件系统(续)
 新建 /opt/root/etc/ld.so.conf文件,加上一行


/usr/local/lib:/usr/lib
 然后执行ld命令



cd /opt/root/etc
vi ld.so.conf
ldconfig -r /opt/root
J. 系统配置
 复制/opt/root/mnt/etc下的所有文件夹到
  opt/root/etc目录下
    linuxrc
    rcS
    rc.local
    MiniGui.cfg

 修改相见教材
K. 制作Linux根文件系统
 使用mkcramfs工具制作根文件系统

cd /opt
mkcramfs root root.cramfs
嵌入式系统程序设计

 大连理工大学软件学院
 嵌入式系统工程系
 赖晓晨
SkyEye
 SkyEye是一个可以运行嵌入式操作系统
  的硬件仿真工具
 它的硬件仿真模块经过了设计者严格的验
  证,工作非常稳定
SkyEye优点
 缩短嵌入式产品设计周期
 降低嵌入式系统学习的门槛
SkyEye程序设计
 基于SkyEye的程序设计与前文提及的基
  于uClinux或miziLinux编程大体相同,
  唯一差别在于事先配置、编译SkyEye源
  码
SkyEye模拟环境
SkyEye上移植uC/OS Ⅱ
 安装交叉编译工具链
 配置交叉编译uC/OSⅡ源码,以生成
 的内核文件作为参数,启动skyeye程序
 如图
SkyEye上移植uClinux
 与uC/OS Ⅱ大同小异
   安装必要的补丁
   配置、编译
   得到的内核文件作为参数运行skyeye
 如图
SkyEye上移植ARM Linux
 与uCLinux基本相同
 如图
ARM Linux上运行的小程序

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:4
posted:5/28/2012
language:
pages:237