• 基于gpio子系统编写LED灯的驱动,编写应用程序测试


    mychrdev.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. // 构建LED开关的功能码,添加ioctl第三个参数int
    10. #define LED_ON _IOW('l', 1, int)
    11. #define LED_OFF _IOW('l', 0, int)
    12. struct device_node *dnode;
    13. struct gpio_desc *gpiono1, *gpiono2, *gpiono3;
    14. int major;
    15. char kbuf[128] = {0};
    16. struct class *cls;
    17. struct device *dev;
    18. int mycdev_open(struct inode *inode, struct file *file)
    19. {
    20. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    21. return 0;
    22. }
    23. long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    24. {
    25. int which;
    26. // 获取arg对应的用户空间中的值
    27. copy_from_user(&which, (void *)arg, 4);
    28. switch (cmd)
    29. {
    30. case LED_ON: // 开灯
    31. gpiod_set_value(gpiono1, 1);
    32. gpiod_set_value(gpiono2, 1);
    33. gpiod_set_value(gpiono3, 1);
    34. break;
    35. case LED_OFF: // 关灯
    36. gpiod_set_value(gpiono1, 0);
    37. gpiod_set_value(gpiono2, 0);
    38. gpiod_set_value(gpiono3, 0);
    39. break;
    40. }
    41. return 0;
    42. }
    43. int mycdev_close(struct inode *inode, struct file *file)
    44. {
    45. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    46. return 0;
    47. }
    48. // 定义操作方法结构体变量并赋值
    49. struct file_operations fops = {
    50. .open = mycdev_open,
    51. .unlocked_ioctl = mycdev_ioctl,
    52. .release = mycdev_close,
    53. };
    54. static int __init mycdev_init(void)
    55. {
    56. // 字符设备驱动注册
    57. major = register_chrdev(0, "mychrdev", &fops);
    58. if (major < 0)
    59. {
    60. printk("字符设备驱动注册失败\n");
    61. return major;
    62. }
    63. printk("字符设备驱动注册成功:major=%d\n", major);
    64. // 向上提交目录
    65. cls = class_create(THIS_MODULE, "mychrdev");
    66. if (IS_ERR(cls))
    67. {
    68. printk("向上提交目录失败\n");
    69. return -PTR_ERR(cls);
    70. }
    71. printk("向上提交目录成功\n");
    72. // 向上提交设备节点信息
    73. int i;
    74. for (i = 0; i < 3; i++)
    75. {
    76. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mychrdev%d", i);
    77. if (IS_ERR(dev))
    78. {
    79. printk("向上提交设备节点信息失败\n");
    80. return -PTR_ERR(dev);
    81. }
    82. }
    83. printk("向上提交设备节点信息成功\n");
    84. // 解析LED的设备树节点
    85. dnode = of_find_node_by_path("/myled");
    86. if (dnode == NULL)
    87. {
    88. printk("解析设备树节点失败\n");
    89. return -ENXIO;
    90. }
    91. printk("解析GPIO信息成功\n");
    92. // 申请gpio对象
    93. gpiono1 = gpiod_get_from_of_node(dnode, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);
    94. gpiono2 = gpiod_get_from_of_node(dnode, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);
    95. gpiono3 = gpiod_get_from_of_node(dnode, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);
    96. if (IS_ERR(gpiono1) || IS_ERR(gpiono2) || IS_ERR(gpiono3))
    97. {
    98. printk("申请gpio对象失败\n");
    99. return PTR_ERR(gpiono2);
    100. }
    101. printk("申请gpio信息对象成功\n");
    102. return 0;
    103. }
    104. static void __exit mycdev_exit(void)
    105. {
    106. /*销毁设备节点信息*/
    107. int i;
    108. for (i = 0; i < 3; i++)
    109. {
    110. device_destroy(cls, MKDEV(major, i));
    111. }
    112. // 销毁目录信息
    113. class_destroy(cls);
    114. // 在卸载驱动时熄灭LED
    115. gpiod_set_value(gpiono1, 0);
    116. gpiod_set_value(gpiono2, 0);
    117. gpiod_set_value(gpiono3, 0);
    118. // 释放gpio编号
    119. gpiod_put(gpiono1);
    120. gpiod_put(gpiono2);
    121. gpiod_put(gpiono3);
    122. // 注销字符设备驱动
    123. unregister_chrdev(major, "mychrdev");
    124. }
    125. module_init(mycdev_init);
    126. module_exit(mycdev_exit);
    127. MODULE_LICENSE("GPL");

    test.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include "head.h"
    10. int main(int argc, char const *argv[])
    11. {
    12. int a;
    13. char buf[128] = {0};
    14. int fd = open("/dev/mychrdev0", O_RDWR);
    15. if (fd < 0)
    16. {
    17. printf("打开设备文件失败\n");
    18. exit(-1);
    19. }
    20. while (1)
    21. {
    22. // 从终端读取
    23. printf("请输入对LED灯的控制:1(开灯)0(关灯)>");
    24. scanf("%d", &a);
    25. switch (a)
    26. {
    27. case 1:
    28. ioctl(fd, LED_ON); // 开灯
    29. break;
    30. case 0:
    31. ioctl(fd, LED_OFF); // 关灯
    32. }
    33. }
    34. close(fd);
    35. return 0;
    36. }

    实验现象

    1:点亮三盏灯

    0:熄灭三盏灯

  • 相关阅读:
    【开发教程4】开源蓝牙心率防水运动手环-外部 Flash 读写
    【自然语言处理(NLP)】基于LSTM实现文字检测
    konachan网站之用户脚本优化Konachan站点浏览体验
    Selenium自动化测试 —— 通过cookie绕过验证码的操作!
    docker-compose安装mysql
    逻辑回归模型公式推导
    [cocos creator] Label设置为RESIZE_HEIGHT,获取height
    微信管理系统
    Linux的介绍与应用
    Django使用Token认证(simplejwt库的配置)
  • 原文地址:https://blog.csdn.net/weixin_47976606/article/details/132991911