【单片机笔记】OLED控制器SSD1306及驱动代码

时间:2022-05-31 08:47:39

前言:

很长一段时间内用OLED的机会都很少,即使用了也是参考的大牛的代码,最近迫不得已又仔细研究了一遍。记下来省的忘记。


手头上用到的是0.61寸的OLED分辨率是96*16,也就是横向有96个点,纵向有16个点,贴上这个的尺寸图

【单片机笔记】OLED控制器SSD1306及驱动代码

我并没有看太多的资料,网上的资料也非常多,大多数是将SSD1306的,这里就简单通俗的记录一下,拿这个96*16的为例子,SSD把纵向(y方向)做了分页处理,每8个像素点作为一组(8个像素点=8个bit=一个字节),那么对于y方向有16个点的那就是分成两页了,从0开始就是0和1。对于其他分辨率的也一样,向上加就对了。在驱动的时候最常规的方法是从左到右,从上到下。值得注意的是不同型号可能取模的方式不一样,有点高位在前也有的低位在前,我现在用的是低位在前,这个手册里面还是有说的。下面附上取模的软件和配置选项:

软件用的是:PCtoLCD2002

取模配置如下:

【单片机笔记】OLED控制器SSD1306及驱动代码

效果图:

【单片机笔记】OLED控制器SSD1306及驱动代码【单片机笔记】OLED控制器SSD1306及驱动代码

最后附上详细的代码(理论上支持所有的SSD1306控制器)我在12832也试过没有问题,需要自行修改宏定义,代码都有详细的中文注释:

#include "fy_oled12832.h"
#include "fy_oledfont.h"  	 



#define OLED_IIC_SCL_PIN  GPIO_PIN_4
#define OLED_IIC_SCL_L() GPIO_WriteLow(OLED_IIC_SCL_PORT,OLED_IIC_SCL_PIN) //SCLIIC接口的时钟信号
#define OLED_IIC_SCL_H() GPIO_WriteHigh(OLED_IIC_SCL_PORT,OLED_IIC_SCL_PIN)//PB4

#define OLED_IIC_SDA_PORT GPIOB
#define OLED_IIC_SDA_PIN  GPIO_PIN_5
#define OLED_IIC_SDA_L() GPIO_WriteLow(OLED_IIC_SDA_PORT,OLED_IIC_SDA_PIN) //SDA IIC接口的数据信号
#define OLED_IIC_SDA_H() GPIO_WriteHigh(OLED_IIC_SDA_PORT,OLED_IIC_SDA_PIN)//PB5
 
/*
96*16像素 
x[0-95]
y[0-15]
注意:y方向分成了两页 每页8个像素点 刚好是一个字节
*/

  
#define Max_x	96
#define Max_y	2 					   
#define OLED_IIC_SCL_PORT GPIOB
		     
#define OLED_CMD  0X00	//写命令
#define OLED_DATA 0X40	//写数据

static void Oled_IIC_Configuration(void)
{
	GPIO_Init(OLED_IIC_SCL_PORT,OLED_IIC_SCL_PIN,GPIO_MODE_OUT_PP_LOW_FAST);//设置PB4为推挽输出
	GPIO_Init(OLED_IIC_SDA_PORT,OLED_IIC_SDA_PIN,GPIO_MODE_OUT_PP_LOW_FAST);//设置PB5为推挽输出 
}

//IIC Start
static void Oled_IIC_Start(void)
{
	OLED_IIC_SCL_H();
	OLED_IIC_SDA_H();
	OLED_IIC_SDA_L();
	OLED_IIC_SCL_L();
}

//IIC Stop
static void Oled_IIC_Stop(void)
{
	OLED_IIC_SCL_L();
	OLED_IIC_SDA_L();
	OLED_IIC_SDA_H();
	OLED_IIC_SCL_H() ;
}

// IIC Send byte
static void Oled_IIC_SendByte(u8 dat)
{
	u8 i;
	for(i=0;i<8;i++)		
	{
		OLED_IIC_SCL_L();
		if(dat & 0x80)
			OLED_IIC_SDA_H();
		else 
			OLED_IIC_SDA_L();
		dat<<=1;
		OLED_IIC_SCL_H();
	}

	OLED_IIC_SCL_L();
	OLED_IIC_SCL_H();
}

//OLED写一个字节 
//dat:写入的字节 
//cmd:命令或者数据
void Oled_WriteByte(u8 dat,u8 cmd)
{
	Oled_IIC_Start();
	Oled_IIC_SendByte(0x78);		
	Oled_IIC_SendByte(cmd);	
	Oled_IIC_SendByte(dat);
	Oled_IIC_Stop();
}

//坐标设置
void Oled_SetPos(u8 x, u8 y) 
{ 
	Oled_WriteByte(0xb0+y,OLED_CMD);
	Oled_WriteByte(((x&0xf0)>>4)|0x10,OLED_CMD);
	Oled_WriteByte((x&0x0f),OLED_CMD); 
}   	  
	   			 
//清屏	  
void Oled_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<Max_y;i++) //有多少个页 
	{  
		Oled_WriteByte (0xb0+i,OLED_CMD);    //设置页地址(0~1)
		Oled_WriteByte (0x00,OLED_CMD);      //设置显示位置—列低地址
		Oled_WriteByte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<Max_x;n++)	Oled_WriteByte(0,OLED_DATA); //每页有多少列
	} //更新显示
}

//在指定位置显示一个字符
void Oled_ShowChar(u8 x,u8 y,u8 chr)
{      	
	u8 c=0,i=0;	
	c=chr-' ';//得到偏移后的值			
	if(x>Max_x-1)
	{
	  x=0;
	  y++;
	  if(y>Max_y-1)	return;
	}//这里的y代表的页地址 6*8的字符所以页加一
		Oled_SetPos(x,y);
	for(i=0;i<6;i++)//6*8的字符 点阵占6列没列8个像素点(一个字节),也就是一页的6列
		Oled_WriteByte(F6x8[c][i],OLED_DATA);
}

//显示一个字符号串
void Oled_ShowString(u8 x,u8 y,u8 *chr)
{
	u8 j=0;
	if(y>Max_y-1)	return;
	while (chr[j]!='\0')
	{		
		Oled_ShowChar(x,y,chr[j]);
		x+=6;//6*8的字符 点阵占6列所以加6
		if(x>Max_x-6){x=0;y++;}          
		j++;
	}
}

//显示汉字 16*16的汉字
void Oled_ShowCHinese(u8 x,u8 y,u8 no)
{      			    
	u8 t;
	Oled_SetPos(x,y);	
	for(t=0;t<16;t++)//先写第一页
	{
		Oled_WriteByte(Hzk[2*no][t],OLED_DATA);
	}	
	Oled_SetPos(x,y+1);	
	for(t=0;t<16;t++)//再写第二页
	{	
		Oled_WriteByte(Hzk[2*no+1][t],OLED_DATA);
	}					
}


//初始化SSD1306					    
void Oled_Configuration(void)
{ 	
  	Oled_IIC_Configuration();
  	Delay_ms(100);

	Oled_WriteByte(0xAE,OLED_CMD);//--display off
	Oled_WriteByte(0x00,OLED_CMD);//---set low column address
	Oled_WriteByte(0x10,OLED_CMD);//---set high column address
	Oled_WriteByte(0x40,OLED_CMD);//--set start line address  
	Oled_WriteByte(0xB0,OLED_CMD);//--set page address
	Oled_WriteByte(0x81,OLED_CMD); // contract control
	Oled_WriteByte(0xFF,OLED_CMD);//--128   
	Oled_WriteByte(0xA1,OLED_CMD);//set segment remap 
	Oled_WriteByte(0xA6,OLED_CMD);//--normal / reverse
	Oled_WriteByte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	Oled_WriteByte(0x0F,OLED_CMD);//--1/16 duty
	Oled_WriteByte(0xC8,OLED_CMD);//Com scan direction
	Oled_WriteByte(0xD3,OLED_CMD);//-set display offset
	Oled_WriteByte(0x00,OLED_CMD);//
	Oled_WriteByte(0xD5,OLED_CMD);//set osc division
	Oled_WriteByte(0x80,OLED_CMD);//
	Oled_WriteByte(0xD9,OLED_CMD);//set pre-charge period
	Oled_WriteByte(0x22,OLED_CMD);//
	Oled_WriteByte(0xDA,OLED_CMD);//set COM pins
	Oled_WriteByte(0x02,OLED_CMD);//
	Oled_WriteByte(0xDB,OLED_CMD);//set vcomh
	Oled_WriteByte(0x40,OLED_CMD);//
	Oled_WriteByte(0x8D,OLED_CMD);//set charge pump enable
	Oled_WriteByte(0x14,OLED_CMD);//
	Oled_WriteByte(0xAF,OLED_CMD);//--turn on oled panel
}  


void Oled_TEST(void)
{
	Delay_ms(200);       	//延时200ms
	Oled_Configuration();	//OLED初始化
	Delay_ms(200);       	//延时200ms
	Oled_Clear();     		//清屏
	Delay_ms(200);       	//延时200ms
	
	while (1)
	{ 
  
	  Oled_Clear();//清屏
	  Oled_ShowString(0,0,"012345678ABCDEFGQWERTYUIOO");//显示数字

	  Delay_ms(2000);
	  
	  Oled_Clear();                        //清屏
	  Oled_ShowCHinese(8,0,0);             //显示汉字“火”
	  Oled_ShowCHinese(24,0,1);            //显示汉字“星”
	  Oled_ShowCHinese(40,0,2);            //显示汉字“科”
	  Oled_ShowCHinese(56,0,3);            //显示汉字“技”
	  
	  Delay_ms(2000);
	}		
}

字库:

#ifndef __FY_OLEDFONT_H
#define __FY_OLEDFONT_H 	   

const unsigned char F6x8[][6] =
{
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // sp
    { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !
    { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
    { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
    { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
    { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 },   // %
    { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 },   // &
    { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
    { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (
    { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )
    { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
    { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
    { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 },   // ,
    { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 },   // -
    { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
    { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
    { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0
    { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1
    { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
    { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
    { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4
    { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
    { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6
    { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
    { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
    { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9
    { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
    { 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
    { 0x08, 0x1C, 0x2A, 0x49, 0x08, 0x08 },   // <
    { 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
    { 0x08, 0x08, 0x49, 0x2A, 0x1C, 0x08 },   // >
    { 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
    { 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E },   // @
    { 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C },   // A
    { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 },   // B
    { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 },   // C
    { 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C },   // D
    { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 },   // E
    { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 },   // F
    { 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A },   // G
    { 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F },   // H
    { 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 },   // I
    { 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 },   // J
    { 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 },   // K
    { 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 },   // L
    { 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F },   // M
    { 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F },   // N
    { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E },   // O
    { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 },   // P
    { 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E },   // Q
    { 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 },   // R
    { 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
    { 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 },   // T
    { 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F },   // U
    { 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F },   // V
    { 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F },   // W
    { 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
    { 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
    { 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
    { 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 },   // [
    { 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 },   // 55
    { 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 },   // ]
    { 0x04, 0x02, 0xFF, 0x02, 0x04, 0x00 },   // ^
    { 0x00, 0x20, 0x40, 0xFF, 0x40, 0x20 },   // _
    { 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 },   // '
    { 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
    { 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 },   // b
    { 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
    { 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F },   // d
    { 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 },   // e
    { 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 },   // f
    { 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C },   // g
    { 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 },   // h
    { 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 },   // i
    { 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 },   // j
    { 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 },   // k
    { 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 },   // l
    { 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 },   // m
    { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 },   // n
    { 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
    { 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 },   // p
    { 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC },   // q
    { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 },   // r
    { 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
    { 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 },   // t
    { 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C },   // u
    { 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C },   // v
    { 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C },   // w
    { 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
    { 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C },   // y
    { 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 },   // z
    { 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 }    // horiz lines
};
char Hzk[][32]={

{0x00,0x00,0xC0,0x38,0x00,0x00,0x00,0xFF,0x00,0x00,0x40,0x20,0x18,0x00,0x00,0x00},
{0x80,0x81,0x40,0x20,0x10,0x0C,0x03,0x00,0x03,0x0C,0x10,0x20,0x40,0x80,0x80,0x00},/*"火",0*/

{0x00,0x00,0x00,0xBE,0x2A,0x2A,0x2A,0xEA,0x2A,0x2A,0x2A,0x3E,0x00,0x00,0x00,0x00},
{0x00,0x44,0x42,0x49,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x49,0x41,0x40,0x00,0x00},/*"星",1*/

{0x24,0x24,0xA4,0xFE,0xA3,0x22,0x00,0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00,0x00},
{0x08,0x06,0x01,0xFF,0x00,0x01,0x04,0x04,0x04,0x04,0x04,0xFF,0x02,0x02,0x02,0x00},/*"科",2*/

{0x10,0x10,0x10,0xFF,0x10,0x90,0x08,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x08,0x00},
{0x04,0x44,0x82,0x7F,0x01,0x80,0x80,0x40,0x43,0x2C,0x10,0x28,0x46,0x81,0x80,0x00},/*"技",3*/

};

#endif


/*********************************************END OF FILE**********************************************/


测试例程:

void Oled_TEST(void)
{
	Delay_ms(200);       	//延时200ms
	Oled_Configuration();	//OLED初始化
	Delay_ms(200);       	//延时200ms
	Oled_Clear();     		//清屏
	Delay_ms(200);       	//延时200ms
	
	while (1)
	{ 
  
	  Oled_Clear();//清屏
	  Oled_ShowString(0,0,"012345678ABCDEFGQWERTYUIOO");//显示字符

	  Delay_ms(2000);
	  
	  Oled_Clear();                        //清屏
	  Oled_ShowCHinese(8,0,0);             //显示汉字“火”
	  Oled_ShowCHinese(24,0,1);            //显示汉字“星”
	  Oled_ShowCHinese(40,0,2);            //显示汉字“科”
	  Oled_ShowCHinese(56,0,3);            //显示汉字“技”
	  
	  Delay_ms(2000);
	}		
}


至此完毕!

By Urien 2017年11月12日 13:30:22