linux应用层中使用ioctl函数操作对驱动层中的GPIO进行拉高拉低操作

文章介绍了如何在Linux中创建一个使用ioctl函数操作GPIO口的驱动程序,包括设备注册、ioctl函数实现以及用户层调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.驱动成代码,注册节点。
 

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>

static long exynos_liao_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{

	 int ret;
    
    // 先检查参数是否有效
    if (arg < 0 ) {
        return -EINVAL; // 参数无效,返回错误码
    }
    
    // 请求注册 GPIO 资源并检查返回值
    ret = gpio_request(arg, "liao_gpio");
    if (ret < 0) {
        return ret; // 注册失败,返回错误码
    }
    
    // 设置 GPIO 值
    gpio_set_value(arg, cmd);
    
    // 释放 GPIO 资源
    gpio_free(arg);
    
    return 0;
}
static int exynos_liao_open(struct inode *inode, struct file *filp)
{

        printk(KERN_ALERT"打开/dev/liao成功 !\n");

        return 0;
}

static int exynos_liao_release(struct inode *inode, struct file *filp)
{
		
        printk(KERN_ALERT"关闭文件/dev/liao!\n");
        return 0;
}

static struct file_operations liao_dev_fops = {
        owner:  THIS_MODULE,
        open:   exynos_liao_open,
//      read:   exynos_adc_read,
        unlocked_ioctl: exynos_liao_ioctl,
        release:        exynos_liao_release,
};



static struct miscdevice gpio_liao_dev = {
        .minor                  = MISC_DYNAMIC_MINOR,
        .name                   = "liao",
        .fops                   = &liao_dev_fops,
};

static int __init gpio_hello_module_init(void)
{
        int ret;

        ret = misc_register(&gpio_liao_dev);
        if(ret==0)
        {
                printk(KERN_ALERT"注册成功 !\n");
        }
    printk(KERN_ALERT"Hello, gpio_hello module is installed !\n");
    return 0;
}

static void __exit gpio_hello_module_cleanup(void)
{

//      gpio_free(221);
        misc_deregister(&gpio_liao_dev);
    printk(KERN_ALERT"Good-bye, Tiny4412 module was removed!\n");
}

module_init(gpio_hello_module_init);
module_exit(gpio_hello_module_cleanup);
//modinfo   模块名 查看下面信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LIAO");  //驱动作者
MODULE_DESCRIPTION("2023 GPIO"); //驱动信息
MODULE_VERSION("v1.0"); //版本号

2.用户层中直接调用ioctl函数对GPIO口进行拉高拉低操作。

int main(void)
{
	int fd;
	fd = open("/dev/liao", O_RDWR | O_NOCTTY | O_NDELAY);  
	printf("%d\n",fd);
	if (fd <0)
  	{
        printf("open error!\n");
        return 0;
    }
	else
	{
		 printf("打开成功!\n");
//		 ioctl(fd,0);
		ioctl(fd,1,221);	//1是拉高0拉低,221是GPIO口编号	

	}

	close(fd);
	return 0;
}

### GPIO 默认输出电平及其用途 #### 设备树配置中的默认电平设定 在设备树中定义GPIO的有效电平时,可以指定`GPIO_ACTIVE_HIGH`或`GPIO_ACTIVE_LOW`来决定逻辑高和对应的物理电压状态[^1]。当设置为`GPIO_ACTIVE_HIGH`时,逻辑‘1’对应于实际的高电平(通常是3.3V或5V),而逻辑‘0’则表示电平(接地)。相反地,在`GPIO_ACTIVE_LOW`模式下,情况正好颠倒。 对于某些特定平台如OK3399而言,由于部分GPIO引脚与电源管理有关联,因此初始化这些引脚至安全的状态非常重要[^3]。这可能意味着将它们预设为已知的安全电平——比如保持在电平直到应用程序显式更改为止。 #### 文件操作函数用于控制GPIO口电平 通过Linux内核提供的字符设备接口,开发者能够利用一组标准文件操作方法实现对GPIO操作,包括但不限于读取当前状态、改变方向以及调整输出值等动作[^2]。例如: ```c // 假定已经成功注册了一个字符设备并获得了相应的file结构体指针filp, // 用户空间程序可以通过ioctl()调用来发送命令给驱动层以执行具体的GPIO控制功能。 int ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ``` 这段代码展示了如何借助系统调用机制间接访问硬件资源而不必直接处理底层细节;同时也说明了为什么理解GPIO初始状态至关重要——因为任何后续基于此基础构建的应用都依赖于此种预先建立好的环境条件。 #### Uboot阶段的GPIO初始化 在嵌入式系统的引导加载过程中,Uboot负责早期外设初始化工作之一就是确保必要的IO端口处于适当的工作条件下。以RK3588为例,在board.c文件里增加了几行简单的C语言语句就可以完成这项任务[^4]: ```c __weak int rk_board_init(void) { gpio_request(125,"test_gpio"); // 请求编号为125 (即GPIO3_PD5) 的GPIO线 gpio_direction_output(125, 1); // 设置该管脚作为输出,并拉高它到高电平 } ``` 上述片段表明,在系统启动初期就可精确控制各个GPIO的功能角色分配及起始电位,从而保障整个电路板正常运作的前提得到满足。 #### 控制vs驱动的区别 - **控制**:指的是软件层面发出指令去操纵某个具体对象的行为方式,像上面提到的例子那样,通过编程手段让处理器向目标外围器件传递信号便是典型的控制系统行为; - **驱动**:更侧重于描述一种使能过程,即将抽象的数据转换成可以直接作用于物理世界的能量形式的过程。例如,把来自CPU的一系列高脉冲转变为电机转动所需的电流强度变化即是驱动的一个实例。 综上所述,无论是为了保证稳定运行还是出于设计考量的目的,合理规划好每一个GPIO引脚的默认输出电平都是非常重要的环节。同时也要注意到不同应用场景下的需求差异可能会导致不同的最佳实践方案的选择。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值