栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux下的综合案例——通过按键控制led的亮灭

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux下的综合案例——通过按键控制led的亮灭

文章目录
  • 前言
  • 一、代码文件
    • 1.led.c文件
    • 2.switch.c文件
    • 3.Makefile文件
    • 4.app.c文件
  • 二、运行结果
  • 总结

前言

本文的主要内容是通过一个综合案例,即按键控制led的亮灭来将之前学过的中断、等待队列、pinctrl和gpio子系统、设备树、platform平台总线以及杂项设备驱动等内容串联起来。
本文以Linux下点亮开发板上通过uart外接的led灯、Linux下的中断介绍及其应用实验——按键响应、Linux下的等待队列及其案例为基础。


一、代码文件 1.led.c文件
#include  
#include  
#include  
#include  
#include  
#include 
#include 
#include 
#include 
#include 
#include 

int size;
u32 out_values[2] = {0};
const char *str;
struct device_node *test_device_node;
struct property *test_node_property;
unsigned int *vir_addr;
int uart3_gpio = 0;

ssize_t misc_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = {0};    //从应用层复制字符串到内核层
    if(copy_from_user(kbuf,ubuf,size)!=0)
    {
        printk("copy_from_user error!n");
        return -1;
    }
    printk("value is: %d.n", kbuf[0]); //打印从应用层传输到内核层的值
    if(kbuf[0] == 1){
		gpio_set_value(uart3_gpio, 1); //设置输出值为高电平
		printk("The led is turned on!n");
	}	
    else if(kbuf[0] == 0){
		gpio_set_value(uart3_gpio, 0); //设置输出值为低电平
		printk("The led is turned off!n");
	}	
    return 0;
}

struct file_operations misc_fops = {  //在结构体中引入相关函数
    .owner = THIS_MODULE,
    .write = misc_write
};

struct miscdevice misc_dev={
    .minor = MISC_DYNAMIC_MINOR, //次设备号
    .name = "misc_device_led",   //设备节点的名字
    .fops = &misc_fops
};

int dts_probe(struct platform_device *pdev)
{
	int ret = 0;
	printk("dts_probe matching ok!n");
	printk("node name is %s.n", pdev->dev.of_node->name); //直接读取节点名字的方法

	
	test_device_node = of_find_node_by_path("/test");  //在设备树节点中查找test这个节点
	if(test_device_node == NULL){
		printk("of_find_node_by_path is error!n");
		return -1;
	}
	
	uart3_gpio = of_get_named_gpio(test_device_node, "uart3-gpio", 0); //设备树中定义的名字
	if(uart3_gpio < 0) {
		printk("of_get_named_gpio is error!n");
		return -1;
	}
	printk("uart3_gpio is %d.n", uart3_gpio);

	ret = gpio_request(uart3_gpio, "gpio_led");
	if(ret < 0) {
		printk("gpio_request is error!n");
		return -1;
	}

	gpio_direction_output(uart3_gpio, 0); //设置gpio为输出类型,默认的输出值设置为0,即驱动加载后led不亮

    ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("miscdevice registered error!n");
	    return -1;
    }

	return 0;
}

int dts_remove(struct platform_device *pdev)
{
	printk("dts_remove!n");
	return 0;
}

const struct platform_device_id dts_idtable = {
	.name = "dts_test"  //匹配优先级 第二
};

const struct of_device_id of_match_table_test[] = {
	{.compatible = "test123"},   //匹配优先级 第一
	{}
};

struct platform_driver dts_device = {
	.probe = dts_probe,
	.remove = dts_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "dts123", //匹配优先级 第三
		.of_match_table = of_match_table_test
	},
	.id_table = &dts_idtable
};

static int dts_driver_init(void)
{
	int ret = 0;
	ret = platform_driver_register(&dts_device);
	if(ret < 0) {
		printk("platform_driver_register error!n");
		return ret;
	}
	printk("platform_driver_register ok!n");
	return 0;
}
static int dts_driver_exit(void)
{
	printk("dts_driver_exit!n");
	gpio_free(uart3_gpio);
	misc_deregister(&misc_dev);
	platform_driver_unregister(&dts_device);
}
module_init(dts_driver_init);
module_exit(dts_driver_exit);
MODULE_LICENSE("GPL");
2.switch.c文件
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include "linux/miscdevice.h"
#include "linux/fs.h"
#include "linux/uaccess.h"
#include "linux/wait.h"
#include "linux/sched.h"
#include 
#include 

struct device_node *test_device_node;
struct property *test_node_property;
DECLARE_WAIT_QUEUE_HEAD(key_wq);   // 定义并初始化等待队列头

int gpio_num;
int irq;
int value = 0;
int wq_flags = 0;  //标志位

int misc_open(struct inode *inode, struct file *file)
{
    printk("hello misc_open!n");
    return 0;
}

int misc_release(struct inode *inode, struct file *file)
{
    printk("misc_release bye!n");
    return 0;
}

ssize_t misc_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)  
{
	wait_event_interruptible(key_wq, wq_flags);
    if(copy_to_user(ubuf,&value,sizeof(value))!=0)
    {
        printk("copy_to_user error!n");
        return -1;
    }
    wq_flags = 0;
    return 0;
}

struct file_operations misc_fops = {  //在结构体中引入相关函数
    .owner = THIS_MODULE,
    .open = misc_open,
    .release = misc_release,
    .read = misc_read,
};

struct miscdevice misc_dev={
    .minor = MISC_DYNAMIC_MINOR, //次设备号
    .name = "misc_device_switch",   //设备节点的名字
    .fops = &misc_fops
};

irq_handler_t test_key(int irq, void *args)
{
	value = ! value;
	wq_flags = 1;  //这里只有先置1,下面的函数才能唤醒
	wake_up(&key_wq);  //唤醒
	return IRQ_HANDLED;
}

int dts_probe(struct platform_device *pdev)
{
	int ret = 0;
	printk("dts_probe matching ok!n");

	
	test_device_node = of_find_node_by_path("/test_key");  //在设备树节点中查找test_key这个节点
	if(test_device_node == NULL){
		printk("of_find_node_by_path is error!n");
		return -1;
	}

	
	gpio_num = of_get_named_gpio(test_device_node,"key-gpio",0);
	if(gpio_num < 0){
		printk("of_get_named_gpio is error!n");
		return -1;
	}

	
	gpio_direction_input(gpio_num); //输入
	
	
	//irq = gpio_to_irq(gpio_num); 
	irq = irq_of_parse_and_map(test_device_node,0); //与上面这句代码的作用相同
	printk("irq is %dn", irq);

	
	ret = request_irq(irq, test_key, IRQF_TRIGGER_RISING, "test_key", NULL); 
	//IRQF_TRIGGER_RISING为上升沿触发,定义在/linux-4.1.15/include/linux/interrupt.h中
	if(ret < 0){
		printk("request_irq is error!n");
		return -1;
	}
	return 0;
}

int dts_remove(struct platform_device *pdev)
{
	printk("dts_remove!n");
	return 0;
}

const struct platform_device_id dts_idtable = {
	.name = "dts_test1"  //匹配优先级 第二
};

const struct of_device_id of_match_table_test[] = {
	{.compatible = "led_keys"},   //匹配优先级 第一
	{}
};

struct platform_driver dts_device = {
	.probe = dts_probe,
	.remove = dts_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "dts_test2", //匹配优先级 第三
		.of_match_table = of_match_table_test
	},
	.id_table = &dts_idtable
};

static int dts_driver_init(void)
{
	int ret = 0;
	ret = platform_driver_register(&dts_device);
	if(ret < 0) {
		printk("platform_driver_register error!n");
		return ret;
	}
	printk("platform_driver_register ok!n");

	ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("miscdevice registered error!n");
	    return -1;
    }
	printk("miscdevice registered successfully!n");
	return 0;
}
static int dts_driver_exit(void)
{
	printk("dts_driver_exit!n");
	free_irq(irq,NULL);
	platform_driver_unregister(&dts_device);
	misc_deregister(&misc_dev);
}
module_init(dts_driver_init);
module_exit(dts_driver_exit);
MODULE_LICENSE("GPL");
3.Makefile文件
obj-m += led.o switch.o
//obj-m += led.o
//obj-m += switch.o  //这样分开写也是可以的
KDIR:=/linux/linux-4.1.15
PWD?=$(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean
4.app.c文件
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    int fd_r,fd_w;
    int value;
    fd_r = open("/dev/misc_device_switch", O_RDWR); 
    fd_w = open("/dev/misc_device_led", O_RDWR); 
    if(fd_r < 0){
        perror("open errorn"); 
        return fd_r;
    }
    if(fd_w < 0){
        perror("open errorn"); 
        return fd_w;
    }
    while(1){
        read(fd_r, &value, sizeof(value));
        write(fd_w, &value, sizeof(value));
    }
    return 0;
}

二、运行结果

编写好以上代码后进行编译,将生成的驱动文件led.ko和switch.ko以及通过arm编译的app文件发送至开发板。

先加载两个驱动,然后运行app程序,此时按下按键,led会亮起来,再按一次,led会熄灭,如此反复执行,开发板也会打印与led亮灭相对应的信息。

按下按键之后led点亮。

按下按键之后led熄灭。


总结

以上就是Linux下通过按键控制led亮灭综合案例的所有内容了,其涉及到之前学过的中断、等待队列、pinctrl和gpio子系统、设备树、platform平台总线以及杂项设备驱动等内容,需要好好体会各内容之间的相互联系。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/641719.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号