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

2019-07-13 01:47发布

                    我的嵌入式学习之路(一) linux 跑的第一个程序 LED   学习嵌入式系统,可能第一个要做的事情就是点亮LED灯,就像写程序的Hello World一样,虽然是非常简单的一个问题,可是让我鼓捣了两三天,才把等灯点亮。所以写下来,能给初学者一些借鉴的地方。 我的开发板用的是S3C2440,基本上所有的2410/2440开发板都一样的,大部分都是抄的三星公司那个开发板,好了废话不说了,看程序。 led驱动代码如下:   /****************************************Copyright(c)******************************************** **                               南京汉德森科技股份有限公司 **                                     显示研发部 **                                         **                                                            wangdongxu@handson.cc **                                 http://www.handson.cc ** **--------------文件信息-------------------------------------------------------------------------------- **      : LED驱动 **      : 王东旭 **最后修改日期: 200882721:10:50 **        : 2440LED驱动程序,这是我能正确运行的第一个嵌入式程序 **              原作者是《嵌入式Linux应用开发完全手册》的作者韦东山先生 **                         我只是在上面又修改了一些内容。 **--------------历史版本信息---------------------------------------------------------------------------- ** 创建人: 王东旭 **   : v1.0 ** 日 期: 200882721:11:37 ** 描 述: 原始版本 ** **------------------------------------------------------------------------------------------------------ ** 修改人: **   : ** 日 期: ** 描 述: ** **--------------当前版本修订------------------------------------------------------------------------------ ** 修改人: ** 日 期: ** 描 述: ** **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/   #include #include #include #include #include #include #include #include   #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;     } }   /* 这个结构是字符设备驱动程序的核心  * 当应用程序操作设备文件时所调用的openreadwrite等函数,  * 最终会调用这个结构中指定的对应函数  */ 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 #include #include #include   #define IOCTL_LED_ON    0 #define IOCTL_LED_OFF   1   void usage(char *exename) {     printf("Usage:/n");     printf("    %s /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