> 技术文档 > 代码详细注释:ARM-Linux字符设备驱动开发案例:LCD汉字输出改进建议开发板断电重启还能显示汉字,显示汉字位置自定义

代码详细注释:ARM-Linux字符设备驱动开发案例:LCD汉字输出改进建议开发板断电重启还能显示汉字,显示汉字位置自定义

代码

/* LCD显示程序 - 在嵌入式设备上显示中文 */#include // 标准输入输出头文件#include \"font.h\" // 字体库头文件(自定义)#include   // 系统数据类型定义#include   // 文件状态信息#include // 文件控制选项#include   // 内存映射支持#include   // UNIX标准函数int fd;  // 全局文件描述符(LCD设备)int (*lcd)[800] = NULL;  // LCD显存映射指针(800x480分辨率)/* 初始化LCD显示 */int init_lcd(){ // 1.打开帧缓冲设备 fd = open(\"/dev/fb0\", O_RDWR); // 以读写模式打开帧缓冲设备 if (fd == -1) // 检查是否打开成功 { perror(\"打开LCD设备失败\\n\"); // 打印错误信息 return -1;// 返回错误状态 } else { printf(\"打开LCD设备成功\\n\"); // 成功提示 } // 2.映射显存到用户空间 lcd = mmap(NULL,  // 由系统选择映射地址  800 * 480 * 4,  // 映射大小(800x480 32bpp)  PROT_READ | PROT_WRITE, // 可读可写  MAP_SHARED,  // 共享映射  fd,// 文件描述符  0);// 偏移量 if (lcd == MAP_FAILED) // 检查映射是否成功 { perror(\"映射LCD设备失败\\n\"); // 打印错误信息 return -1;  // 返回错误状态 } else { printf(\"映射LCD设备成功\\n\"); // 成功提示 } return 0; // 初始化成功}/* 释放LCD资源 */void free_lcd(){ // 3.解除内存映射 munmap(lcd, 800 * 480 * 4); // 释放映射的显存 close(fd); // 关闭设备文件}int main(){ // 初始化LCD显示 init_lcd(); // 调用初始化函数 // 1.加载TrueType字体文件 font *f = fontLoad(\"/usr/share/fonts/DroidSansFallback.ttf\"); // 加载字体 if(!f) { printf(\"字体加载失败\\n\"); // 错误提示 free_lcd();  // 释放资源 return -1;  // 退出程序 } // 2.设置字体大小(128像素) fontSetSize(f, 128);  // 设置字体大小 // 3.配置直接显存画布 bitmap bm; // 定义位图结构体 bm.height = 480;  // 画布高度(像素) bm.width = 800;  // 画布宽度(像素) bm.byteperpixel = 4;  // 每像素4字节(32位色) bm.map = (u8 *)lcd; // 直接映射到显存 // 4.在屏幕上显示绿色文字 fontPrint(f, // 字体对象 &bm,// 目标画布 0, // X起始位置 0, // Y起始位置 \"DIY机器人工房\", // 显示文本 getColor(0, 255, 0, 0), // 颜色值(ABGR格式: 绿) 0);// 背景模式(0=透明) free_lcd(); // 释放LCD资源 return 0; // 程序正常退出}

关键点说明:

  1. 颜色格式getColor(0, 255, 0, 0) 使用ABGR格式:

    • A(alpha)=0:完全透明(但实际效果可能因实现而异)

    • B(蓝)=0

    • G(绿)=255

    • R(红)=0

    • 实际显示绿色文字

  2. 显示流程

    • 初始化LCD帧缓冲 → 加载字体 → 设置画布 → 渲染文字 → 释放资源

  3. 特殊说明

    • 该程序直接操作显存,需要root权限运行

    • 字体路径/usr/share/fonts/DroidSansFallback.ttf是开发板特定路径

    • 颜色值可能需要根据实际硬件调整(BGR/RGB顺序问题)


您的代码在开发板重启后文字消失是正常现象,因为FrameBuffer的显存是临时性的内存映射。要实现\"永久显示\"效果,需要从系统层面进行改造。以下是完整的解决方案:


一、根本原因分析

  1. 显存特性

    • /dev/fb0映射的是显示控制器的临时缓存

    • 所有绘制操作仅保存在易失性内存中

    • 断电后显存内容必然丢失

  2. 程序行为

    c

    mmap()映射 → 绘制文字 → 程序退出 → 内存释放

二、永久显示解决方案

方案1:开机自启动(最简单)

步骤

  1. 将编译好的程序放到/usr/bin/

    bash

    cp your_program /usr/bin/lcd_displaychmod +x /usr/bin/lcd_display
  2. 添加到启动脚本(以GEC6818为例):

    bash

    # 编辑/etc/init.d/rcSecho \"/usr/bin/lcd_display &\" >> /etc/init.d/rcS

特点

  • 每次启动自动恢复显示

  • 无需修改现有代码

方案2:持久化+自动恢复(推荐)

代码改造

c

// 在main()函数中添加持久化逻辑int main() { // 原有初始化... while(1) { fontPrint(f, &bm, 0, 0, \"DIY机器人工房\", getColor(0,255,0,0), 0); sync(); // 确保数据写入磁盘 sleep(10); // 每10秒重绘一次(防闪退) } // 注意:此版本需要Ctrl+C终止}

配套措施

bash

# 创建看门狗脚本/etc/watchdog.sh#!/bin/shwhile true; do if ! pgrep lcd_display; then /usr/bin/lcd_display & fi sleep 5done# 添加到启动chmod +x /etc/watchdog.shecho \"/etc/watchdog.sh &\" >> /etc/init.d/rcS
方案3:硬件级解决方案(最可靠)
  1. 外接EEPROM存储

    c

    // 保存显示状态到I2C EEPROMvoid save_display_state() { int eeprom_fd = open(\"/dev/i2c-0\", O_RDWR); write(eeprom_fd, display_data, sizeof(display_data)); close(eeprom_fd);}
  2. 使用FRAM存储器

    • 替换显存映射为持久存储区域

    • 需硬件改造

方案4:X Window方案(适合高级应用)

bash

# 在~/.xinitrc中添加/usr/bin/your_program &exec startxfce4

三、各方案对比

方案 可靠性 复杂度 是否需要硬件改造 适用场景 开机自启动 ★★☆ 低 否 简单应用 看门狗+定时刷新 ★★★ 中 否 工业控制 EEPROM存储 ★★★★ 高 是 关键任务 X Window集成 ★★☆ 中 否 桌面环境

四、最佳实践建议(GEC6818开发板)

  1. 基础版

    bash

    # 在/etc/init.d/rcS末尾添加:/usr/bin/lcd_display > /dev/null 2>&1 &
  2. 增强版

    c

    // 修改main函数:int main() { init_lcd(); font *f = fontLoad(\"/usr/share/fonts/DroidSansFallback.ttf\"); fontSetSize(f, 128); while(1) { bitmap bm = {480, 800, 4, (u8*)lcd}; fontPrint(f, &bm, 0, 0, \"DIY机器人工房\", getColor(0,255,0,0), 0); fsync(fd); // 强制写入 sleep(10); } return 0; // 实际不会执行到此处}
  3. 部署命令

    bash

    arm-linux-gcc -o lcd_display display.c -lfreetypecp lcd_display /usr/bin/chmod +x /usr/bin/lcd_displayecho \"/usr/bin/lcd_display &\" >> /etc/init.d/rcSsync

五、注意事项

  1. 显存映射的生命周期与进程绑定

  2. 开发板的文件系统可能是只读的,需要先remount:

    bash

    mount -o remount,rw /
  3. 长时间运行需注意内存泄漏问题

  4. 建议添加日志监控:

    bash

    echo \"$(date) LCD程序启动\" >> /var/log/lcd.log

通过以上方法,您的文字显示将在系统重启后自动恢复,实现\"永久显示\"效果。


在您的代码中自定义文字起始位置(而不只是左上角),需要通过修改 fontPrint 函数的坐标参数来实现。以下是具体方法和代码示例:


1. 关键修改点

在您的代码中,这行控制文字位置:

c

fontPrint(f, &bm, 0, 0, \"DIY机器人工房\", getColor(0,255,0,0), 0);// ↑ ↑// X,Y坐标(左上角为0,0)

2. 自定义坐标的方法

修改 fontPrint 的 第3和第4个参数

  • 第3参数:X轴起始位置(水平方向,单位:像素)

  • 第4参数:Y轴起始位置(垂直方向,单位:像素)

示例:将文字显示在屏幕中央

c

int text_x = (800 - text_width) / 2; // 水平居中int text_y = (480 - text_height) / 2; // 垂直居中fontPrint(f, &bm, text_x, text_y, \"居中文字\", getColor(0,255,0,0), 0);

3. 完整代码示例

c

// 在画布上显示字体(自定义位置)int text_x = 100; // 距离左侧100像素int text_y = 200; // 距离顶部200像素fontPrint(f, &bm, text_x, text_y, \"DIY机器人工房\", getColor(0,255,0,0), 0);

4. 动态计算文字宽度(精确居中)

如果需要根据文字内容自动计算居中位置:

c

// 先计算文字像素宽度(需要字体库支持)int text_width = 128 * strlen(\"DIY机器人工房\"); // 假设每个字符宽=字体大小int text_height = 128; // 字体高度// 计算居中坐标int center_x = (800 - text_width) / 2; int center_y = (480 - text_height) / 2;fontPrint(f, &bm, center_x, center_y, \"DIY机器人工房\", getColor(0,255,0,0), 0);

5. 注意事项

  1. 坐标范围

    • X轴有效范围:0 到 800 - 文字宽度

    • Y轴有效范围:0 到 480 - 文字高度

    • 超出范围可能导致显示不全

  2. 字体尺寸影响

    c

    fontSetSize(f, 128); // 字体越大,需要的空间越大
  3. 多行文字
    如需换行显示,需要手动计算Y轴偏移:

    c

    fontPrint(f, &bm, 50, 100, \"第一行\", color, 0);fontPrint(f, &bm, 50, 250, \"第二行\", color, 0); // Y坐标增加
  4. 开发板差异
    某些嵌入式设备的坐标系可能从底部开始(如Y轴反向),此时需要调整:

    c

    int y_pos = 480 - text_y - text_height; // 从底部计算

6. 调试技巧

添加坐标打印,方便调整位置:

c

printf(\"文字位置:X=%d, Y=%d\\n\", text_x, text_y);

通过修改这些参数,您可以自由控制文字在屏幕上的显示位置。