第七篇 OLED屏

OLED即Organic Light-Emitting Diode,相比LCD的屏,LCD屏需要背光,而OLED不需要,因为它本身就是发光的。

开发板上的屏使用的驱动IC是SSD1306,支持并口、I2C和SPI等接口,可以根据自身需要进行灵活的配置。具体是使用的哪种接口,是通过芯片BS0、BS1、BS2三个引脚来控制的,如图所示:


另外,我拿到的屏是配置成四线SPI接口的,而不是像OLED教程所说的是I2C接口。

开发板上的屏有黄、蓝两种颜色显示,前16行为黄色,后48行为蓝色,并且中间有一行不能显示的间隔区。

既然是SPI的接口,我们先来看发送数据的时序图:


先传送高位数据,再传送低位数据,在每个时钟的上升沿进行数据的采样,CS是片选信号,DC是数据/命令控制信号,为高表示发送的是数据,为低是命令。我们先采用GPIO模拟SPI的方式来操作,当然NRF51822芯片是支持硬件SPI的,后面我们再做修改,发送一个字节数据代码如下:
void spi_write_byte(unsigned char val)
{
	char i;
	for (i = 0; i < 8; i++) {
		if (val & 0x80)
			nrf_gpio_pin_set(SPI_SDA);
		else
			nrf_gpio_pin_clear(SPI_SDA);
		val <<= 1;
		nrf_gpio_pin_clear(SPI_CLK);
		nrf_gpio_pin_set(SPI_CLK);
	}
}

写数据还是命令只要控制DC信号就可以了,代码如下:

void spi_write_data(unsigned char data)
{
	nrf_gpio_pin_set(SPI_DC);
	spi_write_byte(data);
}

void spi_write_cmd(unsigned char cmd)
{
	nrf_gpio_pin_clear(SPI_DC);
	spi_write_byte(cmd);
}
然后再来看屏的初始化部分,屏的初始化主要是屏IC里面的寄存器初始化,这里我们直接使用开发板例程所提供的,另外还包括屏的上电和RESET部分。
void lcd_init(void)
{
	nrf_gpio_cfg_output(SPI_CLK);
	nrf_gpio_cfg_output(SPI_SDA);
	nrf_gpio_cfg_output(SPI_CS);
	nrf_gpio_cfg_output(SPI_DC);

	nrf_gpio_cfg_output(LCD_PWR);
	nrf_gpio_cfg_output(LCD_RST);

	nrf_gpio_pin_set(LCD_PWR);	/* power on */

	nrf_gpio_pin_clear(LCD_RST);	/* reset */
	nrf_delay_ms(100);
	nrf_gpio_pin_set(LCD_RST);

	nrf_gpio_pin_clear(SPI_CS);

	spi_write_cmd(0xAE);		/* register init */
	spi_write_cmd(0xD5);
	spi_write_cmd(0x80);
	spi_write_cmd(0xA8);
	spi_write_cmd(0x3F);
	spi_write_cmd(0xD3);
	spi_write_cmd(0x00);
	spi_write_cmd(0x40);
	spi_write_cmd(0x8D);
	spi_write_cmd(0x95);
	spi_write_cmd(0xA1);
	spi_write_cmd(0xC8);
	spi_write_cmd(0xDA);
	spi_write_cmd(0x12);
	spi_write_cmd(0x81);
	spi_write_cmd(0xFF);
	spi_write_cmd(0xD9);
	spi_write_cmd(0xF1);
	spi_write_cmd(0xDB);
	spi_write_cmd(0x30);
	spi_write_cmd(0xAD);
	spi_write_cmd(0x30);
	spi_write_cmd(0xA4);
	spi_write_cmd(0xA6);
	spi_write_cmd(0xAF);

	lcd_clear();
}
最后来看显示部分。

SSD1306显存总共有128*64bit大小,显存总共分成了8页,如图所示:


每页总共128*8bit大小,写数据是按字节为单位写入的(在移植uCGUI时需要注意这一点)。

那么既然显存大小是128*64bit,那么在写入显示数据时首先要指定写入数据的位置。0xB0~0xB7命令用来设置页地址,共8页,0x00~0x0F命令用来指定列地址的低4位,0x10~0x1F命令用来指定列地址的高4位,细心的网友可能会发现16*16总共有256列了,虽然芯片可能支持这么多列,但实际屏上是不会显示的,也就是说列地址的高4位你只能设置为0~7。

这里也写了一个函数,根据x、y的坐标来设置写入数据的起始位置。
#define PAGE_SIZE 8

void lcd_set_xy(unsigned char x, unsigned char y)
{
	y = (y / PAGE_SIZE);

	spi_write_cmd(0xB0 + y);
	spi_write_cmd(((x & 0xF0) >> 4) | 0x10);
	spi_write_cmd(x & 0x0F);
}
虽然这里参数y可以是0~63,但数据写入并不能从坐标的任意位置写入,即y你传0和传7的效果是一样的。

还有需要注意是指定坐标后,写入一个字节的数据,这个数据是体现先在那一列上的,并且是低位在上,高位在下这样显示的。什么意思呢,你比如在(0, 0)这个坐标写入一个字节数据0xF0,那么第0页、第0列是这样显示的(从上往下),[ ][ ][ ][ ][*][*][*][*],(方括号里的*号代表显示,空代表不显示)。

Ok,有了这个基础后,根据这个原理我们就显示一些任意数据了,如果需要显示字符,那么就需要用到字库,这里用到了8*16的ascii字库,其中8代表字符的宽度,16代表字符的高度,代码如下:
void lcd_disp_string(unsigned char x, unsigned char y, char *s)
{
	unsigned char c;
	int i;
	while (*s != '\0') {
		if (x > 120) {
			x = 0;
			y += 16;
		}

		lcd_set_xy(x, y);
		c = *s - 32;
		for (i = 0; i < 8; i++)
			spi_write_data(F8x16[c * 16 + i]);

		lcd_set_xy(x, y + 8);
		for (i = 0; i < 8; i++)
			spi_write_data(F8x16[c * 16 + i + 8]);

		s++;
		x += 8;
	}
}

例如我要显示Hello world!,效果如下:

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值