基于GPIO子系统编写LED驱动,编写应用程序进行测试,设置定时器,5秒钟打印一次hello world

本文主要是介绍基于GPIO子系统编写LED驱动,编写应用程序进行测试,设置定时器,5秒钟打印一次hello world,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

设备树添加的代码

 myled{led-gpios=<&gpioe 10 0>, <&gpiof 10 0>, <&gpioe 8 0>;   };

头文件

#ifndef __HEAD_H__
#define __HEAD_H__#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)#endif

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include "head.h"//定义变量,字符设备驱动对象
struct cdev *cdev;
//定义变量,主设备号、次设备号、设备号
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
//定义变量,向上提交目录信息返回值
struct class *cls;
//定义变量,向上提交设备节点信息返回值
struct device *dev;
//定义变量,解析设备节点信息
struct device_node *dnode;
//定义变量,保存GOIO的对象信息的结构体指针
struct gpio_desc *gpiono[3];
//定义变量,分配一个定时器对象
struct timer_list mytimer;int mycdev_open(struct inode *inode, struct file *file)
{int min = MINOR(inode->i_rdev);  //获取打开的文件的次设备号file->private_data = (void *)min;return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int which;which = (int)file->private_data;  //获取到文件的次设备号switch(which){case 0:switch(cmd){case LED_OFF:gpiod_set_value(gpiono[0], 0);break;case LED_ON:gpiod_set_value(gpiono[0], 1);break;}break;case 1:switch(cmd){case LED_OFF:gpiod_set_value(gpiono[1], 0);break;case LED_ON:gpiod_set_value(gpiono[1], 1);break;}break;case 2:switch(cmd){case LED_OFF:gpiod_set_value(gpiono[2], 0);break;case LED_ON:gpiod_set_value(gpiono[2], 1);break;}break;}return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{return 0;
}
//操作方法结构体
struct file_operations fop ={.open = mycdev_open,.unlocked_ioctl = mycdev_ioctl,.release = mycdev_close,
};//声明注册驱动、创建设备文件的函数
int register_file(void);//GPIO子系统---led灯
int	gpio_led(void);//定时器处理函数
void timer_handel(struct timer_list *timer)
{printk("hello world\n");mod_timer(timer, jiffies+5*HZ);
}
//入口函数
static int __init mycdev_init(void)
{//调用注册驱动,创建设备文件register_file();//GPIO子系统---led灯gpio_led();//初始化定时器timer_setup(&mytimer, timer_handel, 0);mytimer.expires = jiffies+5*HZ;//注册定时器并启用add_timer(&mytimer);return 0;
}//出口函数
static void __exit mycdev_exit(void)
{//销毁设备节点int i;for(i=0; i<3;i++){device_destroy(cls, MKDEV(major, i));}//销毁目录信息class_destroy(cls);//分布注销驱动//1.注销字符设备驱动cdev_del(cdev);//2.释放设备号unregister_chrdev_region(MKDEV(major, minor), 3);//3.释放字符设备驱动对象空间kfree(cdev);//释放GPIO编号for(i=0; i<3; i++){gpiod_put(gpiono[i]);}//关闭定时器del_timer(&mytimer);
}//注册驱动,创建设备文件
int register_file(void)
{//1.申请字符设备驱动对象cdev = cdev_alloc();if(NULL == cdev){printk("申请字符设备驱动对象失败\n");goto out1;}printk("申请字符设备驱动对象成功\n");//2.初始化字符设备驱动对象cdev_init(cdev, &fop);//3.申请设备号if(0 == major){//动态申请字符设备int ret = alloc_chrdev_region(&devno, minor, 3, "mychrdev");if(ret){printk("动态申请设备号失败\n");goto out2;}major = MAJOR(devno);minor = MINOR(devno);printk("动态申请设备号成功\n");}else{//静态指定设备号int ret = register_chrdev_region(MKDEV(major, minor), 3, "mychrdev");if(ret){printk("静态指定设备号失败\n");goto out2;}printk("静态指定设备号成功\n");}//4.注册字符设备驱动对象int ret = cdev_add(cdev, MKDEV(major, minor), 3);if(ret){printk("注册字符设备驱动对象失败\n");goto out3;}printk("注册字符设备驱动对象成功\n");//5.向上提交目录信息cls = class_create(THIS_MODULE, "mychrdev");if(IS_ERR(cls)){printk("向上提交目录信息失败\n");goto out4;}printk("向上提交目录信息成功\n");//6.向上提交设备节点信息int i;for(i=0; i<3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);if(IS_ERR(dev)){printk("向上提交设备节点信息失败\n");goto out5;}}printk("向上提交设备节点信息成功\n");return 0;out5://销毁设备节点for(;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 -1;
}//GPIO子系统---led灯
int gpio_led(void)
{//1.解析设备树节点信息dnode = of_find_node_by_path("/myled");if(NULL == dnode){printk("解析设备树节点信息失败\n");return dnode;}printk("解析设备树节点信息成功\n");//2.获取、申请GPIO编号和指定管脚输入输出方向int i;for(i=0; i<3; i++){gpiono[i] = gpiod_get_from_of_node(dnode, "led-gpios", i, GPIOD_OUT_LOW, NULL);if(IS_ERR(gpiono[i])){printk("申请GPIO编号失败\n");return -PTR_ERR(gpiono[i]);}}printk("申请GPIO编号成功\n");return 0;
}module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

应用程序代码

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "head.h"int main(int argc, const char *argv[])
{int fd1, fd2, fd3;int led_choose, on_off_choose;while(1){printf("请选择开启哪一盏灯(1 led1) (2 led2) (3 led3):");scanf("%d", &led_choose);printf("请选择关灯or开灯(0 off) (1 on):");scanf("%d", &on_off_choose);switch(led_choose){case 1:fd1 = open("/dev/myled0", O_RDWR);switch(on_off_choose){case 0:ioctl(fd1, LED_OFF);break;case 1:ioctl(fd1, LED_ON);break;}close(fd1);break;case 2:fd2 = open("/dev/myled1", O_RDWR);switch(on_off_choose){case 0:ioctl(fd2, LED_OFF);break;case 1:ioctl(fd2, LED_ON);break;}close(fd2);break;case 3:fd3 = open("/dev/myled2", O_RDWR);switch(on_off_choose){case 0:ioctl(fd3, LED_OFF);break;case 1:ioctl(fd3, LED_ON);break;}close(fd3);break;}}return 0;

这篇关于基于GPIO子系统编写LED驱动,编写应用程序进行测试,设置定时器,5秒钟打印一次hello world的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/302283

相关文章

Java进行文件格式校验的方案详解

《Java进行文件格式校验的方案详解》这篇文章主要为大家详细介绍了Java中进行文件格式校验的相关方案,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、背景异常现象原因排查用户的无心之过二、解决方案Magandroidic Number判断主流检测库对比Tika的使用区分zip

Java使用Curator进行ZooKeeper操作的详细教程

《Java使用Curator进行ZooKeeper操作的详细教程》ApacheCurator是一个基于ZooKeeper的Java客户端库,它极大地简化了使用ZooKeeper的开发工作,在分布式系统... 目录1、简述2、核心功能2.1 CuratorFramework2.2 Recipes3、示例实践3

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详

Python使用DrissionPage中ChromiumPage进行自动化网页操作

《Python使用DrissionPage中ChromiumPage进行自动化网页操作》DrissionPage作为一款轻量级且功能强大的浏览器自动化库,为开发者提供了丰富的功能支持,本文将使用Dri... 目录前言一、ChromiumPage基础操作1.初始化Drission 和 ChromiumPage

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

Springboot如何配置Scheduler定时器

《Springboot如何配置Scheduler定时器》:本文主要介绍Springboot如何配置Scheduler定时器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录Springboot配置Scheduler定时器1.在启动类上添加 @EnableSchedulin

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR