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

代码

复制代码
/* LCD显示程序 - 在嵌入式设备上显示中文 */
#include <stdio.h>                      // 标准输入输出头文件
#include "font.h"                       // 字体库头文件(自定义)
#include <sys/types.h>                  // 系统数据类型定义
#include <sys/stat.h>                   // 文件状态信息
#include <fcntl.h>                      // 文件控制选项
#include <sys/mman.h>                   // 内存映射支持
#include <unistd.h>                     // 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_display
    chmod +x /usr/bin/lcd_display
  2. 添加到启动脚本(以GEC6818为例):

    bash

    复制代码
    # 编辑/etc/init.d/rcS
    echo "/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/sh
while true; do
    if ! pgrep lcd_display; then
        /usr/bin/lcd_display &
    fi
    sleep 5
done

# 添加到启动
chmod +x /etc/watchdog.sh
echo "/etc/watchdog.sh &" >> /etc/init.d/rcS
方案3:硬件级解决方案(最可靠)
  1. 外接EEPROM存储

    c

    复制代码
    // 保存显示状态到I2C EEPROM
    void 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 -lfreetype
    cp lcd_display /usr/bin/
    chmod +x /usr/bin/lcd_display
    echo "/usr/bin/lcd_display &" >> /etc/init.d/rcS
    sync

五、注意事项

  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轴有效范围:0800 - 文字宽度

    • Y轴有效范围:0480 - 文字高度

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

  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);

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

相关推荐
iteye_993926 分钟前
让 3 个线程串行的几种方式
java·linux
渡我白衣1 小时前
Linux操作系统:再谈虚拟地址空间
linux
阿巴~阿巴~1 小时前
Linux 第一个系统程序 - 进度条
linux·服务器·bash
DIY机器人工房1 小时前
代码详细注释:通过stat()和lstat()系统调用获取文件的详细属性信息
linux·嵌入式
望获linux2 小时前
【Linux基础知识系列】第四十三篇 - 基础正则表达式与 grep/sed
linux·运维·服务器·开发语言·前端·操作系统·嵌入式软件
眠りたいです2 小时前
Mysql常用内置函数,复合查询及内外连接
linux·数据库·c++·mysql
我的泪换不回玫瑰3 小时前
Linux系统管理命令
linux
jjkkzzzz3 小时前
Linux下的C/C++开发之操作Zookeeper
linux·zookeeper·c/c++
二当家的素材网4 小时前
Centos和麒麟系统如何每天晚上2点10分定时备份达梦数据库
linux·数据库·centos
挑战者6668884 小时前
CentOS 系统高效部署 Dify 全攻略
linux·运维·centos