远程ADC数据读取

    xiaoxiao2021-03-26  24

    内容:

            (一)设计方案

    首先,为开发板编写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

               

     (十)加载模块

    转载请注明原文地址: https://ju.6miu.com/read-650252.html

    最新回复(0)