问:怎么写LED驱动程序?

1.搭建一个字符驱动的框架(上一节已经完成)

2.完善硬件的操作

问:驱动里操作硬件寄存器与单片机操作硬件寄存器有什么不一样的地方?

答:单片机操作的寄存器地址是物理地址,驱动里面操作的必须是虚拟地址,因为驱动是内核的一部分,内核里的地址都是虚拟地址。

问:怎么让物理地址转换为虚拟地址?

答:使用ioremap函数,它的功能就是将物理地址映射为虚拟地址,具体怎么映射需要去看linux内存管理等内容。

问:应用程序如果要传数据给内核怎么办?

答:使用copy_from_user函数,同理如果内核要传数据给应用空间的应用程序则使用copy_to_user函数。

详细请参考驱动源码:

  1. #include <linux/kernel.h>
  2. #include <linux/fs.h>
  3. #include <linux/init.h>
  4. #include <linux/delay.h>
  5. #include <asm/uaccess.h>
  6. #include <asm/irq.h>
  7. #include <asm/io.h>
  8. #include <linux/module.h>
  9. #include <linux/device.h>     //class_create
  10. static struct class *firstdrv_class;
  11. static struct device *firstdrv_device;
  12. volatile unsigned long *gpbcon = NULL;
  13. volatile unsigned long *gpbdat = NULL;
  14. int major;
  15. static int first_drv_open(struct inode * inode, struct file * filp)
  16. {
  17. printk("first_drv_open\n");
  18. /*  LED1,LED2,LED3,LED4对应GPB5、GPB6、GPB7、GPB8
  19. *  配置GPB5,6,7,8为输出
  20. */
  21. *gpbcon &= ~((0x3<<(5*2)) | (0x3<<(6*2)) | (0x3<<(7*2)) | (0x3<<(8*2)));
  22. *gpbcon |= ((0x1<<(5*2)) | (0x1<<(6*2)) | (0x1<<(7*2)) | (0x1<<(8*2)));
  23. return 0;
  24. }
  25. static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
  26. {
  27. int val;
  28. printk("first_drv_write\n");
  29. copy_from_user(&val, buffer, count);
  30. if (val == 1)
  31. {
  32. // 点灯
  33. *gpbdat &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
  34. }
  35. else
  36. {
  37. // 灭灯
  38. *gpbdat |= (1<<5) | (1<<6) | (1<<7) | (1<<8);
  39. }
  40. return 0;
  41. }
  42. /* File operations struct for character device */
  43. static const struct file_operations first_drv_fops = {
  44. .owner      = THIS_MODULE,
  45. .open       = first_drv_open,
  46. .write      = first_drv_write,
  47. };
  48. /* 驱动入口函数 */
  49. static int first_drv_init(void)
  50. {
  51. /* 主设备号设置为0表示由系统自动分配主设备号 */
  52. major = register_chrdev(0, "first_drv", &first_drv_fops);
  53. /* 创建firstdrv类 */
  54. firstdrv_class = class_create(THIS_MODULE, "firstdrv");
  55. /* 在firstdrv类下创建xxx设备,供应用程序打开设备*/
  56. firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx");
  57. /* 将物理地址映射为虚拟地址 */
  58. gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16);
  59. gpbdat = gpbcon + 1;
  60. return 0;
  61. }
  62. /* 驱动出口函数 */
  63. static void first_drv_exit(void)
  64. {
  65. unregister_chrdev(major, "first_drv");
  66. device_unregister(firstdrv_device);  //卸载类下的设备
  67. class_destroy(firstdrv_class);      //卸载类
  68. iounmap(gpbcon);                    //解除映射
  69. }
  70. module_init(first_drv_init);  //用于修饰入口函数
  71. module_exit(first_drv_exit);  //用于修饰出口函数
  72. MODULE_AUTHOR("LWJ");
  73. MODULE_DESCRIPTION("Just for Demon");
  74. MODULE_LICENSE("GPL");  //遵循GPL协议

应用测试程序源码:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. /* first_test on
  8. * first_test off
  9. */
  10. int main(int argc ,char *argv[])
  11. {
  12. int fd;
  13. int val = 0;
  14. fd = open("/dev/xxx",O_RDWR);
  15. if (fd < 0)
  16. {
  17. printf("open error\n");
  18. }
  19. if (argc != 2)
  20. {
  21. printf("Usage:\n");
  22. printf("%s <on|off>\n",argv[0]);
  23. return 0;
  24. }
  25. if(strncmp(argv[1],"on",2) == 0)
  26. {
  27. val = 1;
  28. }
  29. else if (strncmp(argv[1],"off",3) == 0)
  30. {
  31. val = 0;
  32. }
  33. write(fd,&val,4);
  34. return 0;
  35. }

测试步骤:

  1. [WJ2440]# ls
  2. Qt            driver_test   lib           root          udisk
  3. TQLedtest     etc           linuxrc       sbin          usr
  4. app_test      first_drv.ko  mnt           sddisk        var
  5. bin           first_test    opt           sys           web
  6. dev           home          proc          tmp
  7. [WJ2440]# ls -l /dev/xxx
  8. ls: /dev/xxx: No such file or directory
  9. [WJ2440]# insmod first_drv.ko
  10. [WJ2440]# lsmod
  11. first_drv 2300 0 - Live 0xbf003000
  12. [WJ2440]# ls -l /dev/xxx
  13. crw-rw----    1 root     root      252,   0 Jan  2 00:23 /dev/xxx
  14. [WJ2440]# ./first_test
  15. first_drv_open
  16. Usage:
  17. ./first_test <on|off>
  18. [WJ2440]# ./first_test off
  19. first_drv_open
  20. first_drv_write
  21. [WJ2440]# ./first_test on
  22. first_drv_open
  23. first_drv_write
  24. [WJ2440]#

可发现,当执行下面语句时,开发板上的4个LED同时被熄灭:

[WJ2440]# ./first_test off

可发现,当执行下面语句时,开发板上的4个LED同时被点亮:

[WJ2440]# ./first_test on

嵌入式Linux LED小灯点亮实验的更多相关文章

  1. 【.NET 与树莓派】PWM 调节LED小灯的亮度

    在开始本文内容之前,老周先纠正一个错误.在上一篇中,提到过 Arduino 开发板的 Vin 引脚,文中老周说这个供电口的输入电压不能高于 5.5V.这里有错,被卖家给的使用说明忽悠了,上 Ardui ...

  2. Arduino 开关控制小灯持续亮之具体思路

    Arduino 开关控制小灯持续亮之具体思路 为什么写这篇文章: 我们用开关控制灯的亮灭的时候,希望只需要按一下按键就可以做到灯一直亮着.而在<Arduino魔法书>中——有弹性的按键这一 ...

  3. 5-51单片机ESP8266学习-AT指令(8266TCP服务器--用手机TCP调试助手发信息给单片机控制小灯的亮灭)

    http://www.cnblogs.com/yangfengwu/p/8759294.html 源码链接:https://pan.baidu.com/s/1wT8KAOIzvkOXXNpkDI7E8 ...

  4. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  5. 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  6. 单片机与android手机通信(控制LED小灯亮灭)

    1.单片机实验板功能设计 为验证数据通信内容,让单片机板上的四个按键与android手机客户端上的四个LED灯相互控制:为达到上述基本实验要求,采用单字符传输数据即可,硬件需设计两块相同的单片机电路板 ...

  7. 6-51单片机ESP8266学习-AT指令(8266TCP服务器--做自己的AndroidTCP客户端发信息给单片机控制小灯的亮灭)

    http://www.cnblogs.com/yangfengwu/p/8776712.html 先把源码和资料链接放到这里 链接: https://pan.baidu.com/s/1jpHZjW_7 ...

  8. 7-51单片机ESP8266学习-AT指令(8266TCP服务器,编写自己的C#TCP客户端发信息给单片机控制小灯的亮灭)

    http://www.cnblogs.com/yangfengwu/p/8780182.html 自己都是现做现写,如果想知道最终实现的功能,请看最后 先把源码和资料链接放到这里 链接: https: ...

  9. (三)开关检测来控制LED灯的亮灭

    开关检测案例一: 具体电路图如下: K1--K4闭合,控制 D1—D4 亮灭 产生的问题: 1.关于 R8 R9 R7 R10 的阻值选择问题,倘若太大的话,  比如10K 不管开关断开还是闭合,好像 ...

随机推荐

  1. 方法覆盖(override)”的要点

    方法覆盖要求子类与父类的方法一模一样,否则就是方法重载(overload)!请自行编写代码测试以下特性:在子类中,若要调用父类中被覆盖的方法,可以使用super关键字. 结论:          在“ ...

  2. About USB Data Link Cable API

    About USB Data Link Cable API The text on this webpage is licensed under the Creative Commons Attrib ...

  3. 文件:因为懂你,所以永恒 - 零基础入门学习Python028

    文件:因为懂你,所以永恒 让编程改变世界 Change the world by program 因为懂你,所以永恒 大多数的程序都遵循着:输入->处理->输出的模型,首先接受输入数据,然 ...

  4. 学习hadoop

    一.笔记本触摸板关闭方法 1.在windows下有官方驱动. 2.ubuntu下没有 操作方法如下: 1,终端操作 临时禁止触摸板:sudo modprobe -r psmouse 开启触摸板:sud ...

  5. NET站点Web部署

    NET站点Web部署(一键发布的实现) 在开发过程中经常需要发布到开发环境.测试环境或者预发布环境上给其他同事进行测试验证效果等等,每次发布都要备份,拷贝,修改配置文件等等重复操作非常的麻烦,效率大打 ...

  6. CloudStack API编程指引

    原文地址:https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+API+Coding+Guidelines 前言 本文阐述 ...

  7. (转)CentOS搭建Nagios监控

    A.Nagios服务端1.安装软件包 yum install -y httpd 2.下载nagios wget http://syslab.comsenz.com/downloads/linux/na ...

  8. Tomcat JVM

    https://www.mulesoft.com/tcat/tomcat-jvm https://www.mulesoft.com/tcat/tomcat-catalina https://www.m ...

  9. 省去在线安装 直接下载Chrome官方离线安装包

    首页>软件之家>便捷上网 省去在线安装 直接下载Chrome官方离线安装包 2013-10-12 23:22:02来源:IT之家 原创作者:阿象责编:阿象人气:54487 评论:19 谷歌 ...

  10. PowerShell_零基础自学课程_6_PS中获取帮助信息详解、管道、格式化输

    前些文章陆续的说了一些关于这些主题,但是讨论的都不够深入,今天我们深入的了解一下获取帮助信息.管道以及格式化输出的内容. 一.获取帮助信息 在PS中获取帮助信息,最常用的有: -? .get-comm ...