《《嵌入式软件开发》课程设计报告(共27页).docx》由会员分享,可在线阅读,更多相关《《嵌入式软件开发》课程设计报告(共27页).docx(27页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上嵌入式软件开发课程设计报告课题名称: 基于ARM11开发平台小球碰撞设计与实现 专业班级: 计算机科学与技术 指导教师评语: 签名: 年 月 日专心-专注-专业目 录1、使用技术介绍12、需求分析33、概要设计44、详细设计55、成果展示116、设计总结137、附录16 一、 使用技术介绍1.1 LCD显示屏技术液晶显示屏,英文通称为LCD(Liquid Crystal Display),是属于平面显示器的一种。用于电视机及计算机的屏幕显示。LCD液晶显示器的工作原理,在显示器内部有很多液晶粒子,它们有规律的排列成一定的形状,并且它们的每一面的颜色都不同分为:红色,绿
2、色,蓝色。这能还原成任意的其他颜色,当显示器收到电脑的显示数据的时候会控制每个液晶粒子转动到不同颜色的面,来组合成不同的颜色和图像。1)分辨率:显示器支持的像素多少,一般采用屏幕的宽x高表示,如:800x600,1600x1200, 480x320。2)“像素”(Pixel) 是由 Picture(图像) 和 Element(元素)这两个单词的字母所组成的,是用来计算数码影像的一种单位,是计算机屏幕上所能显示的最小单位。3)颜色深度:显示一个像素点的位数;4)颜色:单色、伪彩色、彩色、真彩色像素颜色是由红(Red)、绿(Green)、蓝(Blue)三种颜色组成,即所谓RGB。对于16位深颜色来
3、说,采用565格式表示颜色,其中Red占高5、Green占中间6位、Blue占低5位。每个像素占VRAM中的2个字节。 对于24位深颜色,RGB分别占用8位,每个像素占用VRAM中的3个字节。1.2电阻式触摸屏技术电阻式触摸屏是一种传感器,基本上是加上的结构,薄膜和玻璃相邻的一面上均涂有ITO(纳米铟锡金属氧化物)涂层,具有很好的导电性和透明性。当触摸操作时,薄膜下层的ITO会接触到玻璃上层的ITO,它将矩形区域中触摸点(X,Y)的物理位置转换为代表X坐标和Y坐标的电压,如图1.2。而完成点选的动作,并呈现在屏幕上。很多LCD模块都采用了电阻式触摸屏,这种屏幕可以用四线、五线、七线或八线来产生
4、屏幕偏置电压,同时读回触摸点的电压。运算公式: T_w = T_x2 T_x1 T_h = T_y2 T_y1 L_x = (T_x2-T_x)*L_w / T_wL_y = (T_y T_y1)*L_h / T_h 图1.21.3 五点校准法为了方便理解,我们首先引入2个概念,坐标和逻辑坐标。物理坐标就是触摸屏上点的实际位置,我们通常以液晶上点的个数来度量。逻辑坐标就是触摸屏上这一点被触摸时A/D转换后的坐标值。由于电阻式触摸屏的电压成线性均匀分布,那么A/D转换后的坐标也成线性。假如我们将液晶最左下角点对应的解摸屏上的点定为物理坐标原点A其物理坐标记为(XA=0,YA=0),其逻辑坐标记为
5、(XLA,YLA)(不一定为0)。那么触摸屏上任意一点B的逻辑坐标可表达为:XLB=XLA+KXXB,YLB=YLA+KYYB。其中KX、KY分别为触摸屏X方向和Y方向的因子系数,这就像弹簧一样,拉力与弹簧伸长正比。KX、KY可能为正,也可能为负,这根据具体触摸屏安装的方向和特性。每个液晶触摸屏,我们也应该单独计算每一个触摸屏的K系数。如果A点不是坐标原点,也是任意一点可以表达成:XLB=XLA+KX(XB-XA),YLB=YLA+KY(YB-YA)。我们可以推出计算K系统的公式:KX=(XLB-XLA)/(XB-XA),KY=(YLB-YLA)/(YB-YA)。在液晶上固定的位置显示五个点,
6、因为是固定的位置,所以这五个点的物理坐标是预知的。这五个点不应太靠边,因为边缘点对应的触摸屏线性一般不太好。(1)首先在ABCDE对应的位置逐步用尖状物触摸,得到五个点的逻辑坐标。(2)分别比较A和C、B和D的横坐标,如果差值不在允许范围(你自己规定一个即可,比如5),则重复操作(1)(2)步。(3)分别比较A和B、C和D的纵坐标,如果差值不在允许范围(你自己规定一个即可,比如5),则重复操作(1)(2)(3)步。(4)用2组数据计算X向K系数平均值KX=(XLB-XLA)/(XB-XA)+(XLD-XLD)/(XD-XC)/2(5)用2组数据计算Y系数平均值KY=(YLA-YLC)/(YA-
7、YC)+(YLB-YLD)/(YB-YD)/2(6)将C点逻辑坐标作为基坐标,根据式2-2则触摸屏上任意一点F逻辑坐标与基坐标的关系为:XLF=XLC+KX(XF-XC)YLF=YLC+KY(YF-YC)根据这个公式,我们也可逆推出F点的物理坐标XF=(XLF-XLC)/KX+XCYF=(YLF-YLC)/KY+YC(7)用公式2-4求出E点逻辑坐标,并与(1)步得到的E点坐标比较,如果差值不在允许范围(你自己规定一个即可,比如5),则重复操作以上步骤直到满足要求。(8)将基坐标XLC、YLC、XC、YC和KX、KY记录在存储设备,触摸屏校正完成。二、需求分析2.1 功能需求主要功能:实验设计
8、在基于嵌入式Linux操作系统,arm11开发平台上进行相关操作,要求在LCD显示屏内,分别控制2个不同颜色的小球在LCD屏矩形显示区内不停地运动,当小球碰到边界时,反射改变运动方向,当两个小球相碰时,小球改变运动方向,并统计碰撞的次数。图2.1 小球碰撞界面2.2 界面需求实验界面简洁,显示为一个矩形边框,界面中有两个个小球,小球通过撞击边框和相互碰撞不断运动。开始碰撞:运行程序会出现小球碰撞程序主界面,如图2.2,点击开始碰撞进入小球碰撞程序;退出:点击退出,返回退出小球碰撞界面,如图2.3 图2.2 程序主界面 图2.主界面 图2.3 退出小球碰撞界面三、概要设计 3.1 系统组成小球碰
9、撞系统基于ARM11平台,利用Linux系统的调用和PC机的调试通过使用触摸屏在LED显示屏上显示两个小球相撞。如图3.1 图3.1 系统组成图1.ARM11处理:采用real6410基于ARM11嵌入式处理器内核,主频800MHz;2.LCD显示器:4.3寸,分辨率480272,16位RGB565彩色;3.触摸屏:电阻式,支持40964096;4.网络:以太网,支持100Mbps,TCP/IP协议; 3.2 功能模块工程文件夹:ball头文件程序:gui.h;ts.h主控模块:main.c触摸校准模块:ts.c通过主控模块main.c来调用图形库gui.h和校准模块ts.c,以及小球碰撞函数
10、,来在显示屏上实现小球碰撞功能,如图3.2。 图3.2 功能模块图四、详细设计4.1 main()函数:main函数:程序入口,调用显示屏、触摸屏等初始化函数,显示主界面,等待触摸操作,转相应的功能处理。如图4.1函数原型:int main(int agrc, char *argv);输入参数:argc 整型,命令行以空格分隔的字符串个数; argv 指针的指针型, 指向存放字符串的开始地址。返回值:整型,0 表示正常,非0表示异常 图4.1 main函数流程图4.2 ball_move()函数:void ball_move()函数:实现画出小球并让小球运动,当两个小球碰壁或相撞时,小球向反方
11、向弹开并计算碰撞次数,运动到初始位置时,小球停止。如图4.2函数原型:void ball_move(ball_t *b )输入参数:b 结构体指针类型 通过b的值来判断小球碰撞的次数返回值:无返回值小球运动算法:1)初始化: w=480; h=272; x=old_x=100; y=old_y=100; r=16; x_dir = 1; y_dir = -1;2)如果x = w,则 x_dir = -1 碰到右边界,向左运动;4)如果y= h则y_dir = -1 碰到下边界,向上运动;6)更新圆心坐标:x += x_dir; y += y_dir;7)在原来位置用背景色画(即清除);8)在新
12、位置用前景色画圆;9)延时一段时间,使圆停留在屏幕上显示;10)old_x = x; old_y = y;11)如果运动到初始位置,则退出,否则跳转到2) 图4.2 ball_move函数流程图4.3 get_hotpoint(int x, int y)函数:get_hotpoint()函数:获得触摸屏幕上的热点,并判断是不是点击相应的位置,是返回一个值,不是返回-1,如图4.3函数原型:get_hotpoint(int x, int y);输入参数:x 整型,获得x坐标 y 整型,获得y坐标。返回值:整型,返回r-v表示正常,返回-1表示异常 图4.3 获得热点函数流程图4.4 小球函数所需
13、要的相关函数1) 创建子进程fork():一个进程,包括代码、数据和分配给进程的资源。pid_t pid;pid = fork(); /创建子进程if (pid = -1) exit(-1); /创建失败if (pid = 0)/子进程else/父进程2) 延时函数usleep():函数原型: int usleep(useconds_t usec);参数: usec : 延时时间值,微秒。包含头文件 #include 3) 进程之间共享内存通信:创建或获取一个共享内存:命令格式:shmget(key,size,flag)功能:获得一个内部标识为shmid的共享存储区语句格式:Int shmid
14、 = int shmget(key_t key, int size, int flag );参数说明:key共享存储区关键字,可以由用户指定,如果使用IPC_PRIVATE,其值由系统产生size存储区的大小(字节数)。如果存储区定义为字符型,则大小为定义的字符个数;如果存储区定义为整型,大小可以使用sizeof(int)加以定义。flag用户设置的标志或访问方式,与消息缓冲shmget中的含义相同,在实验中,可以使用0666|IPC_CREAT,表示任意进程可读写。返回值:正确返回:共享存储区的内部标识符shmid错误返回:-14) 将共享内存附接到进程虚拟地址空间:命令格式:字符型共享内存
15、:Shmat( int shmid, char *shmaddr, int msgflg, ulong *raddr);数值型共享内存:Shmat( int shmid, int *shmaddr, int msgflg, ulong *raddr);功能:逻辑上将内部标识符为shmid的共享存储区附接到进程的虚拟地址空间shmaddr。参数说明:shmid共享存储区的描述符,可以由shmget()的返回值得到;shmaddr用户提供的共享存储区附接的虚拟地址,若shmaddr为0,则由系统选择一个适当的地址来附接该存储区;flag规定了对该存储区的操作权限,以及系统是否要对用户规定的地址做舍
16、除操作。若果flag中设置了SHM_RND表示操作系统在必要时舍去这个地址;如果设置了SHM_RDONLY则表示只允许读,flag为0表示可读可写。viraddr附接的虚拟地址,若定义为char *viraddr,则该共享内存作为字符存储区使用,若定义为int *viraddr,则该共享内存作为整型存储区使用。5) 将共享内存从进程地址空间断开:命令格式:shmdt(viraddr)功能: 将一个共享存储区从指定进程的虚拟地址空间断开。参数说明: shmaddr系统调用shmat()所返回的虚拟地址。返回值:正确返回:0错误返回:-16) 对共享内存操作:命令格式:shmctl(int shm
17、id, int cmd, struct shmid_ds *buf)功能:对与共享存储区关联的各种参数进行操作,从而对共享存储区进行控制,包括删除共享存储区。参数说明:shimd共享存储区的内部标识符,由shmget()调用返回;buf用户级数据结构地址,其结构类型与系统定义的shmid_ds一致,可以用0。cmd规定操作的类型。其规定如下: IPC_STAT返回包含在指令的shmid相关数据结构中的状态信息,并把它放置在用户存储区中的*buf指针所指的数据结构中。执行此命令的进程必须有读取允许权。IPC_SET对于指定的shimd,为它设置有效用户和小组标识符和操作存取权。IPC_RMID删
18、除指定的shimd以及与它相关的共享存储区数据结构。SHM_LOCK在内存中锁定指定的共享存储区,必须是超级用户才可以进行此项操作。五、成果展示5.1 将相关的图片、驱动拷贝到用户目录下图5.1 拷贝文件5.2 编译程序 图5.2 编译程序5.3 连接目标机,运行程序 图5.3 运行程序5.4 登录界面展示 图5.4 登录界面5.5 小球碰撞界面展示 图5.5 小球碰撞界面5.6 退出界面展示 图5.6 退出界面六、设计总结七、附录7.1 主函数程序#include #include #include #include #include #include #include #include #
19、include gui.h #include ts.h#define K_SIZE 4 typedef struct int x,y,r,c; int dir_x,dir_y; ball_t; /定义一个小球结构体key_t keyId; int shmid; int w,h; char *bb; ball_t *b1, *b2;/小球碰撞函数 void ball_move(ball_t *b ) int old_x,old_y; int dis,cnt; old_x = b-x; old_y = b-y; cnt = 0; while(1) dis = (b1-x-b2-x)*(b1-x-b
20、2-x) +(b1-y-b2-y)*(b1-y-b2-y); /小球之间的距离 if (dis r + b2-r) * (b1-r + b2-r) /如果小球相撞 b-dir_x = -b-dir_x; b-dir_y = -b-dir_y; if (b = b1) cnt+; printf(cnt = %dn,cnt); /统计碰撞次数 else if (b-x r) b-dir_x = 1; if (b-y r) b-dir_y = 1; if (b-x + b-r) = w) b-dir_x = -1; if (b-y + b-r) = h) b-dir_y = -1; b-x += b
21、-dir_x; b-y += b-dir_y; /重新定义圆心坐标 fill_circle(old_x,old_y,b-r,BLACK);/在原来的地方清屏 fill_circle(b-x,b-y,b-r,b-c); /在新的地方画圆 usleep(5000); /延时函数 old_x = b-x; old_y = b-y; /定义按键坐标结构体typedef struct RECT int x; int y; int w; int h; int v; rect; struct RECT btn_star = 232,127,142,37,0x30; /开始按键坐标struct RECT bt
22、n_exit = 232,192,142,37,0x31; /退出按键坐标/建立坐标位置 struct RECT *btn_menu_set = &btn_star, &btn_exit, NULL ; / 获取屏幕热点函数int get_hotpoint(int x, int y) rect * r; int i; i = 0; for(;) r = btn_menu_seti; if (r = NULL)/按键为空 break; / 获得一个热点范围if (x r-x) & (x x + r-w) & (y r-y) & (y y + r-h) ) return r-v; i+; retu
23、rn -1; /* / 画一个按钮函数void draw_button(int x, int y, int w, int h, const char* str) fill_rectangle(x,y,w,h,GRAY); draw_h_line(x,y,w,WHITE); draw_v_line(x,y,h,WHITE); draw_h_line(x,y+h-1,w,BLACK); draw_v_line(x+w-1,y,h,BLACK); draw_string16(x+4,y+4,BLACK,GRAY,str,0); */int main(int argc, char* argv) int
24、 x,y,btn_n; unsigned int on; fb_init(); /设备初始化函数clr_screen(BLACK); /清屏函数ts_init(); /触摸屏初始化函数on = 0; draw_bmp(main.bmp,0,0); for(;) / 获取屏幕上的坐标get_scrn_xy(&x, &y); / 获得热点坐标 btn_n = get_hotpoint(x,y); if (btn_n = 0x30) on = 1;/状态取反if (on) pid_t pid; w = 480; h = 272; fb_init(); clr_screen(BLACK); keyId
25、 = ftok(argv0, 0); shmid=shmget(keyId, sizeof(ball_t)*2,0777|IPC_CREAT); bb= shmat(shmid, NULL,0); b1 = (ball_t *)bb; b1-r = 24; b1-c= RED; b1-x = 100; b1-y = 100; b1-dir_x = 1; b1-dir_y = -1; /初始ball2 b2 = (ball_t *)bb + sizeof(ball_t); b2-r = 24; b2-c= GREEN; b2-x = 200; b2-y = 120; b2-dir_x = -1;
26、 b2-dir_y = 1; pid = fork(); if (pid =0) ball_move(b1); else ball_move(b2); if (btn_n = 0x31) on = 1;/状态取反if (on) draw_bmp(over.bmp,0,0); ts_close(); fb_close(); return 0; 7.2 编写构建文件EXEC = flashOBJS = main.o ts.oCROSS_COMPILER = arm-none-linux-gnueabi-CC= $(CROSS_COMPILER)gccCFLAG = -cLIBS = -lpthre
27、ad -L./ -lguiall:$(EXEC)$(EXEC): $(OBJS)$(CC) -o $ $(OBJS) $(LIBS)cp $ /nfsroot/usr/%.o:%.c$(CC) $(CFLAG) -o $ $clean:rm -rf $(EXEC) *.o *.bak7.3 编写校准文件#include #include #include #include #include #include gui.h#define CALIB_FNAME calib.txttypedef struct TS_POINTint scrn_x;int scrn_y;int ts_x;int ts
28、_y; ts_point;/*(20,20) (ts_x1, ts_y1) (460,20)(ts_x2, ts_y2)(240,136)(ts_x5, ts_y5) (20,252) (ts_x3, ts_y3) (460,252)(ts_x4, ts_y4)*/#if 0/事件数据结构struct input_event struct timeval time;_u16 type;_u16 code;_s32 value;/* * Event types */#define EV_SYN0x00#define EV_KEY0x01#define EV_REL0x02#define EV_A
29、BS0x03#define EV_MSC0x04#define EV_SW0x05#define EV_LED0x11#define EV_SND0x12#define EV_REP0x14#define EV_FF0x15#define EV_PWR0x16#define EV_FF_STATUS0x17#define EV_MAX0x1f#define EV_CNT(EV_MAX+1)/* event code */#define ABS_X0x00#define ABS_Y0x01#define ABS_Z0x02#define ABS_RX0x03#define ABS_RY0x04#
30、define ABS_RZ0x05#define ABS_THROTTLE0x06#define ABS_RUDDER0x07#define ABS_WHEEL0x08#define ABS_GAS0x09#define ABS_BRAKE0x0a#define ABS_HAT0X0x10#define ABS_HAT0Y0x11#define ABS_HAT1X0x12#define ABS_HAT1Y0x13#define ABS_HAT2X0x14#define ABS_HAT2Y0x15#define ABS_HAT3X0x16#define ABS_HAT3Y0x17#define
31、ABS_PRESSURE0x18#define ABS_DISTANCE0x19#define ABS_TILT_X0x1a#define ABS_TILT_Y0x1b#define ABS_TOOL_WIDTH0x1c#define ABS_VOLUME0x20#define ABS_MISC0x28#define ABS_MAX0x3f#define ABS_CNT(ABS_MAX+1)#define BTN_TOUCH0x14a#endif#define DEV_NAME /dev/input/event1 /触摸屏设备 event0 按键设备int ts_fd;/选取显示屏上的5个点s
32、truct TS_POINT tp5= 20, 20,0,0,460, 20,0,0, 20,252,0,0,460,252,0,0,240,136,0,0;/触摸屏校准使用的变量int ts_min_x, ts_max_x;int ts_min_y, ts_max_y;float rat_x, rat_y;/* 获取触摸屏坐标 */static void get_ts_xy(int *x, int *y)struct input_event t;int sx,sy,ix,iy;while(1)if ( read(ts_fd, &t, sizeof(t) ) = sizeof(t) /读一个事
33、件/printf(type:code:value=%x:%x:%xn,t.type,t.code,t.value);if ( t.type = EV_ABS ) /事件类型为绝对位置switch (t.code)case ABS_X:sx += t.value;ix+;break;case ABS_Y:sy += t.value;iy+;break;case ABS_PRESSURE:/屏上有触摸if (t.value = 1)/按下 = 3,24,2sx = 0;sy = 0;ix = 0;iy = 0;if (t.value = 0) & (ix 0) & (iy 0) /抬起*x = s
34、x/ix;*y = sy/iy;return;break;default:break;/* 画十字交叉线 */static void draw_cross_line(int x, int y, int color)draw_h_line(x-10,y,20,color);draw_v_line(x,y-10,20,color);/* 校准程序 */void calib(void)int i;for (i=0; i ts_max_x)i = ts_min_x;ts_min_x = ts_max_x;ts_max_x = i;if (ts_min_y ts_max_y)i = ts_min_y;t
35、s_min_y = ts_max_y;ts_max_y = i;rat_x = (float)(ts_max_x-ts_min_x) / 440.0;rat_y = (float)(ts_max_y-ts_min_y) / 232.0;ts_min_x -= (int)(rat_x * 20.0);ts_max_x += (int)(rat_x * 20.0);ts_min_y -= (int)(rat_y * 20.0);ts_max_y += (int)(rat_y * 20.0);/* 获取显示屏坐标 */void get_scrn_xy(int *x, int *y)int ts_x,
36、ts_y;get_ts_xy(&ts_x, &ts_y);if (ts_x ts_max_x) ts_x = ts_max_x;if (ts_y ts_max_y) ts_y = ts_max_y;*x = 479 * (ts_x-ts_min_x) / (ts_max_x - ts_min_x);*y = 271 * (ts_y-ts_min_y) / (ts_max_y - ts_min_y);*x = 479 - (*x);/printf(x = %d y = %dn,*x,*y);/触摸屏初始化程序int ts_init(void)int fd;ts_fd = open(DEV_NAME, O_RDONLY); /打开触摸屏设备if ( ts_fd = 0 )