STC89C51驱动0.96寸oled避坑教程(I2C)

   日期:2021-02-07     浏览:94    评论:0    
核心提示:文章目录51单片机一.前言二.代码三.总结51单片机一.前言说起51,可以说是老古董了,刚开始接触单片机就是从51开始,今天就来用51单片机驱动oled显示屏,oled显示屏采用i2c的接口,因为51的代码看起来更容易理解,在移植到其他平台就可以参考这个代码来写了。顺便也将驱动过程中遇到的坑分享给大家二.代码先放上代码的连接1.gitee 代码2.项目下载oled.c#include "oled.h"#include "oledfont.h" //OLED的显存//存放

文章目录

  • 51单片机
    • 一.前言
    • 二.连接方式
    • 三.工程代码
    • 四.避坑环节

51单片机

一.前言

说起51,可以说是老古董了,刚开始接触单片机就是从51开始,今天就来用51单片机驱动oled显示屏,oled显示屏采用i2c的接口,因为51的代码看起来更容易理解,在移植到其他平台就可以参考这个代码来写了。顺便也将驱动过程中遇到的坑分享给大家

二.连接方式

oled和单片机连接如下表所示,管脚定义可以任意选用gpio口,因为写的是软件I2C,所以需要改其他管脚的可以在oled.h文件当中修改

51单片机 OLED
VCC VCC(5V)
GND GND
P1^0 CLK
P1^1 DATA

三.工程代码

先放上代码的连接
1.gitee 代码
2.项目下载

oled.c

#include "oled.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 



void Delay_50ms(unsigned int Del_50ms)
{ 
	unsigned int m;
	for(;Del_50ms>0;Del_50ms--)
		for(m=6245;m>0;m--);
}

void Delay_1ms(unsigned int Del_1ms)
{ 
	unsigned char j;
	while(Del_1ms--)
	{ 	
		for(j=0;j<123;j++);
	}
}



void IIC_Start()
{ 
	OLED_SCLK_Set() ;
	OLED_SDIN_Set();
	OLED_SDIN_Clr();
	OLED_SCLK_Clr();
}


void IIC_Stop()
{ 
	OLED_SCLK_Set() ;
	OLED_SDIN_Clr();
	OLED_SDIN_Set();
}

void IIC_Wait_Ack()
{ 
	OLED_SCLK_Set() ;
	OLED_SCLK_Clr();
}


void Write_IIC_Byte(unsigned char IIC_Byte)
{ 
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_Clr();
	for(i=0;i<8;i++)		
	{ 
			m=da;
		// OLED_SCLK_Clr();
		m=m&0x80;
		if(m==0x80)
		{ OLED_SDIN_Set();}
		else OLED_SDIN_Clr();
			da=da<<1;
		OLED_SCLK_Set();
		OLED_SCLK_Clr();
		}
}


void Write_IIC_Command(unsigned char IIC_Command)
{ 
   IIC_Start();
   Write_IIC_Byte(0x78);            //Slave address,SA0=0
	IIC_Wait_Ack();	
   Write_IIC_Byte(0x00);			//write command
	IIC_Wait_Ack();	
   Write_IIC_Byte(IIC_Command); 
	IIC_Wait_Ack();	
   IIC_Stop();
}

void Write_IIC_Data(unsigned char IIC_Data)
{ 
   IIC_Start();
   Write_IIC_Byte(0x78);			//D/C#=0; R/W#=0
	 IIC_Wait_Ack();	
   Write_IIC_Byte(0x40);			//write data
	 IIC_Wait_Ack();	
   Write_IIC_Byte(IIC_Data);
	 IIC_Wait_Ack();	
   IIC_Stop();
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{ 
	if(cmd)
	{ 
		Write_IIC_Data(dat);
	}
	else 
	{ 	
		Write_IIC_Command(dat);
	}
}


void fill_picture(unsigned char fill_Data)
{ 
	unsigned char m,n;
	for(m=0;m<8;m++)
	{ 
		OLED_WR_Byte(0xb0+m,0);		//page0-page1
		OLED_WR_Byte(0x00,0);		//low column start address
		OLED_WR_Byte(0x10,0);		//high column start address
		for(n=0;n<128;n++)
			{ 
				OLED_WR_Byte(fill_Data,1);
			}
	}
}


//坐标设置
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),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++)  
	{   
		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(0,OLED_DATA); 
	} //更新显示
}

void OLED_On(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(1,OLED_DATA); 
	} //更新显示
}

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示 
//size:选择字体 16/12 
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{       	
	unsigned char c=0,i=0;	
		c=chr-' ';//得到偏移后的值 
		if(x>Max_Column-1){ x=0;y=y+2;}
		if(Char_Size ==16)
			{ 
			OLED_Set_Pos(x,y);	
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
			OLED_Set_Pos(x,y+1);
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
			}
			else { 	
				OLED_Set_Pos(x,y);
				for(i=0;i<6;i++)
				OLED_WR_Byte(F6x8[c][i],OLED_DATA);
				
			}
}

//m^n函数
u32 oled_pow(u8 m,u8 n)
{ 
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}			

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

//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{ 
	unsigned char j=0;
	while (chr[j]!='\0')
	{ 		OLED_ShowChar(x,y,chr[j],Char_Size);
			x+=8;
		if(x>120){ x=0;y+=2;}
			j++;
	}
}

//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{       			    
	u8 t,adder=0;
	OLED_Set_Pos(x,y);	
    for(t=0;t<16;t++)
		{ 
				OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
				adder+=1;
     }	
		OLED_Set_Pos(x,y+1);	
    for(t=0;t<16;t++)
			{ 	
				OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
				adder+=1;
      }					
}


//和之前显示图片的参数不同
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{  	
 unsigned int j=0;
 unsigned char 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);	    	
	    }
	}
} 

//初始化SSD1306 
void OLED_Init(void)
{  	
 
	OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address 
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128 
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//
	
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//
	
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//
	
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//
	
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//
	
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//
	
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//
	
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}  

四.避坑环节

遇到的坑无非就是编译的问题,因为51的内部rom比较小,而oled驱动显示,字符和图片啥的都是取的模,定义的全局变量,所以编译出来的hex超过了rom的容量就报错,无法产生hex文件

51单片机仅有128 Byte内部RAM
52单片机有256 Byte内部RAM

解决办法

  • 将数据保存到外部ROM当中,在keil5中如下设置(当然keil4也是一样的)
  • 在取模汉字或者图片数组前面加 code
//汉字取模
unsigned char code Hzk[][32]={ 

{ 0x20,0x20,0x24,0x24,0x24,0x24,0xBF,0x64,0x24,0x34,0x28,0x24,0x22,0x20,0x20,0x00},
{ 0x10,0x08,0x04,0x02,0x3F,0x45,0x44,0x44,0x42,0x42,0x42,0x41,0x78,0x00,0x00,0x00},

{ 0x00,0x22,0x26,0x1A,0x92,0x02,0x7E,0x80,0x22,0x26,0x1A,0x12,0x02,0x7E,0x00,0x00},
{ 0x08,0x04,0x02,0xFF,0x55,0x55,0x55,0x55,0x7F,0x55,0x55,0x55,0x55,0x41,0x00,0x00},
	
};
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服