问:怎么写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. iscroll源码初涉

    最近尝试做web app时候,用上了神器iScroll,鉴于功力尚浅,并没有完全用好神器,所以今天特意来认真学习! 翻开官网,目前的版本是5,但是相关的文章并不多,具体的文件版本是: iscroll. ...

  2. python Cmd实例之网络爬虫应用

    python Cmd实例之网络爬虫应用 标签(空格分隔): python Cmd 爬虫 废话少说,直接上代码 # encoding=utf-8 import os import multiproces ...

  3. jquery中ajax的dataType属性包括哪几项

    参考ajax api文档:http://www.w3school.com.cn/jquery/ajax_ajax.asp dataType类型:String预期服务器返回的数据类型.如果不指定,jQu ...

  4. nginx网站架构优化思路(原)

    本人接触的优化主要分为三大类 黑体的为本模块下的重点  ---------------安全优化 安全在生产场景中是第一位的 1.1 站点目录权限的优化 (修改权限755 644 所属用户root,需要 ...

  5. 下载Google浏览器(Google Chrome)离线安装包方法

    Chrome浏览器默认是在线安装的,但由于网络的原因,有时很久也不能完成安装.其实Chrome官方是提供离线安装包的.具体地址如下: 稳定版:http://www.google.com/chrome/ ...

  6. Win8.1专业版、核心板和企业版有什么区别

    Win8.1核心版(一般就称之为Windows 8.1) + Win8.1 专业版(称之为Windows 8.1 Pro),根据用户输入的序列号(就是Win8密钥)来区分安装.Win8.1企业版(称之 ...

  7. PowerShell官方的MSDN

    https://msdn.microsoft.com/en-us/powershell/mt173057.aspx 官方还咋github上放置了  扩展模块. 比如 web iis部署.sqlserv ...

  8. Android 获取当前日期算前一年、前一月、前一天Calendar

    使用Calendar的add(int field, int amount)方法 Calendar ca = Calendar.getInstance();//得到一个Calendar的实例 ca.se ...

  9. 2015第15周日PostgreSQL学习

    英文版官网地址:http://www.postgresql.org/ 上面显示的最新版本信息是PostgreSQL 9.4.1, 9.3.6, 9.2.10, 9.1.15 & 9.0.19 ...

  10. linux下strace命令详解

    简介 strace常用来跟踪进程执行时的系统调用和所接收的信号. 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核 ...