本文主要是介绍基于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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!