STM32驱动0.96寸OLED屏幕

引言

Organic Light Emitting Display,即有机发光显示器,在手机LCD上属于新崛起的种类,被誉为“梦幻显示器”。
OLED也被称之为第三代显示技术。OLED不仅更轻薄、能耗低、亮度高、发光率好、可以显示纯黑色,并且还可以做到弯曲,如当今的曲屏电视和手机等。当今国际各大厂商都争相恐后的加强了对OLED技术的研发投入,使得OLED技术在当今电视、电脑(显示器)、手机、平板等领域灵应用愈加广泛。

一、OLED屏的驱动

我们采用是四线的OLED的屏幕,如图所示:
在这里插入图片描述
我们今天采用这个OLED屏幕显示“hello world!!!”字样,首先是SSD1306内部的GDDRAM,大小是128*64,即128列64行。显存区域被分成8页,每页128段。
在这里插入图片描述
在这里插入图片描述

还有这里使用的IIC通信方式,这里会使用就行,具体的通信方式我们在后面的文章中会讲,这里我们会使用就行。

二、使用步骤

我们在使用0.96寸的oled的屏幕时,我们先搞清的它的驱动芯片,而作者使用这款是SSD1306的驱动
采用IIC通信。
##代码如下:

oled.c

#include "oled.h"
#include "delay.h"
#include "oledfont.h"  
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 		   
u8 OLED_GRAM[128][8];	 
			   
void OLED_IICStart()
{
   OLED_SCL = 1;                
   OLED_SDA = 1;
   OLED_SDA = 0;
   OLED_SCL = 0;
}
void OLED_IICStop()
{
   OLED_SCL = 0;
   OLED_SDA = 0;
   OLED_SCL = 1;
   OLED_SDA = 1;
}
void OLED_Byte(u8 dat)//写一个字节
{
	 u8 i;	 
	 for(i=0;i<8;i++)
	 {
			if(dat & 0x80)
							OLED_SDA=1;
			else
							OLED_SDA=0;
			OLED_SCL=1;
			OLED_SCL=0;
			dat<<=1;
	 }
	 OLED_SDA=1;
	 OLED_SCL=1;
	 OLED_SCL=0;	 
}
void OLED_WR_Byte(u8 dat,u8 cmd)//写数据还是写命令  cmd控制命令还是数据
{
   if(cmd == 1)
	 {
	    OLED_IICStart();
		  OLED_Byte(0X78);
		  OLED_Byte(0X40);
		  OLED_Byte(dat);
		  OLED_IICStop();
	 }
	 else
	 {
	    OLED_IICStart();
		  OLED_Byte(0X78);
		  OLED_Byte(0X00);
		  OLED_Byte(dat);
		  OLED_IICStop();
	 }
}


//更新显存到LCD		 
void OLED_Refresh_Gram(void)
{
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); 
	}   
}
//建立像素点
void OLED_Set_Pos(unsigned char x, unsigned char y) 
{ 
	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD); 
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{    
		for(n=0;n<128;n++)
		{
			OLED_GRAM[n][i]=0;
		}
	}
	OLED_Refresh_Gram();//更新显示 
}


//画点 
//x:0~127
//y:0~63
//t:1 填充 0,清空				   
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
	u8 pos,bx,temp=0;
	if(x>127||y>63)return;//超出范围了.
	pos=7-y/8;
	bx=y%8;
	temp=1<<(7-bx);
	if(t)OLED_GRAM[x][pos]|=temp;
	else OLED_GRAM[x][pos]&=~temp;
	//OLED_Refresh_Gram();	    
}

//画一个水平的线
void OLED_XLine(u8 x1,u8 x2,u8 y,u8 t)
{ 
	 u8 i;
   for(i=x1;i<x2;i++)
	 {
	    OLED_DrawPoint(i,y,t);
	 }
	 OLED_Refresh_Gram();
}

//画一个垂直的线
void OLED_YLine(u8 y1,u8 y2,u8 x,u8 t)
{ 
	 u8 i;
   for(i=y1;i<y2;i++)
	 {
	    OLED_DrawPoint(x,i,t);
	 }
	 OLED_Refresh_Gram();
}


//x1,y1,x2,y2 填充区域的对角坐标
//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63	 	 
//dot:0,清空;1,填充	  
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot)  
{  
	u8 x,y;  
	for(x=x1;x<=x2;x++)
	{
		for(y=y1;y<=y2;y++)
		{ 	
			OLED_DrawPoint(x,y,dot);	
		}
	}													    
	OLED_Refresh_Gram();//更新显示
}

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示				 
//size:选择字体 12/16/24
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{      			    
	u8 temp,t,t1;
	u8 y0=y;
	u8 csize=(size/8+((size%8)?1:0))*(size/2);		//得到字体一个字符对应点阵集所占的字节数
	chr=chr-' ';//得到偏移后的值		 
    for(t=0;t<csize;t++)
    {   
		if(size==12)temp=ascii_1206[chr][t]; 	 	//调用1206字体
		else if(size==16)temp=ascii_1608[chr][t];	//调用1608字体
		else if(size==24)temp=ascii_2412[chr][t];	//调用2412字体
		else return;								//没有的字库
        for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)OLED_DrawPoint(x,y,mode);
			else OLED_DrawPoint(x,y,!mode);
			temp<<=1;
			y++;
			if((y-y0)==size)
			{
				y=y0;
				x++;
				break;
			}
		}  	 
    }
    OLED_Refresh_Gram();//更新显? 		
}
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标  
void OLED_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
	u16 t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 
	delta_x=x2-x1; //计算坐标增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //设置单步方向 
	else if(delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平线 
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//画线输出 
	{  
    OLED_DrawPoint(uRow,uCol,1);		
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}
  OLED_Refresh_Gram();//更新显? 
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}

				  
//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{         	
	u8 t,temp;
	u8 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+(size/2)*t,y,' ',size,1);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1); 
	}
} 


//显示字符串
//x,y:起点坐标  
//size:字体大小 
//*p:字符串起始地址 
void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size)
{	
    while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
    {       
        if(x>(128-(size/2))){x=0;y+=size;}
        if(y>(64-size)){y=x=0;OLED_Clear();}
        OLED_ShowChar(x,y,*p,size,1);	 
        x+=size/2;
        p++;
    }  	
}


//显示汉字
//x,y:起点坐标  
//pos:数组位置汉字显示
//size:字体大小 
//mode:0,反白显示;1,正常显示
void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode)
{
	u8 temp,t,t1;
	u8 y0=y;  
	u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数	 
	if(size!=12&&size!=16&&size!=24)return;	//不支持的size
	 
	for(t=0;t<csize;t++)
	{   												   
		if(size==12)temp=FontHzk[pos][t]; 	 	//调用1206字体
		else if(size==16)temp=FontHzk[pos][t];	//调用1608字体
		else if(size==24)temp=FontHzk[pos][t];	//调用2412字体
		else return;								//没有的字库
        for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)OLED_DrawPoint(x,y,mode);
			else OLED_DrawPoint(x,y,!mode);
			temp<<=1;
			y++;
			if((y-y0)==size)
			{
				y=y0;
				x++;
				break;
			}
		}  	 
	}  	
} 	

//显示BMP图片128×64
//起始点坐标(x,y),x的范围0~127,y为页的范围0~7
void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[])
{ 	
 	u16 j=0;
 	u8 x,y;
  
  	if(y1%8==0)y=y1/8;      
  	else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    	for(x=x0;x<x1;x++)
	    {      
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 


//OLED的初始化
void OLED_Init()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);
	/*
		如果我们的开发板没有这俩个引脚,或者我们这俩个引脚被占用,我们可以修改这个地方的引脚初始化
		还有进行修改的就是oled.h中的PBout(5)和PBout(6)
	*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6; 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOB, &GPIO_InitStructure);	 
 	GPIO_SetBits(GPIOB,GPIO_Pin_5|GPIO_Pin_6);	//拉高电?
	delay_ms(500);
					  
	OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
	OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
	OLED_WR_Byte(80,OLED_CMD);   //[3:0],分频因子;[7:4],震荡频率
	OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
	OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) 
	OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
	OLED_WR_Byte(0X00,OLED_CMD); //默认为0

	OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
													    
	OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
	OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
	OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
	OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
	OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
	OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
	OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
	OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
		 
	OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
	OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
	OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
	OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
	OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
	OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

	OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
	OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示	    						   
	OLED_WR_Byte(0xAF,OLED_CMD); //开启显示	 
	OLED_Clear();
	OLED_Refresh_Gram();
}

oled.h

#ifndef _oled_H
	#define _oled_H
	#include "sys.h"
	#include "stdlib.h"	
	#define SIZE 16
	#define XLevelL		0x00
	#define XLevelH		0x10
	#define Max_Column	128
	#define Max_Row		64
	#define	Brightness	0xFF 
	#define X_WIDTH 	128
	#define Y_WIDTH 	64
	//OLDE-IIC总线控制管脚定义
	#define OLED_SCL  PBout(5)
	#define OLED_SDA  PBout(6)		     
	#define OLED_CMD  0	//写命令
	#define OLED_DATA 1	//写数据		    						  
	//OLED控制用函数
	void OLED_WR_Byte(u8 dat,u8 cmd);	    
	void OLED_Display_On(void);
	void OLED_Display_Off(void);
	void OLED_Set_Pos(unsigned char x, unsigned char y);	   							   		    
	void OLED_Init(void);
	void OLED_Refresh_Gram(void);
	void OLED_Clear(void);
	void OLED_DrawPoint(u8 x,u8 y,u8 t);
	void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
	void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
	void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
	void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size); 
	void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode);
	void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]);
	#endif

main.c

#include "delay.h"
#include "key.h"
#include "usart.h"
#include "timer.h"
#include "oled.h"

//GND  接电源地
//VCC  接5V或3.3v电源
//D0   接(SCL)
//D1   接(SDA)

int main(void)
{		
	 delay_init();	    	 //延时函数初始化	  
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	 OLED_Init(); //OLED初始化
	 
	 
   while(1)
	 {
		  OLED_ShowString(0,0,"hello world!!!!",16);
	 }
}

总结

在这里我们只是显示一个hello world!!!字符串,但是我们还是没有办法显示汉字,那我们怎么弄,因为我们SSD1306芯片没有汉字的字库,所以我们需要用一些软件,将文字转化成C数组数据,进行显示。在这里就不多赘述了,下一个文章很短,专门讲一下显示汉字。
最后看一下效果吧。
在这里插入图片描述

相关代码和SSD1306的数据手册:
链接:https://pan.baidu.com/s/15VlIEyc9I-0i8fuTbGxtUQ
提取码:x8ou

  • 26
    点赞
  • 175
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值