应用层读写i2c从设备寄存器

  在配置i2c从设备寄存器时往往需要修改驱动中的初始化函数来修改寄存器的值,这样往往需要重新编译内核,其实可以使用i2c驱动提供给应用层的接口函数ioctl来在命令行修改寄存器,只需要编写一个类似i2c测试程序的程序文件,使用int main(int argc, char **argv) 来向程序传递参数即可实时读写从设备的寄存器,工作队列(workqueue)可以实现多个寄存器的取值

#include <stdio.h> 
#include <linux/types.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/ioctl.h> 
#include <errno.h> 
#include <assert.h> 
#include <string.h> 
#include <linux/i2c.h> 
#include <linux/i2c-dev.h> 

#define MAX_I2C_MSG          2 

#define I2C_RETRIES       0x0701 
#define I2C_TIMEOUT       0x0702 
#define I2C_RDWR          0x0707 
#define ADV7180_REG_NUM      253     /*连续读的寄存器个数*/
#define ADV7180_REG_BASE_ADDR   0   /*要连续读的第一个寄存器的地址,此处从0x00开始连续读253个寄存器值*/

/*此函数作用是把从命令行输入的数字字符转换为十六进制数,即寄存器地址或值*/
int strtol_dzb(unsigned char *ps,int flag)
{
    int i=10;    
    int r=0; 
    char *pc = ps;


    if(NULL==ps )  return -1;

    while(*pc != '\0')
    {
       if((*pc >= 'a' && *pc <= 'f') || 
          (*pc >= 'A' && *pc <= 'F') || 
          (*pc == 'x' || *pc == 'X') )
       {   
           i=16;          
       }
       else if( *pc < '0' || *pc > '9')
       {
           return -1;
       }
       pc++;  
    }  

    if(flag!=0)  i=flag;

    pc = ps;

    while(*pc != '\0')
    {
       r *= i;

       if( *pc>='a' && *pc <= 'f')
       {   
           r += (*pc-'a')+10;
       }
       else if( *pc>='A' && *pc <= 'F')
       {   
           r += (*pc-'A')+10;
       }
       else if( *pc>='0' && *pc <= '9')
       {   
           r += (*pc-'0');
       }
       
       pc++;  
    }    
    return r;
}

/* 主函数,3种情况,一个参数时读出253个值;三个参数时为“./test -r 0x00”,读某个寄存器;四个参数时为“./test -w 0x00 0x11”,写寄存器00值为11。*/
int main(int argc, char **argv) 
{ 
    struct i2c_rdwr_ioctl_data work_queue; 
    unsigned char idx; 
    unsigned char mode=1;//1--read, 0--w; 
    unsigned int fd;     
    unsigned short slave_address=0x68;
    unsigned short reg_address =ADV7180_REG_BASE_ADDR;//0x2c; 
    unsigned char val[256]={0};
    unsigned char data_len=ADV7180_REG_NUM;
    unsigned char data=0;
    int ret,tmp; 

    fd = open("/dev/i2c-1",O_RDWR); 
    work_queue.nmsgs = MAX_I2C_MSG; /*  消息数量  */  
    
    work_queue.msgs  =  (struct  i2c_msg*)malloc(work_queue.nmsgs*sizeof(struct i2c_msg)); 
    if (!work_queue.msgs) 
    { 
      	printf("Memory alloc error\n"); 
      	close(fd); 
      	return 0; 
    } 

    //printf("argc =%d \n",argc);
    if(argc==1) // dump 7180
    {
        idx = reg_address;
        val[idx]=idx;
      	(work_queue.msgs[0]).len = 1; 
        //(work_queue.msgs[0]).flags = 0;//I2C_M_WR;
      	(work_queue.msgs[0]).addr = slave_address; 
      	(work_queue.msgs[0]).buf = &val[idx]; 

        (work_queue.msgs[1]).len = data_len; 
        (work_queue.msgs[1]).flags = 1;//I2C_M_RD; 
      	(work_queue.msgs[1]).addr = slave_address; 
      	(work_queue.msgs[1]).buf  = &val[idx];         
   
	    ioctl(fd, I2C_TIMEOUT, 2); /*  设置超时  */ 
	    ioctl(fd, I2C_RETRIES, 1); /*  设置重试次数  */

	    ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); 

	    if (ret < 0) 
	    { 
	      	printf("Error  during  I2C_RDWR  ioctl  with  error  code:  %d\n",  ret); 
	    } 
	    else
	    {
               
		printf("\n-----------------ADV7180 Reg-Test---------------------\n");
                printf(  "addr:  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f \n");
                printf(  "------------------------------------------------------");
	    
		for(idx = 0; idx < ADV7180_REG_NUM; idx++) 
		{ 
		    if(idx%16==0) printf("\n %02x: ", idx);   
		    printf(" %02x", val[idx]);
		}
                printf("\n-----------------------END----------------------------\n"); 
                           
	    }            
      }    
      else if(argc==2|| argc > 4)
      {
 	    printf("Usage:    %s [[-r regAddr] | [-w regAddr byteData]]\n", argv[0]);
            printf("              -r regAddr     read a byte from register--regAddr of adv7180\n");
            printf("              -w regAddr  data   write a byte data to register--regAddr of adv7180\n");
     }     
     else 
     {
          if(strstr(argv[1],"-r") ) // read a byte only
          {     
                if(-1 == (tmp=(unsigned short)strtol_dzb(argv[2],16)) )
                {
                     printf(" Invalid reg_addr: %s ",argv[2]);
                     close(fd);
                     return -1;
                }    
       
	    	reg_address=(unsigned short)tmp;
                printf("mode: read  reg_addr:  %3d (%02x) \n", reg_address, reg_address);
                
	    	
	    	val[0]=(unsigned char)reg_address;
      	    	(work_queue.msgs[0]).len = 1; 	    	
      	    	(work_queue.msgs[0]).addr = slave_address; 
      	    	(work_queue.msgs[0]).buf = &val[0]; 

	    	(work_queue.msgs[1]).len = data_len; 
	    	(work_queue.msgs[1]).flags = 1;//I2C_M_RD; 
      	    	(work_queue.msgs[1]).addr = slave_address; 
      	    	(work_queue.msgs[1]).buf  = &val[0];         
   	     	work_queue.nmsgs=2;

	    	ioctl(fd, I2C_TIMEOUT, 2); /*  璁剧疆瓒呮椂  */ 
	    	ioctl(fd, I2C_RETRIES, 1); /*  璁剧疆閲嶈瘯娆℃暟  */ 

	    	ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); 

	    	if (ret < 0) 
	    	{ 
	      		printf("Error  during  I2C_RDWR  ioctl  with  error  code:  %d\n",  ret); 
	   	} 
                else 
                {
			printf("Read: Reg--%02x   Data--%02x  \n", reg_address, val[0]);
                }
          }
          else if( strstr(argv[1],"-w") ) // write a byte only
          {
            	   
                if(-1 == (tmp=(unsigned short)strtol_dzb(argv[2],16)) )
                {
                     printf(" Invalid reg_addr: %s ",argv[2]);
                     close(fd);
                     return -1;
                } 

	    	reg_address = (unsigned short)tmp;

            	if(-1 == (tmp=(unsigned short)strtol_dzb(argv[3],16)) )
                {
                     printf(" Invalid data: %s ",argv[3]);
                     close(fd);
                     return -1;
                } 
	    	data = (unsigned char)tmp;

            	printf("mode: write  reg_addr:  0x%02x   data: %x  \n", reg_address, data);
                        	
    		val[0]=(unsigned char)reg_address;
            	val[1]=data;

  	    	(work_queue.msgs[0]).len = 2; 
    		(work_queue.msgs[0]).flags = 0;//I2C_M_WR;
  	    	(work_queue.msgs[0]).addr = slave_address; 
  	    	(work_queue.msgs[0]).buf = &val[0]; 		          
        	work_queue.nmsgs=1;

		ioctl(fd, I2C_TIMEOUT, 2); /*  璁剧疆瓒呮椂  */ 
		ioctl(fd, I2C_RETRIES, 1); /*  璁剧疆閲嶈瘯娆℃暟  */ 

		ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); 

		if (ret < 0) 
		{ 
		    printf("Error  during  I2C_RDWR  ioctl  with  error  code:  %d\n",  ret); 
		} 
#if 0
        	else 
	        {
	                (work_queue.msgs[0]).len = 1; 
		    	(work_queue.msgs[0]).flags = 0;//I2C_M_WR;
	      	        (work_queue.msgs[0]).addr = slave_address; 
	      	        (work_queue.msgs[0]).buf = &val[0]; 

		    	(work_queue.msgs[1]).len = data_len; 
		    	(work_queue.msgs[1]).flags = 1;//I2C_M_RD; 
	      	        (work_queue.msgs[1]).addr = slave_address; 
	                val[idx]=0;
	      	        (work_queue.msgs[1]).buf  = &val[0];         
	   	     	work_queue.nmsgs=2;

		    	ioctl(fd, I2C_TIMEOUT, 2); /*  璁剧疆瓒呮椂  */ 
		    	ioctl(fd, I2C_RETRIES, 1); /*  璁剧疆閲嶈瘯娆℃暟  */ 
		    	ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
				
			if (ret < 0) 
		        { 
		      	    printf("Error  during  I2C_RDWR  ioctl  with  error  code:  %d\n",  ret); 
		        } 
	            	else
		    	{
			    printf("Write: reg--%02x   w-data--%02x  r-data--%02x \n", reg_address,data,val[0]);
	            	}
	        }
#endif
      	} 
    }      

    close(fd); 
    return ; 
} 



  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
里面讲了MSComm控件 、 WinAPI 串口通信、CSerial类,例子很详实,每一步操作都有解释。作者是龚建伟,有一个个人主页www.gjwtech.com,讲串口通信的内容比较多,还行,大家可以先看看这个主页。 本书目录 第1章轻松体验串口通信编程与调试 1.1初识串口 1.1.1从外观上了解串口 1.1.2 串口通信的发展前景 1.2 自己制作简单的串口线 1.2.1 三线制串口接线的规定 1.2.2 焊接制作自己的串口连接线 1.3 调试串口通信程序时的几种使用串口的技巧 1.3.1 查看计算机串口资源 1.3.2 常规调试-2个物理串口之间的通信 1.3.3 特殊调试-单个物理串口之间的通信 1.3.4 虚拟串口-为计算机添加取之不尽的串口资源 1.4 使用串口调试助手来体验串口通信 1.5体验Windows环境下Visual C++串口通信编程 1.6体验DOS环境下Turbo C串口通信编程 第2章 VC多线程串口编程工具CSerialPort类 2.1 类功能及成员函数介绍 2.2 应用CSerialPort类编制基于对话框的应用程序 2.3 应用CSerialPort类编制基于单文档的应用程序 2.4对CSerialPort类的改进 2.5 在Visual C++.NET中应用CSerialPort类 第3章 控件MSComm串口编程 3.1 MSComm控件详细介绍 3.1.1 VC中应用MSComm控件编程步骤 3.1.2 MSComm控件串行通信处理方式 3.1.3 MSComm 控件的属性说明 3.1.4 MSComm控件错误信息 3.2使用MSComm控件的几个疑难问题 3.2.1使用VARIANT 和SAFEARRAY 数据类型从串口读写数据 3.2.2 MSComm控件能离开对话框独立存在吗? 3.2.3 如何发送接收ASCII值为0和大于128的字符? 3.2.4 在同一程序中用MSComm控件控制多个串口的具体操作方法 3.2.5解决使用控件编程时程序占用的内存会不断增大的问题 3.2.6在没有安装Visual Studio的计算机上如何使用MSComm控件 3.2.7 在MSComm控件串口编程时遇到的其它问题说明 3.3在基于单文档(SDI)程序中应用MSComm控件 3.4应用MSComm控件控制多个串口实例 第4章 Windows API串口编程 4.1 Windows API串口编程概述 4.2 API串口编程中用到的结构及相关概念说明 4.2.1 DCB(Device Control Block)结构 4.2.2超时设置COMMTIMEOUTS结构 4.2.3 OVERLAPPED异步I/O重叠结构 4.2.4 通信错误与通信设备状态 4.2.5 串行通信事件 4.3 Windows API串行通信函数 4.4 Win32 API串口通信编程的一般流程和特殊实例 4.4.1 Win32 API串口通信编程的一般流程 4.4.2 用查询方式读串口 4.4.3同步I/O读写数据 4.4.4 关于流控制的设置问题 4.5 CSerialPort类中的API函数编程应用剖析 4.6 Win32 API串口编程TTY(虚拟终端)实例 4.7 Windows API串口精简例程 第5章 串口调试助手V2.2详细编程 5.1 建立SCOMM程序工程实现界面功能 5.2 串口的初始化及关闭 5.3串口数据的发送与接收及十六进制数据的处理 5.3.1 十六进数据发送处理 5.3.2 手动发送处理 5.3.3自动发送处理 5.3.4 接收处理及十六进制显示 5.4 其它辅助功能的实现 5.4.1 接收数据的文件保存 5.4.2 实现小文件发送 5.4.3 图钉按钮功能使程序能浮在最上层 5.4.4 对话框动画图标的实现 5.4.5 超链接功能的实现 5.4.6 如何打开帮助网页文件 第6章 DOS环境下的Turbo C串口编程及通用实例GSerial类 6.1 PC机异步通信适配器8250及其编程操作 6.1.1 INS8250内部寄存器及其选择方式 6.1.2 波特率设置 6.1.3数据位、奇偶校验、停止位等数据格式设置 6.1.4 查询I/O方式相关设置 6.1.5 中断I/O通信方式相关设置 6.1.6 Modem寄存器 6.2 COMRXTX程序实例
### 回答1: 在Linux应用层,我们可以使用相应的库函数来进行读写i2c设备的操作。下面是一个简单的示例代码: 首先,我们需要打开i2c设备文件,可以使用open函数来实现: ```c int fd = open("/dev/i2c-0", O_RDWR); if (fd < 0) { perror("Failed to open i2c device"); return -1; } ``` 接下来,我们需要设置要访问的i2c设备的地址,可以使用ioctl函数来实现: ```c int addr = 0x50; // 替换为你要访问的i2c设备地址 if (ioctl(fd, I2C_SLAVE, addr) < 0) { perror("Failed to set i2c device address"); return -1; } ``` 然后,我们可以使用read函数来读取i2c设备的数据: ```c unsigned char buffer[10]; int length = 5; // 要读取的字节数 if (read(fd, buffer, length) != length) { perror("Failed to read from i2c device"); return -1; } ``` 类似地,我们可以使用write函数来向i2c设备写入数据: ```c unsigned char data[10] = {0x00, 0x01, 0x02, 0x03, 0x04}; // 要写入的数据 int length = 5; // 要写入的字节数 if (write(fd, data, length) != length) { perror("Failed to write to i2c device"); return -1; } ``` 最后,我们需要关闭i2c设备文件,可以使用close函数来实现: ```c close(fd); ``` 通过以上的代码,我们可以在Linux应用层进行i2c设备读写操作。请注意,示例中使用的设备文件路径和i2c设备地址可能需要根据实际情况进行修改。 ### 回答2: 在Linux中,要在应用层读写I2C设备,可以使用Linux提供的I2C工具以及编程接口。 1. 使用I2C工具:Linux提供了一些命令行工具来读写I2C设备,最常用的是`i2c-tools`包中的`i2cget`和`i2cset`命令。可以通过安装`i2c-tools`来获得这些工具。使用时,需要知道目标I2C设备的地址以及要读写寄存器地址,然后可以使用`i2cget`命令读取该寄存器的值,或使用`i2cset`命令向该寄存器写入数据。 2. 使用编程接口:在应用程序中使用编程接口可以更灵活地读写I2C设备。在Linux中,可以使用标准的Linux编程接口,如`ioctl`和`open`等函数来操作I2C设备。首先需要使用`open`函数打开I2C设备文件,然后使用`ioctl`函数设置I2C设备的地址、通信速率等参数。接下来可以使用`read`和`write`函数来读取和写入I2C设备的数据。 这些方法都能实现在Linux应用层中对I2C设备进行读写操作。使用哪种方法取决于具体的需求和场景。如果只是简单的读写操作,可以选择使用I2C工具;如果需要更复杂的控制和处理逻辑,可以选择使用编程接口来实现。 ### 回答3: 在Linux应用层读写I2C,我们可以使用内核提供的i2c-dev驱动来实现。以下是一种基本的方法: 1. 打开I2C设备 首先,我们需要在应用程序中打开I2C设备文件。设备文件的路径通常为"/dev/i2c-N",其中N为I2C控制器的编号。通过调用open()函数打开设备文件,可以获得一个文件描述符(file descriptor)。 2. 设置I2C设备的从属地址 在进行I2C通信之前,我们需要设置I2C设备的从属地址(slave address)。通过ioctl()函数调用I2C_SLAVE命令,将从属地址传递给i2c-dev驱动。 3. 发送和接收数据 在已设置好从属地址的前提下,我们可以通过write()函数向I2C设备发送数据。数据应该是一个字节数组,可以包含多个字节。通过调用read()函数,可以从I2C设备中接收数据,同样以字节数组的形式返回。 4. 关闭I2C设备 在完成I2C通信后,我们应该关闭I2C设备文件,释放资源。通过调用close()函数,可以关闭文件描述符。 需要注意的是,读写I2C设备需要具有对应的权限。通常情况下,我们需要以超级用户或者具有I2C访问权限的用户身份运行应用程序。 以上是一个在Linux应用层读写I2C的简单示例。实际应用中,可能需要更复杂的数据处理和通信协议实现,但基本的读写操作是类似的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值