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驱动就完成了。