使用C語言和i2c-dev驅動
原文地址: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。
先把完整程序擺出來:
- #include <stdio.h>
- #include <stdlib.h> //exit()
- #include <fcntl.h> //define O_RDWR
- #include <linux/i2c-dev.h>
- #include <sys/ioctl.h>
- void main()
- {
- int file,i;
- int addr = 0b01101001; //i2c device address of gyro
- char *filename = "/dev/i2c-1"
- char wbuf[] = {0x20, 0x0f}; //first byte is address to write. others are bytes to be written
- char read_start_buf[1];
- char rbuf[1000] = {0};
- if((file = open(filename, O_RDWR)) < 0)
- {
- perror("Failed to open i2c device.\n");
- exit(1);
- }
- if(ioctl(file, I2C_SLAVE, addr) < 0)
- {
- printf("Failed to access bus.\n");
- exit(1);
- }
- write(file, wbuf, 2); //write 0x0f to register 0x20 to enable gyro.
- for(i=0;i<5;i++)
- {
- read_start_buf[0] = 0x29;
- write(file, read_start_buf, 1); //reposition file pointer to register 0x29
- read(file, rbuf, 1); //read register 0x29 and save to rbuf
- printf("%x", rbuf[0]);
- read_start_buf[0] = 0x28;
- write(file, read_start_buf, 1); //reposition file pointer to register 0x28
- read(file, rbuf, 1); //read register 0x28 and save to rbuf
- printf("%x\n", rbuf[0]);
- sleep(1);
- }
- close(file);
- }
上面的程序首先打開/dev/i2c-1這個設備,然後用ioctl配置成slave模式。然後通過將第0x20這個寄存器寫成0x0f來使能陀螺儀。然後在for循環中依次讀取0x29和0x28兩個寄存器的值並輸出,這兩個寄存器一起組成了X軸的角速度值。
程序輸出如下:
- [email protected]:~/ioctl_test# ./i2c
- 03c
- 04a
- 035
- 05f
- 03c
- [email protected]:~/ioctl_test# ./i2c
- 1f7f
- f2c3
- f567
- 3979
- 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驅動