单片机
返回首页

学习控制发光二极管代码心得

2024-09-29 来源:cnblogs

LED的完整驱动代码

#include

#include

#include

#include

#include

#include

#include

 

#define DEVICE_NAME 's3c6410_leds'

#define DEVICE_COUNT 1               //  设备数量

#define S3C6410_LEDS_MAJOR 0   // 默认主设备号

#define S3C6410_LEDS_MINOR 234  // 默认次设备号

#define PARAM_SIZE  3 //定义数组长度

static unsigned char mem[4]; // 保存4个Leds的设置状态

static int major = S3C6410_LEDS_MAJOR;

static int minor = S3C6410_LEDS_MINOR;

static dev_t dev_number; //  设备号

static int leds_state = 1;

static char *params[] = {'string1', 'string2','string3'};

static int param_size = PARAM_SIZE;

 

static struct class *leds_class = NULL;

/*********5.控制LED**********/

// s3c6410_leds_ioctl函数用于接收向LED驱动传递的命令和参数,通过I/O命令控制LED

static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd,

        unsigned long arg)

{

  //命令只能是0或1

  switch (cmd)

  {

    unsigned tmp;

    case 0:

    case 1:

    if (arg > 4)

    {

      return -EINVAL;

    }

  //读取GPMDAT寄存器的当前值

  tmp = ioread32(S3C64XX_GPMDAT);

  if (cmd == 1)

  {

    tmp &= (~(1 << arg));

  }

  else

  {

    tmp |= (1 << arg);

  }

  //向GPMDAT寄存器写入数据

  iowrite32(tmp, S3C64XX_GPMDAT);

  return 0;

  default:

  return -EINVAL;

  }

}

//s3c6410_leds_write函数用于接收向/dev/s3c6410_leds设备文件写入的字符串

static ssize_t s3c6410_leds_write(struct file *file, const char __user *buf,

        size_t count, loff_t *ppos)

{

  unsigned tmp = count;

  unsigned long i = 0;

  memset(mem, 0, 4);//将mem数组所有元素的值都设为0

  //最多写入4个字符,多余的字符将忽略

  if (count > 4)

  {

    tmp = 4;

  }

  if (copy_from_user(mem, buf, tmp))

  {

    return -EFAULT;

  }

  else

  {

    for (i = 0; i < 4; i++)

    {

      tmp = ioread32(S3C64XX_GPMDAT);

      if (mem[i] == '1')

      {

        tmp &= (~(1 << i));

      }

      else

      {

        tmp |= (1 << i);

      }

      iowrite32(tmp, S3C64XX_GPMDAT);

    }

  return count;

  }

}

static struct file_operations dev_fops ={ .owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, .write =   s3c6410_leds_write };

static struct cdev leds_cdev;

/********2.创建设备文件(/dev/s3c6410_leds)********/

static int leds_create_device(void)

{

  int ret = 0;

  int err = 0;

  // 第1步: 初始化cdev的成员,并建立cdev和file_operations之间的连接

  cdev_init(&leds_cdev, &dev_fops);

  leds_cdev.owner = THIS_MODULE;

  //第2步:主设备号>0,通过指定设备号的方式注册字符设备区域

  if (major > 0)

  {

    //指定设备号的两种方式:直接在代码中指定(硬编码),动态分配

    //  获取设备号(主设备号和次设备号)

    dev_number = MKDEV(major, minor);

    err = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);

    if (err < 0)

    {

      printk(KERN_WARNING 'register_chrdev_region() failedn');

      return err;

    }

  }

  else

  {

    err = alloc_chrdev_region(&leds_cdev.dev, 10, DEVICE_COUNT,

         DEVICE_NAME);

    if (err < 0)//注册字符设备区域失败

    {

      printk(KERN_WARNING 'alloc_chrdev_region() failedn');

      return err;

    }

    //一般采用分别指定主设备号和次设备号的方式指定设备号。

    major = MAJOR(leds_cdev.dev);

    minor = MINOR(leds_cdev.dev);

    //dev_number = MKDEV(major, minor);

    dev_number = leds_cdev.dev; 

  }

  //第3步:将字符设备添加到内核中的字符设备数组中

  ret = cdev_add(&leds_cdev, dev_number, DEVICE_COUNT);

  //第4步:使用class_create宏创建struct class

  leds_class = class_create(THIS_MODULE, DEVICE_NAME);

  //第5步:创建设备文件

  device_create(leds_class, NULL, dev_number, NULL, DEVICE_NAME);

  return ret;

}

/********4.设置寄存器与初始化LED驱动*******/

static void leds_init_gpm(int leds_default)

{

  int tmp = 0;

  //  初始化端口配置寄存器

  tmp = ioread32(S3C64XX_GPMCON);

  tmp &= (~0xFFFF);

  tmp |= 0x1111; // 0001000100010001

  iowrite32(tmp, S3C64XX_GPMCON);

  //  初始化端口上拉电路寄存器

  tmp = ioread32(S3C64XX_GPMPUD);

  tmp &= (~0xFF);

  tmp |= 0xAA; // 01010101

  iowrite32(tmp, S3C64XX_GPMPUD);

   //  初始化端口数据寄存器

  tmp = ioread32(S3C64XX_GPMDAT);

  tmp &= (~0xF);

  tmp |= leds_default;

  iowrite32(tmp, S3C64XX_GPMDAT);

}

/********1. 初始化LED驱动*********/

static int leds_init(void)

{

  int ret;

  ret = leds_create_device();

  leds_init_gpm(~leds_state);

  printk(DEVICE_NAME'tinitializedn');

  //输出params数组中的值

  printk('param0t%sn', params[0]);

  printk('param1t%sn', params[1]);

  printk('param2t%sn', params[2]);

  return ret;

}

/*********3.卸载LED驱动的设备文件*********/

static void leds_destroy_device(void)

{  //移除通过device_create函数建立的字符设备

  device_destroy(leds_class, dev_number);

  if (leds_class)  //销毁struct class

    class_destroy(leds_class);

  //注销字符设备区域

  unregister_chrdev_region(dev_number, DEVICE_COUNT);

  return;

}

static void leds_exit(void)

{

  leds_destroy_device();//卸载LED驱动的设备文件

  printk(DEVICE_NAME'texit!n');

}

//LED驱动的模块参数

module_init(leds_init);

module_exit(leds_exit);

module_param(leds_state, int, S_IRUGO|S_IWUSR);

//下面一行是指定数组类型模块参数的相关信息

module_param_array(params, charp, ¶m_size, S_IRUGO|S_IWUSR);

MODULE_LICENSE('GPL');

MODULE_AUTHOR('Lining');


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 带有短路保护系统的5V直流稳压电源电路图

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章