1. 前言
完成了小车的遥控部分后,考虑外加一个OLED屏来远程调参。Joystick上有一个LCD的模块插口,但是我手头上只有OLED,所以使用了它上面部分引脚口,并用模拟SPI方式实现对OLED的驱动。
2. OLED_SPI类
SPI通讯需要反复使用定位Set_Pos、Write_Byte等函数,为了防止代码冗余,我把它写成一个类。
OLED_SPI.h ↓ ↓ ↓
#define u8 unsigned char // 0~255
#define u16 unsigned int // 0~65535
#define u32 unsigned long // 0~4294967295
class OLED_SPI
{
public:
/* 构造函数 初始化引脚 */
OLED_SPI(u8 D0,u8 D1,u8 RES,u8 DC,u8 CS);
/* 基础成员函数 */
void Init(); //引脚模式初始化 屏幕参数初始化
void WR_Byte(u8 dat,u8 cmd); //根据cmd值发送数据或命令
void Display_On(); //开启OLED显示
void Display_Off(); //关闭OLED显示
void Clear(); //清屏
void Set_Pos(u8 x,u8 y); //定位 x:0~127 y:0~7
/* 其他函数 */
void Dele_Row(u8 row); //删除一整行 row(0~3)
/* 引脚电平变化函数 */
void OLED_CS_Set(u8 staus);
void OLED_RES_Set(u8 staus);
void OLED_DC_Set(u8 staus);
void OLED_SCL_Set(u8 staus);
void OLED_SDA_Set(u8 staus);
private:
u8 OLED_SCL; //D0
u8 OLED_SDA; //D1
u8 OLED_RES; //RES
u8 OLED_DC; //DC
u8 OLED_CS; //CS
};
OELD_SPI.cpp ↓ ↓ ↓
(1) 构造函数:初始化各个引脚
// OLED_SPI构造函数
OLED_SPI::OLED_SPI(u8 D0,u8 D1,u8 RES,u8 DC,u8 CS)
{
this->OLED_SCL=D0;
this->OLED_SDA=D1;
this->OLED_RES=RES;
this->OLED_DC=DC;
this->OLED_CS=CS;
}
(2) 引脚电平变化函数
/* 引脚电平变化函数 */
void OLED_SPI::OLED_SCL_Set(u8 staus)
{
if(staus) digitalWrite(this->OLED_SCL,HIGH);
else digitalWrite(this->OLED_SCL,LOW);
}
void OLED_SPI::OLED_SDA_Set(u8 staus)
{
if(staus) digitalWrite(this->OLED_SDA,HIGH);
else digitalWrite(this->OLED_SDA,LOW);
}
void OLED_SPI::OLED_RES_Set(u8 staus)
{
if(staus) digitalWrite(this->OLED_RES,HIGH);
else digitalWrite(this->OLED_RES,LOW);
}
void OLED_SPI::OLED_DC_Set(u8 staus)
{
if(staus) digitalWrite(this->OLED_DC,HIGH);
else digitalWrite(this->OLED_DC,LOW);
}
void OLED_SPI::OLED_CS_Set(u8 staus)
{
if(staus) digitalWrite(this->OLED_CS,HIGH);
else digitalWrite(this->OLED_CS,LOW);
}
(3) 写字节函数:使用SPI通讯方式写一个字节
// 函数功能:向SSD1306写入一个字节。
// dat:要写入的数据/命令
// cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_SPI::WR_Byte(u8 dat,u8 cmd)
{
u8 i;
if(cmd)
OLED_DC_Set(1); //写数据
else
OLED_DC_Set(0); //写命令
OLED_CS_Set(0); //片选先低后高 上升沿触发
for(i=0;i<8;i++) //发送数据
{
OLED_SCL_Set(0);
if(dat&0x80)
{
OLED_SDA_Set(1);
}
else
OLED_SDA_Set(0);
OLED_SCL_Set(1);
dat<<=1;
}
OLED_CS_Set(1);
OLED_DC_Set(1); //空闲时期默认为写数据
}
(4) 初始化函数:配置引脚模式,初始化OLED系统参数
//初始化SSD1306
void OLED_SPI::Init()
{
pinMode(this->OLED_SDA,OUTPUT); //SDA D1配置为输出模式
pinMode(this->OLED_SCL,OUTPUT); //SCL D0配置为输出模式
pinMode(this->OLED_DC,OUTPUT); //Data/Command配置为输出模式
pinMode(this->OLED_CS,OUTPUT); //CS配置为输出模式
pinMode(this->OLED_RES,OUTPUT); //RES配置为输出模式
OLED_RES_Set(1);
delay(100);
OLED_RES_Set(0);
delay(100);
OLED_RES_Set(1);
WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
WR_Byte(0x00,OLED_CMD);//---set low column address
WR_Byte(0x10,OLED_CMD);//---set high column address
WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
WR_Byte(0x81,OLED_CMD);//--set contrast control register
WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
WR_Byte(0xA6,OLED_CMD);//--set normal display
WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
WR_Byte(0x3f,OLED_CMD);//--1/64 duty
WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
WR_Byte(0x00,OLED_CMD);//-not offset
WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
WR_Byte(0x12,OLED_CMD);
WR_Byte(0xDB,OLED_CMD);//--set vcomh
WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
WR_Byte(0x02,OLED_CMD);//
WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
WR_Byte(0xAF,OLED_CMD); /*display ON*/
Clear();
Set_Pos(0,0);
}
(5) 设置打印点位置函数
// 函数功能:设置坐标
// x:横坐标(0~127)
// y:纵坐标(0~7)
void OLED_SPI::Set_Pos(u8 x, u8 y)
{
WR_Byte(0xb0+y,OLED_CMD);
WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
WR_Byte((x&0x0f)|0x01,OLED_CMD);
}
(6) 其他功能函数
// 函数介绍:开启OLED显示
void OLED_SPI::Display_On()
{
WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
WR_Byte(0X14,OLED_CMD); //DCDC ON
WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
// 函数介绍:关闭OLED显示
void OLED_SPI::Display_Off()
{
WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
WR_Byte(0X10,OLED_CMD); //DCDC OFF
WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
// 函数功能:清屏
void OLED_SPI::Clear()
{
u8 i,n;
for(i=0;i<8;i++)
{
WR_Byte(0xb0+i,OLED_CMD); //设置页地址(0~7)
WR_Byte(0x00,OLED_CMD); //设置显示位置—列低地址
WR_Byte(0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++) WR_Byte(0,OLED_DATA);
}
}
// 功能介绍:删除屏幕中0-3的某一行
void OLED_SPI::Dele_Row(u8 row)
{
if(row >4 ) return; //行数错误
u8 x,y;
WR_Byte(0x00,OLED_CMD); //设置显示位置—列低地址
WR_Byte(0x10,OLED_CMD); //设置显示位置—列高地址
for(y=row*2;y|