目录
前言
近期,市场研究公司IHS Markit公布了最新预测,从2022年开始,全球企业对LCD面板的投资将变得更加谨慎,相关LCD相关设备的供应商将不得不改变其主要业务领域。三星电子近期大幅降低了其7代和8.5代LCD面板的生产量,LG也已停止了其第7.5代和8.5代LCD面板的部分生产线。松下将于2021年终止液晶显示器生产,并正式退出液晶面板业务。 反观OLED市场,却呈现了另一番情况。IHS Markit表示,在未来五年内,OLED行业投入将高达80亿美元,这一切显示出OLED显示屏的良好发展前景。比如,成为中高端手机市场OLED屏幕已经取代LCD成为主流,只iPhone11、iPhone Xr等少数几款使用LCD屏幕。 由于OLED拥有极高反应速度、可柔性、轻薄的特点,也是电竞游戏手机、折叠手机的必选。在可穿戴设备、智能车载、电视等领域,OLED屏幕也逐渐成为产品创新的关键之处。 5G时代宣告了“信息无处不在”时代的到来,因此智能终端的形态也必然会产生巨大变化,而OLED屏幕将会是最好的承载体。 所以,在新的屏幕技术出现之前,OLED将是终端变革的优秀解决方案。
一,OLED作用
OLED不需要背光源,自己本身会发光,是采用发光二极管阵列组成.亮度要比LED液晶高,厚度更薄,是今后LED液晶屏的替代品.
OLED是有机发光二极管,又称为有机电激光显示因为具备轻薄、省电等特性,因此从2003年开始,这种显示设备在MP3播放器上得到了广泛应用,而对
于同属数码类产品的DC与手机,此前只是在一些展会上展示过采用OLED屏幕的工程样品,还并未走入实际应用的阶段。但OLED屏幕却具备了许多LCD不可比拟的优势,因此它也一直被业内人士所看好。
二,OLED的 引脚及作用
OLED本身是没有显存的,它的显存是依赖于SSD1306提供的。SSD1306的显存总共128 * 64bit大小,SSD1306将这些显存分为了8页。每页包含了128个字节,总共8页,这样刚好是128*64的点阵大小。
SSD1306命令
三,IIC协议
I2C协议规定,总线上数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。起始和结束信号总是由主设备产生(意味着从设备不可以主动通信?所有的通信都是主设备发起的,主可以发出询问的command,然后等待从设备的通信)。
起始和结束信号产生条件:总线在空闲状态时,SCL和SDA都保持着高电平,当SCL为高电平而SDA由高到低的跳变,表示产生一个起始条件;当SCL为高而SDA由低到高的跳变,表示产生停止条件。
在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。
主设备在SCL线上产生每个时钟脉冲的过程中将在SDA线上传输一个数据位,当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位, 此时才认为一个字节真正的被传输完成。当然,并不是所有的字节传输都必须有一个应答位,比如:当从设备不能再接收主设备发送的数据时,从设备将回传一个否 定应答位
在前面我们还提到过,I2C总线上的每一个设备都对应一个唯一的地址,主从设备之间的数据传输是建立在地址的基础上,也就是说,主设备在传输有效数据之前要先指定从设备的地址,地址指定的过程和上面数据传输的过程一样,只不过大多数从设备的地址是7位的,然后协议规定再给地址添加一个最低位用来表示接下来数据传输的方向,0表示主设备向从设备写数据,1表示主设备向从设备读数据。向指定设备发送数据的格式如图所示:(每一最小包数据由9bit组成,8bit内容+1bit ACK, 如果是地址数据,则8bit包含1bit方向)
四,代码如下
oled.c
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"
//起始信号
void I2C_Start(void)
{
OLED_SDIN_Set();
OLED_SCLK_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
//结束信号
void I2C_Stop(void)
{
OLED_SCLK_Set();
OLED_SDIN_Clr();
OLED_SDIN_Set();
}
//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
OLED_SCLK_Set();
OLED_SCLK_Clr();
}
//写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i = 0; i < 8; i++)
{
OLED_SCLK_Clr();//将时钟信号设置为低电平
if(dat & 0x80) //将dat的8位从最高位依次写入
{
OLED_SDIN_Set();
}
else
{
OLED_SDIN_Clr();
}
OLED_SCLK_Set();//将时钟信号设置为高电平
OLED_SCLK_Clr();//将时钟信号设置为低电平
dat <<= 1;
}
}
//发送一个字节
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat, u8 mode)
{
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
if(mode)
{
Send_Byte(0x40);
}
else
{
Send_Byte(0x00);
}
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
uint8_t CMD_Data[] =
{
0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,
0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,
0xD8, 0x30, 0x8D, 0x14, 0xAF
}; //初始化命令
/********************************************************************************
* @brief: 写入初始化命令
* @return: None
********************************************************************************/
void Write_Cmd(void)
{
int i;
for (i = 0; i < 27; i++)
{
OLED_WR_Byte(CMD_Data[i], OLED_CMD); //SET DCDC命令
}
}
/********************************************************************************
* @brief: 向设备写控制命令
* @param: cmd
* @return: None
********************************************************************************/
void OLED_WR_CMD(uint8_t cmd)
{
OLED_WR_Byte(cmd, OLED_CMD); //SET DCDC命令
}
/********************************************************************************
* @brief: 写数据
* @param: data
* @return: None
********************************************************************************/
void OLED_WR_DATA(uint8_t data)
{
OLED_WR_Byte(data, OLED_DATA); //SET DCDC命令
}
* @brief: 清屏
* @param: None
* @return: None
********************************************************************************/
void OLED_Clear(void)
{
uint8_t i, n;
for (i = 0; i < 27; i++)
{
OLED_WR_CMD(0xb0 + i);
OLED_WR_CMD(0x00);
OLED_WR_CMD(0x10);
for (n = 0; n < 128; n++)
{
OLED_WR_DATA(0);
}
}
}
/********************************************************************************
* @brief: 开启OLed显示
* @param: None
* @return: None
********************************************************************************/
void OLED_Display_On(void)
{
OLED_WR_CMD(0x8D); //SET DCDC设置电荷泵
OLED_WR_CMD(0x14); //DCDC ON 开启电荷泵
OLED_WR_CMD(0xAF); //DISPlay ON开启显示
}
/********************************************************************************
* @brief: 关闭OLED显示
* @param:
* @return:
********************************************************************************/
void OLED_Display_Off(void)
{
OLED_WR_CMD(0x8D); //SET DCDC设置电荷泵
OLED_WR_CMD(0x10); //DCDC OFF 开启电荷泵
OLED_WR_CMD(0xAE); //DISPlay OFF开启显示
}
/********************************************************************************
* @brief: 设置起始点坐标
* @param: x,y
* @return: None
********************************************************************************/
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
OLED_WR_CMD(0xb0 + y);
OLED_WR_CMD(((x & 0xf0) >> 4) | 0x10);
OLED_WR_CMD(x & 0x0f);
}
void OLED_On(void)
{
uint8_t i, n;
for (i = 0; i < 8; i++)
{
OLED_WR_CMD(0xb0 + i); //设置页地址
OLED_WR_CMD(0x00); //设置显示位置-列低地址
OLED_WR_CMD(0x10); //设置显示位置-列高地址
for (n = 0; n < 128; n++)
{
OLED_WR_DATA(1);
}//刷新显示
}
}
/********************************************************************************
* @brief: n为循环次数,得到值为m的n+1次方
* @param m
* @param n
* @return result
********************************************************************************/
unsigned int oled_pow(uint8_t m, uint8_t n)
{
unsigned int result = 1;
while (n--)result *= m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x, uint8_t y, unsigned int num, uint8_t len, uint8_t size2)
{
uint8_t t, temp;
uint8_t enshow = 0;
for (t = 0; t < len; t++)
{
temp = (num / oled_pow(10, len - t - 1)) % 10;
if (enshow == 0 && t < (len - 1))
{
if (temp == 0)
{
OLED_ShowChar(x + (size2 / 2) * t, y, ' ', size2);
continue;
}
else enshow = 1;
}
OLED_ShowChar(x + (size2 / 2) * t, y, temp + '0', size2);
}
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size)
{
unsigned char c = 0, i = 0;
c = chr - ' ';//得到偏移后的值
if (x > 128 - 1)
{
x = 0;
y = y + 2;
}
if (Char_Size == 16)
{
OLED_Set_Pos(x, y);
for (i = 0; i < 8; i++)
OLED_WR_DATA(F8X16[c * 16 + i]);
OLED_Set_Pos(x, y + 1);
for (i = 0; i < 8; i++)
OLED_WR_DATA(F8X16[c * 16 + i + 8]);
}
else
{
OLED_Set_Pos(x, y);
for (i = 0; i < 6; i++)
OLED_WR_DATA(F6x8[c][i]);
}
}
/********************************************************************************
* @brief: 显示一个字符号串
* @param x
* @param y
* @param chr
* @param Char_Size
* @return: None
********************************************************************************/
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size)
{
unsigned char j = 0;
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j], Char_Size);
x += 8;
//如果--行显示的数字大于16就将行清零,y+2变成下一行
if (x > 120)
{
x = 0;
y += 2;
}
j++;
}
}
/********************************************************************************
* @brief: 显示汉字 hzk 用取模软件得出的数组
* @param x,设置起始点x坐标
* @param y,设置起始点y坐标
* @param no,显示数组的第n个字
* @return:
********************************************************************************/
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no)
{
uint8_t t, adder = 0;
OLED_Set_Pos(x, y);
//显示上面一部分
for (t = 0; t < 16; t++)
{
//Hzk[第几个数组][第几个值]
OLED_WR_DATA(Hzk[2 * no][t]);
adder += 1;
}
//显示下面一部分
OLED_Set_Pos(x, y + 1);
for (t = 0; t < 16; t++)
{
OLED_WR_DATA(Hzk[2 * no + 1][t]);
adder += 1;
}
}
/********************************************************************************
* @brief: 初始化oled屏幕
* @param: None
* @return: None
********************************************************************************/
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( OLED_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = OLED_SCLK_Pin | OLED_SDIN_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(OLED_PORT, &GPIO_InitStructure);
Delay_ms(100);
Write_Cmd();
OLED_Clear();
}
oled.h
#ifndef __OLED_H_
#define __OLED_H_
#include "stm32f10x.h"
#include "sys.h"
#include "stdlib.h"
#define OLED_SCLK_Pin GPIO_Pin_8
#define OLED_SDIN_Pin GPIO_Pin_9
#define OLED_CLK RCC_APB2Periph_GPIOB
#define OLED_PORT GPIOB
#define OLED_SCLK_Clr() GPIO_ResetBits(OLED_PORT,OLED_SCLK_Pin)
#define OLED_SCLK_Set() GPIO_SetBits(OLED_PORT,OLED_SCLK_Pin)//SCL
#define OLED_SDIN_Clr() GPIO_ResetBits(OLED_PORT,OLED_SDIN_Pin)//DIN
#define OLED_SDIN_Set() GPIO_SetBits(OLED_PORT,OLED_SDIN_Pin)
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
void I2C_Start(void);
void I2C_Stop(void);
void I2C_WaitAck(void);
void Send_Byte(u8 dat);
void OLED_WR_Byte(u8 dat, u8 mode);
void Write_Cmd(void);
void OLED_WR_CMD(uint8_t cmd);
void OLED_WR_DATA(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(uint8_t x, uint8_t y);
void OLED_On(void);
void OLED_ShowNum(uint8_t x, uint8_t y, unsigned int num, uint8_t len, uint8_t size2);
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size);
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size);
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no);
#endif
/******************************** END OF FILE *********************************/
oledfont.h
{0x80,0x64,0x2C,0x34,0x24,0x24,0xEC,0x32,0x22,0x22,0x32,0x2E,0x23,0xA2,0x60,0x00},
{0x00,0x41,0x21,0x91,0x89,0x87,0x4D,0x55,0x25,0x25,0x55,0x4D,0x81,0x80,0x80,0x00},/*"爱",0*/
{0x00,0x3E,0x22,0xE2,0x22,0x3E,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0xFE,0x00,0x00},
{0x20,0x3F,0x20,0x1F,0x11,0x11,0x08,0x24,0x92,0x4B,0x26,0x12,0x4E,0x82,0x7E,0x00},/*"踢",1*/
{0x04,0x84,0x84,0xFC,0x84,0x84,0x10,0x50,0x90,0x10,0xFF,0x90,0x11,0x16,0x90,0x00},
{0x20,0x60,0x20,0x1F,0x10,0x10,0x10,0x08,0x45,0x82,0x7F,0x01,0x06,0x09,0x10,0x00},/*"球",2*/
{0x00,0xF8,0x0C,0x0B,0x08,0x08,0xF8,0x40,0x30,0x8F,0x08,0x08,0x08,0xF8,0x00,0x00},
{0x00,0x7F,0x21,0x21,0x21,0x21,0x7F,0x00,0x00,0x00,0x43,0x80,0x40,0x3F,0x00,0x00},/*"的",3*/
{0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00},
{0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00},/*"小",4*/
{0x08,0x08,0x08,0x08,0x08,0xF8,0x89,0x8E,0x88,0x88,0x88,0x88,0x08,0x08,0x08,0x00},
{0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x00,0x00},/*"方",5*/
main.c
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "stm32f10x.h"
#include "oled.h"
int main()
{
/* 初始化 */
OLED_Init();
OLED_Clear();
OLED_ShowString(0, 0, "OLED", 16); //输出字符
OLED_ShowCHinese(0, 4, 0); //爱
OLED_ShowCHinese(16, 4, 1); //踢
OLED_ShowCHinese(32, 4, 2); //球
OLED_ShowCHinese(48, 4, 3); //的
OLED_ShowCHinese(64, 4, 4); //小
OLED_ShowCHinese(80, 4, 5); //方
while(1)
{
}
}