[驱动开发]gpio子系统及中断实现led亮灭

这篇具有很好参考价值的文章主要介绍了[驱动开发]gpio子系统及中断实现led亮灭。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理

1.应用程序发送指令控制发光二极管亮灭

2.按键1按下,led1电位反转;按键2按下,led2电位反转;按键3按下,led3电位反转   

//头文件
#ifndef __LED_H__
#define __LED_H__

//功能码
#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)
#endif
//应用程序实现LED的亮灭
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include "led.h"
int main(int argc, const char *argv[])
{
	int a,b;
	while(1)
	{
		int fd_led = open("/dev/myled0",O_RDWR);	
		if(fd_led < 0)
		{
			printf("打开设备文件失败\n");
			exit(-1);
		}
		printf("请输入要控制的灯:1 2 3>>");
		scanf("%d",&b);
		printf("输入控制命令:0熄灭 1开灯>>>");
		scanf("%d",&a);
		switch(a)
		{
		case 1:
			ioctl(fd_led,LED_ON,&b);
			break;
		case 0:
			ioctl(fd_led,LED_OFF,&b);
			break;
		}
		close(fd_led);
	}
	return 0;
}
//驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include<linux/of_irq.h>
#include<linux/interrupt.h>
#include "led.h"
/*  leds{
	led1-gpios=<&gpioe 10 0>;//10表示引脚编号  0表示默认
	led2-gpios=<&gpiof 10 0>;
	led3-gpios=<&gpioe 8 0>;
	};*/
struct device_node *dnode1;
struct device_node *dnode2;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
struct cdev *cdev;
int major=168;
int minor=0;
struct class *cls;
struct device *dev;
dev_t devno;
int i;
unsigned int irqno[3];      //软中断号

//中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{
	unsigned int id=(unsigned int)dev_id;
	switch(id)
	{
		case 0:
			printk("KEY1_INTERRUPT\n");
			gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));
			break;
		case 1:
			printk("KEY2_INTERRUPT\n");
			gpiod_set_value(gpiono2,!gpiod_get_value(gpiono2));
			break;
		case 2:
			printk("KEY3_INTERRUPT\n");
			gpiod_set_value(gpiono3,!gpiod_get_value(gpiono3));
			break;
	}

	return IRQ_HANDLED;
}
/*********************封装操作方法***************************/
int mycdev_open(struct inode *inode, struct file *file)
{
	//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	return 0;
}


long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int which;
	copy_from_user(&which,(void *)arg,4);
	switch(cmd)
	{
	case LED_ON:         // 亮灯
		switch(which)
		{
		case 1:   
			gpiod_set_value(gpiono1, 1);
			break;
		case 2:
			gpiod_set_value(gpiono2, 1);
			break;
		case 3:
			gpiod_set_value(gpiono3, 1);
			break;
		}
		break;
	case LED_OFF:
		switch(which)
		{
		case 1:
			gpiod_set_value(gpiono1, 0);
			break;
		case 2:
			gpiod_set_value(gpiono2, 0);
			break;
		case 3:
			gpiod_set_value(gpiono3, 0);
		}
		break;
	}
	//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	return 0;
}

int mycdev_close(struct inode *inode, struct file *file)
{
	//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	return 0;
}
/***********************************************************************/

//定义一个操作方法结构体变量并初始化
struct file_operations fops =
{
	.open    =  mycdev_open,
	.release =  mycdev_close,
	.unlocked_ioctl = mycdev_ioctl,
};
static int __init mycdev_init(void)
{
	int ret,i;
	//1.申请对象空间 cdev_alloc
	cdev = cdev_alloc();
	if(cdev == NULL)
	{
		printk("申请对象空间失败\n");
		ret=-EFAULT;
		goto out1;
	}
	printk("申请对象空间成功\n");
	//2.初始化对象 cdev_init
	cdev_init(cdev,&fops);
	printk("初始化对象成功\n");
	//3.申请设备号 register_chrdev_region()或clloc_chrdev_region()
	if(major != 0)  //静态申请
	{
		ret=register_chrdev_region(MKDEV(major,minor),3,"myled");
		if(ret)
		{
			printk("申请静态设备号失败\n");
			goto out2;
		}
		printk("申请静态设备号成功major=%d\n",major);
	}
	else    //动态申请
	{
		ret=alloc_chrdev_region(&devno,minor,3,"myled");
		if(ret)
		{
			printk("申请动态设备号失败\n");
			goto out2;
		}
		major=MAJOR(devno);
		minor=MINOR(devno);
		printk("申请动态设备号成功major=%d\n",major);
	}

	//4.注册驱动对象 cdev_add()
	ret=cdev_add(cdev,MKDEV(major,minor),3);
	if(ret)
	{
		printk("注册驱动对象失败\n");
		goto out3;
	}
	printk("注册驱动对象成功\n");
	//5.向上提交目录 class_create()
	cls=class_create(THIS_MODULE,"myled");
	if(IS_ERR(cls))
	{
		printk("向上提交目录失败\n");
		ret = -PTR_ERR(cls);
		goto out4;
	}
	printk("向上提交目录成功\n");
	//6.向上提交设备信息 device_create()
	for(i=0;i<3;i++)
	{
		dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
		if(IS_ERR(dev))
		{
			printk("向上提交设备节点失败\n");
			ret = -PTR_ERR(dev);
			goto out5;
		}
	}
	printk("向上提交设备信息成功\n");
	// 根据设备树节点的路径解析设备树信息
	dnode1 = of_find_node_by_path("/leds");
	if (dnode1 == NULL)
	{
		printk("解析设备树节点led失败\n");
		return -EFAULT;
	}
	printk("解析设备树节点led成功\n");
	// 申请gpio_desc对象并设置输出为低电平
	gpiono1 = gpiod_get_from_of_node(dnode1, "led1-gpios", 0, GPIOD_OUT_LOW, NULL);
	if (IS_ERR(gpiono1))
	{
		printk("申请gpio1对象失败\n");
		return -PTR_ERR(gpiono1);
	}
	printk("申请gpio1对象成功\n");
	gpiono2 = gpiod_get_from_of_node(dnode1, "led2-gpios", 0, GPIOD_OUT_LOW, NULL);
	if (IS_ERR(gpiono2))
	{
		printk("申请gpio2对象失败\n");
		return -PTR_ERR(gpiono2);
	}
	printk("申请gpio2对象成功\n");
	gpiono3 = gpiod_get_from_of_node(dnode1, "led3-gpios", 0, GPIOD_OUT_LOW, NULL);
	if (IS_ERR(gpiono3))
	{
		printk("申请gpio3对象失败\n");
		return -PTR_ERR(gpiono3);
	}
	printk("申请gpio3对象成功\n");

	// 根据设备树节点的路径解析设备树信息
	dnode2 = of_find_node_by_path("/myirq");
	if (dnode2 == NULL)
	{
		printk("解析设备树节点myirq失败\n");
		return -EFAULT;
	}
	printk("解析设备树节点myirq成功\n");
	for(i=0;i<3;i++)
	{
		//获取软中断号
		irqno[i]=irq_of_parse_and_map(dnode2,i);
		if(!irqno[i])
		{
			printk("软中断号irqno[%d]获取失败\n",i);
			return -ENXIO;
		}
		printk("软中断号获取成功irqno[%d]=%d\n",i,irqno[i]);

		//注册中断
		ret=request_irq(irqno[i],myirq_handler,IRQF_TRIGGER_FALLING,"key",(void *)i);
		if(ret)
		{
			printk("注册驱动失败\n");
			return ret;
		}
		printk("key%d中断注册成功\n",i);
	}
	return 0;
out5:
	for(--i;i>=0;i--)
	{
		//销毁上面提交的设备信息
		device_destroy(cls,MKDEV(major,i));
	}
	class_destroy(cls);
out4:
	cdev_del(cdev);
out3:
	unregister_chrdev_region(MKDEV(major,minor),3);
out2:
	kfree(cdev);
out1:
	return ret;
}
static void __exit mycdev_exit(void)
{
	// 灭灯
	gpiod_set_value(gpiono1, 0);
	gpiod_set_value(gpiono2, 0);
	gpiod_set_value(gpiono3, 0);
	// 释放gpio编号
	gpiod_put(gpiono1);
	gpiod_put(gpiono2);
	gpiod_put(gpiono3);
	//注销中断
	for(i=0;i<3;i++)
	{
		free_irq(irqno[i],NULL);
	}
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

文章来源地址https://www.toymoban.com/news/detail-622576.html

到了这里,关于[驱动开发]gpio子系统及中断实现led亮灭的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 驱动开发作业3——GPIO子系统

    作业1:在内核模块中启用定时器,定时1s,让LED1以1s为周期实现流水灯  myled.c(驱动文件)    作业2:基于GPIO子系统完成LED灯驱动的注册,并利用应用程序测试  chrdevled.c(驱动文件) test.c(测试文件)

    2024年02月16日
    浏览(25)
  • 【Linux驱动开发】011 gpio子系统

    前面我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。本章我们就来学习一下如何借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。   Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于

    2024年02月03日
    浏览(36)
  • 【Linux驱动开发】012 gpio子系统API函数

    设置好设备树以后, 在驱动程序中就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:

    2023年04月18日
    浏览(35)
  • Linux驱动开发之【pinctrl和gpio子系统】

    目录 一、 pinctrl和gpio子系统 1.pinctrl子系统 1.1 pinctrl子系统简介 1.2 pinctrl子系统驱动 1.3 设备树中添加pinctrl节点模版 2. gpio子系统 2.1 gpio子系统简介 2.2 gpio子系统驱动 2.3 gpio子系统API函数 2.4 设备树中添加gpio节点模板 2.5 与gpio相关的OF函数 3. 驱动程序编写 3.1 驱动入口函数 3

    2024年02月06日
    浏览(33)
  • <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

    <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分) <Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分

    2024年02月13日
    浏览(28)
  • 【LED子系统深度剖析】一、开篇词|Linux驱动开发必读

    我的圈子: 高级工程师聚集地 我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强公司! 创作理念:专注分享高质量嵌入式文章,让大家读有所得!

    2024年02月09日
    浏览(26)
  • RK3568驱动指南|第十二篇 GPIO子系统-第128章 GPIO入门实验

    瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网

    2024年01月21日
    浏览(28)
  • 【LED子系统深度剖析】三、硬件驱动层详解

    个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享高质量嵌入式文章,让大家读有所得!

    2024年02月07日
    浏览(64)
  • HCIA-HarmonyOS设备开发认证V2.0-IOT硬件子系统-GPIO

    轻量系统设备通常需要进行外设控制,例如温湿度数据的采集、灯开关的控制,因此在完成内核开发后,需要进行设备驱动的开发。 主要Hi3861芯片介绍如何运用 IoT 硬件子系统进行轻量系统设备的驱动开发。 在轻量系统的联接模组中,智能家居远程控制能力的实现,最终是通

    2024年02月21日
    浏览(37)
  • Linux驱动开发:SPI子系统

    MISO:主设备数据输入,从设备数据输出。 MOSI:主设备数据输出,从设备数据输入。 SCLK:时钟信号,由主设备产生。 CS:    从设备片选信号,由主设备控制。 CPOL(时钟极性) :   0:时钟起始位低电平      1:时钟起始为高电平   CPHA(时钟相位) :0:第一个时钟周期采样   1

    2024年02月06日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包