根据引脚PE10,PF0,PE8,搜索寄存器地址
RCC_AHB4使能以及AHB4总线作用

- #include
- #include
- #include
- #include
- #include
- #include "myled.h"
- #define CNAME "myled"
- //主设备号
- int major;
- char kbuf[128]={0};
- //LED1--PE10
- //LED2--PF10
- //LED3--PE8
- gpio_t *vir_led1_3;
- gpio_t *vir_led2;
- volatile unsigned int *vir_rcc;
- int leds_init()
- {
- //将led的物理地址PHY做映射到vir虚拟空间
- //1个寄存器地址是32位,用4字节存放;映射后可以直接使用
- vir_rcc=ioremap(PHY_RCC,4);
- if(vir_rcc==NULL)
- {
- printk("vir_rcc faild\n");
- return -ENOMEM;
- }
- vir_led1_3=ioremap(0x50006000,sizeof(gpio_t));
- if(vir_led1_3==NULL)
- {
- printk("vir_led1_3 faild\n");
- return -ENOMEM;
- }
- vir_led2=ioremap(0x50007000,sizeof(gpio_t));
- if(vir_led2==NULL)
- {
- printk("vir_led2 faild\n");
- return -ENOMEM;
- }
-
- //LED1--PE10引脚初始化
- *vir_rcc |= (0x1<<4); //rcc使能
- vir_led1_3->MODER &=(~(0x3<<20));
- vir_led1_3->MODER |=(0x1<<20);//设置gpioe引脚输出模式
- //设置PE10引脚默认输出低电平
- vir_led1_3->ODR &= (~(0x1<<10));
- //LED2--PF10引脚初始化
- *vir_rcc |= (0x1<<5); //rcc使能
- vir_led2->MODER &=(~(0x3<<20));
- vir_led2->MODER |=(0x1<<20);//设置gpiof引脚输出模式
- //设置PF10引脚默认输出低电平
- vir_led2->ODR &= (~(0x1<<10));
- //LED3--PE8引脚初始化
- vir_led1_3->MODER &=(~(0x3<<16));
- vir_led1_3->MODER |=(0x1<<16);//设置gpioe引脚输出模式
- //设置PE8引脚默认输出低电平
- vir_led1_3->ODR &= (~(0x1<<16));
-
- return 0;
-
- }
- int mycdev_open(struct inode *inode, struct file *file)
- {
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- return 0;
- }
- ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loffs)
- {
- int ret;
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- //校验传输数据大小
- if(size>sizeof(kbuf)) size = sizeof(kbuf);
- ret = copy_to_user(ubuf,kbuf,size);
- if(ret)
- {
- printk("copy from user is error\n");
- return -EIO;
- }
- return size;
- }
- ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loffs)
- {
- int ret;
- printk("%s:%s:%d\n",__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);
- //连接应用层传参
- if(kbuf[0]=='1')
- {
- if(kbuf[1]=='1')
- {
- //led1输出高电平PE10
- vir_led1_3->ODR |= (0x1<<10);
- }
- else if(kbuf[1]=='0')
- {
- vir_led1_3->ODR &= (~(0x1<<10));
- }
- }else if(kbuf[0]=='2')
- {
- if(kbuf[1]=='1')
- {
- //led2输出高电平PF10
- vir_led2->ODR |= (0x1<<10);
- }
- else if(kbuf[1]=='0')
- {
- vir_led2->ODR &= (~(0x1<<10));
- }
- }else if(kbuf[0]=='3')
- {
- if(kbuf[1]=='1')
- {
- //led3输出高电平PE8
- vir_led1_3->ODR |= (0x1<<8);
- }
- else if(kbuf[1]=='0')
- {
- vir_led1_3->ODR &= (~(0x1<<8));
- }
- }
- return size;
- }
- int mycdev_close(struct inode *inode, struct file *file)
- {
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- return 0;
- }
- //结构体中存放函数指针,指向自己定义的函数
- const struct file_operations fops = {
- .open = mycdev_open,
- .read = mycdev_read,
- .write = mycdev_write,
- .release = mycdev_close,
- };
- //入口
- static int __init mycdev_init(void)
- {
- //1.注册字符设备驱动
- major = register_chrdev(0,CNAME,&fops);
- if(major < 0)
- {
- printk("register chrdev is error\n");
- return major;
- }
-
- printk("major=%d\n",major);
- leds_init();
- return 0;
- }
-
- //出口
- static void __exit mycdev_exit(void)
- {
- iounmap(vir_rcc);
-
- iounmap(vir_led1_3);
-
- iounmap(vir_led2);
- //2.注销字符设备驱动
- unregister_chrdev(major,CNAME);
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
- //许可证
- MODULE_LICENSE("GPL");
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- char buf[128] = {""};
- int main(int argc, char const *argv[])
- {
- int fd = -1;
- fd = open("/dev/myled",O_RDWR);
- if(-1 == fd)
- {
- perror("open is error");
- exit(1);
- }
- while(1)
- {
- //控制哪盏灯,1代表LED1
- buf[0]='1';
- write(fd,buf,sizeof(buf));
- //灯亮
- buf[1]='1';
- write(fd,buf,sizeof(buf));
- sleep(1);
- //灯灭
- buf[1]='0';
- write(fd,buf,sizeof(buf));
- sleep(1);
- //led2
- buf[0]='2';
- write(fd,buf,sizeof(buf));
- //灯亮
- buf[1]='1';
- write(fd,buf,sizeof(buf));
- sleep(1);
- //灯灭
- buf[1]='0';
- write(fd,buf,sizeof(buf));
- sleep(1);
- //led3
- buf[0]='3';
- write(fd,buf,sizeof(buf));
- //灯亮
- buf[1]='1';
- write(fd,buf,sizeof(buf));
- sleep(1);
- //灯灭
- buf[1]='0';
- write(fd,buf,sizeof(buf));
- sleep(1);
- }
-
- close(fd);
- return 0;
- }
- #ifndef __LED_H__
- #define __LED_H__
- //LED1--PE10
- //LED2--PF10
- //LED3--PE8
- #define PHY_RCC 0x50000A28
-
-
- 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 PHY_GPIOE ((gpio_t*)0x50006000)
- #define PHY_GPIOF ((gpio_t*)0x50007000)
- int leds_init(void);
- #endif
- ARCH?=arm
- filename?=myled
- ifeq ($(ARCH),arm)
- KERNDIR:=/home/ubuntu/linux-5.10.61
- else
- KERNDIR:=/lib/modules/$(shell uname -r)/build //x86架构
- endif
- PWD:=$(shell pwd)
- all:
- make -C $(KERNDIR) M=$(PWD) modules
- clean:
- make -C $(KERNDIR) M=$(PWD) clean
- #模块化编译的类型
- obj-m:=$(filename).o
对test.c和myled.c分别编译成arm架构
myled.c编译:make ARCH=arm filename=myled

串口内核启动成功,加载根文件系统,进入用户界面:
安装驱动文件,并执行a.out可执行文件,结果显示如下:并且看到三盏灯亮灭的现象
