• 驱动——按键中断控制LED灯实验


    三个按键实现按键中断

    要求:按键按一下灯亮,再按一下灯灭

    注:由于开发板位置,为了方便一一对应观察,采用key1控制LED3,key2控制LED2,key3控制LED1

    0、添加相关设备树节点信息

    ①按键相关引脚,通过原理图可得:

    key1------>gpiof9;

    key2------>gpiof7;

    key3------>gpiof8

    ②LED灯相关引脚:

    led1----->gpioe10;

    led2------>gpiof10;

    led3------>gpioe8;

    ③编写完成之后在内核顶层目录下执行make dtbs重新生成设备树二进制文件

    cp arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb ~/tftpboot

    ④ 重新启动开发板

    1. myleds{
    2. myled1 = <&gpioe 10 0>;
    3. myled2 = <&gpiof 10 0>;
    4. myled3 = <&gpioe 8 0>;
    5. };
    6. myirq{
    7. interrupt-parent = <&gpiof>;
    8. interrupts = <7 0>,<8 0>,<9 0>;
    9. };

    1、获取设备树节点

    本次采用通过名字进行获取(具体详情见gpio子系统(LED灯的操控实验))

    2、从节点信息中解析出软中断号

    int irq_of_parse_and_map(struct device_node *dev, int index)

    功能:解析设备树节点信息获取软中断号

    参数:

    dev:设备树节点信息结构体指针

    index:中断的索引号

    返回值:成功返回软中断号,失败返回0

     3、将要使用的中断注册进内核

    int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)

    功能:注册中断

    参数:

            irq:软中断号

            handler:中断处理函数 //typedef irqreturn_t (*irq_handler_t)(int, void *);

                    //中断处理函数返回值:

                            //IRQ_NONE //中断不是设备处理或者没处理

                            //IRQ_HANDLED //中断正常处理

                            //IRQ_WAKE_THREAD //开启中断处理线程

            flags:中断触发的方式

                    IRQF_TRIGGER_RISING//上升沿触发

                    IRQF_TRIGGER_FALLING//下降沿触发

                    IRQF_TRIGGER_HIGH//高电平触发

                    IRQF_TRIGGER_LOW//低电平触发

            name:中断的名字//自己指定

                    sudo cat /proc/interrupts

            dev:在这个函数里传给中断处理函数的参数,根据情况决定给是否使用

    返回值:成功返回0,失败返回错误码

     4、注销中断

    void *free_irq(unsigned int irq, void *dev_id)

    功能:注销中断

    参数:

            irq:软中断号 d

            ev_id:向中断处理函数中传递的参数

    返回值:返回设备名

     5、具体代码实现

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include"./six.h"
    15. #define GNAME "mydev"
    16. unsigned int irqno1;//用于接收软中断号
    17. unsigned int irqno2;//用于接收软中断号
    18. unsigned int irqno3;//用于接收软中断号
    19. unsigned int num=0;
    20. //定义一个底半部
    21. struct tasklet_struct tasklet;
    22. irqreturn_t irq_handler1(int irqno,void *dev)
    23. {
    24. num++;
    25. printk("key1 interrupt %d ...\n",num);
    26. gpiod_set_value(gpiono1,(!gpiod_get_value(gpiono1)));
    27. return IRQ_HANDLED;
    28. }
    29. irqreturn_t irq_handler2(int irqno,void *dev)
    30. {
    31. num++;
    32. printk("key2 interrupt %d ...\n",num);
    33. gpiod_set_value(gpiono2,(!gpiod_get_value(gpiono2)));
    34. return IRQ_HANDLED;
    35. }
    36. irqreturn_t irq_handler3(int irqno,void *dev)
    37. {
    38. num++;
    39. printk("key3 interrupt %d ...\n",num);
    40. gpiod_set_value(gpiono3,(!gpiod_get_value(gpiono3)));
    41. return IRQ_HANDLED;
    42. }
    43. static int __init mynode_init(void)
    44. {
    45. int ret;
    46. //通过名字获取设备树节点信息
    47. node = of_find_node_by_name(NULL,"myirq");
    48. if(NULL == node)
    49. {
    50. printk("of find node by name error\n");
    51. return -EFAULT;
    52. }
    53. //根据设备树节点获取软中断号1
    54. irqno1 = irq_of_parse_and_map(node,1);
    55. if(irqno1==0)
    56. {
    57. printk("irq of parse and map error\n");
    58. return EINVAL;
    59. }
    60. printk("irq of parse and map success\n");
    61. //根据设备树节点获取软中断号2
    62. irqno2 = irq_of_parse_and_map(node,0);
    63. if(irqno2==0)
    64. {
    65. printk("irq of parse and map error\n");
    66. return EINVAL;
    67. }
    68. printk("irq of parse and map success\n");
    69. //根据设备树节点获取软中断号3
    70. irqno3 = irq_of_parse_and_map(node,2);
    71. if(irqno3==0)
    72. {
    73. printk("irq of parse and map error\n");
    74. return EINVAL;
    75. }
    76. printk("irq of parse and map success\n");
    77. //将要使用的中断注册进内核
    78. ret = request_irq(irqno1,irq_handler1,IRQF_TRIGGER_FALLING,"key",NULL);
    79. if(ret)
    80. {
    81. printk("request irq irqno1 error\n");
    82. return ret;
    83. }
    84. //将要使用的中断注册进内核
    85. ret = request_irq(irqno2,irq_handler2,IRQF_TRIGGER_FALLING,"key",NULL);
    86. if(ret)
    87. {
    88. printk("request irq irqno1 error\n");
    89. return ret;
    90. }
    91. //将要使用的中断注册进内核
    92. ret = request_irq(irqno3,irq_handler3,IRQF_TRIGGER_FALLING,"key",NULL);
    93. if(ret)
    94. {
    95. printk("request irq irqno1 error\n");
    96. return ret;
    97. }
    98. //通过名字获取设备树节点信息
    99. node = of_find_node_by_name(NULL,"myleds");
    100. if(NULL == node)
    101. {
    102. printk("of find node by name error\n");
    103. return -EFAULT;
    104. }
    105. //获取并申请LED1的gpio编号
    106. gpiono1 = gpiod_get_from_of_node(node,"myled1",0,GPIOD_OUT_LOW,NULL);
    107. if(IS_ERR(gpiono1))
    108. {
    109. printk("1gpiod get from of node error\n");
    110. return PTR_ERR(gpiono1);
    111. }
    112. //获取并申请LED2的gpio编号
    113. gpiono2 = gpiod_get_from_of_node(node,"myled2",0,GPIOD_OUT_LOW,NULL);
    114. if(IS_ERR(gpiono2))
    115. {
    116. printk("2gpiod get from of node error\n");
    117. return PTR_ERR(gpiono2);
    118. }
    119. //获取并申请LED3的gpio编号
    120. gpiono3 = gpiod_get_from_of_node(node,"myled3",0,GPIOD_OUT_LOW,NULL);
    121. if(IS_ERR(gpiono3))
    122. {
    123. printk("3gpiod get from of node error\n");
    124. return PTR_ERR(gpiono3);
    125. }
    126. return 0;
    127. }
    128. static void __exit mynode_exit(void)
    129. {
    130. //注销中断1
    131. free_irq(irqno1,NULL);
    132. //注销中断1
    133. free_irq(irqno2,NULL);
    134. //注销中断1
    135. free_irq(irqno3,NULL);
    136. //卸载驱动前熄灭灯LED1
    137. gpiod_set_value(gpiono1,0);
    138. //卸载驱动前熄灭灯LED1
    139. gpiod_set_value(gpiono2,0);
    140. //卸载驱动前熄灭灯LED1
    141. gpiod_set_value(gpiono3,0);
    142. //释放申请得到的LED1gpio编号
    143. gpiod_put(gpiono1);
    144. //释放申请得到的LED2gpio编号
    145. gpiod_put(gpiono2);
    146. //释放申请得到的LED3gpio编号
    147. gpiod_put(gpiono3);
    148. }
    149. module_init(mynode_init);
    150. module_exit(mynode_exit);
    151. MODULE_LICENSE("GPL");

     头文件代码:

    1. #ifndef __LED_H__
    2. #define __LED_H__
    3. #define LED_ON _IOW('a',1,int)
    4. #define LED_OFF _IOW('a',0,int)
    5. struct device_node *node;
    6. struct gpio_desc *gpiono1;
    7. struct gpio_desc *gpiono2;
    8. struct gpio_desc *gpiono3;
    9. int ret;
    10. typedef enum{
    11. LED1,
    12. LED2,
    13. LED3,
    14. }led_t;
    15. #endif

    makefile脚本文件见gpio子系统(LED灯的操控实验) 

    6、实验现象

    见按键中断控制LED灯实验现象

  • 相关阅读:
    Python【求孪生数】
    计算机毕业设计SSM电脑配件仓储后台管理系统【附源码数据库】
    数字化改革“1612”详解
    vue仿企微文档给页面加水印(水印内容可自定义,超简单)
    C++ 学习(五)数组(一维数组、二维数组)
    (TDChat_GPT,在问,百晓生,Chathttps,思研,chatai,闽狮人工智能)分享7个好用的ChatGPT
    常用软件快捷键
    20、wpf之MVVM命令绑定
    leetcode:644. 子数组最大平均数 II【浮点数二分 + 子数组最大平均值技巧】
    Word Power S
  • 原文地址:https://blog.csdn.net/ww1106/article/details/128085963