基于Linux C应用的0.96寸OLED硬件监测器页面

发布于:2025-03-01 ⋅ 阅读:(100) ⋅ 点赞:(0)

一、前言

        开发板:香橙派 5Plus。

        librknnrt.so 版本:2.3.0。

        rknn driver:0.9.8。

        本次的页面设计基于之前写的手写FrameBuffer驱动:

Linux手写FrameBuffer任意引脚驱动spi屏幕_rk3588 framebuffer-CSDN博客https://blog.csdn.net/plmm__/article/details/145193029?spm=1001.2014.3001.5501之前只写好了应用层的框架,具体的页面内容只有时间。本次基于之前的驱动接口和应用框架,使用sysfs接口查询常用的硬件信息,解析字符串后显示到oled。

二、硬件信息查询

        由于本人的需求是快速查看CPU和NPU的占用率,便于实时调整软件资源,所以显示的信息共四条:CPU占用率、GPU占用率、NPU占用率、芯片温度。

1、CPU占用率        

CPU占用率使用 mpstat 软件查看,C程序内的函数为:

/**
 * @Description: 获取 CPU 占用率
 * @return {*}
 */
int get_cpu_usage(char *cpu_usage, size_t size) {
    // 使用mpstat命令获取CPU占用率,popen 打开的文件会将命令的输出保留在一个缓冲区中
    // mpstat 1 1 表示每秒采样一次,共采样一次
    // /all/:匹配包含 all 的行,$NF 表示最后一列(即 %idle,CPU 空闲率),head -n 1 限制只输出第一行
    FILE *fp = popen("mpstat 1 1 | awk '/all/ {print 100 - $NF}' | head -n 1", "r");
    if (fp == NULL) {
        perror("Failed to run mpstat command");
        return -1;
    }
    // 读取命令输出
    char temp[size];
    if (fgets(temp, size, fp) == NULL) {
        perror("Failed to read CPU usage");
        pclose(fp);
        return -1;
    }
    pclose(fp);
    // 添加前缀
    snprintf(cpu_usage, size, "CPU: %.2f%%", atof(temp));
    // 查找字符串中的换行符并将其替换为终止符 \0,确保字符串没有多余的换行符
    cpu_usage[strcspn(cpu_usage, "\n")] = '\0';
    return 0;
}

       mpstat 1 1是查看CPU使用相对简单的指令,便于快速截取需要的信息,两个1分别代表间隔1秒和查询1次,它的输出为:

输出没有占用率的总和,用100减去最后的空闲即可,其余细节代码中都有详细说明。

2、GPU占用率

        sysfs接口以开发板实际为准,我这里为:

/sys/class/devfreq/fb000000.gpu/load

C函数:

/**
 * @Description: 获取 GPU 占用率
 * @return {*}
 */
int get_gpu_usage(char *gpu_usage, size_t size) {
    FILE *file = fopen("/sys/class/devfreq/fb000000.gpu/load", "r");
    if (file == NULL) {
        perror("Failed to open GPU load file");
        return -1;
    }

    char line[size];
    if (fgets(line, size, file) == NULL) {
        perror("Failed to read GPU load");
        fclose(file);
        return -1;
    }
    fclose(file);
    // 提取@前的数字
    char *at_pos = strchr(line, '@');
    if (at_pos == NULL) {
        fprintf(stderr, "Invalid GPU load format\n");
        return -1;
    }
    *at_pos = '\0'; // 截断字符串,保留@前的部分
    // 添加前缀
    snprintf(gpu_usage, size, "GPU: %d%%", atoi(line));
    return 0;
}

3、NPU占用率

        瑞芯微的接口应该都是一样的:

/sys/kernel/debug/rknpu/load

C函数:

/**
 * @Description: 获取 NPU 占用率
 * @return {*}
 */
int get_npu_usage(char *npu_usage, size_t size) {
    FILE *file = fopen("/sys/kernel/debug/rknpu/load", "r");
    if (file == NULL) {
        perror("Failed to open NPU load file");
        return -1;
    }
    // 读取文件内容
    char line[size];
    if (fgets(line, size, file) == NULL) {
        perror("Failed to read NPU load file");
        fclose(file);
        return -1;
    }
    fclose(file);
    // 添加前缀
    snprintf(npu_usage, size, "NPU: ");
    // 使用 strchr 查找 % 并提取数字
    char *ptr = line;
    int core_count = 0;
    while ((ptr = strchr(ptr, '%')) != NULL) {
        char *num_start = ptr - 1;
        // 回溯直到找到数字的起始位置
        while (num_start >= line && isdigit(*(num_start - 1))) {
            num_start--;
        }
        // 提取数字,atoi 会从给定的字符串起始位置开始解析,直到遇到第一个非数字字符为止(%前的所有数字)
        if (isdigit(*num_start)) {
            int value = atoi(num_start);
            if (value >= 0 && value <= 100) {
                // 将数字追加到结果字符串中
                char buffer[4]; // 最多三位数字
                snprintf(buffer, sizeof(buffer), "%d%%", value);
                strcat(npu_usage, buffer);
                if (core_count >= 0 && core_count < 2) {
                    strcat(npu_usage, " "); // 添加空格分隔
                }
                core_count++;
            } else {
                // 如果数字不在 0-100 范围内,跳过
                fprintf(stderr, "Invalid NPU load value: %d (must be 0-100)\n", value);
            }
        } else {
            // 如果 num_start 指向的位置不是数字字符,跳过
            fprintf(stderr, "Invalid NPU load format: expected a number before %%\n");
        }
        ptr++; // 继续查找下一个 %
    }
    return 0;
}

由于官方给的输出结果较长,于是我选择先找百分号,再找它前面的数字,实现起来相对简单,就是代码长了点。

4、芯片温度

        温度使用 sensors 软件获取,香橙派手册使用的就是这个。这里我使用 awk 来解析输出,代码中也给出了解释:

/**
 * @Description: 获取芯片温度
 * @return {*}
 */
int get_temperature(char *temperature, size_t size) {
    // 使用sensors命令获取温度
    FILE *fp = popen("sensors | awk '/temp1/ {print $2}' | head -n 1", "r");
    if (fp == NULL) {
        perror("Failed to run sensors command");
        return -1;
    }
    // 读取命令输出
    char line[size];
    if (fgets(line, size, fp) == NULL) {
        perror("Failed to read chip temperature");
        pclose(fp);
        return -1;
    }
    pclose(fp);
    // 添加前缀
    snprintf(temperature, size, "Temper: %s", line);
    // 去掉换行符
    temperature[strcspn(temperature, "\n")] = '\0';
    return 0;
}

三、总结

        源码我会推送至 Github 仓库和 Gitee 仓库,由于懒得设计UI,都是直接显示字符串,这里放一张 YOLO 推理时的截图(C艹多线程,140+帧):

1125962926/spi-oled-driver: Framebuffer drivers implemented by char-devices that can change pins at willhttps://github.com/1125962926/spi-oled-driverspi-oled-driver: 手写Linux FrameBuffer 0.96 寸 spi 屏幕驱动,支持从 app 传入任意引脚https://gitee.com/lrf1125962926/spi-oled-driver


网站公告

今日签到

点亮在社区的每一天
去签到