imx6ull Linux C应用编程学习(1.2) LED点灯(代码理解)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define  LED_TRIGGER    "/sys/class/leds/sys-led/trigger"       // 定义LED触发模式文件路径
#define  LED_BRIGHTNESS "/sys/class/leds/sys-led/brightness"    // 定义LED亮度文件路径
#define  USAGE()    fprintf(stderr, "usage:\n"  \                // 定义USAGE宏,用于打印程序使用方法
                "    %s <on|off>\n"   \
                "    %s <trigger> <type>\n", argv[0], argv[0])

int main(int argc, char *argv[])
{
    int fd1, fd2;

    /* 校验传参 */
    if (2 > argc) {                      // 如果传入参数少于2个,打印使用方法并退出
        USAGE();
        exit(-1);
    }

    /* 打开文件 */
    fd1 = open(LED_TRIGGER, O_RDWR);     // 以读写方式打开LED触发模式文件
    if (0 > fd1) {                       // 打开文件失败,打印错误信息并退出
        perror("open error");
        exit(-1);
    }

    fd2 = open(LED_BRIGHTNESS, O_RDWR);  // 以读写方式打开LED亮度文件
    if (0 > fd2) {                       // 打开文件失败,打印错误信息并退出
        perror("open error");
        exit(-1);
    }

    /* 根据传参控制LED */
    if (!strcmp(argv[1], "on")) {        // 如果第一个参数是"on"
        write(fd1, "none", 4); 	        // 先将触发模式设置为none
        write(fd2, "1", 1); 		    // 点亮LED
    }
    else if (!strcmp(argv[1], "off")) {  // 如果第一个参数是"off"
        write(fd1, "none", 4); 	        // 先将触发模式设置为none
        write(fd2, "0", 1); 		    // 关闭LED
    }
    else if (!strcmp(argv[1], "trigger")) {  // 如果第一个参数是"trigger"
        if (3 != argc) {                 // 如果传入参数不是3个,打印使用方法并退出
            USAGE();
            exit(-1);
        }

        if (0 > write(fd1, argv[2], strlen(argv[2])))  // 将第三个参数写入触发模式文件,如果写入失败,打印错误信息
            perror("write error");
    }
    else                                 // 如果第一个参数不是"on", "off"或"trigger",打印使用方法
        USAGE();

    exit(0);                             // 退出程序
}

上面这是led.c源代码的基础上加入了一些自己理解的注释。


#define  USAGE()    fprintf(stderr, "usage:\n"  \                // 定义USAGE宏,用于打印程序使用方法
                "    %s <on|off>\n"   \
                "    %s <trigger> <type>\n", argv[0], argv[0])

关于这段,定义了一个名为 USAGE 的宏,用于打印程序的使用方法。当用户输入的参数不正确时,会调用这个宏来向标准错误输出 (stderr) 打印出正确的使用方法提示信息。所以其主要是判断输入是否正确。

/* 打开文件 */
    fd1 = open(LED_TRIGGER, O_RDWR);     // 以读写方式打开LED触发模式文件
    if (0 > fd1) {                       // 打开文件失败,打印错误信息并退出
        perror("open error");
        exit(-1);
    }

    关于上面这段,其中fd1是open文件LED_TRIGGER的文件描述符,O_RDWR表示文件是读写模式,如果打开错误,其会传回负数。

int main(int argc, char *argv[])
{
    // ... 代码
}

   int main(int argc, char *argv[]) 是程序的入口点。它是程序执行的起始位置。argc:参数个数,argv:参数值的数组。argv 包含两个字符串:argv[0] 是程序名称 "./led"argv[1] 是用户输入的第一个参数 ,比如"on"

/* 根据传参控制LED */
    if (!strcmp(argv[1], "on")) {        // 如果第一个参数是"on"
        write(fd1, "none", 4); 	        // 先将触发模式设置为none
        write(fd2, "1", 1); 		    // 点亮LED

      关于这段代码,则是根据传参控制led,strcmp 用于比较两个字符串。argv[1] 是命令行传递给程序的第一个参数(即用户输入的第一个参数)。strcmp 返回0表示两个字符串相等。用 !strcmp 表示如果 argv[1] 等于 "on",条件为真。所以证明我们输入的是正确的。如果输入正确则开始执行write语句,write 是一个系统调用,用于向文件描述符 fd1 写入数据。

    而fd1 是先前用 open 打开的文件描述符,指向控制LED触发模式的文件 /sys/class/leds/sys-led/trigger。其中

  • "none" 是要写入的数据,表示将LED的触发模式设置为"none"(即手动控制模式)。
  • 4 是写入的数据的长度(包括字符串终止符 '\0')。

由之前可知,fd1文件代表的是触发模式,fd2代表的是亮度,不过开发板led是gpio控制,所以只有1和0亮灭两种形式。

else if (!strcmp(argv[1], "trigger")) {  // 如果第一个参数是"trigger"
        if (3 != argc) {                 // 如果传入参数不是3个,打印使用方法并退出
            USAGE();
            exit(-1);
        }

        if (0 > write(fd1, argv[2], strlen(argv[2])))  // 将第三个参数写入触发模式文件,如果写入失败,打印错误信息
            perror("write error");
    }

而这段代码,如果监测到第一个参数为trigger,则输出标准如上。其中if (0 > write(fd1, argv[2], strlen(argv[2]))) ,将第三个参数写入fd1,如果小于0,则代表写入失败。主要是设置心跳模式。

根据手册,也可以输入./led trigger timer进入定时器控制模式

我根据定义,简单修改了下,加入一个law模式,下面是修改后加入law模式的led.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define  LED_TRIGGER    "/sys/class/leds/sys-led/trigger"       // 定义LED触发模式文件路径
#define  LED_BRIGHTNESS "/sys/class/leds/sys-led/brightness"    // 定义LED亮度文件路径

// 定义USAGE宏,用于打印程序使用方法
#define  USAGE()    fprintf(stderr, "usage:\n"  \
                "    %s <on|off>\n"   \
                "    %s <trigger> <type>\n"   \
                "    %s <law>\n"   \
                "    %s <timer> <type>\n", argv[0], argv[0], argv[0], argv[0])

int main(int argc, char *argv[])
{
    int fd1, fd2;

    /* 校验传参 */
    if (2 > argc) {                      // 如果传入参数少于2个,打印使用方法并退出
        USAGE();
        exit(-1);
    }

    /* 打开文件 */
    fd1 = open(LED_TRIGGER, O_RDWR);     // 以读写方式打开LED触发模式文件
    if (0 > fd1) {                       // 打开文件失败,打印错误信息并退出
        perror("open error");
        exit(-1);
    }

    fd2 = open(LED_BRIGHTNESS, O_RDWR);  // 以读写方式打开LED亮度文件
    if (0 > fd2) {                       // 打开文件失败,打印错误信息并退出
        perror("open error");
        exit(-1);
    }

    /* law模式 */
    if (!strcmp(argv[1], "law")) { 
        int time = 0;
        write(fd1, "none", 4); 	        // 先将触发模式设置为none
        while (time < 3) {
            write(fd2, "1", 1); 		    // 点亮LED
            sleep(1);
            write(fd2, "0", 1); 		    // 关闭LED
            sleep(1);
            time++;
        }
        while (time >= 3) {
            write(fd2, "1", 1); 		    // 点亮LED
            usleep(500000);                // 500毫秒
            write(fd2, "0", 1); 		    // 关闭LED
            usleep(500000);                // 500毫秒
            
            time+=1;
            if (time >= 10) {
                exit(0); 
            }
        }
    }

    /* timer模式 */
    else if (!strcmp(argv[1], "trigger")) {
        if (3 != argc) {                 // 如果传入参数不是3个,打印使用方法并退出
            USAGE();
            exit(-1);
        }
        if (0 > write(fd1, argv[2], strlen(argv[2]))) {  // 将第三个参数写入触发模式文件,如果写入失败,打印错误信息
            perror("write error");
        }
    }

    /* 根据传参控制LED */
    else if (!strcmp(argv[1], "on")) {        // 如果第一个参数是"on"
        write(fd1, "none", 4); 	        // 先将触发模式设置为none
        write(fd2, "1", 1); 		    // 点亮LED
    }
    else if (!strcmp(argv[1], "off")) {  // 如果第一个参数是"off"
        write(fd1, "none", 4); 	        // 先将触发模式设置为none
        write(fd2, "0", 1); 		    // 关闭LED
    }
    else if (!strcmp(argv[1], "trigger")) {  // 如果第一个参数是"trigger"
        if (3 != argc) {                 // 如果传入参数不是3个,打印使用方法并退出
            USAGE();
            exit(-1);
        }
        if (0 > write(fd1, argv[2], strlen(argv[2]))) {  // 将第三个参数写入触发模式文件,如果写入失败,打印错误信息
            perror("write error");
        }
    }
    else {                              // 如果第一个参数不是"on", "off"或"trigger",打印使用方法
        USAGE();
    }

    exit(0);                             // 退出程序
}

law模式实现前6秒每隔一秒灭一次,后7秒,以500ms频率闪烁,等时间到10s后退出程序。在开发板输入

./led law

发现工作正常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值