• 基于GPIO子系统编写LED驱动,编写应用程序进行测试设置定时器,5秒钟打印一次hello world


    应用程序 test.c

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

    驱动文件demo.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. /* myled
    12. {
    13. led1-gpio=<&gpioe 10 0>;
    14. led2-gpio=<&gpiof 10 0>;
    15. led3-gpio=<&gpioe 8 0>;
    16. };
    17. */
    18. struct device_node *dnode;
    19. // unsigned int gpiono;
    20. struct gpio_desc *gpiono[3];
    21. char *str[3] = {"led1-gpio", "led2-gpio", "led3-gpio"};
    22. struct timer_list mytimer;
    23. // 封装操作方法
    24. int major;
    25. char kbuf[128] = {0};
    26. struct class *cls;
    27. struct device *dev;
    28. int mycdev_open(struct inode *inode, struct file *file)
    29. {
    30. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    31. return 0;
    32. }
    33. long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    34. {
    35. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    36. // arg-1 : 0=led1 1=led2 2=led3
    37. // cmd = 0 关灯,cmd = 1 开灯
    38. gpiod_set_value(gpiono[arg - 1], cmd);
    39. return 0;
    40. }
    41. int mycdev_close(struct inode *inode, struct file *file)
    42. {
    43. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    44. return 0;
    45. }
    46. // 定义操作方法结构体变量并赋值
    47. struct file_operations fops = {
    48. .open = mycdev_open,
    49. .unlocked_ioctl = mycdev_ioctl,
    50. .release = mycdev_close,
    51. };
    52. void mytimer_function(struct timer_list *timer)
    53. {
    54. // 每5s打印一次hello world!
    55. printk("hello world!\n");
    56. printk("请输入要实现的功能 0(关灯) 1(开灯) 请输入>\n");
    57. printk("请选择要控制的灯:1(LED1)2(LED2) 3(LED3) 请输入>\n");
    58. mod_timer(timer, jiffies + 5 * HZ);
    59. }
    60. static int __init mycdev_init(void)
    61. {
    62. // 字符设备驱动注册
    63. major = register_chrdev(0, "mychrdev", &fops);
    64. if (major < 0)
    65. {
    66. printk("字符设备驱动注册失败\n");
    67. return major;
    68. }
    69. printk("字符设备驱动注册成功:major=%d\n", major);
    70. // 向上提交目录
    71. cls = class_create(THIS_MODULE, "mychrdev");
    72. if (IS_ERR(cls))
    73. {
    74. printk("向上提交目录失败\n");
    75. return -PTR_ERR(cls);
    76. }
    77. printk("向上提交目录成功\n");
    78. // 向上提交设备节点信息
    79. // 向上提交三次设备节点信息
    80. dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myled%d", 0);
    81. if (IS_ERR(dev))
    82. {
    83. printk("向上提交设备节点失败\n");
    84. return -PTR_ERR(dev);
    85. }
    86. printk("向上提交设备节点成功\n");
    87. // 解析设备树节点信息
    88. dnode = of_find_node_by_path("/myled");
    89. if (dnode == NULL)
    90. {
    91. printk("解析设备树节点失败\n");
    92. return -ENXIO;
    93. }
    94. // 获取LED GPIO编号
    95. int i = 0;
    96. for (i = 0; i < 3; i++)
    97. {
    98. gpiono[i] = gpiod_get_from_of_node(dnode, str[i], 0, GPIOD_OUT_LOW, NULL);
    99. if (IS_ERR(gpiono[i]))
    100. {
    101. printk("申请gpio信息失败\n");
    102. return -PTR_ERR(gpiono[i]);
    103. }
    104. }
    105. // 初始化定时器对象
    106. timer_setup(&mytimer, mytimer_function, 0);
    107. mytimer.expires = jiffies + 5 * HZ; // 定时5s
    108. // 注册定时器
    109. add_timer(&mytimer);
    110. return 0;
    111. }
    112. static void __exit mycdev_exit(void)
    113. {
    114. // 注销定时器
    115. del_timer(&mytimer);
    116. int i = 0;
    117. for (i = 0; i < 3; i++)
    118. {
    119. // gpio_set_value(gpiono,0);
    120. gpiod_set_value(gpiono[i], 0);
    121. // 释放GPIO编号
    122. // gpio_free(gpiono);
    123. gpiod_put(gpiono[i]);
    124. }
    125. // 销毁设备节点信息
    126. device_destroy(cls, MKDEV(major, 0));
    127. // 销毁目录
    128. class_destroy(cls);
    129. // 注销字符设备驱动
    130. unregister_chrdev(major, "mychrdev");
    131. }
    132. module_init(mycdev_init);
    133. module_exit(mycdev_exit);
    134. MODULE_LICENSE("GPL");

     效果:

    在终端输入对应1 0 / 123 就可以控制开发板上led1,led2,led3的亮灭

  • 相关阅读:
    Java 抽象工厂模式
    unity中的SendMessage详解
    面试必杀技:Jmeter性能测试攻略大全(第一弹)
    BP神经网络算法基本原理,bp神经网络的算法步骤
    js 继承内置类型 之 洗牌算法
    保护视力,从 CareUEyes 开始 —— 你的电脑护眼小助手
    Vuex
    Google Analytics优缺点分析
    便捷高效的电能管理:利用PLC远程控制网关实时监控配电箱
    SwiftUI Swift 之正向地理编码与反向地理编码(教程含源码)
  • 原文地址:https://blog.csdn.net/ck0056/article/details/134092627