字符设备分布注册实现LED灯

news2024/12/25 1:20:14

目标:通过字符设备的分布注册实现LED灯的控制

字符分布注册:

 

test.c文件

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

int main(int argc,const char * argv[])
{
    char buf[1024] = {0};
    int a,b;
    int fd = open("/dev/mycdev0",O_RDWR); 
    if(fd < 0)
    {
        printf("打开设备失败\n");
        exit(-1);
    }

    while (1)
    {
        printf("实现功能:1(开灯) 0(关灯) > \n");
        scanf("%d",&a);
        printf("需要控制的灯1(LED1) 2(LED2) 3(LED3) > \n");
        scanf("%d",&b);
        switch (a)
        {
        case 1:
            ioctl(fd,LED_ON,&b);
            break;
        case 0:
            ioctl(fd,LED_OFF,&b);
            break;
        default:
            break;
        }
    }
    close(fd);
    return 0;
}

head.h文件

#ifndef __HEAD_H__
#define __HEAD_H__

typedef struct
{
    unsigned int MODER;
    unsigned int OTYPER;
    unsigned int OSPEEDR;
    unsigned int PUPD;
    unsigned int IDR;
    unsigned int ODR;
}gpio_t;

#define PHY_LED1_ADDR 0x50006000
#define PHY_LED2_ADDR 0x50007000
#define PHY_LED3_ADDR 0x50006000
#define PHY_RCC_ADDR  0x50000A28

// #define LED_ON  _IO('l',1)//开灯
// #define LED_OFF  _IO('l',0)//关灯

#define LED_ON  _IOW('l',1,int)//开灯
#define LED_OFF  _IOW('l',0,int)//关灯


#endif 

Character_devive.c文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "head.h"


unsigned int major = 0;
unsigned int minor = 0;

gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;

struct cdev *cdev;
dev_t devnum;

//向上申请的结构体目录信息
struct class *cls;
//向上申请的结构体节点信息
struct device *dev;

//封装操作方法
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__);
    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__);
    return 0;
}

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

long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    int which;
    int ret = copy_from_user(&which,(unsigned int *)arg,4);
    if(ret)
    {
        printk("copy_from_user is ERR\n");
        return ret;
    }
    switch (cmd)
    {
    case LED_ON:
        switch (which)
        {
        case 1:
            vir_led1->ODR |= 0x1 << 10;
            break;
        case 2:
            vir_led2->ODR |= 0x1 << 10;
            break;
        case 3:
            vir_led3->ODR |= 0x1 << 8;
            break;
        default:
            break;
        }
        break;
    case LED_OFF:
        switch (which)
        {
        case 1:
            vir_led1->ODR &= (~(0x1 << 10));
            break;
        case 2:
            vir_led2->ODR &= (~(0x1 << 10));
            break;
        case 3:
            vir_led3->ODR &= (~(0x1 << 8));
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    return 0;
}

// 寄存器地址映射
int all_led_init(void)
{
    vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
    if (vir_led1 == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }

    vir_led2 = ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    if (vir_led2 == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led3 = vir_led1;
    
    vir_rcc = ioremap(PHY_RCC_ADDR, 4);
    if (vir_rcc == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    printk("物理内存映射成功\n");
    //rcc
    (*vir_rcc) |= 0x3 << 4;
    //LED1
    vir_led1->MODER &= (~(0x3 << 20));
    vir_led1->MODER |= 0x1 << 20;
    vir_led1->ODR &= (~(0x1 << 10));
    //LED2
    vir_led2->MODER &= (~(0x3 << 20));
    vir_led2->MODER |= 0x1 << 20;
    vir_led2->ODR &= (~(0x1 << 10));
    //LED3
    vir_led3->MODER &= (~(0x3 << 16));
    vir_led3->MODER |= 0x1 << 16;
    vir_led3->ODR &= (~(0x1 << 8));

    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .release = mycdev_close,
    .read = mycdev_read,
    .write = mycdev_write,
    .unlocked_ioctl=mycdev_ioctl,
};

static int __init mycdev_init(void)
{
    int ret;
    //1.分配字符设备驱动对象
    cdev = cdev_alloc();
    if(cdev == NULL)
    {
        printk("申请字符设备驱动对象失败\n");
        ret = -EFAULT;
        goto OUT1;
    }
    printk("申请字符设备驱动成功\n");
    //2.初始化字符设备驱动对象
    cdev_init(cdev,&fops);
    //3.申请设备号
    if(major > 0)//静态指定
    {
        ret = register_chrdev_region(MKDEV(major,minor),3,"mycdev");
        if(ret){
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
    }else{
        ret = alloc_chrdev_region(&devnum,minor,3,"mycdev");
        if(ret){
        printk("静态指定设备号失败\n");
        goto OUT2;
        }
        minor = MINOR(devnum);
        major = MAJOR(devnum);
    }
    printk("申请设备号成功\n");
    //4.注册字符设备驱动对象
    ret = cdev_add(cdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto OUT3;
    }
    printk("注册字符设备驱动对象成功\n");

    all_led_init();
    
    // 向上提交目录信息
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls))
    {
        printk("向上提交目录信息失败\n");
        ret = -PTR_ERR(cls);
        goto OUT4;
    }
    printk("向上提交目录信息成功\n");

    // 向上提交设备信息
    int i;
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
        if (IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            ret = -PTR_ERR(cls);
            goto OUT5;
        }
    }
    printk("向上提交设备节点成功\n");
    return 0;

    OUT5:
        for(--i;i>=0;i++)
            device_destroy(cls,MKDEV(major,i));
        class_destroy(cls);
    OUT4:
        cdev_del(cdev);
    OUT3:
        unregister_chrdev_region(MKDEV(major,minor),3);
    OUT2:
        kfree(cdev);
    OUT1:
        return ret;
}

static void __exit mycdev_exit(void)
{
    // 取消物理映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);

    // 销毁设备信息
    int i;
    for (i = 0; i < 3; i++)
        device_destroy(cls, MKDEV(major, i));
    
    // 销毁目录信息
    class_destroy(cls);
    //注销字符设备驱动对象
    unregister_chrdev_region(MKDEV(major,minor),3);
    //释放空间对象
    kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

串口运行结果:

开发板运行实例:

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/891442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

212、仿真-基于51单片机体温脉搏心率血氧报警Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…

快速解决Ubuntu 中 wine 程序 中文显示为方块/显示错误/无法显示中文(2023)

解决办法就是在创建prefix的命令行里加上LANG“zh_CN.UTF8” LC_ALL“zh_CN.UTF8”&#xff0c;并安装cjkfonts&#xff0c;即可。 1、生成prefix、安装cjk字体 以下是基本流程&#xff1a; 现在假定wine和winetricks已经装好&#xff0c; // 先创建一个prefix&#xff0c;按…

切面的魔力:解密Spring AOP 面向切面编程

目录 一、AOP简介 1.1 什么是AOP &#xff1f; 1.2 什么是面向切面编程 &#xff1f; 1.3 AOP 的特点 二、 AOP的基本概念解读 2.1 AOP的基本概念 2.2 AOP 概念趣事解读 三、代码情景演示 3.1 编写目标对象&#xff08;超级英雄们正常的行动&#xff09; 3.2 编写通知…

史上最全HBase面试题,高薪必备,架构必备

说在前面 本文《尼恩 大数据 面试宝典》 是 《尼恩Java面试宝典》姊妹篇。 这里特别说明一下&#xff1a;《尼恩Java面试宝典》41个专题 PDF 自首次发布以来&#xff0c; 已经汇集了 好几千题&#xff0c;大量的大厂面试干货、正货 &#xff0c;足足4800多页&#xff0c;帮助…

【脚踢数据结构】常见排序算法

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;软件配置等领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff01;送给自己和读者的…

keil遇到“Error:CreateProcess failed,Command:“怎么办

解决办法&#xff1a; 第一步&#xff1a;卸载原有的compiler 5; 第二步&#xff1a;安装compiler 5到指定目录&#xff1a;这个目录地址是&#xff1a; 安装目录地址“ARM安装目录” / ARMARM_Compiler_5.06u7 例如我的安装目录是C:\Keil_v5\ARM\ARM_Compiler_5.06u7 第三…

苹果电脑清理软件——CleanMyMac快速清理电脑垃圾

大家在用苹果电脑卸载软件时是不是很苦恼&#xff1f;遇到要清理的垃圾软件太多&#xff0c;总是清理不干净。这时可以借助苹果电脑清理软件——CleanMyMac快速清理&#xff0c;接下来的文章就教教大家快速清理电脑垃圾软件&#xff0c;怎么快速清理电脑垃圾软件。 CleanMyMac …

LangChain手记 Evalutation评估

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Evaluation&#xff08;源代码可见&#xff09; 基于LLM的应用如何做评估是一个难点&#xff0c;本节介绍了一些思路和工具。 “从传统开发转换到基于prompt的开发&#xff0c;开发使用LLM的应用&#xff0c;整个工…

云农场种植模式:数字化农业的崭新未来

在现代科技的映衬下&#xff0c;农业正在经历着前所未有的变革。云农场种植模式作为数字化农业的一个重要组成部分&#xff0c;为农业注入了新的活力和可能性。这种创新模式不仅提升了农业效率&#xff0c;还为农民、消费者以及环境带来了许多积极影响。 云农场种植模式玩法说明…

vue实现可缩放拖拽盒子(亲测可用)

特征 没有依赖 使用可拖动&#xff0c;可调整大小或两者兼备定义用于调整大小的句柄限制大小和移动到父元素或自定义选择器将元素捕捉到自定义网格将拖动限制为垂直或水平轴保持纵横比启用触控功能使用自己的样式为句柄提供自己的样式 安装和基本用法 npm install --save vue-d…

解决“warning: #223-D: function “xPortSysTickHandler“ declared implicitly“告警提示

继上篇文章发布已有时隔两个月之久&#xff0c;今天就把这两个月遇到的一些问题解决分享一下&#xff0c;首先&#xff0c;我们来看今天分享的这个关于我在学习freertos遇到的一个告警。如图所示&#xff1a; 告警提示原句为&#xff1a; warning: #223-D: function "xP…

DNDC模型建模方法及土壤碳储量、温室气体排放、农田减排、土地变化、气候变化应用

DNDC&#xff08;Denitrification-Decomposition&#xff0c;反硝化-分解模型&#xff09;是目前国际上最为成功的模拟生物地球化学循环的模型之一&#xff0c;自开发以来&#xff0c;经过不断完善和改进&#xff0c;从模拟简单的农田生态系统发展成为可以模拟几乎所有陆地生态…

BAT测试专家对web测试和APP测试的总结

单纯从功能测试的层面上来讲的话&#xff0c;App 测试、Web 测试在流程和功能测试上是没有区别的&#xff0c;但由于系统结构方面存在差异&#xff08;web 项目&#xff0c;b/s 架构&#xff1b;app 项目&#xff0c;c/s 结构&#xff09;在测试中还是有不同的侧重点内容&#…

SOLIDWORKS 弹簧扣特征-塑料制品的福音

很多从事塑料制品产业的工程师&#xff0c;每天都在面对如何提高配合精度的问题&#xff0c;特别是扣合的精度。通常情况下扣合类结构采用分开建立扣与槽的形式&#xff0c;该方式已经无法满足当前环境下设计的需要&#xff0c;当然在SOLIDWORKS中此类问题很早之前就已经被考虑…

扁线电机定子转子工艺及自动化装备

售&#xff1a;扁线电机 电驱对标样件 需要请联&#xff1a;shbinzer &#xff08;拆车邦&#xff09; 新能源车电机路线大趋势&#xff0c;自动化装配产线需求迫切永磁同步电机是新能源车驱动电机的主要技术路线。目前新能源车上最广泛应用的类型为永磁同步电机&#xff0c…

数组的详述(2)

2、二维数组的创建和初始化 可以把二维数组理解为一维数组的数组。 行 列 //行可省略&#xff0c;列不能省。 二维数组的使用&#xff08;<而不是<&#xff0c;因为数组下标第一个是0&#xff09; 二维数组在内存中的储存​​​​&#xf…

day4 驱动开发

【ioctl函数的使用】 1.概述 linux有意将对设备的功能选择和设置以及硬件数据的读写分成不同的函数来实现。让read/write函数专注于数据的读写&#xff0c;而硬件功能的设备和选择通过ioctl函数来选择 2.ioctl函数分析 int ioctl(int fd,unsigned long request) 通过&…

Spring-aop特点,专业术语及案例演示

一.aop简介 AOP&#xff08;Aspect-Oriented Programming&#xff09;是Spring框架的一个重要特性&#xff0c;它通过将横切关注点&#xff08;cross-cutting concerns&#xff09;从核心业务逻辑中分离出来&#xff0c;以模块化的方式在整个应用程序中重复使用。以下是关于AOP…

udp与can通信的选择与比较

UDP&#xff08;用户数据报协议&#xff09;和CAN&#xff08;控制器局域网&#xff09;是两种不同的通信协议&#xff0c;它们在实时传递性上有一些区别。 UDP是一种无连接的传输协议&#xff0c;它提供了简单的、不可靠的数据传输。UDP不提供可靠性保证、流控制或重传机制。…

图解二叉树,拿下拿下!

图文详解二叉树 一、树形结构概念特性二、树形结构基本概念术语三、树的存储结构四、二叉树 概念与特性五、特殊的二叉树六、二叉树的性质七、二叉树的存储结构八、二叉树的基本操作1、二叉树的遍历&#xff08;1&#xff09;前中后序遍历&#xff08;2&#xff09;经典找序列&…