嵌入式课程设计

嵌入式课程设计

基于SDL的数字相框

    级:

    院:

指导老师:

    名:

一.  嵌入式课程设计概述:

本程序基于SDL开发的一个带有幻灯片功能的数字相框。

二.  课程设计的目的:

本课程设计的目的是通过开发一个消费类电子产品——数字相框,了解嵌入式产品开发的主要步骤,包括需求分析、系统结构设计、图形界面设计、驱动程序、功能优化、系统测试等,从而培养自己独立完成比较复杂的实际系统设计的能力。

三.  课程设计内容:

3.1设计的内容 

利用SDL实现图片的调用的功能,利用信号来实现图片的播放功能,利用SDL的可移植性,将该设计方案移植到开发板上,该数字相框的功能包括以下方面: 

(1)在LCD屏上全屏循环显示多幅图像文件;

(2)根据设定的时间间隔更新图像;

(4)通过键盘进行操作;

四.  总体设计:

数字相框软件系统功能分为三个模块:

1)图片浏览模块,可以通过按键控制选定某个图像或更新图像页(上一页、下一页)。 

2)播放模块,对浏览界面选定的图片进行循环播放。 

3)退出模块,退出图片播放和退出程序。

功能模块组织架构图:

 

五.  详细设计:

该程序分为2个部分:一部分为用户界面层,一部分为功能模块层。

5.1用户界面层代码设计如下:

int Init()                                                     //初始化SDL

{

   if(( SDL_Init(SDL_INIT_VIDEO) | IMG_Init(IMG_INIT_PNG) ))

   {

            fprintf(stderr,"SDL init error:%s",SDL_GetError());

            return -1;

   }

   return 0;

}

void creatScreen(int width , int height , Uint8 bpp , Uint32 flags)             // 创建屏幕 640*480 0  SDL_SWSURFACE

{

   screen = SDL_SetVideoMode(width , height,  bpp , flags);

  

   if(screen == NULL)

   {

            fprintf(stderr,"Could not Creat a Screen!:%s",SDL_GetError());

            exit(1);

   }

  

   return;

}

void show_Pic(SDL_Surface *bmp ,SDL_Rect *rect) //显示图片

{

   SDL_BlitSurface(bmp , NULL , screen , rect);

   SDL_UpdateRect(screen , 0 , 0 , 0 , 0 );

   SDL_FreeSurface(bmp);

   return ;

}

int appMode()

{

   int width = WIDTH;

   int heigth = HEIGTH;

   Uint8 bpp = 0;

   Init();

   creatScreen(width , heigth, bpp , SDL_SWSURFACE);

   backpng = IMG_Load("./image/beijing.jpg");

   show_Pic(backpng ,&(screen->clip_rect));

   SDL_Delay(3000);

   caidan();

   SDL_WM_SetCaption(TITLE_NAME, ICON_NAME);       //设置窗口标题

   return 0;

}

效果如下图:

封面:

菜单:

5.2.功能模块实现代码:

int getRightPic(int a)

{

   a++;

   if(a > 15 )

   {

            a = 0;

   }

   return a;

}

int  getLeftPic(int a)

{

   a--;

   if(a < 0)

   {

            a = 15;

   }

   return a;

}

int ShowPic(char *string)      //更换显示图片

{

   if(strcmp(string , "left") == 0)

   {       

            i = getLeftPic(i);       

   }

   else

            i = getRightPic(i);

   backpng = IMG_Load(picture[i]);

   if(!backpng)

   {

            fprintf(stderr,"Could not load %s: %s\n",picture[i],SDL_GetError());

            exit(1);    

   }

   SDL_Rect rect;

   rect.x =  (screen->w - backpng->w ) / 2;

   rect.y =  (screen->h - backpng->h ) / 2;                   

   rect.w = backpng->w;

   rect.h = backpng->h;

   SDL_UpdateRect(screen , 0 , 0 , 0 , 0 );

   show_Pic(backpng , &rect);                               

   return 0;

}

int caidan()

{

   png = IMG_Load("./image/caidan.jpg");

   show_Pic(png ,&(screen->clip_rect));

}

void timefunc(int sig)      /* 定时事件代码 */

{

   ShowPic("left");

   signal(SIGPROF, timefunc);    /* 捕获定时信号 */

}

void xinhao(int signo)

{

   if(signo == SIGALRM)

   {

            //printf("123\n");

   }

   else

   {

   signal(SIGALRM,  timefunc);

   struct itimerval value;

   value.it_value.tv_sec=3;    /* 定时3秒后启动定时器 */

   value.it_value.tv_usec=0;

   value.it_interval.tv_sec=3;    /* 每隔3秒执行下一个相应的函数 */

   value.it_interval.tv_usec=0;

   signal(SIGPROF, timefunc);     /* 捕获定时信号 */

   setitimer(ITIMER_PROF, &value, NULL); /* 定时开始 */

   int ret = setitimer(ITIMER_REAL,&value,NULL);

   }

}

int main(int argc,char **argv)

{

   appMode();

   int i=0;

   double zoom_x,zoom_y;

   SDL_Event event;

   while(SDL_WaitEvent(&event))                         

   {       

            switch(event.type)

            {

                     case SDL_KEYDOWN:

                               if(event.key.keysym.sym == SDLK_ESCAPE)

                               {

                                        goto loop;

                               }

                               /*if(event.key.keysym.sym == SDLK_SPACE)

                               {

                                        xinhao(0);

                               }

                               if(event.key.keysym.sym == SDLK_END)

                               {

                                        alarm(1);

                                        SDL_Delay(1000);

                                        caidan();

                               }        */

                               break;

                     case SDL_KEYUP:

                               if(event.key.keysym.sym == 276)

                               {

                                        ShowPic("left");                                   

                               }

                               if(event.key.keysym.sym == 275)

                               {

                                        ShowPic("right");

                               }

                               break;

                     case SDL_QUIT:

                               printf("quit\n");

                               goto loop;

                               break;

            }

   }

loop:

   raise(SIGKILL);

   return 0;

}

效果如下图:

六.  在开发板上移植:

6.1.安装arm-linux交叉编译库.

6.2.对SDL进行交叉编译安装,对程序进行交叉编译。

6.3.挂载6410开发板。

6.4.对程序进行开发板移植。

七.  课程设计总结与体会:

本次课程设计,在linux下的环境下编写程序,然后把程序向开发板上进行移植,比起以往的单一编程,还是有些难度的在课设伊始,单是所熟悉的linux调试环境就用去了我们3天的时间,但事实证明磨刀不误砍柴工,这三天的努力使得我们后面的工作变得容易了许多,主要的困难还是度图形用户界面的控制,但是在老师和同组同学的帮助下,最终我们还是攻克了难题!课设中我们遇到很多的难题,很多东西都是第一次接触,很多用到的技术网上根本没有资料,完全凭借自己去摸索尝试。其中的困难可想而知。然而坚持就是胜利,牙一咬眼一闭坚持做下去,而通过本次课设,我感觉收获还是蛮多的。可能我对于嵌入式的知识学习的还是不太多,但是这之外的东西收获颇丰。它让我学会了如何通过自己的努力去认知一个新事物,更重要的是端正自己的学习态度,只有真正下功夫去学习,才能有收获,正所谓“一份耕耘,一份收获。”没有付出,何谈回报呢?再者,通过本次课设,我也学会了如何去分析问题,如何找出自己设计中的不足,继而去排除解决问题,这就是一个自我学习的过程。当我们通过实验去学习理论知识时,自己动手得出的结论,不仅能加深我们对嵌入式的理解,更能加深我们对此的记忆。  

     当然,在这其中,我也发现自己的许多不足之处,由于学期伊始我没有好好学习,才落到如此地步,这也可以说是一个教训吧!我相信在以后的学习工作中,我一定会端正自己的学习态度,一丝不苟的去对待每一件事。只有做好足够的准备,才能事半功倍!

 

第二篇:嵌入式课程设计之触摸屏程序设计

嵌入式课程设计

设计题目:触摸屏驱动程序设计

班级:

学号:

姓名:

指导老师:

设计时间:20##年12月25日--12月28日


目录

第一部分 要求... 0

1.1设计目的... 1

1.2 设计意义... 1

1.3 设计内容... 1

1.4 主要任务... 1

第二部分 正文... 2

2.1触摸屏工作原理(触摸屏接口工作模式)... 2

2.2、设计总体方案... 3

2.3、设计所需工具... 6

2.4、平台构建过程... 6

2.4.1、硬件平台搭建... 6

2.4.2根文件系统的制作... 8

(1)根文件系统... 8

第三章 程序... 13

3.1.程序流程图:... 13

3.2.分析驱动... 13

3.2.1、触摸屏设备驱动中数据结构... 13

3.2.2、触摸屏驱动模块加载和卸载函数... 15

3.2.3、触摸屏设备驱动的读函数... 17

3.2.4、触摸屏设备驱动的轮询与异步通知... 17

3.2.5源程序触摸屏驱动代码:... 18

3.2.6、实验结果显示:... 29

第四部分 心得... 30

4.1 课程设计心得体会:... 30

第五部分 参考文献... 32

5.1【参考文献】... 32

 

第一部分 要求

1.1 设计目的

1.基于Linux操作系统,以及Emest III实验箱,利用触摸屏返回触点坐标值及动作信息。

2.坐标及动作的具体显示:触摸笔动作,触点X坐标值,触点Y坐标值。

1.2 设计意义

1.   熟悉嵌入式系统开发平台

2.   掌握ARM嵌入式Linux操作系统下的各个指令的使用方法

3.   了解触摸屏的原理

1.3 设计内容

1.Linux系统的正确移植和使用

2.根文件系统的正确移植和使用

3.驱动程序的编译与装载

4.嵌入式系统下应用程序的交叉编译及下载与调试

1.4 主要任务

1.熟悉实验的流程

2.vivi,linux内核的烧写

3.cramfs文件系统(烧写前需编译)的烧写

4.理解驱动程序源代码

5. 调用驱动程序的某些函数,编译与调试应用程序


第二部分 正文

2.1触摸屏工作原理(触摸屏接口工作模式)

(1)普通转换模式

普通转换模式(AUTO_PST = 0,XY_PST = 0)是用作一般目的下的ADC转换。这个模式可以通过设置ADCCON和ADCTSC来进行对AD转换的初始化;而后读取ADCDAT0(ADC数据寄存器0)的XPDATA域(普通ADC转换)的值来完成转换。

2)分离的X/Y轴坐标转换模式:X轴坐标转换和Y轴坐标转换。

X轴坐标转换(AUTO_PST=0且XY_PST=1)将X轴坐标转换数值写入到ADCDAT0寄存器的XPDATA域。转换后,触摸屏接口将产生中断源(INT_ADC)到中断控制器。

Y轴坐标转换(AUTO_PST=0且XY_PST=2)将X轴坐标转换数值写入到ADCDAT1寄存器的YPDATA域。转换后,触摸屏接口将产生中断源(INT_ADC)到中断控制器。

3)自动(连续)X/Y轴坐标转换模式。

自动(连续)X/Y轴坐标转换模式(AUTO_PST=1且XY_PST= 0)以下面的步骤工作:

触摸屏控制器将自动地切换X轴坐标和Y轴坐标并读取两个坐标轴方向上的坐标。触摸屏控制器自动将测量得到的X轴数据写入到ADCDAT0寄存器的XPDATA域,然后将测量到的Y轴数据到ADCDAT1的YPDATA域。自动(连续)转换之后,触摸屏控制器产生中断源(INT_ADC)到中断控制器。

4)等待中断模式

当触摸屏控制器处于等待中断模式下时,它实际上是在等待触摸笔的点击。在触摸笔点击到触摸屏上时,控制器产生中断信号(INC_TC)。中断产生后,就可以通过设置适当的转换模式(分离的X/Y轴坐标转换模式或自动X/Y轴坐标转换模式)来读取X和Y的位置。

5)静态(Standby)模式

当ADCCON寄存器的STDBM位被设为1时,Standby模式被激活。在该模式下,A/D转换操作停止,ADCDAT0寄存器的XPDATA域和ADCDAT1寄存器的YPDATA(正常ADC)域保持着先前转换所得的值。

                                             

2.2、设计总体方案

1、软件

(1)Embest Online Flash Programmer For ARM: Embest Flash在线编程器

(2)HYPER TERMINAL(超级终端):传送vivi.nand;

                            

传送vivi.nand

 vivi> load flash kernel x <回车>  烧写更新内核,传送zImage文件;

等待传送内核文件

                                

传送内核:

      

vivi>load flash root j <回车>  烧写更新文件系统;

烧写新的文件系统 load flash root j 

(3)   EmbestIDE Pro for ARM:

       应用于嵌入式软件开发的新一代集成开发环境,是一个高度集成的图形界面操作环境,包含编辑器、编译汇编链接器、调试器、工程管理、Flash 编程等工具;支持的开发语言包括标准C和汇编语言。

(4)cygwin:

        一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,或者进行某些特殊的开发工作,尤其是使用gnu工具集在windows上进行嵌入式系统开发,把gcc,gdb,gas等开发工具进行了改进,能够生成并解释win32的目标文件。

2、硬件

S3C2410处理器是Samsung公司基于ARM公司的ARM920T处理器核,32位微控制器。该处理器拥有:独立的16KB指令Cache和16KB数据Cache,MMU,支持TFT的LCD控制器,NAND闪存控制器,3路UART,4路DMA,4路带PWM的Timer ,I/O口,RTC,8路10位ADC,Touch Screen接口,IIC-BUS 接口,IIS-BUS 接口,2个USB主机,1个USB设备,SD主机和MMC接口,2路SPI。S3C2410处理器最高可运行在203MHz。

2.3、设计所需工具

1.软件: Embest Online Flash Programmer For ARM,HYPER TERMINAL(超级终端),EmbestIDE Pro for ARM,cygwin

1.  硬件:s3c2410开发板,Embest实验箱

2.4、平台构建过程

2.4.1、硬件平台搭建

硬件流程图:

(1) Vivi烧写过程

1)首先把SW104断开,Flash Programmer的Program,在File选择Open打开要烧写的配置文件S3C2410&NandFLash_vivi.cfg,在Flash Programmer的Program页中选择要烧写的文件vivi.bon&load.bin。点击按钮 Progarm 开始烧写,直到烧写成功

2) 连接串口线到 PC 机 COM1,运行光盘中提供的 Windows 超级终端Hyper Terminal.ht 把开发板重新加电,程序运行后,在超级终端上可以看到串口输出Wating,表示正在等待用户从超级终端下载文件。这时,请点击超级终端菜单"传送"选择 Xmodem 方式下载 vivi.nand 文件,点击 OK 后等待下载烧写结束即可。

(2) 内核zImage烧写

1) 首先SW104设为短接(从Nand Flash启动),并确定已经烧写vivi.nand,加电。

2 ) 在vivi启动等待中,敲入空格键进入vivi界面环境,并输入以下命令:vivi> load flash kernel x <回车烧写更新内核约1分钟即可烧写完毕

3 ) 点击超级终端菜单中的“传送”,选“发送文件”zImage” 并选择xModem方式传送)烧写结束,重起实验板,观测超级终端窗口提示信息就可以启动linux内核,

(3) 新文件系统的烧写

1)首先SW104设为短接(从Nand Flash启动),确定已经成功烧写vivi.nand,加电运行可以看到vivi启动信息,输入空格进入命令状态;

2)双击运行Download.pjf(该文件在/tmp/edukit-2410/image/中)工程(将启动Embest IDE环境),点击连接Remote connect,程序应该正在运行(命令按钮STOP为红色);在串口输入help,看看有没有反应,如果没反应,点击IDE 按钮:Reset ->Start(F5);再输入help测试,直到有反应为止;

3)如果可以输出一些信息,再点击IDE中的Stop,配置Debug的Download地址为0x30000000,并点击IDE菜单Project选择Settings项,在Download页下拉Category到Download项,在Download File选择root.cramfs文件,点击确定后:

点击IDE菜单DEBUG选择Download下载文件系统映象?约1分钟

下载完毕后,点击Start(F5)

然后在超级终端里输入: load flash root j (烧写更新文件系统)?约1分钟即可烧写完毕

注意:只能在“vivi的烧写”操作完成后,才可以按以上方法正确烧写root映象到Nand Flash

重起实验板,观测超级终端窗口提示信息,引导整个系统启动到linux行命令输入状态。

2.4.2根文件系统的制作

(1)根文件系统

根文件系统是Linux系统的核心部分,包含系统使用的软件和库,以及所有用来为用户提供支持架构和用户使用的应用软件,并作为储存数据读写结果的区域。在Linux系统启动时,首先完成内核安装及环境初始化,最后会寻找一个文件系统作为根文件系统被加载。Linux系统中使用“/”来唯一表示根文件系统的安装路径。嵌入式系统中通常可以悬着的根文件系统有:Romfs、CRAMFS、RAMFS、JFFS2、EXT2等,甚至还可以使用NFS作为根文件系统。

(2)cramfs文件系统

Cramfs是Linux创始人Linux torvalds开发的一个适用于嵌入式系统的小文件系统。Cramfs是一个只读文件系统,采用zlib压缩,压缩比一般可以达到1:2,但仍可以做到高效的随机读取。Linux系统中,通常把需要修改的目录压缩存放,并在系统引导的时候再将压缩文件解开。因为cramfs不会影响系统读取文件的速度,而且是一个高度压缩的文件系统,因此非常广泛应用于嵌入式系统中。

(3)cygwin简介

Cygwin是一个在windows平台上运行的unix/Linux模拟环境,是cygnus solutions公司开发的自由软件。Cygwin中,“/”表示根目录,即cygwin的安装目录。我们常用的set_env_linux.sh中定义的目录有:

SOURCEDIR:/tmp/edukit-2410存储了vivi、linux、fs等源代码和例程

WORKDIR:/usr/local/src/edukit-2410工作区。

一般情况下都要把已经规划好的目录结构转换成一个映象文件,即使用命令工具 mkcramfs(cygwin下为 mkcramfs.exe),把相应的 cramfs 目录树压缩为单一的映象文件。其命令格式为:

mkcramfs [-h] [-e edition] [-i file] [-n name] dirname outfile 

可以使用我们提供的 mkcramfs.exe 在 cygwin 下编译生成文件系统映象文件 root.cramfs,再固化到开发系统 FLASH 上运行。

(4)常用的Linux行命令

1)、cd  改变当前目录(文件夹)。例如下,

        cd/  返回到根目录

        cd.. 退回到上级目录

        cd/tmp/edukit-2410/进入/tmp/edukit-2410/文件夹

2)、ls   列出当前目录中的内容。

Ls   简单格式列表

ls–l 使用详细格式列表。

3)、pwd  显示当前所在的目录。

(5)tar工具命令

tar 程序用于储存或展开 tar 存档文件。

命令格式:

tar [-参数]  [文件名][路径]

-x :extract | --get 从存档展开文件

-v :--verbose 详细显示处理的文件

-j :--有 bz2 属性的必须包含

-f :--file [HOSTNAME:]F 指定存档或设备(缺省为 /dev/rmt0)

(6)解压原文件系统(命令+解压目录的存放)

1)先将 root.cramfs.tar.bz2文件放在C:\cygwin目录中

2)解压文件系统

运行cygwin,执行以下命令解压安装:

$> source /tmp/edukit-2410/set_env_linux.sh?Linux编译环境变量设置

$> cd /

$> tar -xvjf  root.cramfs.tar.bz2

$> ls

… root …

root文件夹中就是我们想要的cramfs文件系统

3) 如果在根目录中产生root文件夹,解压成功

4)在root目录中新建xx文件夹,用于存放应用程序

进入该目录后执行以下命令编译链接测试程序:

$> cd  root

$>mkdir  xx

(7)编译应用程序 ts.c (命令+生成文件格式+存放位置):

将编写好的ts.c程序放在C:\cygwin目录中

进入该目录后执行以下命令编译链接测试程序:

$> cd /

$> arm-linux-gcc -o  ts  ts.c (也可以编写Makefile来编译)

生成文件: ts 如下图所示

将ts文件放入root 下的xx文件夹中

(8) 新文件系统的制作:

把刚才编译输出的ts文件拷贝到文件系统所在的工作目录root目录下,执行以下命令生成新的文件系统映象:

$> cd /

$> mkcramfs root root.new

刚刚编译生成的文件系统映象 root.new 中已经包含测试程序即生成文件。

解压文件系统

解压成功如下

在root目录中新建xx文件夹,用于存放应用程序

 


将编写好的ts.c程序放在C:\cygwin目录中

生成文件: ts 如下图所示

新文件系统的制作

生成文件:

 

 

 

 

 

 

 

 

 

第三章 程序

3.1.程序流程图:

3.2.分析驱动

触摸屏驱动在/kernel/drivers/char/s3c2410-ts.c 文件中。

3.2.1、触摸屏设备驱动中数据结构

(1)触摸屏的file_operations

static struct file_operations s3c2410_fops={

    owner: THIS_MODULE,

    open: s3c2410_ts_open,

    read: s3c2410_ts_read,

    release: s3c2410_ts_release,

#ifdef USE_ASYNC

    fasync: s3c2410_ts_fasync,//异步通知

#endif

  poll: s3c2410_ts_poll,//轮询

};

(2)触摸屏设备结构体的成员与按键设备结构体的成员类似,也包含一个缓冲区,同时包括自旋锁、等待队列和fasync_struct指针

typedef struct {

    unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_SAMPLE */

    TS_RET buf[MAX_TS_BUF]; /* protect against overrun(环形缓冲区) */

    unsigned int head, tail;/* head and tail for queued events (环形缓冲区的头尾)*/

    wait_queue_head_t wq; //* 等待队列数据结构

    spinlock_t lock; //* 自旋锁

#ifdef USE_ASYNC

    struct fasync_struct *aq;

#endif

#ifdef CONFIG_PM

    struct pm_dev *pm_dev; //友善之臂专有的,我后面的代码删除了这段

#endif

} TS_DEV;

(3)触摸屏结构体中包含的TS_RET值的类型定义,包含XY坐标和状态(PEN_DOWN、PEN_UP)等信息,这个信息会在用户读取触摸信息时复制到用户空       间

typedef struct {

    unsigned short pressure; //* 压力,这里可定义为笔按下,笔抬起,笔拖曳

    unsigned short x;   //* 横坐标的采样值

    unsigned short y;   //* 纵坐标的采样值

    unsigned short pad;   //* 填充位

} TS_RET;

(4)在触摸屏设备驱动中,将实现open()、release()、read()、fasync()和poll()函数,因此,其文件操作结构体定义

触摸屏驱动文件操作结构体:static struct file_operations s3c2410_fops={}

3.2.2、触摸屏驱动模块加载和卸载函数

(1)在触摸屏设备驱动的模块加载函数中,要完成申请设备号、添加cdev、申请中断、设置触摸屏控制引脚(YPON、YMON、XPON、XMON)等多项工作

触摸屏设备驱动的模块加载函数

  static int __init s3c2410_ts_init(void)

触摸屏设备驱动模块卸载函数

 static void __exit s3c2410_ts_exit(void)

(2)可知触摸屏驱动中会产生两类中断,一类是触点中断(INT-TC),一类是X/Y位置转换中断(INT-ADC)。在前一类中断发生后,若之前处于PEN_UP状态,则应该启动X/Y位置转换。另外,将抬起中断也放在INT-TC处理程序中,它会调用tsEvent()完成等待队列和信号的释放

触摸屏设备驱动的触点/抬起中断处理程序

static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg)

X/Y位置转换中断发生后,应读取XY的坐标值,填入缓冲区

触摸屏设备驱动X/Y位置转换中断处理程序

static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg)

触摸屏设备驱动中获得XY坐标

static inline void s3c2410_get_XY(void)

(3)tsEvent最终为tsEvent_raw(),这个函数很关键,当处于PEN_DOWN状态时调用该函数,它会完成缓冲区的填充、等待队列的唤醒以及异步通知信号的释放;否则(处于PEN_UP状态),将缓冲区头清0,也唤醒等待队列并释放信号

触摸屏设备驱动的tsEvent_raw()函数

static void tsEvent_raw(void)

(4)在包含了对拖动轨迹支持的情况下,定时器会被启用,周期为10ms,在每次定时器处理函数被引发时,调用start_ts_adc()开始X/Y位置转换过程

触摸屏设备驱动的定时器处理函数

static void ts_timer_handler(unsigned long data)

(5)在触摸屏设备驱动的打开函数中,应初始化缓冲区、penStatus和定期器、等待队列及tsEvent时间处理函数指针

触摸屏设备驱动的打开函数

static int s3c2410_ts_open(struct inode *inode, struct file *filp)

(6)触摸屏设备驱动的释放函数非常简单,删除为用于拖动轨迹所使用的定时器即可

触摸屏设备驱动的释放函数

 static int s3c2410_ts_release(struct inode *inode, struct file *filp)

3.2.3、触摸屏设备驱动的读函数

触摸屏设备驱动的读函数实现缓冲区中信息向用户空间的复制,当缓冲区有内容时,直接复制;否则,如果用户阻塞访问触摸屏,则进程在等待队列上睡眠,否则,立即返回-EAGAIN

触摸屏设备驱动的读函数

static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)

3.2.4、触摸屏设备驱动的轮询与异步通知

在触摸屏设备驱动中,通过s3c2410_ts_poll()函数实现了轮询接口,这个函数的实现非常简单。它将等待队列添加到poll_table,当缓冲区有数据时,返回资源可读取标志,否则返回0

触摸屏设备驱动的poll()函数

static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)

而为了实现触摸屏设备驱动对应用程序的异步通知,设备驱动中要实现s3c2410_ts_fasync()函数

触摸屏设备驱动的fasync()函数

static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)

3.2.5源程序触摸屏驱动代码:

/*

 * s3c2410-ts.c

 *

 * touchScreen driver for SAMSUNG S3C2410

 *

 * Author: Janghoon Lyu <nandy@mizi.com>

 * Date  : $Date: 2002/06/04 07:11:00 $

 *

 * $Revision: 1.1.2.6 $

 *

 * Based on pt036001b-ts.c

 *

 * This file is subject to the terms and conditions of the GNU General Public

 * License.  See the file COPYING in the main directory of this archive

 * for more details.

 *

 * History:

 *

 * 20##-05-27: Janghoon Lyu <nandy@mizi.com>

 *    - Add HOOK_FOR_DRAG

 *    - PM 内靛啊 甸绢啊 乐变 窍瘤父 抛胶飘 登瘤 臼疽澜.

 *

 */

#include <linux/config.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/miscdevice.h>

#include <linux/sched.h>

#include <linux/delay.h>

#include <linux/poll.h>

#include <linux/spinlock.h>

#include <linux/irq.h>

#include <linux/delay.h>

#include <asm/hardware.h>

#ifdef CONFIG_PM

#include <linux/pm.h>

#endif

/* debug macros */

#undef DEBUG

#ifdef DEBUG

#define DPRINTK( x... )  printk("s3c2410-ts: " ##x)

#else

#define DPRINTK( x... )

#endif

#define PEN_UP            0    

#define PEN_DOWN  1

#define PEN_FLEETING 2

#define MAX_TS_BUF   16  /* how many do we want to buffer */

#undef USE_ASYNC  1

#define DEVICE_NAME  "s3c2410-ts"

#define TSRAW_MINOR  1

typedef struct {

    unsigned int penStatus;     /* PEN_UP, PEN_DOWN, PEN_SAMPLE */

    TS_RET buf[MAX_TS_BUF];     /* protect against overrun */

    unsigned int head, tail; /* head and tail for queued events */

    wait_queue_head_t wq;

    spinlock_t lock;

#ifdef USE_ASYNC

    struct fasync_struct *aq;

#endif

#ifdef CONFIG_PM

    struct pm_dev *pm_dev;

#endif

} TS_DEV;

static TS_DEV tsdev;

#define BUF_HEAD  (tsdev.buf[tsdev.head])

#define BUF_TAIL  (tsdev.buf[tsdev.tail])

#define INCBUF(x,mod)    ((++(x)) & ((mod) - 1))

static int tsMajor = 0;

static void (*tsEvent)(void);

#define HOOK_FOR_DRAG

#ifdef HOOK_FOR_DRAG

#define TS_TIMER_DELAY  (HZ/100) /* 10 ms */

static struct timer_list ts_timer;

#endif

#define wait_down_int()  { ADCTSC = DOWN_INT | XP_PULL_UP_EN | \

              XP_AIN | XM_HIZ | YP_AIN | YM_GND | \

              XP_PST(WAIT_INT_MODE); }

#define wait_up_int()    { ADCTSC = UP_INT | XP_PULL_UP_EN | XP_AIN | XM_HIZ | \

              YP_AIN | YM_GND | XP_PST(WAIT_INT_MODE); }

#define mode_x_axis()    { ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \

              XP_PULL_UP_DIS | XP_PST(X_AXIS_MODE); }

#define mode_x_axis_n()  { ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \

              XP_PULL_UP_DIS | XP_PST(NOP_MODE); }

#define mode_y_axis()    { ADCTSC = XP_AIN | XM_HIZ | YP_EXTVLT | YM_GND | \

              XP_PULL_UP_DIS | XP_PST(Y_AXIS_MODE); }

#define start_adc_x()    { ADCCON = PRESCALE_EN | PRSCVL(49) | \

              ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | \

              ADC_NORMAL_MODE; \

             ADCDAT0; }

#define start_adc_y()    { ADCCON = PRESCALE_EN | PRSCVL(49) | \

              ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | \

              ADC_NORMAL_MODE; \

             ADCDAT1; }

#define disable_ts_adc() { ADCCON &= ~(ADCCON_READ_START); }

static int adc_state = 0;

static int x, y;  /* touch screen coorinates */

static void tsEvent_raw(void)

{

    if (tsdev.penStatus == PEN_DOWN) {

       BUF_HEAD.x = x;

       BUF_HEAD.y = y;

       BUF_HEAD.pressure = PEN_DOWN;

#ifdef HOOK_FOR_DRAG

       ts_timer.expires = jiffies + TS_TIMER_DELAY;

       add_timer(&ts_timer);

#endif

    } else {

#ifdef HOOK_FOR_DRAG

       del_timer(&ts_timer);

#endif

      

       BUF_HEAD.x = 0;

       BUF_HEAD.y = 0;

       BUF_HEAD.pressure = PEN_UP;

    }

    tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);

    wake_up_interruptible(&(tsdev.wq));

#ifdef USE_ASYNC

    if (tsdev.aq)

       kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);

#endif

#ifdef CONFIG_PM

    pm_access(tsdev.pm_dev);

#endif

}

static int tsRead(TS_RET * ts_ret)

{

    spin_lock_irq(&(tsdev.lock));

    ts_ret->x = BUF_TAIL.x;

    ts_ret->y = BUF_TAIL.y;

    ts_ret->pressure = BUF_TAIL.pressure;

    tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);

    spin_unlock_irq(&(tsdev.lock));

    return sizeof(TS_RET);

}

static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)

{

    TS_RET ts_ret;

retry:

    if (tsdev.head != tsdev.tail) {

       int count;

       count = tsRead(&ts_ret);

       if (count) copy_to_user(buffer, (char *)&ts_ret, count);

       return count;

    } else {

       if (filp->f_flags & O_NONBLOCK)

           return -EAGAIN;

       interruptible_sleep_on(&(tsdev.wq));

       if (signal_pending(current))

           return -ERESTARTSYS;

       goto retry;

    }

    return sizeof(TS_RET);

}

#ifdef USE_ASYNC

static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)

{

    return fasync_helper(fd, filp, mode, &(tsdev.aq));

}

#endif

static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)

{

    poll_wait(filp, &(tsdev.wq), wait);

    return (tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM);

}

static inline void start_ts_adc(void)

{

    adc_state = 0;

    mode_x_axis();

    start_adc_x();

}

static inline void s3c2410_get_XY(void)

{

    if (adc_state == 0) {

       adc_state = 1;

       disable_ts_adc();

       y = (ADCDAT0 & 0x3ff);

       mode_y_axis();

       start_adc_y();

    } else if (adc_state == 1) {

       adc_state = 0;

       disable_ts_adc();

       x = (ADCDAT1 & 0x3ff);

       tsdev.penStatus = PEN_DOWN;

       DPRINTK("PEN DOWN: x: %08d, y: %08d\n", x, y);

       wait_up_int();

       tsEvent();

    }

}

static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg)

{

#if 0

    DPRINTK("Occured Touch Screen Interrupt\n");

    DPRINTK("SUBSRCPND = 0x%08lx\n", SUBSRCPND);

#endif

    spin_lock_irq(&(tsdev.lock));

    if (tsdev.penStatus == PEN_UP)

      s3c2410_get_XY();

#ifdef HOOK_FOR_DRAG

    else

      s3c2410_get_XY();

#endif

    spin_unlock_irq(&(tsdev.lock));

}

static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg)

{

#if 0

    DPRINTK("Occured Touch Screen Interrupt\n");

    DPRINTK("SUBSRCPND = 0x%08lx\n", SUBSRCPND);

#endif

    spin_lock_irq(&(tsdev.lock));

    if (tsdev.penStatus == PEN_UP) {

      start_ts_adc();

    } else {

      tsdev.penStatus = PEN_UP;

      DPRINTK("PEN UP: x: %08d, y: %08d\n", x, y);

      wait_down_int();

      tsEvent();

    }

    spin_unlock_irq(&(tsdev.lock));

}

#ifdef HOOK_FOR_DRAG

static void ts_timer_handler(unsigned long data)

{

    spin_lock_irq(&(tsdev.lock));

    if (tsdev.penStatus == PEN_DOWN) {

       start_ts_adc();

    }

    spin_unlock_irq(&(tsdev.lock));

}

#endif

static int s3c2410_ts_open(struct inode *inode, struct file *filp)

{

    tsdev.head = tsdev.tail = 0;

    tsdev.penStatus = PEN_UP;

#ifdef HOOK_FOR_DRAG

    init_timer(&ts_timer);

    ts_timer.function = ts_timer_handler;

#endif

    tsEvent = tsEvent_raw;

    init_waitqueue_head(&(tsdev.wq));

    MOD_INC_USE_COUNT;

    return 0;

}

static int s3c2410_ts_release(struct inode *inode, struct file *filp)

{

#ifdef HOOK_FOR_DRAG

    del_timer(&ts_timer);

#endif

    MOD_DEC_USE_COUNT;

    return 0;

}

static struct file_operations s3c2410_fops = {

    owner: THIS_MODULE,

    open:  s3c2410_ts_open,

    read:  s3c2410_ts_read, 

    release:   s3c2410_ts_release,

#ifdef USE_ASYNC

    fasync:    s3c2410_ts_fasync,

#endif

    poll:  s3c2410_ts_poll,

};

void tsEvent_dummy(void) {}

#ifdef CONFIG_PM

static int s3c2410_ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,

                               void *data)

{

    switch (req) {

       case PM_SUSPEND:

           tsEvent = tsEvent_dummy;

           break;

       case PM_RESUME:

           tsEvent = tsEvent_raw;

           wait_down_int();

           break;

    }

    return 0;

}

#endif

#ifdef CONFIG_DEVFS_FS

static devfs_handle_t devfs_ts_dir, devfs_tsraw;

#endif

static int __init s3c2410_ts_init(void)

{

    int ret;

    tsEvent = tsEvent_dummy;

    ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);

    if (ret < 0) {

      printk(DEVICE_NAME " can't get major number\n");

      return ret;

    }

    tsMajor = ret;

    /* set gpio to XP, YM, YP and  YM */

#if 0

    set_GPIO_mode(GPIO106_nYPON_MD);

    set_GPIO_mode(GPIO105_YMON_MD);

    set_GPIO_mode(GPIO104_nXPON_MD);

    set_GPIO_mode(GPIO103_XMON_MD);

    GPUP(GPIO106_nYPON) |= GPIO_bit(GPIO106_nYPON);

    GPUP(GPIO105_YMON) &= GPIO_bit(GPIO105_YMON);

    GPUP(GPIO104_nXPON) |= GPIO_bit(GPIO104_nXPON);

    GPUP(GPIO103_XMON) &= GPIO_bit(GPIO103_XMON);

#else

    set_gpio_ctrl(GPIO_YPON);

    set_gpio_ctrl(GPIO_YMON);

    set_gpio_ctrl(GPIO_XPON);

    set_gpio_ctrl(GPIO_XMON);

#endif

    /* Enable touch interrupt */

    ret = request_irq(IRQ_ADC_DONE, s3c2410_isr_adc, SA_INTERRUPT,

             DEVICE_NAME, s3c2410_isr_adc);

    if (ret) goto adc_failed;

    ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT,

             DEVICE_NAME, s3c2410_isr_tc);

    if (ret) goto tc_failed;

    /* Wait for touch screen interrupts */

    wait_down_int();

#ifdef CONFIG_DEVFS_FS

    devfs_ts_dir = devfs_mk_dir(NULL, "touchscreen", NULL);

    devfs_tsraw = devfs_register(devfs_ts_dir, "0raw", DEVFS_FL_DEFAULT,

           tsMajor, TSRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR,

           &s3c2410_fops, NULL);

#endif

#ifdef CONFIG_PM

#if 0

    tsdev.pm_dev = pm_register(PM_GP_DEV, PM_USER_INPUT,

                 s3c2410_ts_pm_callback);

#endif

    tsdev.pm_dev = pm_register(PM_DEBUG_DEV, PM_USER_INPUT,

                 s3c2410_ts_pm_callback);

#endif

    printk(DEVICE_NAME " initialized\n");

    return 0;

 tc_failed:

    free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);

 adc_failed:

    return ret;

}

static void __exit s3c2410_ts_exit(void)

{

#ifdef CONFIG_DEVFS_FS  

    devfs_unregister(devfs_tsraw);

    devfs_unregister(devfs_ts_dir);

#endif

    unregister_chrdev(tsMajor, DEVICE_NAME);

#ifdef CONFIG_PM

    pm_unregister(tsdev.pm_dev);

#endif

    free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);

    free_irq(IRQ_TC, s3c2410_isr_tc);

}

module_init(s3c2410_ts_init);

module_exit(s3c2410_ts_exit);

触摸屏应用程序

#include <stdio.h>

#include <unistd.h>

#include <fcntl.h>              /* 文件操作 */

#define PEN_UP            0     /* 触摸笔抬笔,即触摸屏不被压下 */

#define PEN_DOWN     1      /* 触摸笔下笔,即触摸屏被压下 */

#define PEN_FLEETING 2      /* 触摸笔拖动 */

typedef struct {

  unsigned short pressure;      /* 触摸笔动作 */

  unsigned short x;             /* 触点x座标值 */

  unsigned short y;             /* 触点y座标值 */

  unsigned short pad;

}TS_RET;

int main()

{

    int fd,ret,i;

    unsigned char suba;

    TS_RET tsret;

  

    fd = open("/dev/touchscreen/0raw", O_RDWR);         /* 打开设备 */

    if(fd == -1)

    {

        printf("\nCan't open I2C device!\n");

        exit(-1);

    }

    while(1)

    {

       ret = read(fd, (char *)&tsret, sizeof(TS_RET));

       if (ret != sizeof(TS_RET))

       {

           printf("read touch screen error!");

           close(fd);

           exit(-1);

       }  

       else

       {

           printf("pressure is: %d\n", tsret.pressure);

           printf("x is: %d\n", tsret.x);

           printf("y is: %d\n", tsret.y);

       }

    }

    close(fd); 

    return 0;

}

3.3.应用程序的调试

   使用s3c2410­_ts.c触摸屏驱动编写应用程序,读取触摸屏的触点坐标值及动作信息(触点x坐标值,y坐标及是否有压力值press),并在串口中断打印出来

对触摸屏设别的操作有打开设备,关闭设备,读操作等。编写应用程序读取触摸屏的触点坐标值及动作信息时,只需利用触摸屏驱动程序便可实现,先打开触摸屏设备,然后调用读函数即可。

其中,触摸笔动作取值如下:

#define PEN_UP         0     /* 触摸笔抬笔,即触摸屏不被压下 */

#define PEN_DOWN      1      /* 触摸笔下笔,即触摸屏被压下 */

#define PEN_FLEETING  2      /* 触摸笔拖动 */

结构体定义如下:

typedef struct {

  unsigned short pressure;       /* 触摸笔动作 */

  unsigned short x;              /* 触点x座标值 */

  unsigned short y;              /* 触点y座标值 */

  unsigned short pad;

}TS_RET

打开应用程序:

 


3.2.6、实验结果显示:

第四部分感想

第四部分 心得

4.1 课程设计心得体会:

   为期几天的课程设计结束了,再次期间我积极亲自实验,用的目标板是s3c2410核心子板,用JTAG仿真器,用Cygwin模拟软件来学习触摸板的设计。我学会了很多,学会了很多。

首先我扪主要了解整个设计过程,以及实验环境的建立,这次用的是交叉编译环境,通过这次课设我更清楚搭建嵌入式系统的开发平台,我们用的目标板是s3c2410核心子板,用JTAG仿真器,用Cygwin模拟软件,课设的这几天我学会了熟练的使用Cygwin软件,掌握了一些常用的命令,加上研究生学长给我们的指导,知道了如何学习,如何思考,知道了运linux操作系统开发嵌入式与wince操作系统开发嵌入式的区别。

其次是学会vivi,内核,根文件系统的编译与移植(烧写),通过这个过程我熟悉了怎么把软件固化到硬件上,知道了软件怎么控制硬件,这个步骤很重要,要烧写不成功,目标板系统就运行不起来,实验就失败了,这个过程我们练习了好多变呢,大家都很累哦!

再次我们就开始写我们的应用程序,通过以上步骤实验系统搭建好了,只要调试好应用程序,然后再运行成功就行了,为此我又把课本上讲得触摸屏原理那章认真看了,又看了实验指导书,查资料,上网搜索,终于编出应用程序,经过不断的调试才编译成功,这个过程太辛苦了,加上实验板不太好,真是对我们的挑战,不过看到运行的结果,大家都很高兴,也很有成就感啊!还看懂了一些s3c2410的驱动程序的源代码,了解了s3c2410一些控制器的使用,以及s3c2410A的一些接口原理与应用。

我明白了只有不断的努力,不断的学习,才能在将来遇到的问题中能够游刃有余,才能够不会捉襟见肘。

  

 

第五部分 参考文献

5.1【参考文献】

1  程昌南,方强等.《ARM Linux入门与实践 》【M】.北京:北京航空航天大学出版社,2008.10

2  张晓林等.《嵌入式系统设计与实践》【M】.北京:北京航空航天大学出版社,2006.1

3  李俊等.《嵌入式Linux设备驱动开发详解》【M】.北京:北京人民邮电出版社,2008.3

4  黄智伟,邓月明,王彦.《ARM9嵌入式系统设计基础教程》.北京:北京航空航天大学出版社,2008.8

5    [美]Wayne Wolf. 嵌入式计算系统设计原理. 孙玉芳, 梁彬 罗保国 等译. 北京: 机械工业出版社, 20##

6    李剑, 赵鹏程, 汤建彬. 32位ARM嵌入式处理器的调试技术. 电子技术应用, 2003, (3)

7    钟汉如, 王创生. 嵌入式Linux的中断处理与实时调度的实现机制. 计算机工程, 2002, 28(10)

8    Arnold Berger. 嵌入式系统设计. 吕骏 译. 北京: 电子工业出版社, 20##



软件流程图:

相关推荐