简单的说下OLED
OLED,即有机发光二极管。LCD 需要背光,而OLED不需要,因为它是自发光的。这样同样的显示OLED效果要来得好一些。OLED分辨率是128*64 供电电压可以是3-5V 支持8600和8080通讯协议,4针是使用IIC协议来控制通讯,关于IIC通讯我就不详细介绍,话不多说,我们直接上代码
下方代码是用stm32f103单片机基于标准库写的
注:如果你要更换到不同型号的单片机上,也只需要修改端口,和引用文件,其余都相同,修改点我在代码中也有标注
OLED_I2C.h
#ifndef __OLED_I2C_H
#define __OLED_I2C_H
#include "stm32f10x.h"
#define OLED_ADDRESS 0x78 //通过调整0R电阻,屏可以0x78和0x7A两个地址 -- 默认0x78
#define I2C_Speed 400000
/*I2C接口 代码迁移修改点 */
#define OLED_I2C I2C1
#define OLED_I2C_CLK RCC_APB1Periph_I2C1
#define OLED_I2C_CLK_INIT RCC_APB1PeriphClockCmd
#define OLED_I2C_SCL_PIN GPIO_Pin_6
#define OLED_I2C_SCL_GPIO_PORT GPIOB
#define OLED_I2C_SCL_GPIO_CLK RCC_APB2Periph_GPIOB
#define OLED_I2C_SCL_SOURCE GPIO_PinSource6
#define OLED_I2C_SCL_AF GPIO_AF_I2C1
#define OLED_I2C_SDA_PIN GPIO_Pin_7
#define OLED_I2C_SDA_GPIO_PORT GPIOB
#define OLED_I2C_SDA_GPIO_CLK RCC_APB2Periph_GPIOB
#define OLED_I2C_SDA_SOURCE GPIO_PinSource7
#define OLED_I2C_SDA_AF GPIO_AF_I2C1
void I2C_Configuration(void);
void I2C_WriteByte(uint8_t addr,uint8_t data);
void WriteCmd(unsigned char I2C_Command);
void WriteDat(unsigned char I2C_Data);
void OLED_Init(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);
void OLED_CLS(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
#endif
OLED_I2C.c
/*
* 功能列表:
* 1. void I2C_Configuration(void) -- 配置CPU的硬件I2C
* 2. void I2C_WriteByte(uint8_t addr,uint8_t data) -- 向寄存器地址写一个byte的数据
* 3. void WriteCmd(unsigned char I2C_Command) -- 写命令
* 4. void WriteDat(unsigned char I2C_Data) -- 写数据
* 5. void OLED_Init(void) -- OLED屏初始化
* 6. void OLED_SetPos(unsigned char x, unsigned char y) -- 设置起始点坐标
* 7. void OLED_Fill(unsigned char fill_Data) -- 全屏填充
* 8. void OLED_CLS(void) -- 清屏
* 9. void OLED_ON(void) -- 唤醒
* 10. void OLED_OFF(void) -- 睡眠
* 11. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) -- 显示字符串(字体大小有6*8和8*16两种)
* 12. void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) -- 显示中文(中文需要先取模,然后放到codetab.h中)
* 13. void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) -- BMP图片
*
*/
#include "OLED_I2C.h" //OLED_IIC通讯h文件
#include "codetab.h" //字模h文件
#include "./systick/bsp_SysTick.h" //延时函数h文件
void I2C_Configuration(void) /* 代码迁移修改点 */
{
//开启IIC和IIC端口配置
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*I2C1外设时钟使能 */
OLED_I2C_CLK_INIT(OLED_I2C_CLK,ENABLE);
/*I2C1外设GPIO时钟使能 */
RCC_APB2PeriphClockCmd(OLED_I2C_SCL_GPIO_CLK | OLED_I2C_SDA_GPIO_CLK,ENABLE);
/* I2C_SCL、I2C_SDA*/
GPIO_InitStructure.GPIO_Pin = OLED_I2C_SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
GPIO_Init(OLED_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = OLED_I2C_SDA_PIN;
GPIO_Init(OLED_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; /* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
I2C_InitStructure.I2C_OwnAddress1 =OLED_ADDRESS; //主机的I2C地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /* I2C的寻址模式 */
I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; /* 通信速率 */
I2C_Init(OLED_I2C, &I2C_InitStructure); /* I2C1 初始化 */
I2C_Cmd(OLED_I2C, ENABLE); /* 使能I2C1*/
}
void I2C_WriteByte(uint8_t addr,uint8_t data)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, addr);//寄存器地址
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, data);//发送数据
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
}
void WriteCmd(unsigned char I2C_Command)//写命令
{
I2C_WriteByte(0x00, I2C_Command);
}
void WriteDat(unsigned char I2C_Data)//写数据
{
I2C_WriteByte(0x40, I2C_Data);
}
void OLED_Init(void)
{
//这个延时函数就根据单片机自己构建一个,没准确时间要求,这里我就不提供库文件
Delay_s(1); // 1s,这里的延时很重要,上电后延时,没有错误的冗余设计,也就是等待oled工作稳定
WriteCmd(0xAE); //关闭显示
WriteCmd(0x20); //设置内存地址模式
WriteCmd(0x10); //00,列地址模式;01,行地址模式;10(默认),页地址模式;11,无效
WriteCmd(0xb0); //设置页地址,其中低三位的值对应GRAM地址:B0-B7
WriteCmd(0xc8); //设置COM输出扫描方向
WriteCmd(0x00); //---设置低列地址
WriteCmd(0x10); //---设置高列地址
WriteCmd(0x40); //--设置起始行地址
WriteCmd(0x81); //--设置对比度控制寄存器
WriteCmd(0xff); //亮度调节 0x00~0xff
WriteCmd(0xa1); //--将段重新映射0设置为127
WriteCmd(0xa6); //--设置正常显示
WriteCmd(0xa8); //--设置多路复用比率(1到64)
WriteCmd(0x3F); //
WriteCmd(0xa4); //0xa4,输出跟随RAM内容;0xa5,输出忽略RAM内容
WriteCmd(0xd3); //-设置显示偏移
WriteCmd(0x00); //-不抵消
WriteCmd(0xd5); //--设置显示时钟分频比/振荡器频率
WriteCmd(0xf0); //--设定分割比率
WriteCmd(0xd9); //--设定预充电时间
WriteCmd(0x22); //
WriteCmd(0xda); //--设置com引脚硬件配置
WriteCmd(0x12);
WriteCmd(0xdb); //--set vcomh
WriteCmd(0x20); //0x20,0.77xVcc
WriteCmd(0x8d); //--设置DC-DC启用
WriteCmd(0x14); //
WriteCmd(0xaf); //--开启显示
}
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
WriteCmd(0xb0+y);
WriteCmd(((x&0xf0)>>4)|0x10);
WriteCmd((x&0x0f)|0x01);
}
void OLED_Fill(unsigned char fill_Data)//全屏填充
{
unsigned char m,n;
for(m=0;m<8;m++)
{
WriteCmd(0xb0+m); //page0-page1
WriteCmd(0x00); //low column start address
WriteCmd(0x10); //high column start address
for(n=0;n<128;n++)
{
WriteDat(fill_Data);
}
}
}
void OLED_CLS(void)//清屏
{
OLED_Fill(0x00);
}
void OLED_ON(void) //唤醒
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X14); //开启电荷泵
WriteCmd(0XAF); //OLED唤醒
}
void OLED_OFF(void) //让OLED休眠
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X10); //关闭电荷泵
WriteCmd(0XAE); //OLED休眠
}
/**
* @brief OLED_ShowStr,显示codetab.h中的ASCII字符,有6*8和8*16可选择
* @param x,y : 起始点坐标(x:0~127, y:0~7);
* ch[] :- 要显示的字符串;
* Size : 字符大小(1:6*8 ; 2:8*16)
* @retval 无
*/
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char Size)
{
unsigned char c = 0,i = 0,j = 0;
switch(Size)
{
case 1:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 126)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<6;i++)
WriteDat(F6x8[c][i]);
x += 6;
j++;
}
}break;
case 2:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 120)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<8;i++)
WriteDat(F8X16[c*16+i]);
OLED_SetPos(x,y+1);
for(i=0;i<8;i++)
WriteDat(F8X16[c*16+i+8]);
x += 8;
j++;
}
}break;
}
}
/**
* @brief OLED_ShowCN,显示codetab.h中的汉字,16*16点阵
* @param x,y: 起始点坐标(x:0~127, y:0~7);
* N:汉字在codetab.h中的索引
* @retval 无
*/
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
unsigned char wm=0;
unsigned int adder=32*N;
OLED_SetPos(x , y);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16[adder]);
adder += 1;
}
OLED_SetPos(x,y + 1);
for(wm = 0;wm < 16;wm++)
{
WriteDat</