【ESP32S3-Arduino】驱动OLED SSD1306详解

本文详细介绍了使用ESP32S3开发板、Platformio工具和Arduino框架开发OLED屏的过程,包括OLED屏的工作原理、驱动方式、字符取模方法,以及SPI通信和寄存器操作的代码解读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、我的OLED屏及开发环境简介

        我用EPS32S3开发板,Platformio工具,Arduino代码框架进行开发。

        淘宝上买的便宜0.96寸OLED板子128*32,蓝黄双色(其实就是固定了0-8行黄色,剩余蓝色像素,不能自己选择哪儿显示不同颜色),6线SPI接口,接口这个应该是容易让大家混淆的。

        根据芯片手册,IIC和SPI都是用SSD1306这个驱动芯片,淘宝厂家将其组装成模块过程通过不同的布线可以生产出不同的接口。我这块没有CS(片选线),经研究,其CS已经接地了,永远是低电平。D1是MOSI(ESP32S3的13脚),D0是SCK(接12脚),VCC接3.3V。因此,SPI协议是无法读取SSD1306的,只能单向写入。

二、驱动原理和字符取模简介

2.1、驱动原理        

        OLED液晶屏硬件的显像原理可以看这家厂家的文章:

        https://www.dragonlcm.com/22265.html

        行叫COM,阴极,接地,SSD1306自动控制每行依次接通,不需要我们控制。

        列叫SEG,阳极,通过写入的0和1控制通断。

        由于这是单色屏幕,显像原理就是芯片每次控制一行通,该行上有128个像素点,其0和1的信息记录在SSD1306的GDDRAM上,由芯片自动控制从GDDRAM读取并显示在OLED上,GDDRAM上是什么样的图形方向,OLED上就怎样显示,除非配置寄存器故意搞镜像。

2.2、字符取模

        这个图来自官方手册,再怎么认真理解都不为过,因为容易让人混乱。这个图讲的是编程时如何写图形信息入GDDRAM。这儿引入页这个概念是方便的。一页就是8行,每行128个像素点,至于为何是8行,应该与行业诞生时的一些环境有关,ASCII的一个字符能在8行里面显示出来,8也是一个byte。

        打开PCtoLCD取字模软件(网上容易获得),取个A,8x8像素:

                       

        从左列至右列逐列取模结果是{0x20,0x10,0x0C,0x0A,0x0C,0x10,0x20,0x00},注意最上行像素点是字节的低位。按照这个方式将上述字节自左至右逐列填入GDDRAM,就能正常方向显示A字。按照8x8这个字符大小布局,一页从左至右可以刚好显示16个英文字符,填满一页,页的概念是方便我们写入字。

        

三、代码和数据手册解读

3.1、如何传入数据

        传统spi模式的话,有CS引脚,拉低CS后就可传输一个byte的字节。但我的模块是没CS,所以省去拉低CS这一步,任何时候想写就写信息。传寄存器操作命令时,先将DC引脚拉高,然后直接写1byte寄存器命令进去;传图像数据给GDDRAM时,DC拉低,直接写1byte数据进去。MCU的SPI传输模式用默认的,就是LSBfirst,SCK上升沿采样。

        SSD1306的寄存器操作逻辑类似一级菜单和二级子菜单这样。所以会有单字节命令、双字节命令和多字节命令。

        这儿截图有2个操作命令。第一个对比度配置命令是双字节命令,需要先SPI传输0x81,然后马上传输0x7F,就能将对比度调成118(范围是0~255)。0x81是类似一级菜单,打开了这个菜单才能进入下一级子菜单设置具体对比度数值。图中凡是A0、A1、X0这些位都是允许用户自己填数值的。他已经写上1或0的位置是不允许自行修改数值。

        第二个Entire display on配置是单字节命令,1至7位都已经厂家定好了,只能修改0位,所以这儿只能有2种配置选择,第0位值为1或0,对应的整个字节命令值就是0xA4或0xA5。

3.2、寻址模式

        寻址模式比较少人讲得深入,其实这儿涉及的是从MCU按什么顺序写入GDDRAM的事,不是芯片如何从GDDRAM搬到OLED上的事。

        (1)页寻址

        这个是默认的模式。特色用途就是方便玩家灵活控制整个屏幕上哪个区域写入信息,中间一块、边角一块都行,尤其适用于写入文字。像绿色箭头所示,同一页内,自左至右逐列从MCU写入图像信息到GDDRAM,写入第一列后,芯片自动控制指针到第二列,玩家不用控制,一口气将128byte信息连续不间断写入即可。第128列写完后,列指针跳回到第0列,但页指针不懂得往下移动到下一页,这是页寻址模式跟横向寻址模式的最大区别,页寻址模式需要玩家手动输入命令0xB1后,才能从0页跳到1页继续写入信息。如果页不跳动,就能约束在同一水平区域上不断刷新图像信息,而屏幕其他区域信息不改动这样的效果。

        (2)横向寻址

        

        横向寻址模式,特色用途是整个屏幕一齐刷新画面信息,适用于整个屏幕的图像显示,或视频这种场景。上图的横向绿色箭头跟页寻址一样,先是自左至右写完一页GDDRAM,芯片会控制页指针自动跳到下一页开头继续写,这样写满整个屏幕所有像素点。对于玩家来说,代码是最简单的,不用任何控制,无脑不间断输入128像素点的信息即可。

        (3)竖向寻址

        这个跟横向类似,不解读了。

3、寄存器详解

        (1)初始化配置

        这三张图先讲,因为代码也是先用这三张图。这三个表格的寄存器都是配置用的,大部分是初始化时做一次就行。玩家要先调好初始化这几个寄存器的参数,把图像调正再做下一步。

        其实芯片手册最后一页有个流程图就完整讲了初始化要配置哪些寄存器,我就不再重复,看代码:

void init_ssd1306()
{
  digitalWrite(pinRES,LOW);
  delayMicroseconds(4);
  digitalWrite(pinRES,HIGH);
  writeCMD(0xA8,0x3F);  //MUX ratio 64
  writeCMD(0xD3,0x00); //Display offset
  writeCMD(0x40); //Display startline
  writeCMD(0xA1); //segment remap
  writeCMD(0xC8); //COM scan directionv从0-N
  writeCMD(0xDA,0x02); //COM pin是否交替开通
  writeCMD(0x81,0x8F); //对比度范围0-255
  writeCMD(0xA4); //display on
  writeCMD(0xA6); //是否反色显示
  writeCMD(0xD5,0xF0);//设置晶振频率以及分频,不分频,最快频率
  writeCMD(0x8D,0x14);//电荷泵打开
  writeCMD(0x20, 0x02); // 用页寻址模式
  writeCMD(0xAF); //display on
  delay(100);
}

        RES引脚拉低由拉高是手册说的开机上电的步骤。

        Set Contrast Control设置对比度,0~255,不进行初始化也没问题。

        Entire Display On这个容易与Set Display On/Off 这个命令混淆。Entire On其实就是将全屏所有像素点都点亮,就是整个GDDRAM都填满1,应该容易想象出来。而Set Display On/Off就是真正意义上的亮屏、熄屏。下图是Entire Display On的画面。

entire display on

        Set Inverse Display像素反转,1和0反转。

        Set Display On/Off上面已提及,注意亮屏熄屏有个时间延迟,毫秒级的。

        Set Display Start Line就是设置图像内容的第一行显示在屏幕的第x行。

        Set Segment Re-map就是列的镜像颠倒,就是图像左右颠倒,照镜。

        Set Multiplex ratio就肯定是设置满屏64行了,这个英文我不了解,应该是设置图像在屏幕显示的区域大小。

        Set COM Output Scan Direction其实这个就是行的镜像颠倒,图像上下颠倒。

        Set Display Offset图像向下位移多少行。这个跟StartLine不一样的是,如果图像下方移出屏幕边缘,会接着在屏幕上面区域显示。

        Set COM Pins Hardware Config,比如一个A字原本是8行,如果设置了alternative COM pin config,A的字符会变成4行显示,中间间隔行被抽走了。

        Set Diaplay Clock Divide, Frequency,这个就不用管了,设置最快就行, 当然有的场合要考虑功耗。

        Set Pre-Charge Period,用默认设置就行。

        Set Vcomh Deselect Level,其实这个是怕不显示像素的屏幕黑色区域有泛白光,不够黑而做的反向电压,默认值也很够了,不用设置。

(2)寻址和写入的命令

       从MCU写信息到GDDRAM过程,需要用这些寄存器指令。

       Set Lower Colum Start Addr 和High Column这两个一起看。只有页寻址模式才能用,是控制在一页里面哪列开始写数据,其实也相当于将一页里面的图像右移多少像素的意思。Lower column相当于小数,Higher Column相当于整数,两个加起来就得出要移动多少像素。Lower columnn控制右移1-16像素,而Higher column每加1,都令图像右移16像素。有时你认为只需要右移10像素就够,就可以不写Higher Column这个寄存器的命令了,仅写Lower column的0x0A命令就可。两个命令不是要求必须同时配置成0x00的,可以只配置其中一个。

(3)屏幕滚动

        

        这个是多字节寄存器。要一口气写入7条命令。一次要滚动至少一页。记得设置完任何的滚动配置后,还要再来一条激活滚动的命令0x2F。如果取消激活0x2E,图像不会在当前位置停下,而是回到最开始安放的位置。

斜滚动

<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值