基于嵌入式Linux的温度采集系统的设计与实现.docx
《基于嵌入式Linux的温度采集系统的设计与实现.docx》由会员分享,可在线阅读,更多相关《基于嵌入式Linux的温度采集系统的设计与实现.docx(31页珍藏版)》请在冰豆网上搜索。
基于嵌入式Linux的温度采集系统的设计与实现
课程设计
论文题目
基于嵌入式Linux的温度采集系统
的设计与实现
学院
专业
班级
学号
学生姓名
指导教师
完成时间
2016年5月
摘要
数据采集系统是信息科学的一个重要分支,它研究信息数据的采集、存储、处理以及控制等。
本文提出采用嵌入式Linux作为操作系统,针对三星公司的S5PV210嵌入式处理器,设计一个嵌入式温度采集系统.论文在分析了Linux设备驱动程序的基本工作原理基础上,讨论了开发中经常会碰到的中断处理、拥塞处理、I/O端口,并在此基础上实现了基于S5PV210嵌入式处理器的开、读、写、关外部RAM的字符设备驱动和网络驱动。
结合高精度温度传感器DS18B20,实现温度的正确采集,并通过以太网络将数据上传给上位服务器。
论文首先介绍了通信网络中各种设备特性、总线结构及传输技术,然后介绍根据单片机与PC机之间的串行通信原理,用ubantu完成数据采集系统的软件设计与实现,为用户提供一个友好的人机界面,对采集系统进行控制并显示采集后的数据.使用串口线传输数据,为数据采集系统和计算机之间的通讯开辟了新的道路。
关键词:
数据采集系统;以太网络;S5PV210;DS18B20
I
DesignandImplementationofanEmbeddedTemperatureAcquisitionSystembasedonLinux
Abstract
DataAcquisitionSystemisanimportantbranchofinformationscience,itstudiesthecollection,storage,processingandcontrolofinformationdata。
Inthispaper,theembeddedLinuxisusedastheoperatingsystem,andtheembeddedS5PV210processorisdesignedtodesignanembeddedtemperatureacquisitionsystem。
BasedontheanalysisoftheLinuxdevicedriverbasedonthebasicworkingprinciplediscusseddevelopmentoftenencounterinterruptioncongestionhandling,processing,I/Oports,andonthisbasis,realizeds5pv210embeddedprocessoropen,read,write,outsidetheramofthecharactersetbydriverandthenetworkdriveon。
CombinedwiththehighprecisiontemperaturesensorDS18B20,toachievethecorrecttemperaturecollection,andthroughtheEthernetnetworktouploaddatatothehostserver.
Atfirst,thepaperintroducesthecommunicationnetworkcharacteristicsofvariousdevices,busstructureandtransmissiontechnology,andthenintroduceaccordingtotheprincipleofserialcommunicationbetweenMCUandPC,ubantucompletedsoftwaredesignandimplementationofdataacquisitionsystem,toprovideuserswithafriendlyman-machineinterface,tocontroltheacquisitionsystemanddisplayafterthecollectionofthedata.Theuseofserialdatatransmission,forthedataacquisitionsystemandthecommunicationbetweenthecomputerhasopenedupanewpath。
Keywords:
Dataacquisitionsystem;Ethernet;S5PV210;DS18B20
第一章需求分析
1。
1总体设计
图1-1总体设计图
1.2客户端界面设计(app:
Linux_client)
1.作为用户操作的简单界面
2.用于发送命令控制硬件
3.接收server传输的数据
4.显示数据。
1。
3服务器设计(linux)
1.用于接收(app)客户端发送的命令
2.处理命令
3.转发给硬件
4.读取硬件传输数据
5.把数据传回(app)客户端
1.4硬件设计
1.Led灯
点亮灯:
led1、led2。
2.温度传感器
把温度数据读取到客户端。
3.蜂鸣器
用于报警以及音乐播放.
第二章详细设计
2。
1代码调用过程
代码调用过程如图所示:
图2-1代码调用图
分析代码调用过程:
0.准备工作:
1.先调用insmodled。
ko插入模块
2.register_chrdev注册字符设备驱动
1.App:
fd=open("/dev/led”,O_RDONLY);
2.drivers:
2.sys_open(”/dev/led",O_RDONLY)
3.由内核为我们匹配,看是否能够找到设备号为249的led-drivers
4。
如果匹配成功,继续找到structfile_operationsled_fops结构体
5.通过结构体找到open函数的入口led_fops.open
6。
led_open
7.arm_init
2。
2文件IO(系统库函数)
1.Open打开文件
返回一个文件描述符
2.Read通过文件描述符fd,读取文件
3.Write通过文件描述符fd,写文件
4.Close(进程结束的时候,会自动关闭,可以不必显示的调用close)
阻塞:
poll机制解决
客户端如果要接收服务器回发的数据,则需要读取网络套接字,此时,客户端涉及到读终端和读服务器,而读终端和读服务器都是会阻塞的,所以调用poll机制解决.
intpoll(structpollfd*fds,nfds_tnfds,inttimeout);
功能:
把所关心的文件描述符加入到structpollfd结构中,告诉内核我要非阻塞的读这个文件描述符,内核为我们判断,如果不阻塞,则相应的状态,
参数1:
structpollfd{
intfd;/*所关心的文件描述符*/
shortevents;/*告诉内核我要做什么:
POLLIN:
非阻塞的读*/
shortrevents;/*内核返回的状态*/
};
参数2:
关心的描述符的个数
参数3:
愿意等待多长时间
-1:
一直等待
〉0:
表示愿意等待的时间
返回值:
大于0:
表示至少有一个已经成功返回
==0:
表示超时
〈0:
表示失败
2.3网络编程
TCP(即传输控制协议):
是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。
适用情况:
1.适合于对传输质量要求较高,以及传输大量数据的通信。
2.在需要可靠数据传输的场合,通常使用TCP协议
3.MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议
项目需求:
1.Linux平台下
a)服务器(server)
i.等待连接客户端
ii.接收客户端发送的数据[字符串和文件]
iii.处理客户端发送的数据和命令
iv.发送处理结果给客户端
b)客户端
i.简单的界面
ii.从键盘接收用户输入命令
iii.发送数据或者命令给服务器
iv.接收服务器返回的结果
c)协议:
tcp
2.实现编程
a)TCP四次握手协议
b)TCP编程模型
图2—2TCP编程模型图
3.网络编程所需要的API函数
a)服务器
i.Socket
ii.Bind
iii.Listen
iv.Accept
v.Read/read
vi.Close
b)客户端
i.Socket
ii.Connect
iii.Read/read
iv.Close
通用地址结构
structsockaddr
{
u_shortsa_family;//地址族,AF_xxx
charsa_data[14];//14字节协议地址
};
Internet协议地址结构
structsockaddr_in{
sa_family_tsin_family;/*地址族:
AF_INET*/
in_port_tsin_port;/*端口号*/
structin_addrsin_addr;/*IPV4地址internetaddress*/
};
/*IPv4地址结构*/
structin_addr{
uint32_ts_addr;/*addressinnetworkbyteorder*/
};
2.4内核驱动开发:
(模块编程)
1.模块入口moude_init
2.模块出口module_exit
3.语法:
c语言
4.编译(Makefile)
a)makeinstall
b)make
c)cpled。
ko/opt/filesystem/test
5.执行:
驱动模块后缀:
led。
ko
a)插入内核:
insmodled.ko
b)查看模块:
lsmod
c)移除模块:
rmmodled
2.5注册字符设备驱动
staticinlineintregister_chrdev(unsignedintmajor,constchar*name,
conststructfile_operations*fops)
功能:
把设备注册,添加到字符设备的表格中
图2—3字符设备驱动图
insmodled。
ko调用内核驱动模块注册设备到内核字符设备管理注册表中
图2—4打开文件设备过程图
2。
6操作硬件的过程:
(裸奔代码)
1.找到外设(led),分析外设功能
a)原厂提供
b)Google,baidu
2.led原理图
图2—5led点灯流程图
操作led的GPIO控制器,主要有以下两个:
GPC0CON:
用于控制GPIO引脚输入还是输出
GPC0CON[32]
LED1->GPC0CON[3]->[15-12]——〉0001=Output
LED2->GPC0CON[4]—〉[19—16]—->0001=Output
GPC0DAT:
用于设置电平的高低
GPC0DAT[3]—->GPC0CON[15-12]→led1→亮->高电平1
GPC0DAT[4]--〉GPC0CON[19—16]→led2-〉灭—>低电平0
Led:
GPC0CON寄存器地址0xE0200060
#defineGPC0CON(*(volitaleunsignedlong*)0xE0200060)
GPC0DAT寄存器地址0xE0200064
#defineGPC0DAT(*(volitaleunsignedlong*)0xE0200064)
MMU
当开启了MMU之后,我们是不能直接访问到物理地址的。
需要通过ioreamp把物
理地址映射为虚拟地址,我们只能通过虚拟地址操作硬件
Virt=ioremap(phy);
intstrncasecmp(constchar*s1,constchar*s2,size_tn);
比较字符s1和s2的前n个字符是否相等,如果相等,则返回0
5.裸奔代码操作硬件过程
图2-6操作硬件流程图
第三章测试过程
3。
1测试
1.用户登录
输入用户名和密码进行校验
2.登录成功进入到用户操作界面(如图3-1所示)
输入要控制硬件的命令:
如:
打开led1,则输入on1
关闭led1,则输入off1
打开音乐播放器,则输入song
获取温度,则输入get
……
退出,则输入quit
图3—1用户操作界面
第四章项目拓展
4.1项目拓展
目前本项目实现了通过客户端操作硬件,实现了点亮灯/蜂鸣器报警/音乐播放/温度数据采集功能。
除用于温度监测外,在系统中的ARM外围可接入控制电路、其他性能的传感器甚至摄像头等,还可以实现多种其他特殊需要的远程监测及控制,如水位监测、视频监控等,具有十分广阔的应用背景。
智能硬件框架(如图4-1所示)
图4-1智能硬件框架图
附录
服务器模块:
/*1.调用socket函数创建套接字。
TCP协议:
SOCK_STREAM*/
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(-1==sockfd){
perror(”socket”);
return—1;
}
/*填充服务器信息*/
structsockaddr_inservaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;//PF_INET
servaddr.sin_port=htons(PORT);//端口号(5001—65536)
servaddr.sin_addr.s_addr=inet_addr(SERVERIP);//ip地址
socklen_tadrlen=sizeof(servaddr);
/*2.调用bind指定本地地址和端口。
*/
ret=bind(sockfd,(structsockaddr*)&servaddr,adrlen);
if(-1==ret){
perror("bind”);
return-1;
}
/*3.调用listen启动监听。
*/
ret=listen(sockfd,1000);
if(—1==ret){
perror("listen");
return—1;
}
printf("serverinit.dsuccess..。
\n”);
intnewfd;
charbuf[BUFSZ]={0};
pthread_ttid;
while
(1)
{
/*4.调用accept从已连接列队中提取客户连接。
*/
newfd=accept(sockfd,NULL,NULL);
if(newfd〈=0){
continue;
}
printf("%dconnectsuccess.。
。
\n”,newfd);
/*为每个客户创建线程去维护它
==〉tid:
用于存放新建线程ID
==>do_work:
新建线程从这里开始执行
==>newfd:
传给执行函数的参数*/
ret=pthread_create(&tid,NULL,do_work,&newfd);
if(0!
=ret){
continue;
}
/*设置为可分离态*/
pthread_detach(tid);
}
/*6。
调用close关闭连接.*/
close(sockfd);
close(newfd);
return0;
}
/*执行函数(void* 表示可以接收任意类型)*/
void*do_work(void*arg)
{
intret;
charbuf[BUFSZ];
intnewfd=*(int*)arg;
char*strerr=”密码或者用户名输入有误!
”;
unsignedintcmd=—1;
unsignedlongval=-1;
inti=0;
intn=2;
intdev_fd;
/*5。
调用I/O函数(read/write)与客户端通讯。
*/
intfd_led;
fd_led=open(”/dev/led”,O_RDWR);
if(fd_led<0){
perror(”open”);
return(void*)-1;
}
/*开辟一个线程不停的发送温度给客户*/
pthread_ttid1;
ret=pthread_create(&tid1,NULL,do_temp,&newfd);
pthread_detach(tid1);
while
(1)
{
/*读取客户端信息*/
memset(buf,0,sizeof(buf));
ret=read(newfd,buf,sizeof(buf)-1);
if(ret〉0){
/*发送命令给硬件*/
if(!
strncasecmp(buf,"on1",3)){
cmd=LED_ON;
val=3;
}elseif(!
strncasecmp(buf,”on2",3)){
cmd=LED_ON;
val=4;
}elseif(!
strncasecmp(buf,"off1",4)){
cmd=LED_OFF;
val=3;
}elseif(!
strncasecmp(buf,"off2",4)){
cmd=LED_OFF;
val=4;
}elseif(!
strncasecmp(buf,"onb",3)){
pwm_on();
}elseif(!
strncasecmp(buf,”song”,4)){
pwm_music_fun();
}
if(ioctl(fd_led,cmd,(unsignedlong)val)〈0){
perror(”ioctlfailed\n”);
exit
(1);
}
}
}
客户端模块:
intmain(intargc,char**argv)
{
intret;
charbuf[BUFSZ]={0};
chartemp[BUFSZ]=”26.234000";
/*1.调用socket函数创建套接字。
TCP协议:
SOCK_STREAM*/
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(-1==sockfd){
perror("socket");
return-1;
}
/*填充服务器信息*/
structsockaddr_inservaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr。
sin_family=AF_INET;
servaddr.sin_port=htons(PORT);//端口号
servaddr。
sin_addr.s_addr=inet_addr(SERVERIP);//ip地址
socklen_tadrlen=sizeof(servaddr);
/*2。
调用connect连接服务器端*/
ret=connect(sockfd,(structsockaddr*)&servaddr,adrlen);
if(—1==ret){
perror("connect”);
return-1;
}
printf(”clientconnectsuccess..\n");
structpollfdpfd[2]={0};
pfd[0].fd=0;
pfd[0].events=POLLIN;//不阻塞的读数据
pfd[1].fd=sockfd;
pfd[1]。
events=POLLIN;//不阻塞的读数据
/*登录验证*/
if(-1==login()){
printf(”登录失败\n”);
return—1;
}
printf("登录成功。
。
。
\n”);
interface_print(temp);
/*5。
调用I/O函数(read/write)与客户端通讯。
*/
inti=5;
intpos;
while
(1)
{
ret=poll(pfd,2,-1);
if(ret>0){
if(pfd[0]。
revents==POLLIN){
interface_print(temp);
/*从终端读取数据*/
memset(buf,0,sizeof(buf));
ret=read(pfd[0].fd,buf,sizeof(buf)—1);
if(ret>0){
/*发送数据给服务器*/
write(sockfd,buf,ret);
}
}
if(pfd[1]。
revents==POLLIN){
if(!
strncmp(buf,"get",3)){
/*接收服务器发送的信息*/
memset(temp,0,sizeof(temp));
ret=read(pfd[1].fd,temp,sizeof(temp)—1);
if(ret>0){
temp[ret-1]=’\0';
/*把信息显示到终端*/
interface_print(temp);
}
}
}
}elseif(0==ret){
printf("超时\n”);
br