通信与信息工程学院
嵌入式开发技术
课程设计报告
通信与信息工程学院
二〇##年
目 录
嵌入式课程设计... 1
1 设计要求... 1
1.1 基本题型... 1
1.2 综合题型... 2
2 开发环境、开发工具... 2
3设计过程及结果... 5
3.1 实现交叉编译环境... 5
3.2第几小组成员步骤... 5
3.3实现Linux系统下的简易聊天室... 7
4 设计总结... 20
参考文献... 22
(1)嵌入式开发环境配置
①采用vmware+linux配置开发主机系统,要求构建linux系统,配置nfs,samba;
②掌握minicom、samba及NFS使用,能利用其实现windows、linux开发主机与嵌入式实验系统间的通信;
③利用NFS服务实现主机与实验系统间文件共享;
④利用提供的工具构建交叉编译环境;
要求:在下图时间上面一行显示小组成员姓名
Armv4l-unknown-linux-gcc 是 否 在/opt/host/armv4l/bin/,如果不是这个路径,请使用 vi 修改/root/.bash_profile 文件中 。ATH变 量 为 PATH=$PATH:$HOME/bin:/opt/host/armv4l/bin/ , 存 盘 后 执 行 : source /root/.bash_profile
(2)熟悉VI、GCC、GDB及MAKE文件使用;
(3)在开发系统中编写一个程序,实现打印“通信工程13级第3小组嵌入式开发技术课程设计基础内容”功能,编写makefile文件,并通过NFS下载到实验箱中,验证交叉编译环境配置。
基于socket编程的简单聊天室程序设计:
(1)掌握linux下socket编程方法;
(2)基于C语言设计一个简单的聊天室程序,PC运行客户端程序,嵌入式系统运行服务器端程序,服务器随时侦听客户端请求并将其接入,要求至少实现2个客户端接入服务器并进行通信的功能;
(3)编写Makefile文件;
(4)利用NFS将程序下载到实验箱中,编译执行。
(5)课程设计报告中应包含服务器端socket创建、绑定、监听、允许接入及接收数据等关键代码及其说明,客户端请求及数据发送等关键代码及说明;
(1)安装VWware软件
①开始安装加载文件.双击该文件的图标,进入加载安装文件的界面。
②设置安装类型。安装文件加载完毕后进入开始安装界面。单击next按钮后,进入安装类型选择界面,选择tyical选项。
③执行软件包的安装选项,依据所做的选择,把对应的软件组件安装到系统中,输入正确的序列号。
(2)配置VMware
①打开桌面上VMware图形,双击打开
②再打开原来的文件夹,把汉化包打开
③执行软件的安装选项,依据所做的选择,确认安装。确认完后,即配置完成。
④点击打开虚拟机,选择标准,下一步,执行软件的安装选项。接下是密钥,填写老师所给的密码。安装完成。
(3)安装驱动
点击安装包,根据软件的安装选项,点击next按钮,即可安装完成。
注:在电脑上安装好虚拟机之后配置相关参数
①配置NFS:点击菜单运行系统设置->点击服务器设置->NFS服务器,点击增加,在目录中选择共享目录的路径,在主机(host)中填入主机IP地址(192.168.1.12),并选择客户对共享目录的操作位读写(Read/write);在常规选项中选择允许来自高于1024的端口的连接,点击确定后即可配置好NFS。配置完成后,可以简单测试一下NFS是否配置好了: 在虚拟机上自己 mount 自己,看是否成功就可以判断NFS是否配好了。
mount 192.168.1.12:/arm2410cl /host
之后ls命令查看arm2410cl之下的文件目录,如果文件目录在,那么说明NFS配置成功。
②端口配置
用串口线连接好笔记本电脑和 2410 经典版平台。
计算机,属性,设备管理器,端口
高级设置下端口号COM1
进入虚拟机设置,串行端口
结果:
(1)创建工作目录
【root@vm-dev~】# mkdir winter
【root@vm-dev winter】# cd winter
(2)编写winter.c文件
【root@vm-dev~】# vi winter.c
(3)编写Makefile文件
CC =armv4l-unknown-linux-gcc
EXEC=client server
OBJS=client.o server.o
CFLAGS+=
LDFLAGS+=-static
all:$(EXEC)
$(EXEC):$(OBJS)
$(CC) $(LDFLAGS) –o $@ $(OBJS)
clean:
-rm –f *.elf *.gdb *.o
其中,
CC 指明编译器
EXEC 表示编译后生成的执行文件名称
OBJS 目标文件列表
CFLAGS 编译参数
LDFLAGS 连接参数
all: 编译主入口
clean: 清除编译结果
(4)运行make编译程序
【root@vm-dev~】# make clean
【root@vm-dev winter】# make
(5)源程序
#include<stdio.h>
int main(void)
{
printf(“ 通信工程13级第三小组嵌入式开发技术课程设计基础内容“);
}
6)结果
由于电脑与开发板不匹配,结果没有办法出来
(1)程序流程图
(2)程序工作过程
服务端处于监听状态,客户端发送请求,连接成功并通信。首先服务端调用socket()函数创建一个套接字,然后把协议,端口号,ip信息通过bind()进行绑定。以上操作完后服务端就开始监听客户端的请求,并设置监听的最大数目。当客户端发送链接请求时,服务端就调用accept()函数接受客户端的请求。然后对于客户端来说,也是要先调用socket()函数创建客户端的套接字,这里是用的TCP协议,所以可以不用bind()函数。接着调用connect()函数与服务端建立连接。当服务端和客户端建立连接时,可以通过彼此之间的套接字描述符来进行数据传输。其中一方通过send函数把数据写入数据缓冲区,另一方通过recv()函数从缓冲区内读出数据,这样就完成了服务端与客户端之间的数据传输。当双方数据传输完成后,函数close()关闭各自的 套接字,使客户端和服务端通信中断。
(3)socket编程方案
①设计一个简单的聊天室程序,PC运行客户端程序,嵌入式系统运行服务器端程序,服务器随时侦听客户端请求并将其接入,要求至少实现2个客户端接入服务器并进行通信的功能;
②Makefile文件
③NFS将程序下载到实验箱中,编译执行。
注:程序里的函数解释
(1)Socket()
作用:socket函数为客户机或服务器创建一个sokcet
格式:
int socket(int family,int type,int protocol);
参数说明:
Family:表示地址族,可以去AF_UNLX和AF_INT。
其中,AF_UNLX只能够用于单一的UNIX系统进程间通信;AF_INT是针对Internet的,因而可以允许在远程主机之间通信,实验中使用AF_INT。
Type:网络程序所采用的通信协议,可以取SOCK_STREAM或SOCK_DGRAM。其中,SOCK_STREAM表明使用的是TCP协议,这样提供按顺序的、可靠的、双向、面向连接的比特流;SOCKE_DGRAM表明使用的是UDP协议,这样只会提供定长、不可靠、无连接的通信。
(2)bind( )
格式:
int bind(int sockfd,struct sockaddr *addr,int addrlen);
参数说明:
Sockfd:socket的文件描述符号。
Sockaddr:表示名字所用的一个数据结构,用来保存地址(包括IP地址和端口)
Addrlen:设置结构大小长度。
(3)listen()
格式:
int listen(int sockfd, int backlog);
作用:监听连接信号,和accepted函数合同。
参数说明:
Sockfd:表示socket调用返回的文件描述符。
Backlog:表示接入队列允许的连接数目,大多数系统允许20个,也可以子定义5~10个。
(4)accept()
格式:
Int accept (int sockfd, void *addr, int *addrlen);
作用:与listen函数合用,监听信息、接收客户端请求。
参数说明:
Sockfd:表示socket的文件描述符。
Addr:表示指向局部的数据结构struct sockaddr-in的指针。
Addrlen:表示地址的长度。
(5)connect()
格式:
int connect( int sockfd , struct sockaddr *serv_addr , int addrlen);
作用:在面向连接的系统中客户及连接服务器时使用,connect必须在bind后使用。
参数作用:
Sockfd:表示socket的文件描述符。
Serv-addr:表示村访目的端口和ip地址(套接字)的数据结构。
(6)send() 和 recv()
格式1:
Int send (int sockfd, const vod *msg,int len, int flags);
功能:发送信息。
格式2:
Int recv (int sockfd , void *buf,int len, usigned int flags);
作用:用于流式socket、数据报socket内部之间的通信。
(7)close( ) 和 shutdown ( )
格式:
Close( int sockfd)
或
Int shutdown(int sockfd , int f);
参数说明:
f的值为下面一种:
0----不允许继续接收;
1----不允许继续发送;
2---不允许继续发送和接收。
(8)有关线程的系统调用函数pthread_create()、pthread_join()
实验过程说明(使用TCP/IP)
(1)监听连接
利用socket、bind、listen建立连接,步骤是:
1) 先用socket函数初始化socket,创建新的sockfd。
Sockfd = socket(AF_INT,SOCK_STREAM,0)
2)此步骤涉及到IP地址及其处理过程。
参数说明:
inet_addr 函数 INADDR_ANY
该函数把由小数点分开的十进制IP地址转为unsinged long 类型,而在实验中所使用的为INADDR_ANY,使用利用自已的IP地址自动填充。
a)利用bind函数绑定端口和IP地址。
My_addr.sin_family=AF_INET; /*将地址族类型设定好 */
My_addr.sin_port=htons(MYPORT; /* 将端口给其赋值*/
My_addr.sin_addr.s_addr=INADDR_ANY; /*用连接地址自动填充ip*/
Bind(sockfd,(stuct sockaddr*)&my_addr,sizeof(stuct sockaddr));
/*sockfd 是分配的socket名字,my-addr则便是分配好的端口与IP,用bind绑定*/
b)利用listen监听请求
(2)发送请求
1)利用gethostbyname获取主机信息。
2)初始化socket端口。
3)利用connect函数将自己的IP地址等信息发送到主机,等待主机调用accept函数来接受请求。
(3)主机接收请求,进行数据通信
1)主机利用accept接收请求。
2)创建子进程,显示欢迎信息;
3)接收返回信息,显示连接成功,并推出连接;
4)关闭客户端口socket;
5)关闭服务端socket,结束子线程。
(4)实现步骤
①建立工作目录
【root@vm-dev~】# mkdir server
【root@vm-dev server】# cd server
【root@vm-dev server】# vi server.c
【root@vm-dev~】# mkdir client
【root@vm-dev client】# cd client
【root@vm-dev client】# vi client.c
②编写程序源代码
程序附后
③编译实现过程
ⅰ.在编写完TCP服务端程序server.c后,用 armv4l-unknown-
linux-gcc –lpthread –o server.c server 生成程序server。
ⅱ.在编写完TCP客户端程序client.c后,用armv4l-unknown-linux-gcc –o client.c client 生成程序client
ⅲ.在嵌入式系统上运行server。
在主机上打开一个窗口,运行client,输入服务器的IP地址,并检查器结果的正确性。
ⅳ.输入:
# ./server
# ./client 192.168.1.12 (192.168.1.12为本机的ip地址)
ⅴ.输出:
#server:got connection from 192.168.1.12
ⅵ.客户端发送信息服务器端接收信息。
客户端通过键盘输入消息内容平回车,以发送消息给服务器端;
ⅶ.结果:
服务端:
客户端:
注 :源程序
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h> //数据类型定义
#include <netinet/in.h> //定义数据结构
#include <sys/socket.h>
#include <sys/wait.h>
#include<unistd.h>
#include <arpa/inet.h> //AF_INET相关操作函数
#define SERVER_PORT 8887 /* 客户机连接远程主机的端口 */
#define MAXDATASIZE 100 /* 每次可以接收的最大字节 */
#define SERVER_IP "192.168.1.13" /* 服务器的IP地址 */
//#define WELCOME“******WELCOME TO THE CHATROOM*****”
int main()
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct sockaddr_in server_addr;
printf("\n======================client initialization======================\n");
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
//结构体的定义与初始化
server_addr.sin_family = AF_INET; //使用IPv4的协议
server_addr.sin_port = htons(SERVER_PORT); //端口号,htons()把16位值从主机字节序转换成网络字节序
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);ip地址
bzero(&(server_addr.sin_zero),sizeof(server_addr.sin_zero));
//将第一个参数所指的内存区域前sizeof(第二个参数)个字符清零
if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) == -1) //)&server_addr服务器端地址
{
perror("connect");
exit(1);
}
//循环输入文字
while(1)
{
bzero(buf,MAXDATASIZE);
printf("\nBegin receive...\n");
if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1)
// buf 接收数据缓冲区 ,numbytes接收的字节数
{
perror("recv");
exit(1);
}
else if (numbytes > 0)
{
int len, bytes_sent;
buf[numbytes] = '\0';
printf("Received: %s\n",buf);
printf("Send:");
char msg[MAXDATASIZE];
scanf("%s",msg);
len = strlen(msg);
//发送至服务器
if(send(sockfd,msg,len,0) == -1)
// msg要发送的数据指针
{
perror("send error");
}
}
else
{
//numbytes=0,表示socket已断开
printf("soket end!\n");
}
}
close(sockfd);
return 0;
}
服务器端代码
#include <sys/types.h>
#include <sys/socket.h> // 包含套接字函数库
#include <stdio.h>
#include <netinet/in.h> // 包含AF_INET相关结构
#include <arpa/inet.h> // 包含AF_INET相关操作的函数
#include <unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/shm.h>
#define MYPORT 8887
#define MYKEY 12345
#define SIZE 10240
int main()
{
char buf[100];
memset(buf,0,100);
int server_sockfd,client_sockfd;
socklen_t server_len,client_len; //?
struct sockaddr_in server_sockaddr,client_sockaddr;
printf("\n======================server initialization======================\n");
server_sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(MYPORT);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
server_len = sizeof(server_sockaddr);
//允许重复使用本地地址和套接字绑定
int on = 1;
setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定端口
if(bind(server_sockfd,(structsockaddr*)&server_sockaddr,server_len)==-1)
{
perror("bind");
exit(1);
}
//监听端口
if(listen(server_sockfd,5) == -1)
{
perror("listen");
exit(1);
}
client_len = sizeof(client_sockaddr);
pid_t ppid,pid;
while(1)
{
if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_sockaddr,&client_len))==-1)
{
perror("accept error");
exit(1);
}
else
{
send(client_sockfd,"You have connect Server!",strlen("You have connect Server!"),0);
}
printf("\n%s:%d Login server!\n\n",inet_ntoa(client_sockaddr.sin_addr), ntohs(client_sockaddr.sin_port));
//,inet_ntoa将32位二进制形式的IP地址转换为数字点形式的IP地址
ppid = fork(); //创建子进程
if(ppid == -1)
{
printf("fork 1 failed:");
}
else if(ppid == 0) //子进程用于接收客户端信息并发送
{
int recvbytes;
pid = fork(); //再次创建子进程
if(pid == -1)
{
printf("fork 2 failed:");
exit(1);
}
else if(pid == 0) //子进程的子进程用于接收消息
{
while(1)
{
bzero(buf,100);
if((recvbytes = recv(client_sockfd,buf,100,0))==-1)
{
perror("read client_sockfd failed:");
}
else if(recvbytes != 0)
{
buf[recvbytes] = '\0';
usleep(10000);
printf("%s:%d said:%s\n",inet_ntoa(client_sockaddr.sin_addr), ntohs(client_sockaddr.sin_port), buf);
//将客户端发送过来的消息发回给客户
if(send(client_sockfd,buf,recvbytes,0)==-1){
perror("send error");
break;
}
}
}
}
else if(pid>0) //此时的id为子进程id
{
}
}
else if(ppid>0)
{
//总父进程中关闭client_sockfd(因为有另一个副本在子进程中运行了)返回等待接收消息
close(client_sockfd);
}
}
return 0;
}
在本学期的最后一周,我们被要求完成嵌入式的设计总结,虽然只有不到一周的时间,但是大家都感觉收获颇丰。把课堂上遗忘的、遗落的知识都捡了起来,旧的知识新的知识都掌握了很多,并且切实的体会到软件开发的困难与乐趣,认识到了自己的不足,并且慢慢摸索,不耻下问,在老师和小组成员的共同努力下,结束了这次的实践。
此次课程设计老师要求我们完成两道基础题目,以及一道三选一的综合题目。前面的基础题目大家有在课堂上接触过,并且通过查找资料,大家分工合作一个上午就有了很大的进展,但是在下午的完善工作中还是被卡住了,一个小的程序调试不出来,不能出现要求的结果,最后在其他组一个同学的帮助下完成了基础题目。第二天大家开始做综合题,经过商量选择了《基于socket编程的简单聊天室程序设计》,其实三道题目大家都没有把握能完成,对这道题比较有兴趣就敲定了。开始就是大量的查找资料,因为大家在课堂上学习的知识都太浅,并且大都停留在理论上,没有开发经验,所以大量工作都依靠互联网,不过因为我们组成员的C的能力都挺好,所以能够对代码程序理解并修改以及调试,最终还是尽我们最大努力完成了这次设计。
下面整理一下这次课程设计中个人的总结。
齐秀:搜集资料,写论文
这次的实践中,我负责搜集资料以及论文编撰。在刚拿到题目的时候,因为大家都比较束手无策,所以就必须要借用别人的东西,加以修改整理变成自己的东西。我查找了很多论文和书籍,然后根据设计要求将可用的东西整理打包给其他人,包括一些代码和思想,在程序调试成功后进行了总结并参与撰写论文。在这中间,我认识到了我们的不足,需要学习的东西还有很多。
许婷:编写、调试程序
在这次程序设计过程中,我主要参与了客户端代码的编写和数道是交叉编译环境的问题,还有就是串口速率不一致的问题。总而言之,遇到困难千万不能放弃,要自己搜集资料,询问同学,不断尝试,在一次次失败中汲取教训,从而获得进步。
王青青:编写、调试程序
这次实验中,我们通过开发板与电脑相连,将程序下载到开发板上,进行调试,在下载过程中碰到了minicom老进不去,进去之后,挂载不上,通过同学交流,设置NFS参数,最后挂载上,在调试socket程序时,程序错误,没有办法执行,一遍一遍的读取程序,最终调试成功。
王莉笑:搜集资料,写报告
我负责的是书写报告。报告并不是最后才写的,而是在设计的过程中一点点添加完善,在实践开始先写了大体框架以及设计要求,在大家实践的过程中对流程以及出现的问题、解决方法等进行记录,绘制一些必要的图表并且对结果整理,这些作为核心写进报告里,最后进行总结,并对全文排版。我在这个过程中没有深入了解代码,这是一个遗憾。
张乐:编写、调试程序
在本次嵌入式实验中,我主要完成的任务是编写程序,调试程序。在实验过程碰到了很多问题,比如:minicom连接不上,通过计算机,属性,端口,进行端口与速率设置,将其设置成com1,115200.在虚拟机中也要进行设置,通过 ctrl+A,Z 进入参数配置页面,将tty01改成tty00,将速率改成115200,进行保存。之后进入minicom 然后进行挂载,调试。由于笔记本的原因,好几次键盘失控,这在实验中算是碰到的最大问题,好几次实验停滞不前,老师也没有办法,只能不停的重启。最后重装一次,才正常工作。最后完成实验。
1.孙弋.ARM+Linux嵌入式系统开发基础[M].西安:西安电子科技出版社,2008;
2.周留军,武金磊.基于socket的简单聊天室的设计与实现[J].电脑知识与技术,2008, 3(21);
3.王海勇.基于嵌入式linux串口专用交换机的设计[D]:[硕士学位论文].南京:南京航空航天大学,2011.
福建工程学院嵌入式系统课程设计报告书题目基于S3C2440设备驱动及其界面设计班级姓名学号指导老师陈靖张平均李光炀2目录一设计课题…
福州大学课程设计任务书课程嵌入式课程设计题目姓名李仁煌学号011000610系别电机电器专业电气工程与自动化年级20xx起讫日期2…
嵌入式系统课程设计报告基于ARM的楼宇对讲系统设计摘要采用模块化设计方法设计出一款基于ARM微控制芯片和Linux操作系统的楼宇对…
嵌入式系统开发课程设计专周报告题目:具有日历功能的电子时钟系别及专业:计算机工程系计算机应用技术班级:10511学生姓名:XXX指…
课程设计综合实验报告20xx20xx年度第1学期名称题目院系班级学号学生姓名指导教师设计周数成绩日期年月日一课程设计的目的与要求1…
福建工程学院嵌入式系统课程设计报告书题目基于S3C2440设备驱动及其界面设计班级姓名学号指导老师陈靖张平均李光炀2目录一设计课题…
湖南科技大学计算机科学与工程学院嵌入式系统设计与开发实验报告书题目远程温光数据监测系统班级12级计算机一班姓名刘政材学号120xx…
课程设计报告基于ARM的嵌入式电子点菜系统班学姓级号名09061320xx061316叶尔多斯海拉提20xx年10月1题目基于AR…
中南大学嵌入式系统实验设计报告指导老师吴志虎李志民设计者连金涛专业班级测控0801班学号0909081012时间20xx年6月1实…
XXXX课程设计报告课程名称嵌入式系统设计题目专业班级学生姓名学生学号指导老师二一三年一月八日目录1概述111背景112设计目标2…