[Arduino] Nokia 5110 液晶屏

Nokia 5110可谓是相~ 当~ 经典了,你可以用它来打电话、砸核桃、挡子弹、锤钉子,居家防身,良心佳品~= ̄ω ̄=
它的屏幕因为某宝上只买八块八,八块八啊~ 物美价廉,受到广大青少年的追捧~

广告位招租

技术参数

  • 分辨率: 84 * 48
  • 通信协议: SPI
  • 液晶模块: LPH7366
  • 主控芯片: PCD8544
  • 传送速率: 最高4Mbits/s
  • 工作电压: 3.3v ~5.0v
  • 工作电流: ≤ 200μA

电路连接

Nokia 5110的屏幕使用的是SPI协议,但使用我图片中的屏幕模块,除了需要连接SPI的4条信号线外,还需要另外连接一个RST(重置)和BL(背光)。

Nokia 5110屏幕模块有下列引脚:

  • VCC,电源,输入3.3v ~5v
  • GND,公共接地,提供参考低电平
  • BL,屏幕背光,高电平时点亮,低电平时熄灭
  • DIN,SPI的MISO脚,向
  • DC,DATA/CMD,数据/指令选择,高电平时总线上传送数据,低电平时总线上传送控制指令
  • CLK,SPI的时钟脚
  • CE,SPI的片选脚,低电平时,单片机可对此设备读写,高电平时挂起此设备的通信
  • RST,重置屏幕
其死我是拒绝放这个图的,怎么都是蜘蛛网~🕸

上面的电路图太乱太难看,要理清的话,一半脑细胞都可以住进精神病院了。总之Nokia 5110的屏幕是SPI通信的,参考SPI的连接方法就对了。


SPI接线图

指令集

  • 空操作

    操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
    位值 0 0 0 0 0 0 0 0 0

    用于延时的空操作指令,没有任何作用

  • 写像素数据

    操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
    位值 D7 D6 D5 D4 D3 D2 D1 D0 1

    填充像素数据块,直接把数据写入液晶屏的GRAM中

  • 功能设置

    操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
    位值 0 0 1 0 0 EN VH IS 0
    • EN为屏幕开启开关:1 = 开启屏幕, 0 = 关闭屏幕
    • VH,寻址方式选择: 1 = 使用垂直寻址, 0 = 使用水平寻址
    • IS,指令集选择:1 = 使用扩展指令集, 0 = 使用扩基本指令集
  • 基本指令集

    • 显示设置

      操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
      位值 0 0 0 0 1 D 0 E 0
      • (D, E),显示方式枚举:(0, 0) = 显示空白, (0, 1) = 显示全黑,(1, 0) = 普通模式,(1, 1) = 翻色显示
    • 游标设置:GRAM写入起点X坐标,这里的X是以列(COLUMN)为单位

      操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
      位值 0 1 D5 D4 D3 D2 D1 D0 0
    • 游标设置:GRAM写入起点Y坐标,这里的Y是以页面(PAGE)为单位

      操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
      位值 0 1 0 0 0 D2 D1 D0 0
  • 扩展指令集

    • 温度系数

      操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
      位值 0 0 1 0 0 1 D1 D0 0
      • (D1, D0),显示方式枚举:(0, 0) = 温度系数0, (0, 1) = 温度系数1,(1, 0) = 温度系数2,(1, 1) = 温度系数3
      • 这是用来干嘛用的~(←_←)
    • 偏置混合率

      操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
      位值 0 0 0 1 0 D2 D1 D0 0
      • (D2, D1, D0), 偏置混合率:
        • (0, 0, 0) = 1:100
        • (0, 0, 1) = 1:80
        • (0, 1, 0) = 1:65
        • (0, 1, 1) = 1:48
        • (1, 0, 0) = 1:40/1:34
        • (1, 0, 1) = 1:24
        • (1, 1, 0) = 1:18/1:16
        • (1, 1, 1) = 1:10/1:9/1:8
    • 操作电压

      操作位 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 DC
      位值 0 D6 D5 D4 D3 D2 D1 D0 0
      • (D6, D5, D4, D3, D2, D1, D0)为操作电压的系数
      • LCD偏置电压根据(D6, D5, D4, D3, D2, D1, D0)计算得值为

        VLCD = 3.06 + 0.06 * VOP = 3.06 + 0.06 * (D6, D5, D4, D3, D2, D1, D0)2

初始化流程

  • 拉低RST脚500ms,以重置屏幕
  • 使用扩展指令
    • 设置偏置混合率为4 = (1, 0, 0)2 = 1:40/1:34
    • 设置操作电压VOP40 = 5.46v,用以调节对比度
  • 使用基本指令集
    • 设置显示模式为普通模式
    • 设置游标X到0
    • 设置游标Y到0
    • 84 * 48 / 8个字节的0x00,以清屏

上面的初始化流程中给出了一些默认值,在实际使用的过程中,因为模块的不同,这些参数可能需要重新调整才能获得理想的显示效果

编码实现

我们使用Arduino的硬件SPI接口来和屏幕通信,所以我们需要使用Arduino内建的SPI库

初始化

#include <SPI.h>
#defineRST 15
#defineCE  10
#defineDC  12
#defineDIN 11
#defineCLK 13
#defineBL  16

#define INSTRUCTIONSET 0x20
#define INST_NORMAL    0x00
#define INST_EXTENDED  0x01
#define SETBIAS        0x10
#define SETVOP         0x80
#define DISPLAYCONTROL 0x08
#define DISP_BLANK     0x00
#define DISP_BLACK     0x01
#define DISP_NORMAL    0x04
#define DISP_INVERT    0x05
#define SET_CURSOR_X   0x08
#define SET_CURSOR_Y   0x04

const int bias     = 4;
const int contrast = 40;
byte buffer[84 * 48 / 8];

void setup() {
    // 初始化SPI
    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV4); // 4MHz
    SPI.setDataMode(SPI_MODE0);
    SPI.setBitOrder(MSBFIRST);

    // 初始化其他控制引脚
    pinMode(DC, OUTPUT);
    pinMode(RST, OUTPUT);
    pinMode(CE, OUTPUT);

    // 重置屏幕
    digitalWrite(RST, LOW);
    delay(500);
    digitalWrite(RST, HIGH);

    // 进入扩展指令集
    command(INSTRUCTIONSET | EXTENDED);
    // 设置偏置混合率
    command(SETBIAS | bias);
    // 设置偏置电压V~OP~
    command(SETVOP | contrast);

    // 进入基础指令
    command(INSTRUCTIONSET | NORMAL);
    // 设置正常显示模式
    command(DISPLAYCONTROL | DISPLAYNORMAL);
    // 设置游标(0, 0) = (column, page)
    command(SET_CURSOR_X | 0);
    command(SET_CURSOR_Y | 0);
    // 写入清屏数据
    memset(buffer, 0, 84 * 48 / 8);
    writeGram(buffer, 84 * 48 / 8);
}

写指令

#include <SPI.h>
#define RST 15
#define CE  10
#define DC  12
#define DIN 11
#define CLK 13
#define BL  16

void command(byte cmd) {
    digitalWrite(DC, LOW);
    digitalWrite(CE, LOW);
    SPI.transfer(cmd);
    digitalWrite(CE, HIGH);
}

写数据

#include <SPI.h>
#define RST 15
#define CE  10
#define DC  12
#define DIN 11
#define CLK 13
#define BL  16

void data(byte data) {
    digitalWrite(DC, HIGH);
    digitalWrite(CE, LOW);
    SPI.transfer(cmd);
    digitalWrite(CE, HIGH);
}

void writeGram(byte* buffer, int size) {
    digitalWrite(DC, HIGH);
    digitalWrite(CE, LOW);
    for (int i = 0; i < size; i++) {
         SPI.transfer(buffer[i]);
    }
    digitalWrite(CE, HIGH);
}

推荐阅读更多精彩内容