内容:
(一)设计方案
首先,为开发板编写ADC接口的驱动程序,使开发板自带的三路ADC接口可以像普通文件那样被打开、读、写、关闭。
然后,编写一个 server 端程序和client端程序,使其可以运行在开发板上,选择合适的通信协议族,使得该 server 程序可以接收远程 client的访问(即,client 向server发出的关于server端当前某一路ADC数据的查询)并能返回ADC的读数。
最后,可以在PC机上运行client程序访问开发板上的ADC接口的数据。
(二)设计内容和要求
(1)ADC接口驱动程序
1定义驱动接口结构体。要求实现 open, write, read, close 等ADC设备功能。
2编写驱动程序的 makefile 文件,使 ADC 接口能以模块的形式加载到kernel。
3可以读指定 ADC 接口(ARM2410提供0-2三个可调节ADC接口)。
(2)开发板端server 程序
1server程序要能open ADC设备,像操作文件那样。
2建立inet connection,等待远程client 的访问。
3编写client端程序。Client通过发送指定字符串来表示查询server 上那个ADC的读数,例如,发送”adc0”、 “adc1”、“adc2” 时分别表示预读取server端(开发板)编号为0、1、2的ADC接口。
4Server 端识别client的具体请求,返回相应的读数。在此基础上,建议实现client对server的另一种查询方式:查询开发板上某个ADC接口近30秒钟内读数的平均值(提示:修改server程序)。
5编写server端和client端程序的makefile文件。
实现方法:
(一)ADC驱动程序
1、ADC驱动程序的设计思路
(1)定义驱动接口结构体,实现open, write, read, close 等ADC设备功能。
(2)编写驱动程序的makefile 文件,使 ADC 接口能以模块的形式加载到 kernel。
(3)可以读指定ADC 接口。(ARM2410提供0-2三个可调节ADC接口)
2、具体程序如下
(1) s3c2410-adc.c(使用开发板自带的程序)
#include<linux/config.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/sched.h>
#include<linux/irq.h>
#include<linux/delay.h>
#include<asm/hardware.h>
#include<asm/semaphore.h>
#include<asm/uaccess.h>
#include"s3c2410-adc.h"
#undefDEBUG
//#defineDEBUG
#ifdefDEBUG
#define DPRINTK(x...){printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
#else
#defineDPRINTK(x...) (void)(0)
#endif
#defineDEVICE_NAME "s3c2410-adc"
#defineADCRAW_MINOR 1
staticint adcMajor = 0;
typedefstruct {
struct semaphore lock;
wait_queue_head_twait;
int channel;
intprescale;
}ADC_DEV;
staticADC_DEV adcdev;
#define START_ADC_AIN(ch,prescale) \
do{\
ADCCON= PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
ADCCON|= ADC_START; \
}while(0)
staticvoid adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg){
wake_up(&adcdev.wait);
}
//ADC驱动程序中open, close,read和write方法的实现
static ssize_ts3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){
int data;
if(count!=sizeof(data)){
//errorinput data size
DPRINTK("the size of input data must be %d\n", sizeof(data));
return0;
}
copy_from_user(&data, buffer, count);
adcdev.channel=ADC_WRITE_GETCH(data);
adcdev.prescale=ADC_WRITE_GETPRE(data);
DPRINTK("set adc channel=%d,prescale=0x%x\n", adcdev.channel, adcdev.prescale);
return count;
}
static ssize_ts3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){
int ret = 0;
if (down_interruptible(&adcdev.lock))
return -ERESTARTSYS;
START_ADC_AIN(adcdev.channel, adcdev.prescale);
interruptible_sleep_on(&adcdev.wait);
ret = ADCDAT0;
ret &= 0x3ff;
DPRINTK("AIN[%d] = 0xx,%d\n", adcdev.channel, ret, ADCCON & 0x80 ? 1:0);
copy_to_user(buffer, (char *)&ret, sizeof(ret));
up(&adcdev.lock);
return sizeof(ret);
}
staticint s3c2410_adc_open(struct inode *inode, struct file *filp){
init_MUTEX(&adcdev.lock);
init_waitqueue_head(&(adcdev.wait));
adcdev.channel=0;
adcdev.prescale=0xff;
MOD_INC_USE_COUNT;
DPRINTK( "adc opened\n");
return0;
}
staticint s3c2410_adc_release(struct inode *inode, struct file *filp){
MOD_DEC_USE_COUNT;
DPRINTK("adc closed\n");
return0;
}
staticstruct file_operations s3c2410_fops = {
owner: THIS_MODULE,
open: s3c2410_adc_open,
read: s3c2410_adc_read,
write: s3c2410_adc_write,
release: s3c2410_adc_release,
};
#ifdefCONFIG_DEVFS_FS
staticdevfs_handle_t devfs_adc_dir, devfs_adcraw;
#endif
int__init s3c2410_adc_init(void){
int ret;
/* normal ADC */
ADCTSC= 0; //XP_PST(NOP_MODE);
ret = request_irq(IRQ_ADC_DONE,adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL);
if(ret) {
returnret;
}
ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);
if (ret < 0) {
printk(DEVICE_NAME " can'tget major number\n");
returnret;
}
adcMajor=ret;
#ifdefCONFIG_DEVFS_FS
devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL);
devfs_adcraw =devfs_register(devfs_adc_dir, "0raw", DEVFS_FL_DEFAULT,
adcMajor, ADCRAW_MINOR, S_IFCHR |S_IRUSR | S_IWUSR, &s3c2410_fops, NULL);
#endif
printk (DEVICE_NAME"\tinitialized\n");
return 0;
}
module_init(s3c2410_adc_init);
#ifdefMODULE
void__exit s3c2410_adc_exit(void){
#ifdefCONFIG_DEVFS_FS
devfs_unregister(devfs_adcraw);
devfs_unregister(devfs_adc_dir);
#endif
unregister_chrdev(adcMajor, DEVICE_NAME);
free_irq(IRQ_ADC_DONE, NULL);
}
module_exit(s3c2410_adc_exit);
MODULE_LICENSE("GPL");
#endif
(二)server程序
1、server程序的设计思路
(1)server程序能open ADC设备,像操作文件那样。
(2)建立inet connection,等待远程 client 的访问。
(3)server 端识别client的具体请求,返回相应的读数。在此基础上,实现client对server的另一种查询方式:查询开发板上某个ADC接口近30秒钟内读数的平均值。
2、具体程序如下
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<errno.h>
#include<sys/stat.h>
#include<dirent.h>
#include<signal.h>
#include<unistd.h>
#include<ctype.h>
#include"pthread.h"
#defineADC_DEV "/dev/adc/0raw"
#ifndef_S3C2410_ADC_H_
#define_S3C2410_ADC_H_
#defineADC_WRITE(ch, prescale) ((ch)<<16|(prescale))
#defineADC_WRITE_GETCH(data) (((data)>>16)&0x7)
#defineADC_WRITE_GETPRE(data) ((data)&0xff)
#endif
intadc_fd = -1;
intinit_ADdevice(){
if((adc_fd=open(ADC_DEV,O_RDWR))<0){
printf("Error opening %s adc device\n", ADC_DEV);
return -1;
}
}
floatGetADresult(int channel){
int PRESCALE=0XFF;
int data=ADC_WRITE(channel, PRESCALE);
write(adc_fd, &data, sizeof(data));
read(adc_fd, &data, sizeof(data));
return (data*3.3)/1024.0;
}
intmain(void){
doubleadc_reading;
inti;
float sum=0.0;
intserver_sockfd, client_sockfd;
intserver_len, client_len;
structsockaddr_in server_address;
structsockaddr_in client_address;
chartemp[30];
intchoose;
inttimes;
char*msg = "welcome,clients";
charch;
printf("Waiting......\n");
if(init_ADdevice()<0)
return -1;
server_sockfd= socket( AF_INET, SOCK_STREAM, 0 );
server_address.sin_family= AF_INET;
server_address.sin_addr.s_addr= inet_addr("192.168.221.200");
server_address.sin_port= 9734;
/* thesize of socket address structure */
server_len= sizeof( server_address );
/*Bind the socket descriptor and its address (name) */
bind(server_sockfd, (struct sockaddr *)&server_address, server_len );
/*Create a connection queue and wait for clients' requests */
listen(server_sockfd, 5 );
client_len= sizeof( client_address );
client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, &client_len );
while(1){
read(client_sockfd,temp,30);
sscanf(temp,"%d",&choose);
printf("choose:%d\n",choose);
read(client_sockfd,temp,30);
sscanf(temp,"%d",×);
printf("times:%d\n",times);
sprintf(temp,"Now the voltage is%.2f\n",GetADresult(choose));
write(client_sockfd,temp,30);
sum=0;
for(i=0;i<(times);i++){
sum+=GetADresult(choose);
}
sprintf(temp,"%.2f\n",sum/times);
write(client_sockfd,temp,30);
}
close(client_sockfd );
return0;
}
3、程序分析
(1)server程序对client端请求的分析
确定要采样的 channel 号(以及采样时间长度)
while(1){
read(client_sockfd,temp,30);
sscanf(temp,"%d",&choose);
printf("choose:%d\n",choose);
read(client_sockfd,temp,30);
sscanf(temp,"%d",×);
printf("times:%d\n",times);
sprintf(temp,"Nowthe voltage is %.2f\n",GetADresult(choose));
write(client_sockfd,temp,30);
sum=0;
for(i=0;i<(times);i++){
sum+=GetADresult(choose);
}
sprintf(temp,"%.2f\n",sum/times);
write(client_sockfd,temp,30);
}
(2)server程序中对adc接口的调用
float GetADresult(int channel){
int PRESCALE=0XFF;
int data=ADC_WRITE(channel, PRESCALE);
write(adc_fd, &data, sizeof(data));
read(adc_fd, &data, sizeof(data));
return (data*3.3)/1024.0;
}
(三)client程序
1、client 程序的设计思路
编写client端程序。client 通过发送指定字符串来表示查询server 上那个ADC的读数,例如,发送”adc0”、 “adc1”、“adc2” 时分别表示预读取server端(开发板)编号为0、1、2的ADC接口。
2、具体程序如下
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<errno.h>
#include<sys/stat.h>
#include<dirent.h>
#include<signal.h>
#include<unistd.h>
#include<ctype.h>
#include"pthread.h"
int main(void){
intsockfd;
int len;
structsockaddr_in address;
int result;
int choose;
char temp[30];
/* Create asocket for the client*/
sockfd =socket( AF_INET, SOCK_STREAM, 0 );
/*Name the socket as agreed with the server */
address.sin_family=AF_INET;
address.sin_addr.s_addr=inet_addr("192.168.221.200");
address.sin_port=9734;
len = sizeof(address );
/* Connectthe socket to the server's socket */
result =connect( sockfd, (struct sockaddr *)&address, len );
if( result ==-1 ){
perror("client: fail to connect the server\n" );
exit(1);
}
/* Use tosocket's write function to specifies the channel, and then
* read resultfrom the server running on ARM system.*/
choose=0;
while(choose>=0&& choose<=2){
printf("input(4means end)\n");
scanf("%s",temp);
sscanf(temp,"%d",&choose);
if(choose>=3)
break;
write(sockfd,temp,30);
printf("times\n");
scanf("%s",temp);
write(sockfd,temp,30);
read(sockfd,temp,30);
printf("%s",temp);
read(sockfd,temp,30);
printf("%s",temp);
}
close(sockfd);
exit(0);
}
(五)启动NFS服务
配置完成后,需要启动NFS服务。
在终端中,执行如下命令:
[root@BC root]#service nfs restart
(六)启动Samba服务,命令如下。
[root@BC root]#service smb restart
(七)开发板配置IP、建立主机与开发板的连接
通过超级终端界面,设置开发板的IP地址192.168.221.200。
[/mnt/yaffs]ifconfig eth0 192.168.221.200
(八)ping
(九)挂载共享目录
1、挂载前/mnt/yaffs目录下的内容:
2、将宿主机NFS服务所共享的目录/arm2410s/cwsaqadc挂载到开发板/mnt/yaffs/cwsaq目录下:
mount -t nfs –o nolock 192.168.221.140:/arm2410s/cwsaqadc /mnt/yaffs/cwsaq
(十)加载模块
