问:怎么写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. JAVA采用JDBC连接操作数据库详解

    JDBC连接数据库概述 一.JDBC基础知识 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供 ...

  2. poj3258 二分 最小值最大化问题

    River Hopscotch Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10842   Accepted: 4654 ...

  3. CODEVS 2451 互不侵犯

    2451 互不侵犯 题目描述 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格 ...

  4. 自动化测试CTS命令

    #!/sbin/sh chmod +x /system/bin/input i=0 while [ "$i" != "10" ] do #am instrume ...

  5. maven项目依赖被改为文件夹时如何改回lib

    如图

  6. The Lead Game Add problem to Todo list Problem code: TLG

    '''def count_lead(first, second): if first > second: return 1, first - second elif first == secon ...

  7. gridview中判断隐藏还是现实

    <asp:TemplateField HeaderText="呼出" HeaderStyle-Width="60px" HeaderStyle-Horiz ...

  8. zoj 3772 Calculate the Function

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5235 这道题需要构造矩阵:F(X)=F(X-1)+F(X-2)*A(X)转化为 ...

  9. C# XmlReader/XmlWriter 类

    XmlReader用于读取Xml文件,XmlWriter用于将数据写到Xml文件.其实,在印象当中,XML很多的操作类都支持直接Save.Read也支持接受XmlReader与XmlWriter类的示 ...

  10. jquery第六期:位置选择器

    <html> <head> <script type="text/javascript" src="jquery-1.10.1.js&quo ...