爱车的诺诺 2018-03-06
在裸板下使用 SPI 的话,有两种方法可选:
这里我们选用控制器的方式,简单方便。
static void SPIControllerInit(void) { /* 设置频率 */ SPPRE0 = 2; SPPRE1 = 2; /* 配置 SPI */ SPCON0 = (1<<4) | (1<<3); SPCON1 = (1<<4) | (1<<3); }
如手册所示,频率配置公式如下:
Baud rate = PCLK / 2 / (Prescaler value + 1) PCLK = 50MHZ
设置 SPPREn = 2,符合 OLED 的频率要求。
配置 SPCONn 寄存器如下:
/* [6:5] : 00, polling mode * [4] : 1 = enable * [3] : 1 = master * [2] : 0 = active high * [1] : 0 = format A * [0] : 0 = normal mode */
/* 发送一字节 */ void SPISendByte(unsigned char val) { /* 等待发送或接收 ready */ while (!(SPSTA1 & 1)); SPTDAT1 = val; } /* 接收一字节 */ unsigned char SPIRecvByte(void) { SPTDAT1 = 0xff; /* 等待发送或接收 ready */ while (!(SPSTA1 & 1)); return SPRDAT1; }
我们选用的是 SSD1306 这款 OLED,根据手册说明,它有 4 种操作接口可以选择,如图所示:
Different MCU mode can be set by hardware selection on BS[2:0] pins.
可以通过 BS[2:0] 来选择模式,如下图所示:
参照如下流程图写出 OLED 的初始化程序:
void OLEDInit(void) { /* 向 OLED 发命令以初始化 */ OLEDWriteCmd(0xAE); /*display off*/ OLEDWriteCmd(0x00); /*set lower column address*/ OLEDWriteCmd(0x10); /*set higher column address*/ OLEDWriteCmd(0x40); /*set display start line*/ OLEDWriteCmd(0xB0); /*set page address*/ OLEDWriteCmd(0x81); /*contract control*/ OLEDWriteCmd(0x66); /*128*/ OLEDWriteCmd(0xA1); /*set segment remap*/ OLEDWriteCmd(0xA6); /*normal / reverse*/ OLEDWriteCmd(0xA8); /*multiplex ratio*/ OLEDWriteCmd(0x3F); /*duty = 1/64*/ OLEDWriteCmd(0xC8); /*Com scan direction*/ OLEDWriteCmd(0xD3); /*set display offset*/ OLEDWriteCmd(0x00); OLEDWriteCmd(0xD5); /*set osc division*/ OLEDWriteCmd(0x80); OLEDWriteCmd(0xD9); /*set pre-charge period*/ OLEDWriteCmd(0x1f); OLEDWriteCmd(0xDA); /*set COM pins*/ OLEDWriteCmd(0x12); OLEDWriteCmd(0xdb); /*set vcomh*/ OLEDWriteCmd(0x30); OLEDWriteCmd(0x8d); /*set charge pump enable*/ OLEDWriteCmd(0x14); OLEDSetPageAddrMode(); OLEDClear(); OLEDWriteCmd(0xAF); /*display ON*/ }
设置为页显示模式:
static void OLEDSetPageAddrMode(void) { OLEDWriteCmd(0x20); OLEDWriteCmd(0x02); }
OLED 的分辨率为 128 x 64,每 8 行为一页,我们选用 8 x 16 的字模进行显示。
void OLEDPutChar(int page, int col, char c) { int i = 0; /* 得到字模 */ const unsigned char *dots = oled_asc2_8x16[c - ' ']; /* 发给 OLED */ OLEDSetPos(page, col); /* 发出 8 字节数据 */ for (i = 0; i < 8; i++) OLEDWriteDat(dots[i]); OLEDSetPos(page+1, col); /* 发出 8 字节数据 */ for (i = 0; i < 8; i++) OLEDWriteDat(dots[i+8]); }
页模式下定位方法:
即:
static void OLEDSetPos(int page, int col) { OLEDWriteCmd(0xB0 + page); /* page address */ OLEDWriteCmd(col & 0xf); /* Lower Column Start Address */ OLEDWriteCmd(0x10 + (col >> 4)); /* Lower Higher Start Address */ }
下篇将写出在 Linux 下操作 OLED 的驱动及应用程序。