基于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

相关文章

linux hostname设置全过程

《linuxhostname设置全过程》:本文主要介绍linuxhostname设置全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录查询hostname设置步骤其它相关点hostid/etc/hostsEDChina编程A工具license破解注意事项总结以RHE

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

使用Python进行GRPC和Dubbo协议的高级测试

《使用Python进行GRPC和Dubbo协议的高级测试》GRPC(GoogleRemoteProcedureCall)是一种高性能、开源的远程过程调用(RPC)框架,Dubbo是一种高性能的分布式服... 目录01 GRPC测试安装gRPC编写.proto文件实现服务02 Dubbo测试1. 安装Dubb

Python的端到端测试框架SeleniumBase使用解读

《Python的端到端测试框架SeleniumBase使用解读》:本文主要介绍Python的端到端测试框架SeleniumBase使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录SeleniumBase详细介绍及用法指南什么是 SeleniumBase?SeleniumBase

Qt 设置软件版本信息的实现

《Qt设置软件版本信息的实现》本文介绍了Qt项目中设置版本信息的三种常用方法,包括.pro文件和version.rc配置、CMakeLists.txt与version.h.in结合,具有一定的参考... 目录在运行程序期间设置版本信息可以参考VS在 QT 中设置软件版本信息的几种方法方法一:通过 .pro

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

PostgreSQL 默认隔离级别的设置

《PostgreSQL默认隔离级别的设置》PostgreSQL的默认事务隔离级别是读已提交,这是其事务处理系统的基础行为模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一 默认隔离级别概述1.1 默认设置1.2 各版本一致性二 读已提交的特性2.1 行为特征2.2

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

mtu设置多少网速最快? 路由器MTU设置最佳网速的技巧

《mtu设置多少网速最快?路由器MTU设置最佳网速的技巧》mtu设置多少网速最快?想要通过设置路由器mtu获得最佳网速,该怎么设置呢?下面我们就来看看路由器MTU设置最佳网速的技巧... 答:1500 MTU值指的是在网络传输中数据包的最大值,合理的设置MTU 值可以让网络更快!mtu设置可以优化不同的网