1.0 ST7735s 芯片简介

st7735s 132RGB x 162 点 262k 色,带帧存储器的单芯片 TFT 控制器/驱动器

ST7735s 使用 SPI 通讯接口可以将显示数据存储到芯片内部的显示 RAM 中,其容量位 132 162 18 位。

[分辨率]

其支持的分辨率为 132Bits 162Bits RGB

[显示模式]

  • 全彩色 (Full Color):262K,RGB=(666)
  • 真彩色 (Color Reduce):8色,RGB=(111)

[显示特性]

  • 软件可编程色彩深度模式
  • 局部窗口移动和数据滚动功能

2.0 电气连接&STM32引脚配置

我这里使用的是一块集成了编码器的 1.8inc 屏幕:

引脚功能
BLK背光信号,文本例程不包含背光控制
CSSPI 片选
DC数据模式选择信号,1 -> 写命令/ 0 -> 写数据
RST复位信号
SDASPI 数据线,ST7735s 作从机,接主机的 MOSI
SCLSPI 时钟线
VDD供电引脚,兼容 5V&3.3V
GND接地

本文基于 STM32401CCU6 HAL 库,采用硬件 SPI + DMA 的方式发送数据。

  • APB 总线时钟频率配置为 84MHz。

  • 使用 SPI1_CH1,PA5->SCK/PA6->SPI1_MOSI/PA7->SPI1_MISO,这里我没有实现硬件片选,IO 配置为推挽输出手动操纵片选信号。

  • 配置三个推挽输出引脚用于 ST7735s 的 DC/CS/RST 引脚,PC13 用于操控指示灯。

  • 开启 DMA 连接到 SPI1_TX,这里 ST7735s 作为从机不会向主机发送信号,这里的 DMA 仅需要 TX 不需要 RX。

  • 使用外部时钟,开启 SWD 调试接口,开启 USART1 用于串口调试。



  • 上述配置完毕后 GENERATE CODE 生成代码,关于生成平台和 CubeMX 生成配置此处不赘述。

3.0 ST7735s 控制流程

flowchart TD A[启动] --> B B[复位] --> C C[初始化、配置参数] --> D D[控制现存]

3.0.5 SPI 基本操作功能封装

根据前表可知,ST7735s 通过 DC 引脚控制数据&命令模式,结合软件控制 CS 引脚将其封装成指令&数据发送函数。

  • 发送指令
void st7735s_sendCommand(uint8_t command) {
    st7735s_setNSS(GPIO_PIN_RESET);    // 拉低 CS 引脚,SPI 开始通讯
    HAL_GPIO_WritePin(ST7735S_DC_GRP, ST7735S_DC_PIN, GPIO_PIN_RESET);    // 将 DC 引脚置低代表传输的是指令
    HAL_SPI_Transmit(&hspi1, &command, 1, 0xFFFF);    // 调用硬件 SPI 发送数据
    st7735s_setNSS(GPIO_PIN_SET);    // 释放 CS 引脚,结束 SPI 通讯
}
  • 发送数据
void st7735s_sendData(uint8_t data) {
    st7735s_setNSS(GPIO_PIN_RESET);    // 拉低 CS 引脚,SPI 开始通讯
    HAL_GPIO_WritePin(ST7735S_DC_GRP, ST7735S_DC_PIN, GPIO_PIN_SET);    // 将 DC 引脚置高代表传输的是数据
    HAL_SPI_Transmit(&hspi1, &data, 1, 0xFFFF);    // 调用硬件 SPI 发送数据
    st7735s_setNSS(GPIO_PIN_SET);    // 释放 CS 引脚,结束 SPI 通讯
}

3.1 复位信号

上表可知 Reset Pulse Duration(复位脉冲持续时间) 最小为 10us,Rest Cancel(复位取消) 最大时间为 5ms,并且复位后最好等待 120ms

因此这里拉低 RST 引脚 1ms 后等待 120ms 再进行后续操作即可

/* *.h */
#define ST7735S_RES_H       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET)
#define ST7735S_RES_L       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET)

/* *.c */
void st7735s_sendResetSignal(void) {
    ST7735S_RES_H;
    HAL_Delay(1);
    ST7735S_RES_L;
    HAL_Delay(120);
}

3.2 参数配置

3.2.1 0x11 退出睡眠模式

首先执行指令 0x11 退出睡眠模式,方便后续配置,值得注意的是当退出睡眠模式后,此指令不会再发生作用,如果想要使用则需要再次进入睡眠模式 0x10 实现。

当发送了指令退出睡眠模式后,需要等待 120ms 待电源电压和时钟电路稳定后再发送下一个命令&数据。

st7735s_sendCommand(0x11);
HAL_Delay(120);

3.2.2 帧率控制

这里的 0xB10xB3 寄存器用于配置不同屏幕模式下的帧率,这里的三个寄存器配置方式一致,因此这里只给出 0xB1 的图片和配置参考,后两个寄存器参数与第一个一致:

  • 0xB1:正常模式/全彩色彩
  • 0xB2:空闲模式/8 色色彩
  • 0xB3:部分模式/全彩色彩

这个配置项由三个 parameter 组成,每个 parameter 配置一个参数,不过这里不太一样,下面会解释:

RTNA 这个参数占该寄存器的低四位,在配置这个参数前我们先看手册中给出的信息可知,这三个参数作为一个公式的变量存在,最后计算得到当前模式下的刷新率:

$$ \frac{fosc}{(RTNA \times 2 + 40) \times (LINE + FPA + BPA + 2)}= FrameRate $$

  • FrameRate 最终得到的刷新率
  • fosc 这是一个固定值 850kHz
  • FPA 和 BPA 的值大于 0

RTNA、FPA、BPA 这三个值由我们配置寄存器控制,LINE 是每行像素数量,我的屏幕是 160 (横向分辨率)

得到了上面的条件后在我们配置寄存器前先计算一下参数:

我们想将屏幕配置为 60Hz 根据公式可得:

$$ \frac{850000}{(RTNA \times 2 + 40) \times (160 + FPA + BPA + 2)}= 60 $$

整理可得

$$ 14166.66 = (2 \times RTNA + 40) \times (162 \times FPA \times BPA) $$

下面我们只需要找到三个参数满足上述上述式子并且 FPA 和 BPA 大于 0 即可,我们先假设 RTNA = 5

$$ 14166.66 = 50(162 \times FPA \times BPA) $$

$$ FPA + BPA = 121.33 $$

现在的式子显而易见 FPA 取 60 BPA 取 61 即可。

此时再回到寄存器表中 RTNA 取 5 -> 0101 -> 0x05,FPA 取 60 -> 111100 -> 0x3C,BPA 取 61 -> 111101 -> 0x3D

0xB20xB3 使用同样的参数进行配置。

/* Frame Rate Control - 帧率控制 */
st7735s_sendCommand(0xB1);  // Frame Rate Control - In normal Mode/Full colors
st7735s_sendData(0x05);
st7735s_sendData(0x3C);
st7735s_sendData(0x3C);

st7735s_sendCommand(0xB2);  // Frame Rate Control - In Idle mode/8 - colors
st7735s_sendData(0x05);
st7735s_sendData(0x3C);
st7735s_sendData(0x3C);

st7735s_sendCommand(0xB3);  // Frame Rate Control - In Partial mdoe/full colors
st7735s_sendData(0x05);
st7735s_sendData(0x3C);
st7735s_sendData(0x3C);

3.2.3 0xB4 显示反转控制

这个寄存器用于控制在各个模式下的像素反转方式,可以减少闪烁和提高显示质量;其有三个参数每个占一位:

  • NLA:正常模式/全彩色彩
  • NLB:空闲模式/8 色色彩
  • NLC:部分模式/全彩色彩

每一位置 0 代表点反转,1 代表列反转。其中点反转是用于大部分情况,这里全部置 0 -> 0x00

/* Display Inversion Control - 显示反转控制 */
st7735s_sendCommand(0xB4);
st7735s_sendData(0x00);

3.2.4 电源控制

[0xC0 Power Control 1 - 电源控制 1]

手册第 163 页

手册第 163 页

0xC0 的寄存器手册如图,可见需要配置的参数比较多,该寄存器主要用于配置显示器的工作电压和模式,并且显而易见 C0H 列有五行,有三行参数可以配置,下面按照顺序介绍每行参数和每位的作用。

  • [1st Parameter]

AVDD 首先是该寄存器的高三位配置参数:AVDD 这是一个三位字段,用于配置模拟电源电压,用为液晶显示器提供驱动电压,根据表可得其有 8 种组合,对应的电压值为 4.5v5.2v(步长 0.1v)

至于如何配置该位需要取决于你的硬件设计和显示需求,如果需要更高的亮度和对比度可以选较高的值:111 -> 5.2v。相反如果需要较低的功耗等则可以选择较低的电压。

不过此处我们采取一个中间值:100 -> 4.9v 作为我们的配置。

VRHP 占用了剩下的五位,其作用是正参考电压高电平,它影响到了显示器内部的电压调节器的工作范围,正确的设置该参数有助于确保色彩和对比度的正确。

首先根据手册可得,该位的配置分为了两个部分,首先 VRHP 的最高位用于配置 GVDD 的两种可选范围,我们也能看到当 VRHP 最高位为 1 时 GVDD 仅有六位有效位,其在范围上远不如为 0 时的范围(32 位)这种分段设计允许用户在较宽的范围内灵活调整 GVDD,同时保留了一个小范围的高电压的选项。

这里我们选用 GVDD 范围较宽的配置,VRHP 最高位置 0

如上,VRHP 最高位为 0 后,低四位就有了 32 种组合,对应 GVDD 的范围为:4.7v3.15v,步长为 0.05v,这里的配置与上一步配置 AVDD 时相同,如果需要更高的对比度或亮度等则可以配置更高的 GVDD 值反之亦然。

因此与 AVDD 配置时相同,我们选用一个中间值:01000 -> 4.3v 作为我们的配置。

结合上述文字,VRHP 部分的配置就为:001000

到此 针对 1 parameter 的配置解析就完成了,不过在我们将数据写入到寄存器之前还有一个细节需要注意,前文我们提到 AVDD 需要三位用于配置,而在介绍 VRHP 的时候提到了通过 VRHP[5] 配置电压范围,这里的 5 很关键,这代表了这一个参数配置需要使用 6 位的空间?这明显不对,与 AVDD 的配置数据加起来明显超了!再次查表发现 VRHP[5] 被放在了 3rd parameter 的最低位中,同样后文要讲的 VRHN[5] 也在这配置,所以需要要将刚刚配置好的 VRHP 001000 中的最高位摘取出 1 位,即 01000 与 AVDD 的配置位合并写入到第一个数据包中:10001000 -> 0x88

  • [2nd Parameter]

VRHN 第二个数据包就比较简单了,仅有低 5 位用于配置 VRHN 与刚才讲到的 VRHP 相反,用于配置负参考电压高电平,该参数的影响前文也提到了,若想拥有用户需要的显示效果则需要正确配置这两个参数。

VRHN 的配置方式与 VRHP 的配置方式完全相同,这里就不再赘述了,不过值得注意的是它的 VRHN[5] 同样在第三个数据包中 (在第三个数据包中还会提的)

同样的我们采用中间值作为我们的配置:01000 -> 4.3v 作为我们的配置。

到此 第二个数据包就配置完成了,根据手册高三位写 0 低五位写 01000 即为 00001000 -> 0x08

  • [3rd Parameter]

MODE 这是一个两位字段,占用寄存器高两位进行配置,用于控制电源模式,其有四种合。

其中表中标注了 0111 该两位作为保留位并不建议使用Don't use this setting!

那么此时仅剩两个配置项:00 -> 2X 模式和 10 -> AUTO 模式

  • 00 可以将倍压电路设置工作在 2 倍增压模式。
  • 10 可以自动调整倍压电路的工作状态,根据负载动态优化功耗和性能。

可见既然提供了 AUTO 模式,无脑配置为 AUTO 也可以适应绝大多数应用场景。

到此 我们配置好了 0xC0 的所有参数,并且将我们上述提到的 VRHP 和 VRHN 的范围控制位和 MDOE 配置位打包写入即可完成配置,根据手册可得 MODE 写入到高两位,另外两个参数 (均为 0) 写入低两位,其余位根据手册要求 [D5 - D2] -> 0001

最终得到 10000100 -> 0x84,结合上面的配置,针对 0xC0 的配置数据包即为 0x880x080x84

[0xC1 Power Control 2 - 电源控制 2]

手册第 165 页

手册第 165 页

0xC1 同样是电源配置寄存器,不过它需要发送的数据包还是比较少的 (发送一个就行),首先介绍一些该寄存器的功能,它主要用于控制 VGH 和 VGL 的供电电平,这些电压直接影响到显示器的驱动能力和功耗。

  • VGH:正高压,用于驱动液晶单元的开启状态。
  • VGL:负低压,用于驱动液晶单元的关闭状态。

下面我们优先介绍位于 D3D2 位的 VGHBT 这个参数直接影响 VGH 的输出,VGH 的值通常会带来更高的对比度和更快的相应速度,但是可能会增加功耗。

这是一个两位的参数,共有四种配置选项:

  • 00 -> $2 \times AVDD + VGH25 - 0.5$
  • 01 -> $3 \times AVDD - 0.5$
  • 10 -> $3 \times AVDD + VGH25 - 0.5$
  • 11 -> 不推荐使用,保留用于测试

可以看到关于 VGH 的值有三种可用的配置公式,其中涉及到 AVDD 和本寄存器中可以配置 VGH25。

在我们的配置中,还是选择一个平衡的方案进行配置,这里选用计算较为简单的 $3 \times AVDD - 0.5$ 方案 -> 01 根据前文的配置可以知道 AVDD 我们配置为了 4.9v 我们已知了所有的参数,但是现在并不要着急计算该式子的值,我们继续往下看寄存器的配置。

VGLSEL 该参数同样有四种配置选项,其不用计算直接控制 VGL 的输出:

  • 00 -> -7.5
  • 01 -> -10
  • 10 -> -12.5
  • 11 -> -13

一样的理念,采用 -10v -> 01 作为一个平衡的选择。

现在我们已经有了计划好的 VGH 和 VGL 我们还需要注意一件事情,手册中提到:

$VGH - VGL \le 32V$ 这个条件限制了 VGH 和 VGL 之间的差值不能超过 32V 这一限制可以保护液晶显示器中的电子元件。

根据上述的限制我们计算一下刚才选择的配置是否合理。

$$ VGH = 3 \times 4.9 - 0.5 = 14.2V $$

$$ VGL = -10V $$

将二者相减可得 24.2V 满足限制条件。

现在我们配置好了两个参数,还有一个参数 VGH25 并未配置,虽然它会在 VGHBT 中参与运算,但是本次我们并未选用,不过该位置也要配置一个参数防止未来切换配置或者硬件中存在以来该值的位置。

对照手册将其设置位一个平衡值 2.2 -> 01 即可。

综上所述根据手册的要求将 VGH25 置于高两位,VGHB 和 VGLSEL 按照顺序置于最低位,其余位置 0 即可 01000101 -> 0x69

[0xC2 Power Control 3 - 电源控制 3]

手册第 167 页

手册第 167 页

与 Power Control 1 寄存器类似,它由两个数据包配置,一共控制三个参数。

  • [1st Parameter]

DCA 首先,我们先看第一个 parameter 的高两位,是 DCA9DCA8 如果此时关注一下第二个 parameter 就能发现还有 DCA7DCA6 很显然这个参数的配置有一点不一样!不过在配置这个参数之前需要了解这一位是做什么的:DCA 用于将升压电路的升压周期设置为正常模式或全彩模式,具体来说它通过调整升压时钟 (BCLK) 的分频系数来控制升压电路的工作频率,关于这个参数配置我们需要重点关注一下手册中提供的表格。

首先从位于第一个 parameter 高两位的 DCA[9:8] 看起,这一位用于配置整体的分频系数的范围,它决定了升压电路的基本工作频率范围,在该参数选定后后续的参数用于调节每一个部分的分频比例。

DCA[9:8] 有四种选择,对应了四种范围,如何判断范围呢?这张表需要以行为单位看,比如 DCA[9:8] = 00DCA[7:0] 的可选项就已经配置好了 BLCK/3BLCK/1BLCK/1BLCK/1,根据表可得:

  • BLCK/1 -> 00
  • BLCK/3 -> 01
  • BLCK/2 -> 10
  • BLCK/4 -> 11

BLCK/3BLCK/1BLCK/1BLCK/1 -> 01_00_00_00

在确定好了后续可以选择的范围之后我们着重关心的就是 DCA[9:8] 的选择了,此时众多的分频频率到底是如何影响最终的显示效果的?前面我们在配置 VGH 和 VGL 的时候看到这两个参数配置好后往往需要 4/5V 以上的电压,这就依赖升压电路来提供所需电压:

  • 较高的分频值就意味着更长的升压周期,通常会降低功耗但是可能会导致升压效率的下降。
  • 较低的分频值就意味着更快的升压周期,通常能提供更高的升压效率,但是可能会增加功耗。

了解了上面的信息后,对于参数的配置就豁然开朗了,我们还是选择平衡的配置选项,首先将分频范围限制在 BCLK/1BLCK/3 之间,对应 DCA[9:8] -> 00

在这种范围限制下表格给出了如下分配分频配置:

  • DCA[7:6] -> BCLK/3 -> 01
  • DCA[5:4] -> BCLK/1 -> 00
  • DCA[3:2] -> BCLK/1 -> 00
  • DCA[1:0] -> BCLK/1 -> 00

综上所述针对 DCA[9:0] 的配置应该为 0001000000 由于我们先构建第一个 parameter 因此只抽取 DCA[9:8] -> 00

AP 这个参数占用了寄存器的低三位,共有 8 种组合,用于配置运算放大器中的电流量。运算放大器在液晶显示器中用于信号放大和电压调节,通过调整运算放大器的电流量可以调整显示效果、功耗和响应速度。

  • 000 -> 运算放大器停止工作
  • 001 -> 小电流
  • 010 -> 中低电流
  • 011 -> 中电流
  • 100 -> 中高电流
  • 101 -> 大电流
  • 110 -> 保留/不使用
  • 111 -> 保留/不使用

根据上述的数据显而易见,最后两种组合为保留组合并且如果关闭了运算放大器可能会导致显示器无法正常工作,根据文字叙述我们采用中等电流 011 即可。

SPA 手册中同样提供了这个参数的表格,可见他跟 AP 的配置完全一样,它的作用是控制源极驱动电路中的运算放大器电流量,虽然与 AP 名字上有所不同,但是功能上大抵相同这里不再赘述直接使用 AP 的配置 011

至此第一个数据包就构建完毕了由两位 DAC 参数 00 加三位 SPA 和 两位 AP 参数构成 00011011 -> 0x1B

  • [2nd Parameter]

根据一个数据包构建时的分析来看,这第二个数据包就很简单了,将剩余的分频配置写入即可 01000000 -> 0x40

[0xC3 Power Control 4 - 电源控制 4]

手册第 169 页

手册第 169 页

这个部分的配置整体上与 0xC2 的配置相同 0x1B0x40

[0xC4 Power Control 5 - 电源控制 5]

手册第 171 页

手册第 171 页

同样的这里的配置比较无趣,与上面相同 0x1B0x40

[0xC5 VCOM Control 1]

手册第 173 页

手册第 173 页

VCOM 控制,该寄存器仅配置一个参数,VCOM 电压,VCOM 是显示器中公共极电压,其对显示效果有重要影响具体会影响闪烁、对比度和色彩均匀性。

  • 闪烁:过高的 VCOM 电压会导致屏幕闪烁,过低会导致图像暗淡或出现色彩偏差。
  • 对比度:适当的 VCOM 电压会增强图像对比度,使颜色更加鲜明。

手册提供了详细的配置项和电压的对照表,这里选用位于中间的 -1.2v -> 011111 -> 0x1F

由于该配置项占低位因此空余位置全部写 0 该寄存器配置为 0x1F 即可。

[0xC5 VCOM Offset Control]

手册第 175 页

手册第 175 页

这是电源配置部分的最后一个寄存器,用于配置 VCOM 偏移量,微调 VCOM 电压,功能上与上一个寄存器相同,或者说这两个寄存器配置的都是同一个参数,这个参数分为两个部分;此外手册中提到如果需要使用这个参数需要将位于 0xD9VMF_EN 位置 1

  • VMF[4]:用于控制偏移方向 0 正向偏移,1 负向偏移。
  • VMF[3:0]:配置具体的偏移量,从 +16d-15d

由于这里是用于微调 VCOM 参数的,这里根据需要开启和配置参数进行调整,本例中就不开启这个参数了。

[电源配置 - 代码]

到这里电源部分就配置完毕了,代码部分如下:

/* Power Contrl - 电源配置 */
st7735s_sendCommand(0xC0);  // Power Control 1
st7735s_sendData(0x88);
st7735s_sendData(0x08);
st7735s_sendData(0x84);

st7735s_sendCommand(0xC1);  // Power Control 2
st7735s_sendData(0x69);

st7735s_sendCommand(0xC2);  // Power Control 3
st7735s_sendData(0x1B);
st7735s_sendData(0x40);

st7735s_sendCommand(0xC3);  // Power Control 4
st7735s_sendData(0x1B);
st7735s_sendData(0x40);

st7735s_sendCommand(0xC4);  // Power Control 5
st7735s_sendData(0x1B);
st7735s_sendData(0x40);

st7735s_sendCommand(0xC5);  // VCOM Voltage
st7735s_sendData(0x1F);

3.2.5 0x36 配置显存数据访问方式

[地址顺序配置 - 高三位]

  • MY:行地址顺序 - 如果希望图像上下反转此位置高

    用于控制行地址顺序是否反转 MY 置高则行地址顺序将被反转(即从最后一行开始到第一行)

  • MX:列地址顺序 - 如果希望图像左右反转此位置高

    这一位用于控制列地址是否反转其功能与 MY 位功能一致不再赘述。

  • MV:行列地址顺序交换 - 如果希望图像旋转 90°/270° 此位置高

    当此位被置高时,原本的行地址将作为列地址使用,列地址将作为行地址使用;通常的表现时屏幕内容向左或者向右旋转了 90°

这三位搭配使用可以用于配置屏幕内容的方向,以便适应不同的硬件布局等;本例中不需要特殊布局全部置 0

[ML 垂直刷新方向配置]

此位用于配置屏幕的垂直刷新方向,默认(0)位从上到下刷新屏幕;配置为 1 后变为从下到上刷新屏幕;此处使用默认刷新方向配置为 0

[RGB&BGR 颜色选择开关控制]

此位配置位低使用 RGB 模式,配置为高则为 BGR 模式,此处使用 RGB 模式配置为 0注意,屏幕色彩如果出现问题则可以优先检查程序中使用的 RGB 模式与配置的模式相同

[MH 水平刷新方向配置]

此位作用与 ML 位相同,配置水平刷新方向,配置为 0 则为从左向右刷新,配置为 1 则为从右向左刷新,此处使用默认配置为 0

由于我打算竖着用这块屏幕所以将其上下左右翻转 0xC0

/* Memory Data Access Control - 显存数据访问方式 */
st7735s_sendCommand(0x36);
st7735s_sendData(0xC0);

3.2.6 Gamma 矫正

[正 Gamma 矫正]

这个配置这个指令所需要的 parameter 比较多,足足有 16 个,但是仔细看一看给出的寄存器表格就可以发现实际上一共配置了三个参数:

  • VRF0P[5:0] - 6 位二进制值,用于调整高电平可变电阻 VRHP,较大的值可以提高最高灰度级的亮度,但可能会导致过曝。
  • PK0P[5:0] ~ PK9P[5:0] - 这些参数用于配置不同灰度级别上的表现,可以精细调整这里的参数用于获得更好的显示效果。
  • SELVOP[5:0] ~ SELV63P[5:0] - 6 位二进制值,用于选择不同灰度级的电压,影响颜色显示的准确性和均匀性,这里可以参照标准 Gamma 曲线进行设置。
  • VOS0P[5:0] - 6 位二进制值,用于调整低电平可变电阻 VRLP,较大的值可以提高最低灰度级的亮度,但可能导致黑场不纯。

[负 Gamma 矫正]

由于负 Gamma 矫正配置的是当像素电平较低时的参数,因此与正 Gamma 矫正使用同样的参数。

综上 Gamma 配置部分我直接采用了别人验证好的一套参数,代码如下:

/* Gamma Correction Characteristics Setting - Gamma 矫正设置 */
st7735s_sendCommand(0xE0);  // 正极性 Gamma 校正
st7735s_sendData(0x20);     // VRF0P = 0x20
st7735s_sendData(0x00);     // SELV0P = 0x00
st7735s_sendData(0x02);     // SELV1P = 0x02
st7735s_sendData(0x04);     // SELV2P = 0x04
st7735s_sendData(0x08);     // SELV3P = 0x08
st7735s_sendData(0x0E);     // SELV4P = 0x0E
st7735s_sendData(0x12);     // SELV5P = 0x12
st7735s_sendData(0x1A);     // SELV6P = 0x1A
st7735s_sendData(0x24);     // SELV7P = 0x24
st7735s_sendData(0x2A);     // SELV8P = 0x2A
st7735s_sendData(0x30);     // SELV9P = 0x30
st7735s_sendData(0x36);     // SELV10P = 0x36
st7735s_sendData(0x3C);     // SELV11P = 0x3C
st7735s_sendData(0x3F);     // SELV12P = 0x3F
st7735s_sendData(0x00);     // SELV13P = 0x00
st7735s_sendData(0x00);     // SELV14P = 0x00

st7735s_sendCommand(0xE1);  // 负极性 Gamma 校正
st7735s_sendData(0x04);     // VRF0N
st7735s_sendData(0x16);     // SELV0N
st7735s_sendData(0x06);     // SELV1N
st7735s_sendData(0x0D);     // SELV2N
st7735s_sendData(0x2D);     // SELV3N
st7735s_sendData(0x26);     // SELV4N
st7735s_sendData(0x23);     // SELV5N
st7735s_sendData(0x27);     // SELV6N
st7735s_sendData(0x27);     // SELV7N
st7735s_sendData(0x25);     // SELV8N
st7735s_sendData(0x2D);     // SELV9N
st7735s_sendData(0x3B);     // SELV10N
st7735s_sendData(0x02);     // SELV11N
st7735s_sendData(0x03);     // SELV12N
st7735s_sendData(0x06);     // SELV13N
st7735s_sendData(0x13);     // SELV14N

3.2.7 0x3A 接口像素格式

这个寄存器用于配置每位像素使用的颜色深度,这会影响显示颜色的质量和数据传输效率,这个寄存器只有一个参数 IFPF 根据表可得:

  • 011 -> 12-bit
  • 101 -> 16-bit
  • 110 -> 18-bit
  • 111 -> 未使用

这里使用最常用的 16bit 色彩深度 101 -> 0x05

/* Interface Pixel Format - 接口像素格式 */
st7735s_sendCommand(0x3A);
st7735s_sendData(0x05);

3.2.8 0x29 开启显示

到了这里 ST7735s 的初始化配置流程就结束了,最后发送 0x29 命令即可开启显示。

3.3 屏幕坐标位置控制

由于我使用的屏幕分辨率为 128 * 160 因此在这个屏幕中表示坐标仅需要两个八位数据即可,同理如果需要表示一个范围直接使用四个八位数据即可。在 ST7735s 中使用 0x2A0x2B 分别表示 x 范围和 y 范围。由于我们只用到了每个寄存器的低八位进行传输,因此两个寄存器不使用的部分填充 0 即可。

st7735s_sendCommand(0x2A);  // Cloumn Address Set
st7735s_sendData(0x00);
st7735s_sendData(xStart);
st7735s_sendData(0x00);
st7735s_sendData(xEnd);

st7735s_sendCommand(0x2B);  // Row Address Set
st7735s_sendData(0x00);
st7735s_sendData(yStart);
st7735s_sendData(0x00);
st7735s_sendData(yEnd);

坐标范围配置好后通过发送 0x2C 指令后即可开始发送颜色数据,对坐标范围内的颜色进行配置。

void st7735s_write_address(uint8_t xStart, uint8_t xEnd, uint8_t yStart, uint8_t yEnd) {
    st7735s_sendCommand(0x2A);  // Cloumn Address Set
    st7735s_sendData(0x00);
    st7735s_sendData(xStart);
    st7735s_sendData(0x00);
    st7735s_sendData(xEnd);

    st7735s_sendCommand(0x2B);  // Row Address Set
    st7735s_sendData(0x00);
    st7735s_sendData(yStart);
    st7735s_sendData(0x00);
    st7735s_sendData(yEnd);

    st7735s_sendCommand(0x2C);
}

3.4 全屏颜色填充

从这里开始初始化的工作完成了,下面有一些简单的图形绘制示例展示,展示一些绘制方面的基本原理。

简单实现全屏颜色填充的逻辑比较简单,先发送需要填充颜色的区域后再循环向区域写入需要的颜色数据即可。

前面配置时提到了,我在这里将颜色深度配置为了 16bit 因此我们需要向其中传入一个 16bit 的颜色数据;这就需要一个通过 SPI 总线发送 16bit 数据的函数:

void st7735s_sendu16Data(uint16_t data) {
    // 将 16bit 数据拆分为两个 8bit 数据用于发送
    uint8_t dataH = (uint8_t)(data >> 8);
    uint8_t dataL = (uint8_t)(data & 0xFF);


    ST7735S_NSS_L;  // 拉低片选 - 开始通讯
    ST7735S_DC_H;   // 拉高 DC 代表的是数据
    // 先发送高字节,再发送低字节
    HAL_SPI_Transmit(&hspi1, &dataH, 1, 0xFFFF);
    HAL_SPI_Transmit(&hspi1, &dataL, 1, 0xFFFF);
    ST7735S_NSS_H;  // 拉高片选 - 结束通讯
}

然后根据上面描述的流程,先设置范围,再循环填充即可:

// 我选用了一个淡绿色作为测试 -> 0x8426

void st7735s_RefreshAll(uint16_t rgb) {
    st7735s_write_address(0, 127, 0, 159);      // 设置显示范围
    for(uint16_t j = 0; j < 160; j++) {         // 两个 for 遍历这个范围发送颜色数据
        for(uint16_t i = 0; i < 128; i++) {
            st7735s_sendu16Data(rgb);
        }
    }
}

[显示效果]

3.5 区域颜色填充

区域填充的原理与全屏一样,只不过是设置计算好的范围后再填充。

void st7735s_drawBlock(uint8_t x, uint8_t y, uint8_t len, uint16_t color) {
    st7735s_write_address(x, x + len - 1, y, y + len - 1);
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < len; j++) {
            st7735s_sendu16Data(color);
        }
    }
}

[显示效果]

3.7 画点

画点函数非常简单,简单视作绘制一个边长为 1 像素的正方形即可。

void st7735s_drawPoint(uint8_t x, uint8_t y, uint16_t color) {
    st7735s_write_address(x, x, y, y );
    st7735s_sendu16Data(color);
}

3.8 显示图片

待编写

3.9 LVGL 显示测试

待编写

END 参考与引用

[参考地址]

本文部分内容由 Ai 辅助生成