衡山派开发板驱动移植实战:0.96寸IIC单色OLED屏(SSD1306)
衡山派开发板驱动移植实战0.96寸IIC单色OLED屏SSD1306最近在衡山派开发板上做项目需要用到一个小屏幕来显示一些状态信息0.96寸的OLED屏是个不错的选择体积小、功耗低、显示清晰。很多朋友在问怎么把这种IIC接口的OLED屏驱动移植到RT-Thread系统上今天我就把完整的移植过程从代码准备到编译烧录再到功能测试一步步分享给大家。这篇文章就是一份手把手的实战指南目标是让你能在衡山派开发板上成功驱动起这块0.96寸的OLED屏并显示字符、汉字和动态数字。整个过程我会尽量讲得详细把可能遇到的坑也提前指出来。1. 准备工作认识我们的屏幕在动手移植之前咱们先了解一下要驱动的对象。这块屏幕的核心参数如下参数项规格说明工作电压3.3V工作电流约9mA屏幕尺寸27.3 x 27.8 mm分辨率128 (水平) x 64 (垂直) 像素驱动芯片SSD1306通信协议IIC (I2C)接口引脚4 Pin (2.54mm间距排针)这块屏用的是IIC总线只需要两根线SDA数据线和SCL时钟线就能通信接线非常方便。它的IIC设备地址是0x78注意有些资料里写的是0x3c其实是同一个地址的不同表示方式后面代码里会看到。屏幕的显存可以理解为一个128列 x 64行的点阵。在驱动里每8行被划分为1“页”(Page)所以总共是8页。每一列的数据用一个字节8位来存储一页就需要128个字节。记住一个关键点数据是高位在下低位在上。也就是说字节的最高位(bit7)对应页面的最下面一个点最低位(bit0)对应最上面一个点。2. 驱动代码移植我们的目标是把现成的驱动代码移植到衡山派开发板的RT-Thread工程里。官方已经提供了完整的驱动代码包我们只需要把它放到正确的位置并进行一些配置。2.1 获取并放置驱动代码首先你需要下载驱动代码包。这个包可以在衡山派Wiki的“资料下载中心” - “模块移植资料下载”章节中找到。下载后你会得到一个压缩包解压后里面应该包含以下几个关键文件oled.c/oled.h: 核心的OLED驱动文件实现了初始化、画点、显示字符/汉字/数字等功能。oledfont.h: 字库文件里面存放了ASCII字符和汉字的点阵数据。Kconfig: 用于在RT-Thread的menuconfig配置菜单中增加选项。SConscript: RT-Thread的SCons构建脚本。test_0_96_iic_single_screen.c: 一个测试线程的示例代码用来验证屏幕是否工作。接下来找到你的衡山派工程目录路径通常是luban-lite\application\rt-thread\helloworld\。在这个目录下你应该能看到一个user-bsp文件夹。如果没看到说明你还没有进行模块移植的前置操作需要先参考官方手册完成必要的配置。把解压出来的整个驱动文件夹例如叫0-96-iic-single-screen复制到user-bsp目录下。2.2 修改Kconfig文件为了让我们的驱动模块能出现在配置菜单里并被编译需要修改工程顶层的Kconfig文件。用VSCode或其他编辑器打开application\rt-thread\helloworld\Kconfig文件。翻到文件末尾在#endif这一行之前添加下面这行代码# 0.96寸单色iic屏幕 source application/rt-thread/helloworld/user-bsp/0-96-iic-single-screen/Kconfig这行代码的作用是告诉构建系统去我们刚放进去的驱动文件夹里找它的Kconfig文件来解析。保存文件。2.3 使用menuconfig进行配置现在我们需要在RT-Thread的配置系统中启用这个屏幕驱动。打开Env工具在工程根目录luban-lite文件夹下双击win_env.bat脚本打开RT-Thread的Env配置环境。应用默认配置在Env命令行中先输入以下命令查看所有可用的默认配置scons --list-def你会看到一个列表找到名为d13x_JLC_rt-thread_helloworld的配置这是衡山派开发板的默认配置记下它的编号比如是7。然后应用它scons --apply-def7或者直接使用配置名scons --apply-defd13x_JLC_rt-thread_helloworld_defconfig进入图形化配置菜单输入命令进入配置界面scons --menuconfig启用驱动模块在配置界面中用方向键找到并选中Porting code using the LCKFB module这个选项按Y键选中前面会出现[*]。按回车键进入这个子菜单。在里面找到Use 0.96 inch i2c screen选项同样按Y键选中它。按左右方向键选择Save保存配置然后一路退出 (Exit) 直到回到命令行。提示在menuconfig里Y表示编译进内核N表示不编译M表示编译为模块。这里我们选Y。2.4 编译工程配置保存好后就可以开始编译了。在Env命令行中输入scons如果你的电脑CPU核心数比较多想加快编译速度可以加上-j参数比如我用的是16核scons -j16编译成功后会在\luban-lite\output\d13x_JLC_rt-thread_helloworld\images目录下生成一个d13x_JLC_v1.0.0.img镜像文件。2.5 烧录镜像最后一步就是把这个.img文件烧录到衡山派开发板里。烧录方法请参考衡山派官方文档中的“镜像烧录”章节通常需要使用专用的烧录工具连接开发板的USB口进行操作。烧录完成后给开发板上电准备工作就全部完成了。3. 代码解析与使用驱动移植好了咱们来看看代码是怎么工作的以及怎么用它来显示内容。3.1 核心驱动文件解析驱动核心主要在oled.c和oled.h两个文件里。IIC设备初始化驱动首先会查找并绑定名为i2c0的IIC总线设备。这是衡山派开发板上IIC0接口在RT-Thread设备框架中的注册名。关键代码如下#define I2C_BUS_NAME i2c0 /* IIC总线设备名称 */ #define OLED_ADDR 0x3c /* 从机地址 */ static struct rt_i2c_bus_device *i2c_bus RT_NULL; void OLED_Init(void) { /* 查找I2C总线设备获取I2C总线设备句柄 */ i2c_bus (struct rt_i2c_bus_device *)rt_device_find(I2C_BUS_NAME); if(i2c_busRT_NULL) { rt_kprintf(no device: %s\n,I2C_BUS_NAME); } else { rt_kprintf(find device: %s\n,I2C_BUS_NAME); } // ... 后续的SSD1306初始化命令序列 }这里有个细节屏幕的IIC地址手册上写的是0x78但代码里用的是0x3c。其实0x78是7位地址左移一位后的写地址0x3c 1 0x78。RT-Thread的IIC框架通常使用7位地址所以这里填0x3c是正确的。显存与刷新机制驱动内部定义了一个显存数组OLED_GRAM[144][8]它比实际屏幕128x64宽一点可能是为了滚动显示等功能预留的。我们所有画点、画线、写字符的操作实际上都是在修改这个数组里的数据。修改完数据后必须调用OLED_Refresh()函数它才会把OLED_GRAM里的数据一次性发送到屏幕的显存中从而更新显示。这个设计避免了频繁的IIC通信提高了效率。基本绘图函数驱动提供了丰富的API供我们调用OLED_DrawPoint(x, y, t): 在指定坐标(x,y)画一个点t1点亮t0熄灭。OLED_DrawLine(): 画直线。OLED_ShowChar(): 显示一个ASCII字符可以指定字体大小(8,12,16,24)。OLED_ShowString(): 显示字符串。OLED_ShowChinese(): 显示汉字需要提供汉字在字库数组中的索引号。OLED_ShowNum(): 显示数字。OLED_Clear(): 清屏。3.2 测试程序详解提供的test_0_96_iic_single_screen.c文件是一个很好的使用示例。它创建了一个线程在屏幕上循环显示不同大小的“ABC”字符串、“电子技术”四个汉字以及一个不断递增的数字。static void sreen_thread_entry(void *param) { u8 t 0; OLED_Init(); //初始化OLED OLED_Clear(); //清屏 while(1) { // 显示不同字体的“ABC” OLED_ShowString(0, 0, (unsigned char*)ABC, 8, 1); //6x8字体 OLED_ShowString(0, 8, (unsigned char *)ABC, 12, 1); //6x12字体 OLED_ShowString(0, 20, (unsigned char *)ABC, 16, 1); //8x16字体 OLED_ShowString(0, 36, (unsigned char *)ABC, 24, 1); //12x24字体 // 显示汉字“电子技术”参数3,4,5,6是字库中对应的索引 OLED_ShowChinese(54, 0, 3, 16, 1); //“电” OLED_ShowChinese(72, 0, 4, 16, 1); //“子” OLED_ShowChinese(90, 0, 5, 16, 1); //“技” OLED_ShowChinese(108, 0, 6, 16, 1); //“术” // 显示一个动态递增的数字范围0-254 OLED_ShowNum(72, 20, t, 3, 16, 1); if(t 255) t 0; OLED_Refresh(); // 刷新屏幕将显存数据发送出去 delay_ms(500); // 延时500ms } }这个线程的入口函数通过MSH_CMD_EXPORT导出成了一个Shell命令方便我们测试。3.3 运行与测试硬件连接将0.96寸OLED屏的4个引脚连接到衡山派开发板的IIC0接口上。通常连接关系是VCC - 3.3VGND - GNDSCL - IIC0_SCL引脚SDA - IIC0_SDA引脚 具体引脚位置请查阅衡山派开发板的原理图或引脚定义表。串口调试通过USB转TTL模块连接开发板的调试串口到电脑。运行测试命令系统启动后在串口终端波特率默认为115200里输入命令test_0_96_iic_single_screen你可以按TAB键来自动补全这个命令。如果一切顺利你应该能看到OLED屏幕被点亮并开始循环显示“ABC”、“电子技术”和一个不断增长的数字。4. 特别注意事项与排坑指南在实际移植和使用的过程中我踩过一些坑这里特别提醒大家注意1. 配置冲突问题如果你之前为了测试其他功能比如LVGL图形库或DVP摄像头在menuconfig中启用过一些选项它们可能会和这个OLED驱动冲突导致编译失败或运行异常。在menuconfig中请检查并确保取消选中以下冲突选项按N取消Application options --- [ ] LVGL (official): powerful and easy-to-use embedded GUI library [ ] ArtInChip LVGL demo Board options --- [ ] Using DVP这些配置会占用大量的内存或硬件资源可能与我们的OLED驱动产生冲突先关掉它们。2. 屏幕无任何显示检查电源和接线首先确认VCC接的是3.3V不是5V接错会烧屏。确认SDA、SCL线没有接反或接触不良。检查IIC地址如果屏幕还是没反应可以尝试修改oled.c中的OLED_ADDR在0x3c和0x78之间切换试试。有些屏幕模块的地址可能是0x3d。确认IIC总线在oled.c中打印的rt_kprintf信息看是否成功找到了i2c0设备。如果没有可能是板子的IIC驱动没正确加载。3. 显示乱码或错位检查初始化序列OLED_Init()函数里有一长串SSD1306的初始化命令这些命令是屏幕厂商提供的一般不要改动。如果显示异常可以对照屏幕数据手册检查。注意坐标系统屏幕的坐标原点(0,0)在左上角。X轴向右增加范围0-127Y轴向下增加范围0-63。调用显示函数时不要超出范围。字库问题如果汉字显示为乱码检查oledfont.h文件是否完整以及OLED_ShowChinese函数中使用的索引号是否与字库中的汉字顺序对应。4. 移植到自己的应用当你想在自己的应用程序中使用这个OLED驱动时只需要在你的源文件中#include oled.h。在程序初始化部分调用OLED_Init()和OLED_Clear()。使用OLED_ShowString、OLED_ShowNum等函数来显示内容。记得在显示内容后调用OLED_Refresh()来更新屏幕。驱动移植本身并不复杂关键是把代码放对地方、配置选对选项、硬件接对线。按照上面的步骤一步步来你就能在衡山派开发板上点亮这块小巧的OLED屏为你的项目增添一个信息显示的窗口。