Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14860
  • 博文数量: 4
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-10 08:38
文章分类
文章存档

2014年(4)

我的朋友
最近访客

分类: LINUX

2014-05-26 21:20:09

原文地址:数码管程序分析 作者:竹韵清风尚

 数码管.rar  

#include
#include
#include
#include
    
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
    
// SERIAL_LED DEVICE MAJOR
#define SERIAL_LED_MAJOR    105    //定义主设备号;
#define OURS_SERIAL_LED_DEBUG    // 
    
#define VERSION         "PXA270RP-V1.00-090224"    //定义程序版本号;
     struct serial_led_dev    //定义设备结构体;
{
     struct cdev cdev;    //设备结构体成员;
    unsigned char value;
 };
 struct serial_led_dev *serial_led_devp;    //定义设备结构体变量;
 static int serial_led_major = SERIAL_LED_MAJOR;
   void showversion(void) 
{
     printk("*********************************************\n");    //打印版本信息;
    printk("\t %s \t\n", VERSION);
     printk("*********************************************\n\n");
  }  void write_bit(int data)    //此函数用于产生时钟信号,使得74HC164能够实现一位串行输入数据到8位并行输出数据的转换;
{
      GPCR2 |= (0x1 << 27);    /* //将GPIO91的引脚清0当时钟信号从低电平到高电平的时候将输出一个数据到输出端Q0;
当时钟第二次由低电平变为高电平的时候将输出第二个数据到Q0而将第一个数据转移到Q1端口依次类推每一个时钟周期中都有一个串行
数据输出到Q0而其他的数据则不断往高位移动直到所有数据传输结束,如果不再有时钟周期输入,则将这些数据暂存在输出端。*/
     if ((data & 0x80) == 0x80)    //比较data最高位的值;已实现对下一个输出位写0或1;
    {
         GPSR2 |= (0x1 << 26);    //若读取的二进制为最高位为1则设置GPIO90的引脚置1; 例如第一次输出到Q0的将是1
    }
     
    else
          {
         GPCR2 |= (0x1 << 26);    //  否则设置GPIO90的引脚置0;例如第一次输出到Q0的将是0, 通过控制74HC164输出端引脚的高低电位来控制数码管的数字
        }
      GPSR2 |= (0x1 << 27);    //CLOCK   //将GPIO91的引脚置1; 
 }

   void write_byte(int data) 
{
     int i;
     for (i = 0; i < 8; i )    /*用一个循环实现对输出端口写数据公共八位,第一次写最高位,第二次写次高位,
依次往后写,写的data是write中调用的应用程序buf 中的数据;*/
    {
         write_bit(data << i);    //将data左移i为作为参数传入write_bit中;
    }
 }

  
// ------------------- READ ------------------------
    ssize_t SERIAL_LED_read(struct file *file, char *buf, size_t count,
                loff_t * f_ops) 
{
     
#ifdef OURS_SERIAL_LED_DEBUG
        printk("SERIAL_LED_read [ --kernel--]\n");    //设备驱动的读函数,打印相关信息;
#endif                /*   */
     return count;        //返回count个字节;
}

 
// ------------------- WRITE -----------------------
    ssize_t SERIAL_LED_write(struct file * file, const char *buf,
                 size_t count, loff_t * f_ops) 
{
     
#ifdef OURS_SERIAL_LED_DEBUG
        printk("SERIAL_LED_write [ --kernel--]\n");    //驱动函数的写函数,打印相关信息;
#endif                /*   */
    write_byte(*buf);    //调用函数 write_byte实现对data的处理;
    return count;
 }

 
// ------------------- IOCTL -----------------------
    ssize_t SERIAL_LED_ioctl(struct inode * inode, struct file * file,
                 unsigned int cmd, unsigned long data) 
{
     
//struct serial_led_dev *dev=file->private_data;             //驱动程序的设备控制函数;
        
#ifdef OURS_SERIAL_LED_DEBUG
        printk("SERIAL_LED_ioctl [ --kernel--]\n");    // 打印相关信息;
#endif                /*   */
      return 0;
 }

 
// ------------------- OPEN ------------------------
    ssize_t SERIAL_LED_open(struct inode * inode, struct file * file) 
{
     
#ifdef OURS_SERIAL_LED_DEBUG
        printk("SERIAL_LED_open [ --kernel--]\n");    //驱动程序的打开函数;
#endif                /*   */
      return 0;
 }

 
// ------------------- RELEASE/CLOSE ---------------
    ssize_t SERIAL_LED_release(struct inode * inode, struct file * file) 
{
     
#ifdef OURS_SERIAL_LED_DEBUG
        printk("SERIAL_LED_release [ --kernel--]\n");    //驱动程序的释放函数;
#endif                /*   */
      return 0;
 }

 
// -------------------------------------------------
struct file_operations serial_led_fops = {    // file_operations用来存储驱动内核模块提供的对 设备进行各种操作的函数的指针。
      .open = SERIAL_LED_open,    //系统调用函数和驱动函数的对应关系;
     .read = SERIAL_LED_read,   .write = SERIAL_LED_write,   .ioctl =
        SERIAL_LED_ioctl,   .release = SERIAL_LED_release,  
};

  void gpio_init(void)        //数码管设备初始化函数;
{
     
        // init GPIO
        GAFR2_U &= 0xff0fffff;    //SET GPIO91,90 I/O MODE 
     GPDR2 |= (1 << 26);    // SET GPIO90 OUTPUT MODE
    GPCR2 |= (1 << 26);    // SET LOW LEVEL
    GPDR2 |= (1 << 27);    // SET GPIO91 OUTPUT MODE
    GPCR2 |= (1 << 27);    // SET LOW LEVEL 
}  static void serial_led_setup_cdev(struct serial_led_dev *dev, int index)    //初始化并添加cdev结构体的函数;
{
     int err, devno = MKDEV(serial_led_major, index);    //获得设备号;
    cdev_init(&dev->cdev, &serial_led_fops);    //初始化cdev
    dev->cdev.owner = THIS_MODULE;    //使驱动程序属于该模块;
    dev->cdev.ops = &serial_led_fops;    //cdev连接file_operations指针;
    err = cdev_add(&dev->cdev, devno, 1);    //设备号加入到内核中;
    if (err)
         printk(KERN_NOTICE "Error %d adding serial_led%d", err, index);    //如果注册字符设备失败,则打印出错信息;
}

  int serial_led_init(void) 
{
     int result;        //定义一个局部变量用来作为alloc_chrdev_region的返回值;
     dev_t dev = MKDEV(serial_led_major, 0);    //获得主设备号为0的设备号通过宏MKDEV获得32位的设备驱动号;
     if (serial_led_major)    //判断是否事先分配了主设备号;
        result = register_chrdev_region(dev, 1, "serial_led");    //申请设备号(给定主设备号)应该链接到这个编号的设备名字 成功返回0;
    else
          {
         result = alloc_chrdev_region(&dev, 0, 1, "serial_led");    //若没有给定主设备号则用动态分配;
        serial_led_major = MAJOR(dev);    //提取主设备号;
        }
     if (result < 0)    //若返回值为负数说明申请设备号失败;
        return result;
       serial_led_devp = kmalloc(sizeof(struct serial_led_dev), GFP_KERNEL);    //为serial_led_dev动态分配内存空间;
    if (!serial_led_devp)    //若分配空间失败则跳到fail_malloc处;
    {
        result = -ENOMEM;
         goto fail_malloc;
     }
     memset(serial_led_devp, 0, sizeof(struct serial_led_dev));    //用memset对动态分配的内存进行初始化;
     serial_led_setup_cdev(serial_led_devp, 0);    //cdev的注册;serial_led_setup_cdev函数对cdev初始化并将此设备注册到内核
    printk("serial_led_init\n");    //打印设备初始化信息;
    //init SERIAL_LED
    gpio_init();        //调用gpio_init函数实现对数码管设备的初始化;
    showversion();        //调用此函数打印版本信息;
     return 0;
        fail_malloc:unregister_chrdev_region(dev, 1);
     return result;
 }

 void serial_led_cleanup(void) 
{
     cdev_del(&serial_led_devp->cdev);    //释放serial_led_dev;
    kfree(serial_led_devp);    //释放分配为给 serial_led_dev的内存
    unregister_chrdev_region(MKDEV(serial_led_major, 0), 1);    //注销设备号;
    printk("serial_led_cleanup\n");    //打印清除设备的信息;
}   MODULE_DESCRIPTION("simple serial_led driver module");    //模块功能描述;

MODULE_AUTHOR("guliangzeng");    //模块所有者;
MODULE_LICENSE("Dual BSD/GPL");    //
MODULE_ALIAS("serial_led module");
  module_init(serial_led_init);    //加载模块内核模块的入口函数是也就是告诉内核“从这个函数入口;
module_exit(serial_led_cleanup);    //卸载模块;
阅读(1164) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~