• 20231027 基于STM32mp157a 的内核与应用层通过子系统控制led灯,以及计时器功能


    1.基于GPIO子系统编写LED驱动,编写应用程序进行测试

    stm32mp157a-fsmp1a.dts

    内核程序:ledk.c

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/of.h>
    4. #include <linux/of_gpio.h>
    5. #include <linux/delay.h>
    6. #include <linux/timer.h>
    7. struct device_node *dnode1;
    8. struct gpio_desc *gpiono1;
    9. struct gpio_desc *gpiono2;
    10. struct gpio_desc *gpiono3;
    11. struct timer_list mytimer;
    12. unsigned int *vir_rcc;
    13. struct class *cls;
    14. struct device *dev;
    15. int major;
    16. char kbuf[128] = {0};
    17. //定义操作方法
    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. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    24. {
    25. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    26. int ret1=copy_to_user(ubuf,kbuf,size);
    27. if(ret1)
    28. {
    29. printk("copy_to_user filed\n");
    30. return -EIO;
    31. }
    32. return 0;
    33. }
    34. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    35. {
    36. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    37. int ret=copy_from_user(kbuf,ubuf,size);
    38. if(ret)
    39. {
    40. printk("copy_from_user filed\n");
    41. return -EIO;
    42. }
    43. //设定该GPIO管脚的输出值
    44. if(!strcmp(kbuf,"off"))
    45. {
    46. gpiod_set_value(gpiono1,0);
    47. gpiod_set_value(gpiono2,0);
    48. gpiod_set_value(gpiono3,0);
    49. }
    50. else if(!strcmp(kbuf,"on"))
    51. {
    52. gpiod_set_value(gpiono1,1);
    53. gpiod_set_value(gpiono2,1);
    54. gpiod_set_value(gpiono3,1);
    55. }
    56. return 0;
    57. }
    58. int mycdev_close(struct inode *inode, struct file *file)
    59. {
    60. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    61. return 0;
    62. }
    63. //定义操作方法结构体变量并赋值
    64. struct file_operations fops = {
    65. .open = mycdev_open,
    66. .read = mycdev_read,
    67. .write = mycdev_write,
    68. .release = mycdev_close,
    69. };
    70. static int __init mycdev_init(void)
    71. {
    72. // 字符设备驱动注册
    73. major = register_chrdev(0, "mychrdev", &fops);
    74. if (major < 0)
    75. {
    76. printk("字符设备驱动注册失败\n");
    77. return major;
    78. }
    79. printk("字符设备驱动注册成功:major=%d\n", major);
    80. // 向上提交目录
    81. cls = class_create(THIS_MODULE, "mychrdev");
    82. if (IS_ERR(cls))
    83. {
    84. printk("向上提交目录失败\n");
    85. return -PTR_ERR(cls);
    86. }
    87. printk("向上提交目录成功\n");
    88. // 向上提交设备节点信息
    89. int i; // 向上提交三次设备节点信息
    90. for (i = 0; i < 3; i++)
    91. {
    92. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    93. if (IS_ERR(dev))
    94. {
    95. printk("向上提交设备节点失败\n");
    96. return -PTR_ERR(dev);
    97. }
    98. }
    99. printk("向上提交设备节点成功\n");
    100. //解析设备树节点信息
    101. dnode1 = of_find_node_by_path("/myled");
    102. if(dnode1 == NULL)
    103. {
    104. printk("path_find failed \n");
    105. return -ENXIO;
    106. }
    107. //根据GPIO相关节点得到GPIO编号
    108. gpiono1 = gpiod_get_from_of_node(dnode1,"led1-gpio",0,GPIOD_OUT_LOW,NULL);
    109. if(IS_ERR(gpiono1))
    110. {
    111. printk("申请gpiono1信息失败 \n");
    112. }
    113. printk("申请gpiono1信息成功 \n");
    114. gpiono2 = gpiod_get_from_of_node(dnode1,"led2-gpio",0,GPIOD_OUT_LOW,NULL);
    115. if(IS_ERR(gpiono2))
    116. {
    117. printk("申请gpiono2信息失败 \n");
    118. }
    119. printk("申请gpiono2信息成功 \n");
    120. gpiono3 = gpiod_get_from_of_node(dnode1,"led3-gpio",0,GPIOD_OUT_LOW,NULL);
    121. if(IS_ERR(gpiono3))
    122. {
    123. printk("申请gpiono3信息失败 \n");
    124. }
    125. printk("申请gpiono3信息成功 \n");
    126. //GPIO的状态
    127. return 0;
    128. }
    129. static void __exit mycdev_exit(void)
    130. {
    131. //设定该GPIO管脚的输出值
    132. gpiod_set_value(gpiono1,0);
    133. gpiod_set_value(gpiono2,0);
    134. gpiod_set_value(gpiono3,0);
    135. //释放GPIO编号
    136. gpiod_put(gpiono1);
    137. gpiod_put(gpiono2);
    138. gpiod_put(gpiono3);
    139. // 销毁设备节点信息
    140. int i;
    141. for (i = 0; i < 3; i++)
    142. {
    143. device_destroy(cls, MKDEV(major, i));
    144. }
    145. // 销毁目录
    146. class_destroy(cls);
    147. // 注销字符设备驱动
    148. unregister_chrdev(major, "mychrdev");
    149. }
    150. module_init(mycdev_init);
    151. module_exit(mycdev_exit);
    152. MODULE_LICENSE("GPL");

    应用程序:ledu.c

    1. #include <stdlib.h>
    2. #include <stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/stat.h>
    5. #include <sys/ioctl.h>
    6. #include <fcntl.h>
    7. #include <unistd.h>
    8. #include <string.h>
    9. int main(int argc,const char * argv[])
    10. {
    11. int a=0;
    12. char buf[128] = "";
    13. char buf1[128] = "";
    14. int fd1=open("/dev/myled0",O_RDWR);
    15. int fd2=open("/dev/myled1",O_RDWR);
    16. int fd3=open("/dev/myled2",O_RDWR);
    17. if(fd1<0)
    18. {
    19. printf("打开设备文件1失败\n");
    20. exit(-1);
    21. }
    22. if(fd2<0)
    23. {
    24. printf("打开设备文件2失败\n");
    25. exit(-1);
    26. }
    27. if(fd3<0)
    28. {
    29. printf("打开设备文件3失败\n");
    30. exit(-1);
    31. }
    32. memset(buf,0,sizeof(buf));
    33. while(1)
    34. {
    35. printf("请输入灯的控制(1开灯/0关灯) => ");
    36. scanf("%d",&a);
    37. write(fd1,buf,sizeof(buf));
    38. write(fd2,buf,sizeof(buf));
    39. write(fd3,buf,sizeof(buf));
    40. if(a == 1)
    41. {
    42. strcpy(buf,"on");
    43. write(fd1,buf,sizeof(buf));
    44. write(fd2,buf,sizeof(buf));
    45. write(fd3,buf,sizeof(buf));
    46. }
    47. else if(a == 0)
    48. {
    49. strcpy(buf,"off");
    50. write(fd1,buf,sizeof(buf));
    51. write(fd2,buf,sizeof(buf));
    52. write(fd3,buf,sizeof(buf));
    53. }
    54. read(fd1,buf1,sizeof(buf));
    55. printf("buf1:%s\n",buf1);
    56. }
    57. return 0;
    58. }

    2.设置定时器,5秒钟打印一次hello world

    内核程序

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/of.h>
    4. #include <linux/of_gpio.h>
    5. #include <linux/delay.h>
    6. #include <linux/timer.h>
    7. struct device_node *dnode1;
    8. struct gpio_desc *gpiono1;
    9. struct gpio_desc *gpiono2;
    10. struct gpio_desc *gpiono3;
    11. struct timer_list mytimer;
    12. char kbuf[128] = {0};
    13. void mytimer_funtion(struct timer_list *timer)
    14. {
    15. //PRINTK
    16. printk("阿巴阿巴阿巴阿巴阿巴\n");
    17. gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));
    18. //启用定时器
    19. mod_timer(timer,jiffies + msecs_to_jiffies(5000));
    20. }
    21. static int __init mycdev_init(void)
    22. {
    23. //解析设备树节点信息
    24. dnode1 = of_find_node_by_path("/myled");
    25. if(dnode1 == NULL)
    26. {
    27. printk("path_find failed \n");
    28. return -ENXIO;
    29. }
    30. //根据GPIO相关节点得到GPIO编号
    31. gpiono1 = gpiod_get_from_of_node(dnode1,"led1-gpio",0,GPIOD_OUT_LOW,NULL);
    32. if(IS_ERR(gpiono1))
    33. {
    34. printk("申请gpiono1信息失败 \n");
    35. }
    36. gpiono2 = gpiod_get_from_of_node(dnode1,"led2-gpio",0,GPIOD_OUT_LOW,NULL);
    37. if(IS_ERR(gpiono2))
    38. {
    39. printk("申请gpiono2信息失败 \n");
    40. }
    41. gpiono3 = gpiod_get_from_of_node(dnode1,"led3-gpio",0,GPIOD_OUT_LOW,NULL);
    42. if(IS_ERR(gpiono3))
    43. {
    44. printk("申请gpiono3信息失败 \n");
    45. }
    46. //分配定时器对象(timer_list)
    47. //初始化定时器(timer_setup)
    48. timer_setup(&mytimer,mytimer_funtion,0);
    49. mytimer.expires = jiffies+HZ;
    50. //注册定时器并启用(add_timer)
    51. add_timer(&mytimer);
    52. //GPIO的状态
    53. return 0;
    54. }
    55. static void __exit mycdev_exit(void)
    56. {
    57. //设定该GPIO管脚的输出值
    58. gpiod_set_value(gpiono1,0);
    59. gpiod_set_value(gpiono2,0);
    60. gpiod_set_value(gpiono3,0);
    61. //释放GPIO编号
    62. gpiod_put(gpiono1);
    63. gpiod_put(gpiono2);
    64. gpiod_put(gpiono3);
    65. //注销定时器(del_timer)
    66. del_timer(&mytimer);
    67. }
    68. module_init(mycdev_init);
    69. module_exit(mycdev_exit);
    70. MODULE_LICENSE("GPL");

  • 相关阅读:
    微信扫码把手机文件上传到电脑
    Vue 03 数据绑定
    生成网络论文阅读styleGAN1(一):论文速览
    从零开发短视频电商 自动化测试SikuliX-编程方式
    1000道最新高频Java面试题,覆盖25个技术栈(多线程、JVM、高并发、spring、微服务、kafka,redis、分布式)从底层原理到架构
    Kafka-UI
    windows@按流量计费网络设置@电脑风扇降噪的可能方法
    计算机毕设(附源码)JAVA-SSM基于Java的医疗器械销售系统
    C++解析XML文件(TinyXML)
    Qt学习12 计算器核心解析算法 (上)
  • 原文地址:https://blog.csdn.net/ainitjq1314/article/details/134083746