您的位置:首页 > 运维架构 > Linux

linux下i386平台gpio端口操作

2013-08-16 14:11 746 查看
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驱动就完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: