驱动——串口工具点灯实验
创始人
2024-02-01 20:11:56

 通过串口工具输入命令,操作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:注销字符设备驱动

许可证

 附:实现代码

头文件:

#ifndef __MYLED_H__
#define __MYLED_H_typedef struct{volatile unsigned int MODER;volatile unsigned int OTYPER;volatile unsigned int OSPEEDR;volatile unsigned int PUPDR;volatile unsigned int IDR;volatile unsigned int ODR;
}gpio_t;#define GPIOE_ADDR 0x50006000
#define GPIOF_ADDR 0x50007000
#define RCC_ADDR 0x50000A28typedef enum{LED1,LED2,LED3,
}leds_t;#endif

 makefile代码:

ARCH ?= x86
FILE ?= led
ARM:=arm
X86:=x86
ifeq ($(ARCH),$(ARM))
KERNEDIR:=/home/ubuntu/linux-5.10.61
endif
ifeq ($(ARCH),$(X86))
KERNEDIR:=/lib/modules/$(shell uname -r)/build
endif
PWD:=$(shell pwd)
KBUILD_EXTRA_SYMBOLS:=/home/ubuntu/ww/driver/01_linux/03_sym/01_demo/Module.symvers
all:make -C $(KERNEDIR) M=$(PWD) modules
clean:make -C $(KERNEDIR) M=$(PWD) clean
obj-m:=$(FILE).o

 功能代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include"./led.h"
#define GNAME "mydev"volatile gpio_t* VIRT_GPIOE;
volatile gpio_t* VIRT_GPIOF;
volatile unsigned int* VIRT_RCC;unsigned int major =0;
char kbuf[128]={0};
struct cdev* cdev;
struct class * cls;
struct device *devic;
dev_t dev1;
int minor = 0;
unsigned count=3;int mydev_open(struct inode *inode, struct file *file)
{int min;printk("%s:%s:%d",__FILE__,__func__,__LINE__);min=MINOR(inode->i_rdev);file->private_data=(void*)min;return 0;
}
ssize_t mydev_read(struct file *file, char __user *ubuf, size_t size, loff_t * loff)
{printk("%s:%s:%d",__FILE__,__func__,__LINE__);return 0;
}
ssize_t mydev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{int ret;int min;//printk("%s:%s:%d",__FILE__,__func__,__LINE__);if(size > sizeof(kbuf)) size = sizeof(kbuf);ret = copy_from_user(kbuf,ubuf,size);if(ret){printk("copy from user is error\n");return -EIO;}//printk("copy from user kbuf = %s\n",kbuf);min=(int)file->private_data;switch(min){case 0:if(kbuf[0]=='1'){VIRT_GPIOE->ODR |= (0x1<<10);}else if(kbuf[0]=='0'){VIRT_GPIOE->ODR &= (~(0x1<<10));}break;case 2:if(kbuf[0]=='1'){VIRT_GPIOE->ODR |= (0x1<<8);}else if(kbuf[0]=='0'){VIRT_GPIOE->ODR &= (~(0x1<<8));}break;case 1:if(kbuf[0]=='1'){VIRT_GPIOF->ODR |= (0x1<<10);}else if(kbuf[0]=='0'){VIRT_GPIOF->ODR &= (~(0x1<<10));}break;}return 0;
}int mydev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d",__FILE__,__func__,__LINE__);return 0;
}
struct file_operations fops={.open=mydev_open,.read=mydev_read,.write=mydev_write,.release=mydev_close,
};
static int __init myled_init(void)
{int i;int ret;//分配字符设备驱动cdev=cdev_alloc();if(NULL==cdev){printk("cdev alloc error\n");goto ERR1;}//设备驱动初始化cdev_init(cdev,&fops);//申请设备号if(major>0){ret=register_chrdev_region(MKDEV(major,minor),count,GNAME);if(ret!=0){printk("register chrdev region error\n");ret = -ENOMEM;goto ERR2;}}else{ret=alloc_chrdev_region(&dev1,0,count,GNAME);if(ret!=0){printk("alloc chrdev region error\n");ret = -ENOMEM;goto ERR2;}major = MAJOR(dev1);minor = MINOR(dev1);}//驱动的注册ret = cdev_add(cdev,MKDEV(major,minor),count);if(ret!=0){printk("cdev add error\n");ret = -EIO;goto ERR3;}//寄存器初始化VIRT_RCC = ioremap(RCC_ADDR,4);if(NULL == VIRT_RCC){printk("VIRT_RCC error\n");return -ENXIO;}VIRT_GPIOE = ioremap(GPIOE_ADDR,sizeof(gpio_t));if(NULL == VIRT_GPIOE){printk("VIRT_GPIOE error\n");return -ENXIO;}VIRT_GPIOF = ioremap(GPIOF_ADDR,sizeof(gpio_t));if(NULL == VIRT_GPIOF){printk("VIRT_GPIOF error\n");return -ENXIO;}*VIRT_RCC |= (0x3<<4);VIRT_GPIOE->MODER &= (~(0x3<<20));VIRT_GPIOE->MODER |= (0x1<<20);VIRT_GPIOE->ODR &= (~(0x1<<10));VIRT_GPIOE->MODER &= (~(0x3<<16));VIRT_GPIOE->MODER |= (0x1<<16);VIRT_GPIOE->ODR &= (~(0x1<<8));VIRT_GPIOF->MODER &= (~(0x3<<20));VIRT_GPIOF->MODER |= (0x1<<20);VIRT_GPIOF->ODR &= (~(0x1<<10));//自动创建设备节点cls = class_create(THIS_MODULE,GNAME);if(IS_ERR(cls)){ret = PTR_ERR(cls);goto ERR4;}for(i=0;i=0;i--){device_destroy(cls,MKDEV(major,i));}class_destroy(cls);
ERR4:cdev_del(cdev);
ERR3:unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:kfree(cdev);
ERR1:return -EIO;}static void __exit myled_exit(void)
{int i;//销毁设备节点信息for(i=0;i

点灯测试现象:

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灯熄灭

点灯实验现象

 

串口点灯实验现象

上一篇:延期的同义词

下一篇:关于雁南飞的诗

相关内容

热门资讯

应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...