单片机
返回首页

代码示例_poll的多路复用

2025-02-06 来源:cnblogs

//头文件

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include

#include

#include

#include


//定义一个按键的数据包

struct button_event{

    int code;         //按键的名称---键值:KEY_DOWN

    int value;        //按键的状态---按下:1,松开:0

};


//设计一个描述按键的结构体类型

struct buttons{

    char *name;        //名称

    unsigned int irqno;        //中断号

    int gpio;                //按键对应的gpio口

    int code;                //键值

    unsigned long flags;    //触发方式

};


//定义一个数组来保存多个按键的数据

struct buttons buttons_set[] = {

    [0] = {

        .name = 'key1_up',

        .irqno = IRQ_EINT(0),

        .gpio = S5PV210_GPH0(0),

        .code = KEY_UP,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

    [1] = {

        .name = 'key2_down',

        .irqno = IRQ_EINT(1),

        .gpio = S5PV210_GPH0(1),

        .code = KEY_DOWN,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

    [2] = {

        .name = 'key3_left',

        .irqno = IRQ_EINT(2),

        .gpio = S5PV210_GPH0(2),

        .code = KEY_LEFT,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

    [3] = {

        .name = 'key4_right',

        .irqno = IRQ_EINT(3),

        .gpio = S5PV210_GPH0(3),

        .code = KEY_RIGHT,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

};


//面向对象编程----设计设备的类型

struct s5pv210_button{

    //unsigned int major;

    dev_t  devno;

    struct class * cls;

    struct device * dev;

    struct cdev  *cdev;

    unsigned int irqno;

    struct button_event event;

    wait_queue_head_t wq_head;

    

    int have_data;        //表示当前是否有数据可读,可读--1,不可读--0

};

struct s5pv210_button *button_dev;


//实现中断处理函数--------当触发中断时会被执行

irqreturn_t button_irq_svc(int irqno, void *dev)

{

    int value;

    struct buttons *p;

    printk('--------^_^ %s------------n',__FUNCTION__);


    //获取当前触发中断的按键信息

    p = (struct buttons *)dev;

    

    //获取产生中断的gpio口的值

    value = gpio_get_value(p->gpio);

    //判断是按下还是松开

    if(value){

        //松开

        printk('kernel:%s up!n',p->name);

        button_dev->event.code = p->code;

        button_dev->event.value = 0;

    }else{

        //按下

        printk('kenel:%s pressed!n',p->name);

        button_dev->event.code = p->code;

        button_dev->event.value = 1;

    }


    //此时有数据可读

    button_dev->have_data = 1;


    //从等待队列中唤醒阻塞的进程

    wake_up_interruptible(&button_dev->wq_head);

    

    return IRQ_HANDLED;

}


//实现设备操作接口

int button_open(struct inode *inode, struct file *filp)

{


    printk('--------^_^ %s------------n',__FUNCTION__);

    

    return 0;

}

ssize_t button_read(struct file *filp , char __user *buf , size_t size, loff_t *flags)

{

    int ret;

    printk('--------^_^ %s------------n',__FUNCTION__);

    //判读open时,有没有设置flags为NONBLOCK

    if(filp->f_flags & O_NONBLOCK && !button_dev->have_data)

        return -EAGAIN;

        

    //判断此时是否有数据可读

    wait_event_interruptible(button_dev->wq_head,button_dev->have_data);

    

    //将内核数据转换为用户空间数据

    ret = copy_to_user(buf,&button_dev->event,size);

    if(ret > 0){

        printk('copy_to_user error!n');

        return -EFAULT;

    }


    //将数据返回给应用空间后,清空数据包,同时将hava_data置零

    memset(&button_dev->event,0,sizeof(button_dev->event));

    button_dev->have_data = 0;

    return size;

}


ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags)

{


    printk('--------^_^ %s------------n',__FUNCTION__);


    return size;

}


long button_ioctl(struct file *filp, unsigned int cmd , unsigned long args)

{

    

    printk('--------^_^ %s------------n',__FUNCTION__);

    

    return 0;

}

unsigned int button_poll(struct file *filp, struct poll_table_struct *pts)

{

    unsigned int mask = 0;

    printk('--------^_^ %s------------n',__FUNCTION__);


    //1,将等待队列头注册到系统中(VFS)

    poll_wait(filp,&button_dev->wq_head,pts);


    //2,如果产生按键中断-有数据可读,此时返回POLLIN,如果没有数据返回0

    if(button_dev->have_data)

        mask |= POLLIN;


    return mask;

    

}


int button_close(struct inode *inode, struct file *filp)

{

    printk('--------^_^ %s------------n',__FUNCTION__);

    

    return 0;

}



static struct file_operations fops = {

    .open = button_open,

    .read = button_read,

    .write = button_write,

    .poll = button_poll,

    .unlocked_ioctl = button_ioctl,

    .release = button_close,

};



//加载函数和卸载函数

static int __init button_init(void)   //加载函数-----在驱动被加载时执行

{

    int ret,i;

    printk('--------^_^ %s------------n',__FUNCTION__);

    //0,实例化设备对象

    //参数1 ---- 要申请的空间的大小

    //参数2 ---- 申请的空间的标识

    button_dev = kzalloc(sizeof(struct s5pv210_button),GFP_KERNEL);

    if(IS_ERR(button_dev)){

        printk('kzalloc error!n');

        ret = PTR_ERR(button_dev);

        return -ENOMEM;

    }

    

    //1,申请设备号-----新方法

#if 0

    //静态申请设备号

    button_dev->major = 256;

    ret = register_chrdev_region(MKDEV(button_dev->major,0),1,'button_drv');

    if(ret < 0){

        printk('register_chrdev_region error!n');

        ret =  -EINVAL;

        goto err_kfree;

    }

#else

    //动态申请设备号

    ret = alloc_chrdev_region(&button_dev->devno,0,1,'button_drv');

    if(ret < 0){

        printk('register_chrdev_region error!n');

        ret =  -EINVAL;

        goto err_kfree;

    }

#endif


    //创建cdev


    //申请cdev的空间

    button_dev->cdev = cdev_alloc();

    if(IS_ERR(button_dev->cdev)){        

        printk('button_dev->cdev error!n');

        ret = PTR_ERR(button_dev->cdev);

        goto err_unregister;

    }


    //初始化cdev的成员

    cdev_init(button_dev->cdev,&fops);


    //将cdev加入到内核中----链表

    ret = cdev_add(button_dev->cdev,button_dev->devno,1);



    

    //2,创建设备文件-----/dev/button

    button_dev->cls = class_create(THIS_MODULE,'button_cls');

    if(IS_ERR(button_dev->cls)){

        printk('class_create error!n');

        ret = PTR_ERR(button_dev->cls);

        goto err_cdev_del;

    }

    

    button_dev->dev = device_create(button_dev->cls,NULL,button_dev->devno,NULL,'button');

    if(IS_ERR(button_dev->dev)){

        printk('device_create error!n');

        ret = PTR_ERR(button_dev->dev);

        goto err_class;

    }



    //3,硬件初始化---申请中断

    for(i = 0; i < ARRAY_SIZE(buttons_set);i++){

        ret = request_irq(buttons_set[i].irqno,button_irq_svc,buttons_set[i].flags,buttons_set[i].name,&buttons_set[i]);

        if(ret != 0){

            printk('request_irq error!n');

            ret = -EBUSY;

            goto err_device;

        }

    }

    //初始化等待队列头

    init_waitqueue_head(&button_dev->wq_head);

    


    return 0;

    

err_device:

    device_destroy(button_dev->cls,button_dev->devno);

err_class:

    class_destroy(button_dev->cls);

    

err_cdev_del:

    cdev_del(button_dev->cdev);

    

err_unregister:

    unregister_chrdev_region(button_dev->devno,1);

    

err_kfree:

    kfree(button_dev);

    return ret;


    

}


static void __exit button_exit(void)   //卸载函数-----在驱动被卸载时执行

{

    int i;

    printk('--------^_^ %s------------n',__FUNCTION__);

    for(i = 0; i < ARRAY_SIZE(buttons_set);i++){

        free_irq(buttons_set[i].irqno,&buttons_set[i]);

    }

    device_destroy(button_dev->cls,button_dev->devno);

    class_destroy(button_dev->cls);

    cdev_del(button_dev->cdev);

    unregister_chrdev_region(button_dev->devno,1);

    kfree(button_dev);

}


//声明和认证

module_init(button_init);

module_exit(button_exit);

MODULE_LICENSE('GPL');


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


//定义一个按键的数据包

struct button_event{

    int code;    //按键的名称---键值:KEY_DOWN

    int value;        //按键的状态---按下:1,松开:0

};


int main(void)

{


    int fd;

    int ret;

    struct button_event event;

    struct pollfd pfds[2];

    char buf[128];


    fd = open('/dev/button',O_RDWR);

    if(fd < 0){

    perror('open');

    exit(1);

    }


    pfds[0].fd = 0;        //标准输入文件描述符

    pfds[0].events = POLLIN;    //是否可读


    pfds[1].fd = fd;        //开发板中的键盘

    pfds[1].events = POLLIN;    //按键是否触发中断



    while(1){


    ret = poll(pfds,2,-1);

    if(ret < 0){

        perror('poll');

        exit(1);

    }

    if(ret > 0){


        //标准输入可读

        if(pfds[0].revents & POLLIN){

        fgets(buf,sizeof(buf),stdin);

        printf('%s',buf);

        }

        //开发板中的按键触发了中断 

        if(pfds[1].revents & POLLIN){


        bzero(&event,sizeof(event));

        ret = read(fd,&event,sizeof(event));

        if(ret < 0){

            perror('read');

            exit(1);

        }


        switch(event.code){

            case KEY_UP:

            if(event.value)

                printf('按下了上键!n');

            else

                printf('松开了上键!n');

            break;

            case KEY_DOWN:

            if(event.value)

                printf('按下了下键!n');

            else

                printf('松开了下键!n');

            break;

            case KEY_LEFT:

            if(event.value)

                printf('按下了左键!n');

            else

                printf('松开了左键!n');

            break;

            case KEY_RIGHT:

            if(event.value)

                printf('按下了右键!n');

            else

                printf('松开了右键!n');

            break;

        }

        }

    }

    }


    close(fd);

    return 0;

}


#指定内核源码路径

KERNEL_DIR = /home/farsight/s5pv210/kernel/linux-3.0.8

CUR_DIR = $(shell pwd)

MYAPP = test


all:

    #让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译

    make -C $(KERNEL_DIR) M=$(CUR_DIR) modules

    arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c


clean:

    #删除上面编译生成的文件

    make -C $(KERNEL_DIR) M=$(CUR_DIR) clean

    rm -rf $(MYAPP)


install:

    cp *.ko $(MYAPP) /opt/rootfs/drv_module


#指定当前目录下哪个文件作为内核模块编

obj-m = button_drv.o


Stay hungry, stay foolish 待续。。。


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章