当前位置: 首页 > article >正文

STM32MP157A单片机驱动--控制拓展版的灯实现流水效果

1.注册字符设备驱动
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
功能:进行字符设备驱动的注册,申请了256个次设备号(0-255)
参数:
    major:   >0:手动指定的当前驱动的主设备号
            ==0:由系统内核动态分配一个主设备号
    name:设备名或者驱动名
    fops:操作方法对象指针
        /*
            应用程序调用文件操作接口对设备文件进行操作时,驱动中要有操作方法被回调,想要这些操作方法被回调,需要将
            操作方法的指针放在一个操作方法对象中进行统一管理
            struct file_operations {
                    int (*open) (struct inode *, struct file *);
                  ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
                 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 
                   int (*release) (struct inode *, struct file *); 
                   };
        */
返回值:
    调用失败返回错误码
    成功:
        major==0,成功返回动态申请的主设备号
        major>0,成功返回0
2.注销字符设备驱动
void unregister_chrdev(unsigned int major, const char *name)
功能:进行字符设备驱动的注销
参数:
    major:注册时得到的主设备号
    name:注册时填写的设备名
返回值:无

led.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define LED1_PHY_GPIO_MODER 0x50006000
#define LED1_PHY_GPIO_ODR   0x50006014
#define LED1_PHY_RCC_GPIO   0x50000A28

#define LED2_PHY_GPIO_MODER 0x50007000
#define LED2_PHY_GPIO_ODR   0x50007014
#define LED2_PHY_RCC_GPIO   0x50000A2C

#define LED3_PHY_GPIO_MODER 0x50006000
#define LED3_PHY_GPIO_ODR   0x50006014
#define LED3_PHY_RCC_GPIO   0x50000A28

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

unsigned int *led1_vir_moder;
unsigned int *led1_vir_odr;
unsigned int *led1_vir_rcc;

unsigned int *led2_vir_moder;
unsigned int *led2_vir_odr;
unsigned int *led2_vir_rcc;

unsigned int *led3_vir_moder;
unsigned int *led3_vir_odr;
unsigned int *led3_vir_rcc;

// 封装各种操作方法
int myled_open(struct inode *inode, struct file *file) {
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft) {
    unsigned long ret = copy_to_user(ubuf, kbuf, size);
    if (ret) {
        printk("copy_to_user failed\n");
        return -ret;
    }
    return 0;
}

ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft) {
    unsigned long ret = copy_from_user(kbuf, ubuf, size);
    if (ret) {
        printk("copy_from_user failed\n");
        return -ret;
    }

    if (strcmp(kbuf, "1") == 0) {  // 点亮 LED1
        *led1_vir_odr |= (0x1 << 10);
        printk("点亮 LED1\n");
    } else if (strcmp(kbuf, "2") == 0) {  // 点亮 LED2
        *led2_vir_odr |= (0x1 << 10);
        printk("点亮 LED2\n");
    } else if (strcmp(kbuf, "3") == 0) {  // 点亮 LED3
        *led3_vir_odr |= (0x1 << 8);
        printk("点亮 LED3\n");
    } else if (strcmp(kbuf, "0") == 0) {  // 全部熄灭
        *led1_vir_odr &= ~(0x1 << 10);
        *led2_vir_odr &= ~(0x1 << 10);
        *led3_vir_odr &= ~(0x1 << 8);
        printk("全部熄灭\n\n");
    }

    return 0;
}

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

// 定义一个操作方法结构体变量
struct file_operations fops = {
   .open = myled_open,
   .read = myled_read,
   .write = myled_write,
   .release = myled_close,
};

static int __init mycdev_init(void) {
    // 进行字符设备驱动的注册
    major = register_chrdev(0, "myled", &fops);
    if (major < 0) {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功 major=%d\n", major);

    // 进行 LED1 寄存器的地址映射
    led1_vir_moder = ioremap(LED1_PHY_GPIO_MODER, 4);
    if (led1_vir_moder == NULL) {
        printk("LED1 物理内存映射失败%d\n", __LINE__);
        return -ENOMEM;
    }
    led1_vir_odr = ioremap(LED1_PHY_GPIO_ODR, 4);
    if (led1_vir_odr == NULL) {
        printk("LED1 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        return -ENOMEM;
    }
    led1_vir_rcc = ioremap(LED1_PHY_RCC_GPIO, 4);
    if (led1_vir_rcc == NULL) {
        printk("LED1 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        return -ENOMEM;
    }

    // 进行 LED2 寄存器的地址映射
    led2_vir_moder = ioremap(LED2_PHY_GPIO_MODER, 4);
    if (led2_vir_moder == NULL) {
        printk("LED2 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        iounmap(led1_vir_rcc);
        return -ENOMEM;
    }
    led2_vir_odr = ioremap(LED2_PHY_GPIO_ODR, 4);
    if (led2_vir_odr == NULL) {
        printk("LED2 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        iounmap(led1_vir_rcc);
        iounmap(led2_vir_moder);
        return -ENOMEM;
    }
    led2_vir_rcc = ioremap(LED2_PHY_RCC_GPIO, 4);
    if (led2_vir_rcc == NULL) {
        printk("LED2 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        iounmap(led1_vir_rcc);
        iounmap(led2_vir_moder);
        iounmap(led2_vir_odr);
        return -ENOMEM;
    }

    // 进行 LED3 寄存器的地址映射
    led3_vir_moder = ioremap(LED3_PHY_GPIO_MODER, 4);
    if (led3_vir_moder == NULL) {
        printk("LED3 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        iounmap(led1_vir_rcc);
        iounmap(led2_vir_moder);
        iounmap(led2_vir_odr);
        iounmap(led2_vir_rcc);
        return -ENOMEM;
    }
    led3_vir_odr = ioremap(LED3_PHY_GPIO_ODR, 4);
    if (led3_vir_odr == NULL) {
        printk("LED3 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        iounmap(led1_vir_rcc);
        iounmap(led2_vir_moder);
        iounmap(led2_vir_odr);
        iounmap(led2_vir_rcc);
        iounmap(led3_vir_moder);
        return -ENOMEM;
    }
    led3_vir_rcc = ioremap(LED3_PHY_RCC_GPIO,4);
    if (led3_vir_rcc == NULL) {
        printk("LED3 物理内存映射失败%d\n", __LINE__);
        iounmap(led1_vir_moder);
        iounmap(led1_vir_odr);
        iounmap(led1_vir_rcc);
        iounmap(led2_vir_moder);
        iounmap(led2_vir_odr);
        iounmap(led2_vir_rcc);
        iounmap(led3_vir_moder);
        iounmap(led3_vir_odr);
        return -ENOMEM;
    }
    printk("物理内存映射成功\n");

    //PE10设置为输出
    (*led1_vir_moder) &= (~(0X3<<20));
    (*led1_vir_moder) |= (0x1<<20);
    //让PE10默认输出低电平
    (*led1_vir_odr) &= (~(0X1<<10));

    //PF10设置为输出
    (*led2_vir_moder) &= (~(0X3<<20));
    (*led2_vir_moder) |= (0x1<<20);
    //让PF10默认输出低电平
    (*led2_vir_odr) &= (~(0X1<<10));

    //PE8设置为输出
    (*led3_vir_moder) &= (~(0X3<<16));
    (*led3_vir_moder) |= (0x1<<16);
    //让PE8默认输出低电平
    (*led3_vir_odr) &= (~(0X1<<8));
    
    return 0;
}

static void __exit mycdev_exit(void)
{
    //取消物理内存的映射
    iounmap(led1_vir_moder);
    iounmap(led1_vir_odr);
    iounmap(led1_vir_rcc);
    iounmap(led2_vir_moder);
    iounmap(led2_vir_odr);
    iounmap(led2_vir_rcc);
    iounmap(led3_vir_moder);
    iounmap(led3_vir_odr);
    iounmap(led3_vir_rcc);
    //进行字符设备驱动的注销
    unregister_chrdev(major,"myled");

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");


app.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, char const *argv[])
{
    int fd = open("/dev/myLed", O_RDWR);
    if (fd < 0) {
        printf("设备文件打开失败\n");
        return -1;
    }
 
    char cmd[2] = {0}; // 优化缓冲区大小 
    
    while(1) {
        // LED1亮 
        cmd[0] = '1';
        if(write(fd, cmd, sizeof(cmd)) < 0) {
            perror("write error");
            break;
        }
        sleep(1); // 延时1秒 
        
        // LED2亮(保持LED1亮)
        cmd[0] = '2';
        write(fd, cmd, sizeof(cmd));
        sleep(1);
        
        // LED3亮(保持前两盏亮)
        cmd[0] = '3';
        write(fd, cmd, sizeof(cmd));
        sleep(1);
        
        // 全部熄灭 
        cmd[0] = '0';
        write(fd, cmd, sizeof(cmd));
        sleep(1); // 全灭保持1秒 
    }
 
    close(fd);
    return 0;
}


http://www.kler.cn/a/557852.html

相关文章:

  • 从函数到神经网络
  • Elasticsearch常用的查询条件
  • [Android]使用WorkManager循环执行任务
  • 【开放词汇分割】Image Segmentation Using Text and Image Prompts
  • 设计心得——解耦的实现技术
  • 打开Firefox自动打开hao360.hjttif.com标签解决方案
  • java Web
  • 【论文解析】Fast prediction mode selection and CU partition for HEVC intra coding
  • 【漫话机器学习系列】100.L2 范数(L2 Norm,欧几里得范数)
  • .NET MVC实现电影票管理
  • 电商API安全防护:JWT令牌与XSS防御实战
  • android 快速定位当前页面
  • 设计模式之组合设计模式实战 文件展示 树叶子节点
  • chrome扩展程序如何实现国际化
  • springboot3.x整合fastdfs
  • Wireshark详解
  • cs106x-lecture14(Autumn 2017)-SPL实现
  • Python Matplotlib图形美化指南
  • C#DevExpress使用GridLookUpEdit实现订单明细选择商品
  • vue3 文件类型传Form Data数据格式给后端