1. 程式人生 > >使用C語言和i2c-dev驅動

使用C語言和i2c-dev驅動

ati 感謝 none 末尾 當前 lose error 寄存器 但是

原文地址:blog.csdn.NET/wyt2013/article/details/20740659 感謝作者分享。

在本博客的《使用Beaglebone Black的I2C(一)》中,介紹了BBB上無需編程對i2c總線進行讀寫操作的方法,本文將介紹如何在C語言程序中使用i2c-dev驅動來操作i2c設備。


以下將還以前文中使用過的L3G4200D三軸陀螺儀為例。

BBB自帶了i2c-dev驅動,它使用ioctl方法對i2c設備進行配置,然後利用read()、write()函數就可以操作i2c設備了。

要操作某個i2c設備,首先要確定它的地址。按照我在前文中的說法,通常i2cdetect顯示的器件地址是由“7位”二進制數換算成的,而器件的讀寫地址則需要將這7位左移,然後在末尾添加一個1或0。但是對於i2c-dev驅動來說,我們不必費此周折,只要告訴他i2cdetect顯示的那個地址就可以了,驅動會自動根據你的讀操作或寫操作來相應地在末尾添加1或者0。


先把完整程序擺出來:

  1. #include <stdio.h>
  2. #include <stdlib.h> //exit()
  3. #include <fcntl.h> //define O_RDWR
  4. #include <linux/i2c-dev.h>
  5. #include <sys/ioctl.h>
  6. void main()
  7. {
  8. int file,i;
  9. int addr = 0b01101001; //i2c device address of gyro
  10. char *filename = "/dev/i2c-1"
    ;
  11. char wbuf[] = {0x20, 0x0f}; //first byte is address to write. others are bytes to be written
  12. char read_start_buf[1];
  13. char rbuf[1000] = {0};
  14. if((file = open(filename, O_RDWR)) < 0)
  15. {
  16. perror("Failed to open i2c device.\n");
  17. exit(1);
  18. }
  19. if(ioctl(file, I2C_SLAVE, addr) < 0)
  20. {
  21. printf("Failed to access bus.\n");
  22. exit(1);
  23. }
  24. write(file, wbuf, 2); //write 0x0f to register 0x20 to enable gyro.
  25. for(i=0;i<5;i++)
  26. {
  27. read_start_buf[0] = 0x29;
  28. write(file, read_start_buf, 1); //reposition file pointer to register 0x29
  29. read(file, rbuf, 1); //read register 0x29 and save to rbuf
  30. printf("%x", rbuf[0]);
  31. read_start_buf[0] = 0x28;
  32. write(file, read_start_buf, 1); //reposition file pointer to register 0x28
  33. read(file, rbuf, 1); //read register 0x28 and save to rbuf
  34. printf("%x\n", rbuf[0]);
  35. sleep(1);
  36. }
  37. close(file);
  38. }

上面的程序首先打開/dev/i2c-1這個設備,然後用ioctl配置成slave模式。然後通過將第0x20這個寄存器寫成0x0f來使能陀螺儀。然後在for循環中依次讀取0x29和0x28兩個寄存器的值並輸出,這兩個寄存器一起組成了X軸的角速度值。

程序輸出如下:

  1. [email protected]:~/ioctl_test# ./i2c
  2. 03c
  3. 04a
  4. 035
  5. 05f
  6. 03c
  7. [email protected]:~/ioctl_test# ./i2c
  8. 1f7f
  9. f2c3
  10. f567
  11. 3979
  12. 3aca

運行了兩次,第一次陀螺儀靜止(但輸出仍有一點小波動),第二次陀螺儀在晃動。可以看到輸出值的不同。


需要註意的一點,讀i2c設備時如何定位讀取的位置?

使用lseek()的話會返回-1,這個是不可行的。答案就是程序中,用write()寫一個字節。write函數參數中的buf數組裏的第一項代表了write的位置,從第二項開始是寫入的內容,因此只寫一個字節就是把指針移動過去了但是不寫入任何內容。


用這個方法就無需其他驅動也可以操作任意i2c外設了。


另外有個疑問。按理說執行 read(file, rbuf, 10); 的話,可以讀出當前指針位置開始的10個字節的內容。我在其他設備上也驗證了這點。但是在L3G4200D陀螺儀上,一次讀取10個的話,讀出的就全是一樣的數值,都是第一個數值。所以只能一位一位地讀取。難道是陀螺儀芯片有意設置成這樣?(這個現象跟我在《使用Beaglebone Black的I2C(一)》中的問題相符,即執行 i2cdump -y 1 0x69 c 會導致輸出全部是一樣的,都是第一個字節的內容。把c參數去掉才可以。)

使用C語言和i2c-dev驅動