1. 项目概述
这个基于FPGA的IIC OLED字符显示系统,是我在自制橙月FPGA开发板上实现的一个实用案例。核心功能是通过FPGA控制0.96寸OLED屏幕显示特定字符。选择这个项目作为入门案例有几个原因:首先,IIC接口是嵌入式系统中最常用的通信协议之一;其次,OLED显示是验证FPGA数字逻辑设计的直观方式;最后,整个系统涉及从底层协议到上层应用的全流程开发,非常适合FPGA初学者练手。
我使用的FPGA芯片是Cyclone IV E系列的EP4CE6E22C8N,这块芯片虽然不算最新型号,但6272个逻辑单元和270kbits嵌入式存储器的资源对于这类基础项目绰绰有余。开发板上的OLED模块采用常见的SSD1306驱动芯片,分辨率128×64,通过IIC接口与FPGA通信。最终实现的效果是在OLED上稳定显示"欢迎关注'学习FPGA的电气小兴兴'"这18个16×16点阵的汉字字符。
2. 硬件平台搭建
2.1 FPGA开发板选型与配置
橙月FPGA开发板是我自制的学习板,核心芯片选用Cyclone IV E系列主要基于以下考虑:
- 性价比高:相比Artix-7等新型号,Cyclone IV E价格更亲民
- 资源适中:6272LEs足够实现基础外设控制
- 开发环境成熟:Quartus II支持完善,编译速度快
开发板上的关键外设包括:
- 50MHz系统时钟
- 复位电路(上电复位+按键复位)
- 4个用户按键(用于功能控制)
- OLED接口(4Pin IIC)
- 调试用LED指示灯
特别注意:FPGA的I/O电压需要与OLED模块匹配。本设计中,OLED支持3.3V/5V双电压,而Cyclone IV E的Bank电压可配置为3.3V,因此直接使用3.3V电平通信,无需电平转换。
2.2 OLED模块详解
采用的0.96寸OLED模块有以下技术特点:
- 驱动芯片:SSD1306
- 通信接口:IIC(地址通常为0x78或0x7A)
- 显示分辨率:128×64
- 显存结构:8页(Page)×128列
- 供电电压:3.3V-5V
硬件连接时需注意:
- SDA/SCL信号线需要上拉电阻(通常4.7KΩ)
- 如果OLED不带稳压电路,需要外部提供稳定的3.3V电源
- 建议在电源引脚就近放置0.1μF去耦电容
实际调试中发现,某些廉价OLED模块的IIC上拉电阻缺失或阻值过大,会导致通信失败。建议用示波器检查信号质量,必要时外接4.7KΩ上拉电阻。
3. 系统设计与实现
3.1 整体架构设计
系统采用模块化设计,主要功能模块如下:
code复制┌───────────────────────┐
│ 顶层模块 │
├───────────┬───────────┤
│ IIC主控制器 │ 显示控制逻辑 │
│ (I2C_Master)│ (Oled_Show_control)│
└───────────┴───────────┘
│ │
▼ ▼
┌───────────────────────┐
│ OLED驱动层 │
├───────────┬───────────┤
│ 初始化模块 │ 清屏模块 │
│ (Oled_Init)│ (Oled_Clear)│
└───────────┴───────────┘
│
▼
┌───────────────────────┐
│ 字符显示模块 │
│ (Oled_Show_Info) │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 字模数据模块 │
│ (font_data) │
└───────────────────────┘
3.2 IIC主控制器实现
I2C_Master.v模块是系统的核心基础,实现了标准的IIC协议。关键设计点包括:
- 状态机设计:
verilog复制localparam [2:0] IDLE = 3'b000,
START = 3'b001,
ADDR = 3'b010,
WRITE = 3'b011,
READ = 3'b100,
STOP = 3'b101;
- 时钟分频:
系统时钟50MHz,IIC标准模式时钟100kHz,因此需要分频:
verilog复制always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_cnt <= 0;
iic_clk <= 1'b1;
end else begin
if(clk_cnt == DIVIDER/2-1) begin
clk_cnt <= 0;
iic_clk <= ~iic_clk;
end else begin
clk_cnt <= clk_cnt + 1;
end
end
end
- 关键时序参数:
- 启动条件保持时间:>4.7μs
- 停止条件建立时间:>4μs
- 数据保持时间:>250ns
调试中发现,某些OLED模块对时序要求严格。建议在Quartus中设置时序约束:
sdc复制create_clock -name iic_clk -period 10 [get_ports iic_scl]
set_input_delay -clock iic_clk 2 [get_ports iic_sda]
3.3 显示控制逻辑
Oled_Show_control.v模块负责协调显示流程:
- 显示流程:
- 等待系统复位完成
- 发送初始化命令序列
- 执行清屏操作
- 按坐标逐个写入字符数据
- 坐标系统:
- X轴:0-127(列地址)
- Y轴:0-7(页地址)
- 每个16×16字符占用2页高度和16列宽度
- 关键代码片段:
verilog复制// 字符位置查找表
localparam [7:0] CHAR_POS_X [0:17] = {
0, 16, 32, 48, 64, 80, 96, 112, // 第一行
0, 16, 32, 48, 64, 80, 96, 112 // 第二行
};
localparam [7:0] CHAR_POS_Y [0:17] = {
0, 0, 0, 0, 0, 0, 0, 0, // 第一行
2, 2, 2, 2, 2, 2, 2, 2 // 第二行
};
4. 字符显示实现细节
4.1 字模提取与处理
使用PCtoLCD2002软件生成字模,关键配置:
- 字体:宋体
- 字号:16
- 取模方式:列行式
- 取模走向:逆向
- 输出格式:C51格式
生成的字符数据格式示例:
c复制/*"欢",0*/
0x40,0x40,0x42,0xCC,0x00,0x40,0x20,0x18,
0x0F,0xE8,0x08,0x08,0x08,0xF8,0x00,0x00,
0x00,0x00,0x00,0x3F,0x10,0x88,0x40,0x20,
0x18,0x07,0x00,0x00,0x00,0x3F,0x00,0x00,
在font_data.v中,我们将这些数据转换为Verilog数组:
verilog复制reg [7:0] font_data [0:17][0:31] = {
{"欢"字模数据},
{"迎"字模数据},
// ...其他字符
};
4.2 字符显示驱动
Oled_Show_Info.v模块的工作流程:
- 接收显示控制模块的坐标和字符索引
- 从font_data读取对应字符的32字节数据
- 分两次写入OLED(每页8列数据)
- 自动计算下一页的起始地址
关键实现代码:
verilog复制always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
// 初始化
end else begin
case(state)
IDLE: if(show_en) begin
data_index <= 0;
page_addr <= y_pos;
col_addr <= x_pos;
state <= WRITE_PAGE1;
end
WRITE_PAGE1: begin
// 写入第一页数据
if(data_index == 15) begin
data_index <= 0;
page_addr <= y_pos + 1;
state <= WRITE_PAGE2;
end
end
// 其他状态...
endcase
end
end
5. 系统调试与优化
5.1 常见问题排查
- OLED无显示:
- 检查电源电压(3.3V是否稳定)
- 测量IIC信号(SCL/SDA是否有波形)
- 确认设备地址(0x78或0x7A)
- 验证初始化序列是否完整发送
- 显示乱码:
- 检查字模数据是否正确
- 确认取模参数与显示代码匹配
- 验证坐标计算逻辑
- 检查显存更新时序
- 显示闪烁:
- 优化刷新率(建议30-60Hz)
- 增加显示缓冲区
- 检查电源滤波电容
5.2 性能优化技巧
- 双缓冲技术:
- 在FPGA内部RAM开辟显示缓冲区
- 后台更新缓冲区,完成后切换显示
- 可消除刷新时的闪烁现象
- 部分刷新:
- 只更新变化的显示区域
- 减少IIC通信量
- 特别适合动态数据显示
- 时钟优化:
- 适当提高IIC时钟频率(最高400kHz)
- 使用PLL生成精确的IIC时钟
- 添加时序约束保证稳定性
6. 功能扩展思路
6.1 动态内容显示
当前系统只能显示静态字符,可以扩展:
- 实时时钟显示
- 传感器数据(温度、湿度)
- 滚动字幕效果
实现方法:
- 增加RTC模块或传感器接口
- 设计动态字模更新机制
- 添加滚屏控制逻辑
6.2 多字体支持
扩展字库功能:
- 添加12×12、16×8等不同字号
- 支持英文、数字、特殊符号
- 实现字体切换功能
技术要点:
- 设计灵活的字模存储结构
- 增加字体选择信号
- 优化显存管理
6.3 图形显示功能
升级为图形显示系统:
- 实现画点、画线等基本绘图功能
- 支持BMP位图显示
- 添加GUI界面元素
实现方案:
- 设计图形加速模块
- 扩展显存容量
- 开发图形API接口
7. 工程实践建议
- 版本控制:
- 使用Git管理工程文件
- 合理划分模块目录
- 添加详细注释
- 仿真验证:
- 编写IIC时序仿真测试
- 验证字模数据正确性
- 使用ModelSim进行功能仿真
- 文档记录:
- 记录硬件连接图
- 维护寄存器映射表
- 编写用户操作手册
- 功耗优化:
- 合理使用OLED睡眠模式
- 优化刷新频率
- 考虑使用低功耗FPGA型号
这个项目从最初的IIC协议调试到最终稳定显示,我遇到了不少挑战。最深刻的体会是:FPGA开发中,时序问题往往最难调试。建议在IIC实现初期就加入充分的仿真测试,用逻辑分析仪实时监控信号,这样可以节省大量调试时间。另外,OLED显示效果对字模质量非常敏感,不同取模软件生成的数