代码详细注释: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; // 程序正常退出}
关键点说明:
-
颜色格式:
getColor(0, 255, 0, 0)
使用ABGR格式:-
A(alpha)=0:完全透明(但实际效果可能因实现而异)
-
B(蓝)=0
-
G(绿)=255
-
R(红)=0
-
实际显示绿色文字
-
-
显示流程:
-
初始化LCD帧缓冲 → 加载字体 → 设置画布 → 渲染文字 → 释放资源
-
-
特殊说明:
-
该程序直接操作显存,需要root权限运行
-
字体路径
/usr/share/fonts/DroidSansFallback.ttf
是开发板特定路径 -
颜色值可能需要根据实际硬件调整(BGR/RGB顺序问题)
-
您的代码在开发板重启后文字消失是正常现象,因为FrameBuffer的显存是临时性的内存映射。要实现\"永久显示\"效果,需要从系统层面进行改造。以下是完整的解决方案:
一、根本原因分析
-
显存特性:
-
/dev/fb0
映射的是显示控制器的临时缓存 -
所有绘制操作仅保存在易失性内存中
-
断电后显存内容必然丢失
-
-
程序行为:
c
mmap()映射 → 绘制文字 → 程序退出 → 内存释放
二、永久显示解决方案
方案1:开机自启动(最简单)
步骤:
-
将编译好的程序放到
/usr/bin/
:bash
cp your_program /usr/bin/lcd_displaychmod +x /usr/bin/lcd_display
-
添加到启动脚本(以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:硬件级解决方案(最可靠)
-
外接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);}
-
使用FRAM存储器:
-
替换显存映射为持久存储区域
-
需硬件改造
-
方案4:X Window方案(适合高级应用)
bash
# 在~/.xinitrc中添加/usr/bin/your_program &exec startxfce4
三、各方案对比
四、最佳实践建议(GEC6818开发板)
-
基础版:
bash
# 在/etc/init.d/rcS末尾添加:/usr/bin/lcd_display > /dev/null 2>&1 &
-
增强版:
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; // 实际不会执行到此处}
-
部署命令:
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
五、注意事项
-
显存映射的生命周期与进程绑定
-
开发板的文件系统可能是只读的,需要先remount:
bash
mount -o remount,rw /
-
长时间运行需注意内存泄漏问题
-
建议添加日志监控:
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. 注意事项
-
坐标范围:
-
X轴有效范围:
0
到800 - 文字宽度
-
Y轴有效范围:
0
到480 - 文字高度
-
超出范围可能导致显示不全
-
-
字体尺寸影响:
c
fontSetSize(f, 128); // 字体越大,需要的空间越大
-
多行文字:
如需换行显示,需要手动计算Y轴偏移:c
fontPrint(f, &bm, 50, 100, \"第一行\", color, 0);fontPrint(f, &bm, 50, 250, \"第二行\", color, 0); // Y坐标增加
-
开发板差异:
某些嵌入式设备的坐标系可能从底部开始(如Y轴反向),此时需要调整:c
int y_pos = 480 - text_y - text_height; // 从底部计算
6. 调试技巧
添加坐标打印,方便调整位置:
c
printf(\"文字位置:X=%d, Y=%d\\n\", text_x, text_y);
通过修改这些参数,您可以自由控制文字在屏幕上的显示位置。