点亮LED灯驱动

功能:串口助手中输入0:灯全灭,输入1:LED1亮,输入2:LED2亮,输入3:LED3亮

my_led.h

#ifndef __MY_LED_H__
#define __MY_LED_H__

#define PHY_GPIO_RCC      0x50000A28
#define PHY_GPIOE_MODER   0x50006000
#define PHY_GPIOE_ODR     0x50006014
#define PHY_GPIOF_MODER   0x50007000
#define PHY_GPIOF_ODR     0x50007014

#endif

my_led.c

#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "my_led.h"
#define DEVNAME "mydev"
char kbuf[128]={0};
int ret;
int major;
unsigned int* vir_rcc;
unsigned int* vir_emoder;
unsigned int* vir_eodr;
unsigned int* vir_fmoder;
unsigned int* vir_fodr;
int my_open(struct inode *myinode, struct file *myfile)
{
	printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
	return 0;
}
int my_close(struct inode *myinod, struct file *myfile)
{
	printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
	return 0;
}
ssize_t my_read(struct file *myfile, char __user * ubuf, size_t size, loff_t * myloff)
{
	printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
	if(size>sizeof(kbuf))
	{
		size = sizeof(kbuf);
	}
	ret = copy_to_user(ubuf,kbuf,size);
	if(ret)
	{
		printk("用户读取数据失败\n");
		return -EIO;
	}
	return size;
}
ssize_t my_write(struct file *myfile, const char __user * ubuf, size_t size, loff_t * myloff)
{
	printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
	if(size>sizeof(kbuf))
	{
		size = sizeof(kbuf);
	}
	ret = copy_from_user(kbuf,ubuf,size);
	if(ret)
	{
		printk("内核读取数据失败\n");
		return -EIO;
	}
	switch(kbuf[0])
	{
		case '0': 
			(*vir_eodr) &= ~(1<<10);
			(*vir_fodr) &= ~(1<<10);
			(*vir_eodr) &= ~(1<<8);
			break;
		case '1':
			(*vir_eodr) |= (1<<10);
			break;
		case '2':
			(*vir_fodr) |= (1<<10);
			break;
		case '3':
			(*vir_eodr) |= (1<<8);
			break;

	}
	return size;
}
struct file_operations fop=
{
	.open = my_open,
	.release = my_close,
	.read = my_read,
	.write = my_write,
};


static int __init demo_init(void)
{
	printk(KERN_ERR "内核加载\n");
	major=register_chrdev(0, DEVNAME,&fop);
	printk("%d\n",major);
	
	//进行物理地址的映射
	vir_fmoder=ioremap(PHY_GPIOF_MODER,4);
    if(vir_fmoder==NULL)
    {
        printk("vir_fmoder 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_fmoder 映射成功\n");
    vir_fodr=ioremap(PHY_GPIOF_ODR,4);
    if(vir_fodr==NULL)
    {
        printk("vir_fodr 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_fodr 映射成功\n");
    vir_emoder=ioremap(PHY_GPIOE_MODER,4);
    if(vir_emoder==NULL)
    {
        printk("vir_emoder 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_emoder 映射成功\n");
    vir_eodr=ioremap(PHY_GPIOE_ODR,4);
    if(vir_eodr==NULL)
    {
        printk("vir_eodr 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_eodr 映射成功\n");
    vir_rcc=ioremap(PHY_GPIO_RCC,4);
    if(vir_rcc==NULL)
    {
        printk("vir_rcc 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_rcc 映射成功\n");
    //寄存器的初始化
    (*vir_emoder) &= ~(3<<20);
    (*vir_emoder) |= (1<<20);
    (*vir_eodr) &= ~(1<<10);
    (*vir_rcc) |= (1<<4);

	(*vir_fmoder) &= ~(3<<20);
    (*vir_fmoder) |= (1<<20);
    (*vir_fodr) &= ~(1<<10);
    (*vir_rcc) |= (1<<5);

	(*vir_emoder) &= ~(3<<16);
    (*vir_emoder) |= (1<<16);
    (*vir_eodr) &= ~(1<<8);
    (*vir_rcc) |= (1<<4);

	return 0;
}

static void __exit demo_exit(void)
{
	printk(KERN_ERR "内核卸载\n");
	unregister_chrdev(major, DEVNAME);
}

module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

Makefile:

modname ?= my_led
arch ?= arm
ifeq ($(arch),arm)
KERNELDIR := /home/ubuntu/fsmp1a/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
KERNELDIR := /lib/modules/5.3.0-28-generic/build
endif
PWD:=$(shell pwd)
all:
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	make -C $(KERNELDIR) M=$(PWD) clean
obj-m:=$(modname).o

 test.c

#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "my_led.h"
#define DEVNAME "mydev"
char kbuf[128]={0};

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char const *argv[])
{
    char buf[128]={};
    int fd=open("/dev/my_lednod",O_RDWR);
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    printf("设备文件打开成功\n");
    //在终端输入
    while(1)
    {
    printf("请输入控制命令 0:全灭 1:LED1亮 2:LED2亮 3:LED3亮\n");
        fgets(buf,sizeof(buf),stdin);
        //吃掉换行符
        buf[strlen(buf)-1]='\0';
        write(fd,buf,sizeof(buf));
        //清空buf
        memset(buf,0,sizeof(buf));
        read(fd,buf,sizeof(buf));
        printf("读取到的数据为%s\n",buf);
    }
    close(fd);
    return 0;
}

测试结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

傾语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值