linux下i386平台gpio端口操作

时间:2021-02-03 02:48:04

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