最全OLED驱动集合,IIC、三线SPI、四线SPI、8080驱动
OLED
## 阅读须知
阅读本⽂需要有⼀定的STM32基础。
## 前⾔
我经常⽤的是IIC驱动,因为只有2个IO⼝,使⽤也⽅便。
前段时间拿到SPI接⼝的OLED,于是就去捣⿎了三线SPI驱动。
本驱动适⽤SSD1306,其他芯⽚的鄙⼈没有测试,仅供参考。
代码中的宏定义对应接线:
OledCS  :CS--->PB12
OledRS  :DC--->PB14
OledRst  :RES-->PB13,可以直接接单⽚机RST引脚
OledSck :D0--->PB0
OledSdin:D1--->PB1
//OLED模式设置
//0: SPI串⾏模式  (模块的BS1,BS2均接GND)
//1: 并⾏8080模式 (模块的BS1,BS2均接VCC)
#define  OLED_MODE            0
//SPI模式设置
//0: 4线串⾏模式 8 bit data send
//1: 3线串⾏模式 9 bit data send
#define  OLED_SPI_X        0
## 驱动原理
钟汉良个人资料档案不管是IIC还是三线SPI、四线SPI,乃⾄8080并⼝驱动OLED,他们的本质都是⼀样的:写数据和写命令。也就是说当你已经有⼀份可以驱动的代码,你就可以很快的修改成其他接⼝协议来驱动OLED。
如果是7针的OLED,接线和改电阻参考(也可以直接看元器件的丝印):
### IIC驱动OLED
没有什么好说的,直接上源码。
最后得出2个函数,写命令和写数据函数,然后拿着这2个函数去写OLED操作。如显⽰数字、字符、字符串、中⽂,
void WriteCmd(u8 command);
void WriteDat(u8 data);
只要其他接⼝实现这2个函数的功能,那么就可以在IIC接⼝的驱动延伸出其它接⼝的OLED驱动。开始,写底层驱动~~~。
为了不影响阅读,OLED显⽰代码我放在最后。
#define  OledSCL_H()        I2CSCLPort->BSRR = I2CSCLPin
#define  OledSCL_L()        I2CSCLPort->BRR  = I2CSCLPin
#define  OledSDA_H()        I2CSDAPort->BSRR = I2CSDAPin
#define  OledSDA_L()        I2CSDAPort->BRR  = I2CSDAPin
#define  OledSDA_Read      I2CSDAPort->IDR  & I2CSDAPin
#define  OledSDA_Read      I2CSDAPort->IDR  & I2CSDAPin
/**
**  设置SDA为输出
朱时茂老婆
**/
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructer;
GPIO_InitStructer.GPIO_Pin= I2CSDAPin;
陈为民章龄之
GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(I2CSDAPort, &GPIO_InitStructer);
也许有一天我老无所依
}
/**
**  设置SDA为输⼊
**/
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructer;
GPIO_InitStructer.GPIO_Pin= I2CSDAPin;
GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(I2CSDAPort, &GPIO_InitStructer);
}
//开始信号
void IIC_Start(void)
{
SDA_OUT();
OledSDA_H();
OledSCL_H();
delay_us(2);
OledSDA_L();
delay_us(2);
OledSCL_L();
delay_us(2);
}
void IIC_Stop(void)
{
OledSCL_H();
OledSDA_L();
delay_us(2);
OledSDA_H();
delay_us(2);
}
/*
*  返回1--应答出错
*  放回0--应答正确
*/
u8 IIC_Wait_Ask(void)
{
int count=0;
SDA_IN();
OledSCL_H();
delay_us(2);
while(OledSDA_Read)
{
count++;
if(count>250)
{
IIC_Stop();
IIC_Stop();
return 1;
}
}
OledSCL_L();
delay_us(2);
return 0;
}
//写⼀个字节
void IIC_WriteByte(u8 data)
{
u8 i;
SDA_OUT();
for(i=0;i<8;i++)
{
OledSCL_L();
delay_us(2);
if(data & 0x80)    //MSB,从⾼位开始⼀位⼀位传输
OledSDA_H();
else
OledSDA_L();
OledSCL_H();
delay_us(2);
OledSCL_L();
data<<=1;
}
}
u8 IIC_ReadByte(void)
{
u8 data,i;
OledSDA_H();
delay_us(3);
for(i=0;i<8;i++)
{
data<<=1;
OledSCL_L();
delay_us(1);
OledSCL_H();
delay_us(1);
if(GPIO_ReadInputDataBit(I2CSDAPort, I2CSDAPin))            data=data | 0x01;
else
data=data & 0xFE;
}
OledSCL_L();
delay_us(3);
return data;
}
void WriteCmd(u8 command)
{
IIC_Start();
IIC_WriteByte(0x78);//OLED地址
IIC_Wait_Ask();
IIC_WriteByte(0x00);//寄存器地址
IIC_Wait_Ask();
IIC_WriteByte(command);
IIC_Wait_Ask();
IIC_Stop();
}
void WriteDat(u8 data)
{
IIC_Start();
适合送给老师的礼物
IIC_WriteByte(0x78);//OLED地址
IIC_Wait_Ask();
IIC_WriteByte(0x40);//寄存器地址
IIC_Wait_Ask();
IIC_WriteByte(data);
IIC_Wait_Ask();
IIC_Stop();
}
### 四线SPI驱动OLED
四线SPI使⽤CS、D0、D1、DC。分别对应SPI的CS、Sck、Sdin、命令数据选择。注:RES是要使⽤的。
官⽅说明:
第⼀段是说使⽤到什么线的,每⼀个IO的功能。
第⼆段是告诉你怎么编程的。
### 对应的编程,这⾥只考虑写,不考虑读取。以下为写8bit。
void OLED_WR_Byte(u8 dat,u8 cmd)
{
char i;
OledCs_L();//⽚选
if(cmd)    //判断是写数据还是写命令
OledRS_H();
else
OledRS_L();
for(i=0;i<8;i++)//8bit
{
OledSck_L();
if(dat&0x80)
OledSdin_H();
else
OledSdin_L();
OledSck_H();
dat<<=1;
}
五一去哪里旅游最好
OledCs_H();
OledRS_H();
}
### 三线SPI驱动OLED
三线SPI使⽤CS、D0、D1。分别对应SPI的CS、Sck、Sdin。
注:RES是要使⽤的。
官⽅的说明:
第⼀段是说使⽤到什么线的,每⼀个IO的功能。
第⼆段是告诉你怎么编程的。这⾥说⼀下三线SPI的原理:其实就是⼀次发9bit数据,把命令/数据使⽤Sdin线的1bit,(1:写数据,0:写命令)⽽在四线SPI中,根据D/C线的电平判断写命令还是写数据。
### 对应的编程,这⾥只考虑写,不考虑读取。
那么我们就再四线SPI的基础上加上⼏⾏(配合宏定义):