Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2363407
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-03-24 17:04:29

18)改进led驱动和流星灯程序

 

 

注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方

1.本文所介绍的程序平台

开发板:arm9-mini2440

虚拟机为:Red Hat Enterprise Linux 5

开发板上系统内核版本:linux-2.6.32.2

 

2.程序清单

本次实验程序为网络代码,本人作了改动和较为详细的注释,如有错误请指出。

 

官方手册上写,mini2440的四个LED与CPU的GPIO相连,LED1, LED2, LED3, LED4分别对应的

是GPB5, GPB6, GPB7, GPB8。那什么是GPIO呢?

 

GPIO是通用输入输出口的简称,只需要设置相应的CPU寄存器,就可以改变引脚的用途。

控制硬件,其实就是控制对应的寄存器。

 

四个LED的采用GPBCON寄存器上的4组2bit位来配置对应引脚的状态。4组2bit位的功能都

一样:00表示输入,01表示输出,10为特殊功能,11是保留的。

LED1对应的是GPB5, GPB5使用[11:10]位

LED2对应的是GPB6, GPB6使用[12:13]位

LED3对应的是GPB7, GPB7使用[14:15]位

LED4对应的是GPB8, GPB8使用[16:17]位

驱动需要先设置LED为输出状态,也就是要把对应的GPBX设置为01。

 

四个LED采用CPBDAT寄存器来对应4个LED的数值状态,GPBDAT5就对应GPB5,GPBDAT6就对

应GPB6,以此类推。手册上写低电平有效,就是说当GPBDAT寄存器位置为0时,LED就发光。

 

在三星官方的手册S3C2440.pdf中有寄存器状态描述

 

mini2440_leds.h

 

#ifndef _LEDDEV_H_

#define _LEDDEV_H_

 

#include

 

/* 定义幻数 */

#define LEDDEV_IOC_MAGIC  'k'

 

/* 定义命令 */

#define LEDDEV_IOGET  _IOWR(LEDDEV_IOC_MAGIC, 1, int)/*从驱动中读写数据*/

#define LEDDEV_IOSET _IOW(LEDDEV_IOC_MAGIC, 2, int)/*写数据到驱动中*/

 

#define LEDDEV_IOC_MAXNR 2

 

#endif /* _LEDDEV_H_ */

mini2440_leds.c

 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#include "mini2440_leds.h"

 

#define DEVICE_NAME "my_leds"

 

/* GPBX */

 

static unsigned long led_table [] = {

    S3C2410_GPB(5),

    S3C2410_GPB(6),

    S3C2410_GPB(7),

    S3C2410_GPB(8),

};

 

/* GPBX的输出状态 */

static unsigned int led_cfg_table [] = {

    S3C2410_GPIO_OUTPUT,

    S3C2410_GPIO_OUTPUT,

    S3C2410_GPIO_OUTPUT,

    S3C2410_GPIO_OUTPUT,

};

 

 

/* 驱动接口函数

* ioctl的内核空间版本和用户控件的版本不同

* 内核版为:

* int (*ioctl)( struct inode *inode, struct file *file, unsigned int

* cmd, unsigned long arg);

* */

 

static int sbc2440_leds_ioctl(

    struct inode *inode,

    struct file *file,

    unsigned int cmd,

    unsigned long arg)

{

    int err =0;

    int ret = 0;

    int ioarg = 0;

 

       /* 检测命令的有效性 */

      if (_IOC_TYPE(cmd) != LEDDEV_IOC_MAGIC)

          return -EINVAL;

      if (_IOC_NR(cmd) > LEDDEV_IOC_MAXNR)

          return -EINVAL;

     /* 根据命令类型,检测参数空间是否可以访问 */

    if (_IOC_DIR(cmd) & _IOC_READ)  

        err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));

    else if (_IOC_DIR(cmd) & _IOC_WRITE)

        err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));

    if (err)

        return -EFAULT;

    /*

    switch(cmd) {

    case 0:

    case 1:

        if (arg > 4) {

            return -EINVAL;

        }

       

          // 设置数据寄存器GPBDAT

          //低电平有效,用户程序传来的cmd取反

          //

        s3c2410_gpio_setpin(led_table[arg], !cmd);

 

         

        return 0;

    default:

        return -EINVAL;

    }*/

     /* 根据命令,执行相应的操作 */

     switch(cmd) {

        //获取第ioarg灯的状态

     case LEDDEV_IOGET :

        ret = __get_user(ioarg, (int *)arg);       

        printk("<5> ioarg : %d , ret : %d \n", ioarg, ret);

        if(ioarg >= 4)

            return -EINVAL;

        ret = s3c2410_gpio_getpin(led_table[ioarg]);

        printk("<5>  ret : %d \n", ret);

        ret = __put_user(ret, (int *)arg);

      return 0;

      //设置第ioarg灯的状态

     case LEDDEV_IOSET:

       ret = __get_user(ioarg, (int *)arg);

       printk("<5> ioarg : %d , ret : %d \n", ioarg, ret);

       if(ioarg >= 4)

            return -EINVAL;

       ret = s3c2410_gpio_getpin(led_table[ioarg]);

       printk("<5> led %d is %d \n",ioarg, ret);

       s3c2410_gpio_setpin(led_table[ioarg], !ret);

      return 0;

     default:

      return -EINVAL;

     }

}

 

/* 接口对象 */

static struct file_operations dev_fops = {

    .owner  =   THIS_MODULE,

    .ioctl  =   sbc2440_leds_ioctl,

};

 

 

/* 设备对象 */

static struct miscdevice misc = {

    .minor = MISC_DYNAMIC_MINOR,/* 动态设备号 */

    .name = DEVICE_NAME,/* 将在/dev目录生成led设备 */

    .fops = &dev_fops,/* 驱动接口 */

};

 

static int __init dev_init(void)

{

    int ret;

    int i;

   

   

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

        /*设置GPIO对应的配置寄存器GPIOCON为输出状态*/

        s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

 

        /*设置GPIO对应的数据寄存器GPIODAT为低电平

       *在模块加载结束后,四个LED应该是全部都是熄灭状态*/

        s3c2410_gpio_setpin(led_table[i], 1);

    }

 

    /* 注册设备 */

    ret = misc_register(&misc);

 

    printk (DEVICE_NAME"\tinitialized\n");

 

    return ret;

}

 

static void __exit dev_exit(void)

{

    /* 注销设备 */

    misc_deregister(&misc);

}

 

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("FriendlyARM Inc.");

 

flyleds.c

 

#include

#include

#include

#include       // open() close()

#include      // read() write()

#include "mini2440_leds.h"

 

int main(int argc, char **argv)

{

       int fd;

       int ret;

       int i;

                if(argc != 2)

                {

                    printf("usage: name msecond \n");

                    return -1;

                   

                    }

       fd = open("/dev/my_leds", 0);

           

       if (fd < 0)

        {

                printf("open device %s error\n", "my_leds");

        }

        else

        {

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

        {

             ioctl(fd,LEDDEV_IOSET,&i);

             printf("i : %d  %d\n",i, ret);

            

        }

        sleep(1);//等待1秒再做下一步操作

        while(1)

        {

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

        {

             ioctl(fd,LEDDEV_IOSET,&i);

             printf("i is %d \n", i);

             usleep(atoi(argv[1])*1000);//等待           

        }

         

       }

           close(fd);

      }

           return 0;

}

 

阅读(2851) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~