linu系统下,在i386平台上操作gpio端口其实很简单,可分为两种:用户层操作和驱动层操作(即编写gpio驱动)。
一、用户层操作gpio端口
可分两种方法:
1、一般方法:关键调用ioperm()函数来获取端口号的操作权限,然后调用inb()、outb()、inw()、outw()等端口操作函数来直接操作端口地址,参考链接:
http://wenku.baidu.com/view/7ddaae02de80d4d8d15a4f8f.html
下面是我写的一个简单例子:
gpio_writ.c
include <stdio.h> #include <sys/io.h> #include <unistd.h> int main() { /*向系统申请0x000~0x3FF的地址空间控制权*/ ioperm(0x000,0x8FF,1); //0x000是开始地址,0x8FF是结束地址,因为我的gpio端口地址是0x84D,在其范围之内/*向0x84D地址bit0写入全1*/ int i=0; for(i;i<10;i++) { outb(0x40,0x84D);//向0x84D地址bit0写入全1,将电平拉高 sleep(1); outb(0x00,0x84D);//向0x84D地址bit0写入全0,将电平拉低 sleep(1); } /*向系统交回0x000~0x3FF的地址空间控制权*/ ioperm(0x000,0x8FF,0); return 0; }
2、采用文件操作的方法
gpio设备文件 控制读代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/select.h> int main() { int fd = -1; fd = open("/dev/port",O_RDWR); if(-1 == fd) { perror("open port"); exit(EXIT_FAILURE); } fd_set readfd; struct timeval tv; int retval = -1; unsigned char readData; int i = 0; for(i;i<300;i++) { FD_ZERO(&readfd); FD_SET(fd,&readfd); if(-1 == lseek(fd,0x84E,SEEK_SET)) { perror("lseek"); exit(EXIT_FAILURE); } tv.tv_sec = 1; tv.tv_usec = 0; retval = select(fd+1,&readfd,NULL,NULL,&tv); if(-1 == retval) { perror("select"); exit(EXIT_FAILURE); } else if(0 == retval) { continue; } else { if(FD_ISSET(fd, &readfd)) { if(-1 == read(fd,&readData,1)) { perror("read"); exit(EXIT_FAILURE); } if(readData & 0x40) printf("The bit6 is high!\n"); else printf("The bit6 is low!\n"); } } } close(fd); return 0; }
GPIO设备文件控制写 代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main() { int fd = -1; fd = open("/dev/port",O_RDWR); if(-1 == fd) { perror("open port"); exit -1; } unsigned char writeHighData = 0x40; unsigned char writeLowData = 0x0; int i = 0; for(i;i<100;i++) { if(-1 == lseek(fd,0x84D,SEEK_SET)) { perror("lseek"); exit -1; } if(-1 == write(fd,&writeHighData,1)) { perror("write"); exit -1; } sleep(1); if(-1 == lseek(fd,0x84D,SEEK_SET)) { perror("lseek"); exit -1; } if(-1 == write(fd,&writeLowData,1)) { perror("write"); exit -1; } sleep(1); } close(fd); return 0; }
二、gpio端口驱动
gpio的端口驱动也很简答,大概流程就是:
申请端口号------> 操作端口--------->释放端口号
下面我写一个例子供参考:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/types.h> #include <asm/io.h> #include <linux/kdev_t.h> #include <linux/fs.h> #define DEV_NAME "mygpio" static int myIoOperation(void) { unsigned char ioData = '0'; if(!request_region(0x84D,10,DEV_NAME)) { printk(KERN_ERR "myIoOperation error:request_region\n "); return -1 ; } ioData = inb(0x84D); ioData |= 0x40; outb(ioData,0x84D); return 0; } static void myIoRelease(void) { unsigned char ioData = inb(0x84D); ioData &= 0xbf; outb(ioData,0x84D); release_region(0x84D,10); } int mygpio_init(void) { //ÉêÇë¶Ë¿ÚºÅ£¬²¢ÇÒÀžßbit0 if(-1 == myIoOperation()) { printk(KERN_ERR "myIoOpration fail!\n"); return -1; } return 0;/*init succeed*/ } void mygpio_exit(void) { // myIoRelease(); } MODULE_LICENSE("Dual BSD/GPL"); module_init(mygpio_init); module_exit(mygpio_exit);
gpio.c驱动程序编写完成之后,再编写Makefile
Makefile:
KVERS = /home/wxf/sourceCode/linux-2.6.39 #kernel modules obj-m += gpio.o build: make -C $(KVERS) M=$(PWD) modules clean: make -C $(KVERS) M=$(PWD) clean
之后执行make,生成gpio.ko驱动模块,就是加载驱动模块了:
insmod gpio.ko
如果驱动加载成功,则gpio的第一个引脚被拉高;
卸载驱动:
rmmod gpio
卸载成功后,gpio的的第一个引脚被拉低。
此时一个简单的gpio驱动就完成了。