




已阅读5页,还剩20页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
开放性实验报告题 目: 基于ARM的多线程应用程序设计 院系名称: 电气工程学院 专业班级: 自动1302 学生姓名: 张鹏涛 学 号: 201323020219 指导教师: 张晓东 成绩:指导老师签名: 日期:2017.1.6 目 录1 系统概述与设计要求11.1 系统概述11.2 设计要求22 方案论证22.1 实现方法22.2 线程优势23 硬件设计33.1 树莓派接口驱动LED电路设计34 软件设计44.1 驱动三色LED灯44.1.1 驱动实现方法44.1.2 wiringPi库安装和软件编程44.2 服务器和客户端54.2.1 服务器设计方法54.2.2 客户端设计方法55 系统调试6设计心得6参考文献7附录1(LED驱动程序)8附录2(服务器程序)10附录3(客户端程序代码)161 系统概述与设计要求1.1 系统概述 本系统设计是基于树莓派开发板上实现的,树莓派由注册于英国的慈善组织“Raspberry Pi 基金会”开发,EbenUpton/埃厄普顿为项目带头人。2012年3月,英国剑桥大学埃本阿普顿(Eben Epton)正式发售世界上最小的台式机,又称卡片式电脑,外形只有信用卡大小,却具有电脑的所有基本功能,这就是Raspberry Pi电脑板,中文译名树莓派。它是一款基于ARM的微型电脑主板,以SD/MicroSD卡为内存硬盘,卡片主板周围有1/2/4个USB接口和一个10/100 以太网接口(A型没有网口),可连接键盘、鼠标和网线,同时拥有视频模拟信号的电视输出接口和HDMI高清视频输出接口,以上部件全部整合在一张仅比信用卡稍大的主板上,具备所有PC的基本功能。而树莓派2具有900MHz内核频率, 4核 ARM Cortex-A7,1GB 内存,带Micro SD 卡插槽(支持通过它启动 Linux 操作系统,如 Fedora),40PIN接口(可以增加驱动外设)。本系统设计正式在树莓派2环境下开发实现多线程设计,设计的主要功能就是两个客户端通过服务器互相收发信息。1.2 设计要求 要求多个客户端能够同时连接服务器,而服务器需要创建线程来管理这多个客户端,并且能够把一个客户端发来的数据进行解析,发给另一个客户端,实现两个甚至多个客户端互相收发信息。能够通过驱动三色灯来发现系统运行的状态,红色说明有错误发生,绿色说明正在正常运行,蓝色说明有用户连接,绿色说明有客户端互相收发信息。2 方案论证2.1 实现方法 要实现服务器同时管理两个甚至多个客户端,就必须引入进程或线程。2.2 线程优势 一是和进程相比,它是一种非常节俭的多任务操作方式。 进程是系统中程序执行和资源分配的基本单位。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这就导致了进程在进行切换等操作起到了现场保护作用, 这是一种昂贵的多任务工作方式。 但是为了进一步减少处理机的空转时间支持多处理器和减少上下文切换开销,进程演化中出现了另外一个概念,这就是线程,也被人称为轻量级的进程。它是一个进程内的基本调度单位。线程是在共享的内存空间中并发的多道执行路径,它们共享一个进程的资源,比如文件描述符和信号处理等。因此,大大减少了上下文切换的开销。 二是线程间方便的通信机制。 对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。3 硬件设计3.1 树莓派接口驱动LED电路设计图 3.1 从图3.1可以知道,要想让三色灯的红色亮起来,首先控制树莓派GPIO.27引脚输出低电平,同理可以控制GPIO.28、GPIO29引脚电瓶来控制绿、蓝LED的启动和关闭。树莓派开发板上的相关引脚如图3.2。图 3.24 软件设计4.1 驱动三色LED灯4.1.1 驱动实现方法 控制引脚电瓶的高低就能实现控制LED灯的变化,实际上三色LED可以显示无数种颜色,要想超过三种颜色的显示实现,就必须引入PWM。PWM是模拟脉宽调制来控制输出引脚的实际输出电瓶大小,此系统可以控制引脚从03.3V变化来显示不同的颜色。wiringPi适合那些具有C语言基础,在接触树莓派之前已经接触过单片机或者嵌入式开发的人群。wiringPi的API函数和arduino非常相似,这也使得它广受欢迎。作者给出了大量的说明和示例代码,这些示例代码也包括UART设备,I2C设备和SPI设备等。4.1.2 wiringPi库安装和软件编程 首先需要在树莓派上安装wiringPi库,我们选择直接在网上下载安装源码,输入命令:cd 进入根目录下,输入命令:git clone git://wiringPi 从网上下载源码包,输入命令cd wiringPi 进入安装包目录下,依次输入命令:configure make make install来配置、编译和安装,最后输入命令sudo ./build 来执行编译之后生成的可执行文件,完成安装。最后输入命令:gpio readall会出来引脚图来确定已经安装成功。 接下来就需要运用库的软件编程来驱动led灯啦,在写C文件时首先要加入库的头文件:#include 和C语言必要的头文件:#include ,然后还需要加入实现软件PWM的头文件:#include 。接下来我们就需要运用库的API函数wiringPiSetup()初始化wiringPi,若初始化失败会返回-1;然后运用库的API函数softPwmCreate()创建软件PWM,此函数有3个输入参数,分别是控制引脚号,PWM最小值,PWM最大值;运用库的API函数softPwmWrite()写PWM的值,此函数有2个输入参数,分别是控制那个引脚号,写入的PWM的值,此值需要在最小最大值之间。 完整代码如附录1。4.2 服务器和客户端4.2.1 服务器设计方法 为了方便起见,我们把服务器和客户端都定义在本地IP上进行测试,服务器端的话,首先我们需要把主函数传入的端口号记录下来,并且利用C语言标准函数atoi转换成整型值。接着我们定义两个整型数组来存放两个客户端的套接字,然后我们根据端口去创建服务器,创建服务器需要几个函数来实现,第一个就是socket()函数来创建一个服务器的套接字,此函数有3个输入参数,我们选择ipv4协议族,流式Socket,TCP协议类型。然后根据端口号和本地IP配置服务器,之后就是调用绑定bind(),监听listen()函数来完成服务器的创建。之后就是根据创建的套接字来进行循环,如果有客户端连接,就保存客户端套接字创建一个线程去处理,此处我们以两个客户端为例来进行操作。若是套接字编号0发来消息,我们就转发给套接字编号1,若是超过2个的客户端连接进来我们直接关闭创建的线程就行,之后要是有客户端掉线,就把线程和客户端一块销毁。 具体代码实现见附录24.2.2 客户端设计方法 首先我们封装三个函数,分别是连接、读数据、写数据,开始就调用连接函数,在连接函数里我们创建客户端并通过输入的服务器ip和端口去连接服务器,然后我们创建两个线程分别是读和写,在读函数里我们不间断读键盘数据并发送给服务器,在写函数里不间断的读服务器发来的数据并显示在屏幕上。 具体代码实现见附录3。5 系统调试 此系统的调试,我们选择Linux虚拟机模拟调试,首先运行服务器和两个客户端,然后客户端连接服务器,之后两个客户端互相收发数据。为了方便起见,我在PC机上运行和仿真,首先安装虚拟机VMware8.0,然后安装VMware Tools,虚拟机的工具是为了共享电脑上的文件,这样可以在电脑上编写代码,在虚拟机上编译运行。 编译服务器的代码,输入命令gcc server.c -o server.exe -lpthread,回车之后会生成server.exe可执行文件,之后我们运行服务器,输入命令./server.exe 6789,运行服务器,其中6789为输入的端口号。之后编译客户端代码,输入命令gcc client.c -o client.exe -lpthread,回车之后会生成client.exe可执行文件,我们事先查看虚拟机ip,输入命令ifconfig回车就能看到虚拟机本机ip,为我们客户端连接服务器所用。之后我们运行客户端一,输入命令./client.exe 09 6789,回车,然后用同样的命令运行客户端二,之后我们在一个客户端输入信息回车,在另一个客户端就能接收到,具体运行结果如图5.1,5.2,5.3。图 5.1图5.2图5.3设计心得 此次开发性试验设计让我收获甚多。一是要有一个积极的心态,独立解决问题的意识,培养扎实基础的认识。不要什么东西都感觉跟简单(很多东西可能是看似简单)就不去做了或者不屑一做,以至于性网上搜搜就可以了,这样很不好。有自己的东西有自己的付出才会有程序运行成功时的喜悦和小自豪,这样也有助于培养自己的兴趣。要时刻牢记态度决定一切。其次是兴趣,感觉学习工作中兴趣很关键,只是一个引发人积极性的问题,有了兴趣就自觉了,效率自然就高了。再次要敢于尝试和挑战。不要安于现成的程序,而且不要害怕失败,在程序调试的过程中这点尤为重要,“发现出问题然后解决问题”是一个积累经验的过程,而且很高效。最后要不懈追求。对于源代码进行不断的完善,要尽可能的实现课题所要求的功能。对于初学者或者开发较少的人来说,大量大写程序还是有必要的,但同时要注意思考,理解其实现的内在意义。还可以自己添加一些有意义的功能来实现。当看到自己编写的程序正常运行时,兴趣也会随之而来,乐此不疲,形成一个良性循环。 短短一周的开放性ARM多线程设计很快结束了,我发现我对嵌入式这个方向、对嵌入式技术、对Linux都有了新的认识。通过这次的编程,我了解到,要真真正正的掌握计算机程序还不是一件简单容易的事儿,但真正掌握后,它带给我们的将是无穷的便捷与科技,我喜欢高端便捷的生活。我希望我能做计算机这个万能机器人的主人而不是奴隶,我会努力加油的!参考文献1徐千洋.LinuxC函数库参考手册.M中国青年出版社.20022马忠梅,马广云,徐英慧,田译.ARM嵌入式处理结构与应用基础M.北京航空航天大学出版社.20023邹思铁.嵌入式Linux设计与应用M.北京清华大学出版社.20024杜春雷.ARM体系结构与编程M.清华大学出版社.20035田泽.嵌入式系统开发与应用M.北京航空航天大学出版社.200511陈鑫.嵌入式软件技术的现状与发展动向M.软件世界.20016田泽.嵌入式系统开发与应用实验教程M.北京航空航天大学出版社.20047AlessandroRubini,JonathanCorbet.Linux设备驱动程序M.中国电力出版社.2002附录1(LED驱动程序)#include #include #include #define uchar unsigned char#define LedPinRed 27#define LedPinGreen 28#define LedPinBlue 29void ledInit(void) softPwmCreate(LedPinRed, 0, 100); softPwmCreate(LedPinGreen,0, 100); softPwmCreate(LedPinBlue, 0, 100);void ledColorSet(uchar r_val, uchar g_val, uchar b_val) softPwmWrite(LedPinRed, r_val); softPwmWrite(LedPinGreen, g_val); softPwmWrite(LedPinBlue, b_val);int main(void) int i; if(wiringPiSetup() = -1) printf(setup wiringPi failed !); return 1; ledInit(); while(1) ledColorSet(0xff,0x00,0x00); /red delay(500); ledColorSet(0x00,0xff,0x00); /green delay(500); ledColorSet(0x00,0x00,0xff); /blue delay(500); return 0;附录2(服务器程序)#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFSIZE 1024 int socket_client2; int socket_create(int port) int st = socket(AF_INET, SOCK_STREAM, 0); int on = 1; if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) = -1) printf(setsockopt is failed %sn, strerror(errno); return 0; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(st, (struct sockaddr *) &addr, sizeof(addr) = -1) printf(zhang.pt:bind is failed %sn, strerror(errno); return 0; if (listen(st, 300) = -1) printf(zhang.pt:listen is failed %sn, strerror(errno); return 0; return st; void deliver(int index, const char *buf, ssize_t len) ssize_t rc = 0; if(index = 0) if (socket_client1 = 0) printf(%d:user not onlinen, index); else rc = send(socket_client1, buf, len, 0); printf(send:%s,send:%u bytesn, buf, rc); if (rc = 0) if (rc = 0) printf(zhang.pt:send failed, disconnection,n); else printf(zhang.pt:send failed, %sn, strerror(errno); if(index = 1) if(socket_client0 = 0) printf(%d:user not onlinen, index); else rc = send(socket_client0, buf, len, 0); printf(send:%s,send:%u bytesn, buf, rc); if(rc = 0) if (rc = 0) printf(zhang.pt:send failed, disconnection,n); else printf(zhang.pt:send failed, %sn, strerror(errno); void socket_work(int index) char bufBUFSIZE; ssize_t rc = 0; while(1) memset(buf, 0, sizeof(buf); rc = recv(socket_clientindex, buf, sizeof(buf), 0); if (rc sin_addr.s_addr); sprintf(IPAddr, %u.%u.%u.%u, p0, p1, p2, p3); void socket_accept(int st) pthread_t thr_d; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); while(1) memset(&client_addr, 0, sizeof(client_addr); int client_st = accept(st, (void *)&client_addr, &len); if(client_st = -1) printf(zhang.pt:accept failed %sn, strerror(errno); break; else char sIP32; memset(sIP, 0, sizeof(sIP); sockaddr_toa(&client_addr, sIP); printf(zhang.pt:accept by %sn, sIP); int *tmp = malloc(sizeof(int); *tmp = client_st; pthread_create(&thr_d, &attr, socket_handle, tmp); pthread_attr_destroy(&attr); int main(int arg, char *args) if(arg 2) printf(zhang.pt:server port error!n); return 0; int iport = atoi(args1); if(iport = 0) printf(zhang.pt:port %d is invalid!n, iport); return 0; printf(zhang.pt:server is begin*v*!n); memset(socket_client, 0, sizeof(socket_client); int st = socket_create(iport); if(st = 0) return 0; socket_accept(st); close(st); printf(zhang.pt:server is endn); return 0; 附录3(客户端程序代码)#include #include #include #include #include #include #include #include #include #define BUFSIZE 1024 void *socket_read(void *arg) int st = *(int *)arg; char bufBUFSIZE; while(1) memset(buf, 0, sizeof(buf); ssize_t rc = recv(st, buf, sizeof(buf), 0); if(rc = 0) printf(zhang.pt:recv failed, %sn, strerror(errno); break; else printf(zhang.pt:recv:%s,recv:%u byten, buf, rc); return NULL; void *socket_write(void *arg) int st = *(int *)arg; char bufBUFSIZE; while(1) memset(buf, 0, sizeof(buf); read(STDIN_FILENO, buf, sizeof(buf); int ilen = strlen(buf); if(bufilen - 1 = n) bufilen - 1 = 0; ssize_t rc = send(st, buf, sizeof(buf), 0); printf(zhang.pt:send:%s,send:%u byten, buf, rc); if(rc = 0) printf(zhang.pt:send failed, %sn, strerror(errno); return NULL; in
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高锰酸钾制备氧气的课件
- 济宁市2024-2025学年九年级下学期语文月考模拟试卷
- 高速铁路道岔检查课件
- 高速路上骑行安全知识培训课件
- 电表知识培训资料课件
- 高警示药品课件
- 高血压的危险因素
- 电脑知识培训照片课件
- 电脑新手培训知识课件
- pta考试真题及答案
- 幕墙施工培训课件
- 2025年北京东城二中学英语八下期末联考试题含答案
- 2025届安徽省蒙城县英语七下期末考试试题含答案
- 设备巡回检查管理制度
- 产房安全核查管理制度
- 阿尔茨海默症的护理
- (2025)公共基础知识考试试题附及答案
- 中国五矿笔试题库及答案
- 2025年茶叶加工工职业技能竞赛参考试题库500题(含答案)
- 加强未成年思想道德教育
- 马克思主义与社会科学方法论课后思考题答案
评论
0/150
提交评论