• 驱动——串口工具点灯实验


     通过串口工具输入命令,操作LED灯的点亮与熄灭

    要求:

    1)分部实现注册字符设备驱动

    2)自动创建设备节点

    3)通过结构体对led灯地址进行映射

    4)次设备号完成私有数据传参

    代码实现:

    1、头文件代码的编写:

    ①对GPIO寄存器进行结构体的封装

    ②对寄存器的地址进行宏定义

    ③通过枚举给LED灯进行赋值

     2、编写功能代码:

    open函数:

    通过inode结构体获取次设备号,并通过私有数据进行传参

    入口函数:

    ①分布实现字符设备驱动

    a:分配字符设备驱动(struct cdev *cdev_alloc(void))

    b:完成设备驱动的初始化(void cdev_init(struct cdev *cdev, const struct file_operations *fops))

    c:申请设备号(静态指定:int register_chrdev_region(dev_t from, unsigned count, const char *name);动态申请:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name))

    d:注册字符设备驱动(int cdev_add(struct cdev *p, dev_t dev, unsigned count))

    ②完成LED灯相应寄存器的初始化

    ③自动创建设备节点(class_create提交目录信息,device_create提交设备节点信息)

    出口函数:

    a:销毁设备节点信息

    b:释放驱动

    c:释放设备号

    d:注销字符设备驱动

    许可证

     附:实现代码

    头文件:

    1. #ifndef __MYLED_H__
    2. #define __MYLED_H_
    3. typedef struct{
    4. volatile unsigned int MODER;
    5. volatile unsigned int OTYPER;
    6. volatile unsigned int OSPEEDR;
    7. volatile unsigned int PUPDR;
    8. volatile unsigned int IDR;
    9. volatile unsigned int ODR;
    10. }gpio_t;
    11. #define GPIOE_ADDR 0x50006000
    12. #define GPIOF_ADDR 0x50007000
    13. #define RCC_ADDR 0x50000A28
    14. typedef enum{
    15. LED1,
    16. LED2,
    17. LED3,
    18. }leds_t;
    19. #endif

     makefile代码:

    1. ARCH ?= x86
    2. FILE ?= led
    3. ARM:=arm
    4. X86:=x86
    5. ifeq ($(ARCH),$(ARM))
    6. KERNEDIR:=/home/ubuntu/linux-5.10.61
    7. endif
    8. ifeq ($(ARCH),$(X86))
    9. KERNEDIR:=/lib/modules/$(shell uname -r)/build
    10. endif
    11. PWD:=$(shell pwd)
    12. KBUILD_EXTRA_SYMBOLS:=/home/ubuntu/ww/driver/01_linux/03_sym/01_demo/Module.symvers
    13. all:
    14. make -C $(KERNEDIR) M=$(PWD) modules
    15. clean:
    16. make -C $(KERNEDIR) M=$(PWD) clean
    17. obj-m:=$(FILE).o

     功能代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include"./led.h"
    10. #define GNAME "mydev"
    11. volatile gpio_t* VIRT_GPIOE;
    12. volatile gpio_t* VIRT_GPIOF;
    13. volatile unsigned int* VIRT_RCC;
    14. unsigned int major =0;
    15. char kbuf[128]={0};
    16. struct cdev* cdev;
    17. struct class * cls;
    18. struct device *devic;
    19. dev_t dev1;
    20. int minor = 0;
    21. unsigned count=3;
    22. int mydev_open(struct inode *inode, struct file *file)
    23. {
    24. int min;
    25. printk("%s:%s:%d",__FILE__,__func__,__LINE__);
    26. min=MINOR(inode->i_rdev);
    27. file->private_data=(void*)min;
    28. return 0;
    29. }
    30. ssize_t mydev_read(struct file *file, char __user *ubuf, size_t size, loff_t * loff)
    31. {
    32. printk("%s:%s:%d",__FILE__,__func__,__LINE__);
    33. return 0;
    34. }
    35. ssize_t mydev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
    36. {
    37. int ret;
    38. int min;
    39. //printk("%s:%s:%d",__FILE__,__func__,__LINE__);
    40. if(size > sizeof(kbuf)) size = sizeof(kbuf);
    41. ret = copy_from_user(kbuf,ubuf,size);
    42. if(ret)
    43. {
    44. printk("copy from user is error\n");
    45. return -EIO;
    46. }
    47. //printk("copy from user kbuf = %s\n",kbuf);
    48. min=(int)file->private_data;
    49. switch(min)
    50. {
    51. case 0:
    52. if(kbuf[0]=='1')
    53. {
    54. VIRT_GPIOE->ODR |= (0x1<<10);
    55. }
    56. else if(kbuf[0]=='0')
    57. {
    58. VIRT_GPIOE->ODR &= (~(0x1<<10));
    59. }
    60. break;
    61. case 2:
    62. if(kbuf[0]=='1')
    63. {
    64. VIRT_GPIOE->ODR |= (0x1<<8);
    65. }
    66. else if(kbuf[0]=='0')
    67. {
    68. VIRT_GPIOE->ODR &= (~(0x1<<8));
    69. }
    70. break;
    71. case 1:
    72. if(kbuf[0]=='1')
    73. {
    74. VIRT_GPIOF->ODR |= (0x1<<10);
    75. }
    76. else if(kbuf[0]=='0')
    77. {
    78. VIRT_GPIOF->ODR &= (~(0x1<<10));
    79. }
    80. break;
    81. }
    82. return 0;
    83. }
    84. int mydev_close(struct inode *inode, struct file *file)
    85. {
    86. printk("%s:%s:%d",__FILE__,__func__,__LINE__);
    87. return 0;
    88. }
    89. struct file_operations fops={
    90. .open=mydev_open,
    91. .read=mydev_read,
    92. .write=mydev_write,
    93. .release=mydev_close,
    94. };
    95. static int __init myled_init(void)
    96. {
    97. int i;
    98. int ret;
    99. //分配字符设备驱动
    100. cdev=cdev_alloc();
    101. if(NULL==cdev)
    102. {
    103. printk("cdev alloc error\n");
    104. goto ERR1;
    105. }
    106. //设备驱动初始化
    107. cdev_init(cdev,&fops);
    108. //申请设备号
    109. if(major>0)
    110. {
    111. ret=register_chrdev_region(MKDEV(major,minor),count,GNAME);
    112. if(ret!=0)
    113. {
    114. printk("register chrdev region error\n");
    115. ret = -ENOMEM;
    116. goto ERR2;
    117. }
    118. }
    119. else
    120. {
    121. ret=alloc_chrdev_region(&dev1,0,count,GNAME);
    122. if(ret!=0)
    123. {
    124. printk("alloc chrdev region error\n");
    125. ret = -ENOMEM;
    126. goto ERR2;
    127. }
    128. major = MAJOR(dev1);
    129. minor = MINOR(dev1);
    130. }
    131. //驱动的注册
    132. ret = cdev_add(cdev,MKDEV(major,minor),count);
    133. if(ret!=0)
    134. {
    135. printk("cdev add error\n");
    136. ret = -EIO;
    137. goto ERR3;
    138. }
    139. //寄存器初始化
    140. VIRT_RCC = ioremap(RCC_ADDR,4);
    141. if(NULL == VIRT_RCC)
    142. {
    143. printk("VIRT_RCC error\n");
    144. return -ENXIO;
    145. }
    146. VIRT_GPIOE = ioremap(GPIOE_ADDR,sizeof(gpio_t));
    147. if(NULL == VIRT_GPIOE)
    148. {
    149. printk("VIRT_GPIOE error\n");
    150. return -ENXIO;
    151. }
    152. VIRT_GPIOF = ioremap(GPIOF_ADDR,sizeof(gpio_t));
    153. if(NULL == VIRT_GPIOF)
    154. {
    155. printk("VIRT_GPIOF error\n");
    156. return -ENXIO;
    157. }
    158. *VIRT_RCC |= (0x3<<4);
    159. VIRT_GPIOE->MODER &= (~(0x3<<20));
    160. VIRT_GPIOE->MODER |= (0x1<<20);
    161. VIRT_GPIOE->ODR &= (~(0x1<<10));
    162. VIRT_GPIOE->MODER &= (~(0x3<<16));
    163. VIRT_GPIOE->MODER |= (0x1<<16);
    164. VIRT_GPIOE->ODR &= (~(0x1<<8));
    165. VIRT_GPIOF->MODER &= (~(0x3<<20));
    166. VIRT_GPIOF->MODER |= (0x1<<20);
    167. VIRT_GPIOF->ODR &= (~(0x1<<10));
    168. //自动创建设备节点
    169. cls = class_create(THIS_MODULE,GNAME);
    170. if(IS_ERR(cls))
    171. {
    172. ret = PTR_ERR(cls);
    173. goto ERR4;
    174. }
    175. for(i=0;i
    176. {
    177. devic = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    178. if(IS_ERR(devic))
    179. {
    180. ret = PTR_ERR(devic);
    181. goto ERR5;
    182. }
    183. }
    184. return 0;
    185. ERR5:
    186. for(--i;i>=0;i--)
    187. {
    188. device_destroy(cls,MKDEV(major,i));
    189. }
    190. class_destroy(cls);
    191. ERR4:
    192. cdev_del(cdev);
    193. ERR3:
    194. unregister_chrdev_region(MKDEV(major,minor),count);
    195. ERR2:
    196. kfree(cdev);
    197. ERR1:
    198. return -EIO;
    199. }
    200. static void __exit myled_exit(void)
    201. {
    202. int i;
    203. //销毁设备节点信息
    204. for(i=0;i
    205. {
    206. device_destroy(cls,MKDEV(major,i));
    207. }
    208. class_destroy(cls);
    209. //释放驱动
    210. cdev_del(cdev);
    211. //释放设备号
    212. unregister_chrdev_region(MKDEV(major,minor),count);
    213. //注销字符设备驱动
    214. kfree(cdev);
    215. }
    216. module_init(myled_init);
    217. module_exit(myled_exit);
    218. MODULE_LICENSE("GPL");

    点灯测试现象:

    1.在串口工具进行输入:

    echo 1 > /dev/myled0 ---->led1灯点亮

    echo 0 > /dev/myled0 ---->led1灯熄灭

    echo 1 > /dev/myled1 ---->led1灯点亮

    echo 0 > /dev/myled1 ---->led1灯熄灭

    echo 1 > /dev/myled2 ---->led1灯点亮

    echo 0 > /dev/myled2 ---->led1灯熄灭

    点灯实验现象

     

    串口点灯实验现象

  • 相关阅读:
    ABAP 企业微信ASE CBC 解密算法
    故障维修无忧服务:OLED透明拼接屏的专业技术支持与保修服务
    机器视觉杂
    数组复制(java)
    运行java命令出现 Error: Invalid or corrupt jarfile XXX.jar
    apollo源码启动服务,apollo源码分析
    进程控制,父子进程
    linux查看进程对应的线程(数)
    Spring之文件上传下载,jrebel,多文件上传
    自动安装系统-桌面
  • 原文地址:https://blog.csdn.net/ww1106/article/details/127937189