您的位置:首页 > 运维架构 > Linux

我的嵌入式学习之路(一) linux 跑的第一个程序 LED灯

2008-08-27 21:33 369 查看
[/b]我的嵌入式学习之路(一)[/b][/b]

linux 跑的第一个程序 LED灯

学习嵌入式系统,可能第一个要做的事情就是点亮LED灯,就像写程序的Hello
World一样,虽然是非常简单的一个问题,可是让我鼓捣了两三天,才把等灯点亮。所以写下来,能给初学者一些借鉴的地方。

我的开发板用的是S3C2440,基本上所有的2410/2440开发板都一样的,大部分都是抄的三星公司那个开发板,好了废话不说了,看程序。

led驱动代码如下:

/****************************************Copyright(c)********************************************

** 南京汉德森科技股份有限公司

** 显示研发部

**

** wangdongxu@handson.cc

** http://www.handson.cc
**

**--------------文件信息--------------------------------------------------------------------------------

**文 件
名: LED驱动

**创 建
人: 王东旭

**最后修改日期: 2008年8月27日21:10:50

**描 述: 2440的LED驱动程序,这是我能正确运行的第一个嵌入式程序

** 原作者是《嵌入式Linux应用开发完全手册》的作者韦东山先生

** 我只是在上面又修改了一些内容。

**--------------历史版本信息----------------------------------------------------------------------------

** 创建人: 王东旭

** 版 本: v1.0

** 日 期: 2008年8月27日21:11:37

** 描 述: 原始版本

**

**------------------------------------------------------------------------------------------------------

** 修改人:

** 版 本:

** 日 期:

** 描 述:

**

**--------------当前版本修订------------------------------------------------------------------------------

** 修改人:

** 日 期:

** 描 述:

**

**------------------------------------------------------------------------------------------------------

********************************************************************************************************/

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <asm/irq.h>

#include <asm/arch/regs-gpio.h>

#include <asm/hardware.h>

#define DEVICE_NAME "leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */

#define LED_MAJOR 231
/* 主设备号 */

/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */

#define IOCTL_LED_ON 0

#define IOCTL_LED_OFF 1

/* 用来指定LED所用的GPIO引脚 */

static unsigned long led_table [] = {

/*
★★★★这里一定要注意,你用的是那个管脚,我就因为弄错了,一个上午就没有了。

下面这些定义可以在内核根目录
/include/asm/arch/regs-gpio.h中找到

*/

S3C2410_GPF4,

S3C2410_GPF5,

S3C2410_GPF6,

S3C2410_GPF7,

};

/* 用来指定GPIO引脚的功能:输出 */

static unsigned int led_cfg_table [] = {

S3C2410_GPF4_OUTP,

S3C2410_GPF5_OUTP,

S3C2410_GPF6_OUTP,

S3C2410_GPF7_OUTP,

};

/* 应用程序对设备文件/dev/leds执行open(...)时,

* 就会调用s3c24xx_leds_open函数

*/

static int s3c24xx_leds_open(struct inode *inode, struct file
*file)

{

int i;

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

// 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能

/*

★★★★s3c2410_gpio_cfgpin()、s3c2410_gpio_setpin可以在

内核根目录 /include/asm/arch/hardware.h中找到

*/

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

}

return 0;

}

/* 应用程序对设备文件/dev/leds执行ioclt(...)时,

* 就会调用s3c24xx_leds_ioctl函数

*/

static int s3c24xx_leds_ioctl(

struct inode *inode,

struct file *file,

unsigned int cmd,

unsigned long arg)

{

if (arg > 4) {

return -EINVAL;

}

switch(cmd) {

case IOCTL_LED_ON:

// 设置指定引脚的输出电平为0

s3c2410_gpio_setpin(led_table[arg],
0);

return 0;

case IOCTL_LED_OFF:

// 设置指定引脚的输出电平为1

s3c2410_gpio_setpin(led_table[arg],
1);

return 0;

default:

return -EINVAL;

}

}

/* 这个结构是字符设备驱动程序的核心

* 当应用程序操作设备文件时所调用的open、read、write等函数,

* 最终会调用这个结构中指定的对应函数

*/

static struct file_operations s3c24xx_leds_fops = {

.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

.open = s3c24xx_leds_open,

.ioctl = s3c24xx_leds_ioctl,

};

/*

* 执行“insmod s3c24xx_leds.ko”命令时就会调用这个函数

*/

static int __init s3c24xx_leds_init(void)

{

int ret;

/* 注册字符设备驱动程序

* 参数为主设备号、设备名字、file_operations结构;

* 这样,主设备号就和具体的file_operations结构联系起来了,

* 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数

* LED_MAJOR可以设为0,表示由内核自动分配主设备号

*/

ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);

if (ret < 0) {

printk(DEVICE_NAME " can't register major number/n");

return ret;

}

printk(DEVICE_NAME " initialized/n");

return 0;

}

/*

* 执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数

*/

static void __exit s3c24xx_leds_exit(void)

{

/* 卸载驱动程序 */

unregister_chrdev(LED_MAJOR, DEVICE_NAME);

}

/* 这两行指定驱动程序的初始化函数和卸载函数 */

module_init(s3c24xx_leds_init);

module_exit(s3c24xx_leds_exit);

/* 描述驱动程序的一些信息,不是必须的 */

MODULE_AUTHOR("http://www.100ask.net"); // 驱动程序的原作者

MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver"); // 一些描述信息

MODULE_LICENSE("GPL"); // 遵循的协议

驱动写好以后,文件名为s3c24xx_leds.c把这个文件放到 /drivers/char子目录下,修改这个目录的Makefile,其实只需要增加一行,obj
+= s3c24xx_leds.o,然后,退回到这个内核的根目录下(比如内核源码文件夹叫linux-2.6,在tmp目录下,则你的内核根目录就是/tmp/linux-2.6,以下内核根目录,我简称为根目录),执行make modules,执行完你可以在/drivers/char目录下找到s3c24xx_leds.ko这个文件,把这个文件发送到开发板上去,可以在串口运行r z命令,接收文件,把文件拷贝到开发板上的/lib/module目录下,然后在开发板执行insmod s3c24xx_leds.ko,这个时候如果出现leds
initialized,说明加载成功 ,然后,建立设备文件,在开发板上执行mknod /dev/leds c
231 0,

好了我们开始写测试程序了,这个是在PC上写的,代码如下:

#include
<stdio.h>

#include
<stdlib.h>

#include
<unistd.h>

#include
<sys/ioctl.h>

#define
IOCTL_LED_ON 0

#define
IOCTL_LED_OFF 1

void usage(char
*exename)

{

printf("Usage:/n");

printf(" %s <led_no> <on/off>/n",
exename);

printf(" led_no = 1, 2, 3 or 4/n");

}

int main(int argc,
char **argv)

{

unsigned int led_no;

int fd = -1;

if (argc != 3)

goto err;

fd = open("/dev/leds", 0); // 打开设备

if (fd < 0) {

printf("Can't open
/dev/leds/n");

return -1;

}

led_no = strtoul(argv[1], 0, 0) - 1; // 操作哪个LED?

if (led_no > 3)

goto err;

if (!strcmp(argv[2], "on")) {

ioctl(fd, IOCTL_LED_ON, led_no); // 点亮它

} else if (!strcmp(argv[2],
"off")) {

ioctl(fd, IOCTL_LED_OFF, led_no);
// 熄灭它

} else {

goto err;

}

close(fd);

return 0;

err:

if (fd > 0)

close(fd);

usage(argv[0]);

return -1;

}

保存文件名为led_test.c ,保存到任意一个单独的文件夹下,比如/tmp/led目录,然后写makefile,如下

CROSS=arm-linux-

all: led_test

led_test:
led_test.c

$(CROSS)gcc -o $@ led_test.c -static

clean:

@rm -rf led_test *.o

保存名Makefile ,保存到/tmp/led,然后在这个目录下执行make命令。会生成一个led_test文件,同样传输到开发板上,保存在开发板的/usr/bin目录下

这个时候在超级终端中输入 led_test 1 on 这个时候led应该会亮的,输入led_test 1 off 这个时候会灭的。
如果你在使用 led_test这条命令的时候,出现了这样的错误:Permission denied,这是权限问题,用 chmod 777 led_test 就可以解决了。

实验到此结束。希望能给你们帮助。

我的邮箱 wangdongxu@handson.cc
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: