You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM平台Linux 3.14帧缓冲字符显示实现求助(附改色代码)

在Linux帧缓冲(FB)上显示字符的实现方案

嘿,既然你已经能成功操作ARM板上的Linux 3.14帧缓冲绘制图形了,那实现字符显示其实就是把字符的点阵数据映射到帧缓冲的像素点就行,下面给你一套适配你现有代码的解决方案:

核心思路

帧缓冲是直接操作像素内存的,显示字符需要两步:

  1. 准备字符的点阵数据(比如用常用的8x16点阵字体,每个字符用16字节表示,每字节对应一行的8个像素)
  2. 遍历字符串中的每个字符,根据目标位置,把点阵中为1的位置设置成指定颜色,0的位置保持背景(或者覆盖成背景色)

完整代码示例

我基于你现有的代码做了修改,添加了字符绘制逻辑,能显示"Hello world !!!":

#include <stdio.h>
#include <string.h>

// 颜色定义(和你原代码保持一致的4字节格式)
unsigned char colours[8][4] = {
    {0x00, 0x00, 0x00, 0xFF},   // 黑色(背景)
    {0x00, 0xFF, 0x00, 0xFF},   // 绿色(字符颜色)
    {0x00, 0xFF, 0x00, 0xFF},
    {0x00, 0xFF, 0x00, 0xFF},
    {0x00, 0xFF, 0x00, 0xFF},
    {0x00, 0xFF, 0x00, 0xFF},
    {0x00, 0xFF, 0x00, 0xFF},
    {0x00, 0xFF, 0x00, 0xFF}
};

// 8x16点阵字体示例(仅包含需要的字符:H,e,l,o,w,r,d,!,空格)
// 每个字符用16字节表示,每字节对应一行的8个像素(bit为1表示点亮)
unsigned char font_8x16[] = {
    // 空格 (0x20)
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    // H (0x48)
    0x00,0x7C,0x12,0x11,0x11,0x12,0x7C,0x00,0x00,0x7C,0x12,0x11,0x11,0x12,0x7C,0x00,
    // e (0x65)
    0x00,0x7F,0x49,0x49,0x49,0x49,0x41,0x00,0x00,0x7F,0x48,0x48,0x48,0x48,0x70,0x00,
    // l (0x6C)
    0x00,0x40,0x40,0x40,0x40,0x40,0x7F,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x7F,0x00,
    // o (0x6F)
    0x00,0x3E,0x41,0x41,0x41,0x41,0x3E,0x00,0x00,0x3E,0x42,0x42,0x42,0x42,0x3E,0x00,
    // w (0x77)
    0x00,0x41,0x41,0x22,0x14,0x22,0x41,0x00,0x00,0x81,0x81,0x42,0x24,0x42,0x81,0x00,
    // r (0x72)
    0x00,0x7F,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x7F,0x10,0x10,0x10,0x10,0x00,0x00,
    // d (0x64)
    0x00,0x41,0x41,0x41,0x41,0x49,0x7F,0x00,0x00,0x42,0x42,0x42,0x42,0x52,0x7F,0x00,
    // ! (0x21)
    0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00
};

int frames[] = {0,5,10,15,20,25,30};
int columns = 800;  // 屏幕宽度(像素)
int lines = 480;    // 屏幕高度(像素)
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))

// 原有的边框绘制函数
int frame(int c, int l){
    int i;
    for(i=0; i < ARRAY_SIZE(frames); i++){
        if((c==frames[i])&&((l>=frames[i])&&l<=(lines-frames[i]))){
            return 1;
        }
        if((c==columns-frames[i])&&((l>=frames[i])&&l<=(lines-frames[i]))){
            return 1;
        }
        if((l==frames[i])&&((c>=frames[i])&&c<=(columns-frames[i]))){
            return 1;
        }
        if((l==lines-frames[i])&&((c>=frames[i])&&c<=(columns-frames[i]))){
            return 1;
        }
    }
    return 0;
}

// 绘制单个字符的函数
// 参数:文件指针、字符、起始x坐标、起始y坐标、颜色索引
void draw_char(FILE *fb, char ch, int x, int y, int color_idx) {
    if (ch < 0x20 || ch > 0x7E) return; // 只处理可打印ASCII字符
    int char_offset = (ch - 0x20) * 16; // 计算字符在点阵数组中的偏移

    for (int row = 0; row < 16; row++) {
        unsigned char row_data = font_8x16[char_offset + row];
        // 超出屏幕高度就停止
        if (y + row >= lines) break;

        for (int col = 0; col < 8; col++) {
            int pixel_x = x + col;
            // 超出屏幕宽度就停止
            if (pixel_x >= columns) break;

            // 如果当前bit为1,绘制颜色;否则保持背景(或者你可以改成背景色)
            if (row_data & (0x80 >> col)) {
                fseek(fb, ( (y + row)*columns + pixel_x ) * 4, SEEK_SET);
                fwrite(colours[color_idx], 1, sizeof(colours[color_idx]), fb);
            }
        }
    }
}

// 绘制字符串的函数
void draw_string(FILE *fb, const char *str, int x, int y, int color_idx) {
    int str_len = strlen(str);
    for (int i = 0; i < str_len; i++) {
        draw_char(fb, str[i], x + i*8, y, color_idx);
        // 每个字符宽度是8像素,所以x坐标每次加8
    }
}

int main(int argc, char **argv) {
    int l, c;
    char *filename = argv[1];
    printf("Device : %s\n", filename);

    FILE *f = fopen(filename, "wb");
    if(f){
        printf("Device open success\n");

        // 第一步:绘制背景和边框(和你原代码逻辑一致)
        for(l=0; l<lines; l++){
            for(c=0; c < columns; c++){
                if(frame(c,l)){
                    fwrite(colours[1], 1, sizeof(colours[1]), f);
                }else{
                    int colour = c/(columns/ARRAY_SIZE(colours));
                    fwrite(colours[colour], 1, sizeof(colours[colour]), f);
                }
            }
        }

        // 第二步:绘制字符串"Hello world !!!",起始位置(100, 100),用绿色(索引1)
        draw_string(f, "Hello world !!!", 100, 100, 1);

        fclose(f);
    } else {
        printf("Device open failed\n");
    }
    return 0;
}

关键部分说明

  1. 点阵字体:我用了8x16的点阵,每个字符占16字节,你可以根据需要扩展更多字符的点阵数据,或者替换成其他尺寸的字体(比如16x16)。
  2. 字符绘制逻辑:draw_char函数会根据字符的ASCII码找到对应的点阵,然后逐行逐位检查,把需要点亮的像素写入帧缓冲。注意帧缓冲的像素是4字节,所以每个像素的偏移量是(y*width + x)*4。
  3. 字符串绘制:draw_string函数循环调用draw_char,每个字符间隔8像素(对应字体宽度),你可以调整这个间隔来改变字符间距。
  4. 适配你的代码:保留了你原有的背景和边框绘制逻辑,只添加了字符相关的函数和调用,你可以直接替换原代码使用。

编译与运行

和你之前编译原代码一样,用交叉编译器编译(比如arm-linux-gcc):

arm-linux-gcc fb_draw_text.c -o fb_draw_text

然后拷贝到ARM板上,运行时指定帧缓冲设备(通常是/dev/fb0):

./fb_draw_text /dev/fb0

内容的提问来源于stack exchange,提问作者Selva Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:43:12