在OLED驱动中,字库(通常是大数组形式的点阵数据)的存储和访问是跨平台移植的关键挑战。以下是如何设计兼容不同单片机架构的字库存储方案:
兼容性设计原则
统一存储位置:确保字库始终存放在Flash中
抽象访问方式:隐藏底层架构差异
最小化平台依赖:集中处理编译器特定代码
实现方案(分步骤)
步骤1:创建统一的Flash存储定义头文件
- // flash_storage.h
- #ifndef FLASH_STORAGE_H
- #define FLASH_STORAGE_H
- #include <stdint.h>
- // 平台检测 ========================
- #if defined(__C51__) || defined(SDCC) // 8051
- #define PLATFORM_8051
- #elif defined(__XC8__) || defined(__XC16__) // PIC
- #define PLATFORM_PIC
- #elif defined(__AVR__) // AVR
- #define PLATFORM_AVR
- #elif defined(__MSP430__) || defined(__TI_COMPILER_VERSION__) // MSP430
- #define PLATFORM_MSP430
- #endif
- // Flash存储修饰符定义 ================
- #if defined(PLATFORM_8051)
- #define FLASH_STORAGE code const
- #elif defined(PLATFORM_PIC)
- #define FLASH_STORAGE const __flash
- #elif defined(PLATFORM_AVR)
- #include <avr/pgmspace.h>
- #define FLASH_STORAGE const PROGMEM
- #else // MSP430及其他
- #define FLASH_STORAGE const // 默认const足够
- #endif
- // Flash数据访问宏 ==================
- #if defined(PLATFORM_AVR)
- #define FLASH_READ_BYTE(addr) pgm_read_byte(addr)
- #define FLASH_READ_WORD(addr) pgm_read_word(addr)
- #else
- // 统一编址架构可直接访问
- #define FLASH_READ_BYTE(addr) (*(const uint8_t *)(addr))
- #define FLASH_READ_WORD(addr) (*(const uint16_t *)(addr))
- #endif
- #endif // FLASH_STORAGE_H
步骤2:定义字库数据结构
- // font_data.h
- #ifndef FONT_DATA_H
- #define FONT_DATA_H
- #include "flash_storage.h"
- // 通用字库结构(示例:16x16点阵汉字)
- typedef struct {
- uint16_t unicode; // 字符编码
- uint8_t width; // 实际宽度
- uint8_t height; // 实际高度
- uint8_t data[32]; // 点阵数据(16x16/8=32字节)
- } FontChar;
- // 声明字库(实际定义在.c文件)
- extern FLASH_STORAGE FontChar font_lib[];
- extern const uint16_t font_lib_size;
- #endif // FONT_DATA_H
步骤3:实现字库数据(平台无关)
- // font_data.c
- #include "font_data.h"
- // 使用统一修饰符定义字库
- FLASH_STORAGE FontChar font_lib[] = {
- {0x4E2D, 16, 16, { // 汉字"中"
- 0x00,0x40,0x00,0x40,0x7F,0xFE,0x40,0x02,
- 0x5F,0xFA,0x50,0x0A,0x50,0x0A,0x5F,0xFA,
- 0x50,0x0A,0x50,0x0A,0x5F,0xFA,0x40,0x02,
- 0x7F,0xFE,0x00,0x40,0x00,0x40,0x00,0x00}},
- // ...其他字符
- };
- const uint16_t font_lib_size = sizeof(font_lib)/sizeof(FontChar);
步骤4:实现跨平台字库访问函数
- // oled_font.c
- #include "font_data.h"
- #include "flash_storage.h"
- // 获取字符点阵数据(兼容所有平台)
- bool font_get_char_data(uint16_t unicode, uint8_t* buffer, uint8_t buf_size) {
- for (uint16_t i = 0; i < font_lib_size; i++) {
- // 平台安全的Unicode读取
- uint16_t current_unicode;
-
- #if defined(PLATFORM_AVR)
- current_unicode = pgm_read_word(&font_lib[i].unicode);
- #else
- current_unicode = font_lib[i].unicode; // 直接访问
- #endif
- if (current_unicode == unicode) {
- // 复制点阵数据
- uint8_t data_size = font_lib[i].height * ((font_lib[i].width + 7) / 8);
- if (buf_size < data_size) return false;
-
- for (uint8_t j = 0; j < data_size; j++) {
- #if defined(PLATFORM_AVR)
- buffer[j] = pgm_read_byte(&font_lib[i].data[j]);
- #else
- buffer[j] = font_lib[i].data[j]; // 直接访问
- #endif
- }
- return true;
- }
- }
- return false; // 未找到字符
- }
- // 优化版本:直接访问(非AVR平台)
- const FontChar* font_get_char(uint16_t unicode) {
- #if !defined(PLATFORM_AVR)
- for (uint16_t i = 0; i < font_lib_size; i++) {
- if (font_lib[i].unicode == unicode) {
- return &font_lib[i]; // 直接返回Flash中的指针
- }
- }
- #endif
- return NULL; // AVR不支持直接返回指针
- }
步骤5:OLED驱动中使用字库(示例)
- // oled_driver.c
- #include "font_data.h"
- void oled_draw_char(uint16_t unicode, uint8_t x, uint8_t y) {
- uint8_t char_data[64]; // 足够存放最大字符
-
- // 通用访问方式(全平台兼容)
- if (font_get_char_data(unicode, char_data, sizeof(char_data))) {
- // 使用char_data绘制...
- }
-
- // 优化路径(非AVR平台)
- #if !defined(PLATFORM_AVR)
- const FontChar* font_char = font_get_char(unicode);
- if (font_char) {
- // 直接访问font_char->data绘制...
- // 示例:绘制一个字节
- uint8_t pixel_data = font_char->data[0];
- // ...
- }
- #endif
- }
|