【驱动开发】实现三盏灯的控制,编写应用程序测试

head.h

cs 复制代码
#ifndef __HEAD_H__
#define __HEAD_H__

//LED1:PE10
//LED2:PF10
//LED3:PE8

#define LED_RCC 0X50000A28         //使能GPIO

#define LED_MODER 0X50006000      //设置输出模式
#define LED_ODR 0X50006014        //设置输出高低电平

#define LED2_MODER 0X50007000       //设置输出模式
#define LED2_ODR 0X50007014         //设置输出高低电平

#endif

mychrdev.c

cs 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"

unsigned int major; //保存主设备号
char kbuf[128] = {0};

unsigned int *vir_rcc;
unsigned int *vir_moder;
unsigned int *vir_odr;
unsigned int *vir_moder_led2;
unsigned int *vir_odr_led2;


//封装操作方法
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 *ubuf,size_t size,loff_t *lof)
{
   // printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    
    int ret;
    ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user err\n");
        return -EIO;
    }
    return 0;
}

ssize_t mycdev_write(struct file *file,const char *ubuf,size_t size,loff_t *lof)
{
    //printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); 

    int ret;
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user err\n");
        return -EIO;
    }

//控制LED1-LED3开和关
    if(kbuf[0] == '1')      //开灯
    {
        (*vir_odr) |= (0x1<<10);    //输出高电平
        (*vir_odr_led2) |= (0x1<<10);    //输出高电平
        (*vir_odr) |= (0x1<<8);    //输出高电平
    }
    else if(kbuf[0] == '0') //关灯
    {
        (*vir_odr) &= (~(0x1<<10));  //输出低电平
        (*vir_odr_led2) &= (~(0x1<<10));    //输出高电平
        (*vir_odr) &= (~(0x1<<8));    //输出高电平
    }
    return 0;
}

int mycdev_close(struct inode *inode,struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); 
    return 0;
}

struct file_operations fops={       //定义一个操作方法结构体对象并初始化
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};   



static int __init mycdev_init(void) //入口函数  安装内核模块时执行
{
    major=register_chrdev(0,"mychrdev",&fops);     //字符设备驱动的注册
    if(major<0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功 major=%d\n",major);


//进行LED控制相关寄存器的内存映射
    vir_rcc = ioremap(LED_RCC,4);
    if(vir_rcc == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_moder = ioremap(LED_MODER,4);
    if(vir_moder == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_odr = ioremap(LED_ODR,4);
    if(vir_odr == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_moder_led2 = ioremap(LED2_MODER,4);
    if(vir_moder_led2 == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_odr_led2 = ioremap(LED2_ODR,4);
    if(vir_odr_led2 == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }


    printk("寄存器内存映射成功\n");

//控制led1-led3硬件寄存器的初始化
    (*vir_rcc) |= (0x1<<4);         //RCC使能GPIO E组
    (*vir_rcc) |= (0x1<<5);         //RCC使能GPIO F组

    (*vir_moder) &= (~(0x3<<20));   //设置PE10为输出
    (*vir_moder) |= (0x1<<20);

    (*vir_moder_led2) &= (~(0x3<<20));   //设置PF10为输出
    (*vir_moder_led2) |= (0x1<<20);  

    (*vir_moder) &= (~(0x3<<16));       //设置PE8为输出
    (*vir_moder) |= (0x1<<16);    

    (*vir_odr) &= (~(0x1<<10));         //设置led1默认关灯
    (*vir_odr_led2) &= (~(0x1<<10));    //设置led2默认关灯
    (*vir_odr) &= (~(0x1<<8));          //设置led3默认关灯

    return 0;
}

static void __exit mycdev_exit(void)    //出口函数,卸载内核模块时执行
{
    iounmap(vir_moder);         //取消物理内存映射
    iounmap(vir_moder_led2);    //取消物理内存映射
    iounmap(vir_odr);           //取消物理内存映射
    iounmap(vir_odr_led2);      //取消物理内存映射
    iounmap(vir_rcc);           //取消物理内存映射
    
    unregister_chrdev(major,"mychrdev");  //注销字符设备驱动
}

module_init(mycdev_init);   //用于声明当前内核模块入口函数的地址
module_exit(mycdev_exit);   //用于声明当前内核模块出口函数的地址
MODULE_LICENSE("GPL");  //声明当前内核模块遵循GPL协议

led_test.c

cs 复制代码
#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] = {0};
    int fd=open("/dev/mychrdev",O_RDWR);
    if(fd < 0)
    {
        printf("设备文件打开失败\n");
        exit(-1);
    }

    while(1)
    {   //控制LED亮和灭
        printf("请输入LED的控制命令:1(开灯),0(关灯) >>");
        fgets(buf,sizeof(buf),stdin);       //从终端输入数据传递到buf中
        buf[strlen(buf)-1] = '\0';          //末尾替换\n
        write(fd,buf,sizeof(buf));   
    }
    
    return 0;
}

测试结果如下:

相关推荐
sukalot6 小时前
window显示驱动开发—显示适配器的子设备
驱动开发
Evan_ZGYF丶15 小时前
【RK3576】【Android14】如何在Android14下单独编译kernel-6.1?
linux·驱动开发·android14·rk3576
sukalot1 天前
window显示驱动开发—视频呈现网络简介
驱动开发
sukalot2 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)
驱动开发
zwhSunday2 天前
Linux驱动开发(1)概念、环境与代码框架
linux·运维·驱动开发
sukalot2 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(三)
驱动开发
sukalot3 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(一)
驱动开发
cxr8284 天前
基于Claude Code的 规范驱动开发(SDD)指南
人工智能·hive·驱动开发·敏捷流程·智能体
zwhSunday4 天前
Linux驱动开发(2)进一步理解驱动
linux·驱动开发
被遗忘的旋律.4 天前
Linux驱动开发笔记(十)——中断
linux·驱动开发·笔记