STC90C51驱动LCD1602、LCD12864、OLED

主控芯片(STC90C516RD+PG5151028)介绍

STC90C5116RD芯片引脚图

ROM=64K,RAM=1280字节,40Pin,3个定时器,1个串口,8个中断源(分别是:外部中断0(INTO)、外部中断 1(INT1)、外部中断 2(INT2)、外部中断 3(INT3)、定时器 0中断、定时器 1 中断、定时器 2 中断、串口(UART)中断),所有的中断都具有4个中断优先级

1.LCD1602

1.1.LCD1602简介

1602 液晶也叫 1602 字符型液晶,它能显示 2 行字符信息,每行又能显示 16个字符。它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若干个 5x7 或者 5x10 的点阵字符位组成,每个点阵字符位都可以用显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。

局部接线图
引脚说明(16引脚):
VSS: 电源地
VDD:电源正极(+5V)
VO:液晶显示偏压信号,用于调整 LCD1602 的显示对比度,一般会外接电位器用以调整偏压信号,注意此脚电压为 0 时可以得到最强的对比度。
RS:数据/命令选择端,当此脚为高电平时,可以对 1602 进行数据字节的传输操作,而为低电平时,则是进行命令字节的传输操作。命令字节,即是用来对 LCD1602 的一些工作方式作设置的字节;数据字节,即使用以在 1602 上显示的字节。值得一提的是,LCD1602 的数据是 8 位的。
RW:读写选择端。当此脚为高电平可对 LCD1602 进行读数据操作,反之进行写数据操作。
E:使能信号,其实是 LCD1602 的数据控制时钟信号,利用该信号的上升沿实现对 LCD1602 的数据传输。
D0-D7:8 位并行数据口,而 51 单片机一组 IO 也是 8 位,使得对 LCD1602的数据读写大为方便。
A:背光源正极
K:背光源负极
在这里插入图片描述
在 LCD1602 内部含有 80 个字节的 DDRAM,它是用来寄存显示字符的。不是所有的地址都可以直接用来显示字符数据,只有第一行中的 00-0F,第二行中的 40-4F 才能显示,其他地址只能用于存储。
LCD1602 操作步骤如下所示: (1)初始化 (2)写命令(RS=L),设置显示坐标 (3)写数据(RS=H)
①当要写指令字,设置 LCD1602 的工作方式时:需要把 RS 置为低电平,RW置为低电平,然后将数据送到数据口 D0~D7,最后 E 引脚一个高脉冲将数据写入。
②当要写入数据字,在 1602 上实现显示时:需要把 RS 置为高电平,RW 置为低电平,然后将数据送到数据口 D0~D7,最后 E 引脚一个高脉冲将数据写入。

硬件连接:
VSS------GND
VDD------5V
RS-------P2.6
RW-------P2.5
E--------P2.7
D0-D7-------P0
VO---------RJ6调节背光

1.2驱动代码

led.h

#ifndef __LCD_H_
#define __LCD_H_

/**********************************
包含头文件
**********************************/
#include<reg52.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;

/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/	
void LcdWriteData(uchar dat)	;
/*LCD1602初始化子程序*/		
void LcdInit();	
void lcd_clear();
void lcd_show_string(uchar x,uchar y,uchar *str);					  

#endif

lcd.c

#include "lcd.h"

/*******************************************************************************
* 函 数 名         : Lcd1602_Delay1ms
* 函数功能		   : 延时函数,延时1ms
* 输    入         : c
* 输    出         : 无
* 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/

void Lcd1602_Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}

/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能		   : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/

void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}

/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能		   : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/		   
		   
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}

/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能		 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/
		   
void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}

/*******************************************************************************
* 函 数 名       : lcd_clear
* 函数功能		 : LCD 清屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/
		   
void lcd_clear()						  
{
   LcdWriteCom(0x01);
}

/*******************************************************************************
* 函 数 名       : lcd_show_string
* 函数功能		 : LCD 显示字符
* 输    入       : x,y:显示坐标,x=0~15,y=0~1;str:显示字符串
* 输    出       : 无
*******************************************************************************/
		   
void lcd_show_string(uchar x,uchar y,uchar *str)						  
{
   uchar i = 0;
   if(y>1||x>15)return;//行列参数不对则强制退出
   if(y<1) //第 1 行显示
    {
        while(*str!='\0')//字符串是以'\0'结尾,只要前面有内容就显示
        {
            if(i<16-x)//如果字符长度超过第一行显示范围,则在第二行继续显示
            {
                LcdWriteCom(0x80+i+x);//第一行显示地址设置
            }
         else
         {
                LcdWriteCom(0x40+0x80+i+x-16);//第二行显示地址设置
         }
         LcdWriteData(*str);//显示内容
         str++;//指针递增
         i++;
        }
    }
   else
   {
        while(*str!='\0')
        {
            if(i<16-x)  //如果字符长度超过第二行显示范围,则在第一行继续显示
               LcdWriteCom(0x80+0x40+i+x); 
            else
               LcdWriteCom(0x80+i+x-16);

         LcdWriteData(*str);//显示内容
         str++;//指针递增
         i++;
        }
 
   }



}

main.c

/**************************************************************************************
*		              LCD1602液晶显示实验												  *
实现现象:	具体接线操作请参考视频教程
			下载程序后插上LCD1602液晶在开发板上,即可显示
注意事项:																				  
***************************************************************************************/

#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
#include "lcd.h"

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;


/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void main(void)
{
	
	LcdInit();
    lcd_clear();
    lcd_show_string(0,0,"Hello World!");//第一行显示
    lcd_show_string(0,1,"0123456789");//第二行显示
	while(1);				
}

1.3显示效果图

在这里插入图片描述

2.LCD12864

2.1LCD12864简介

12864 是以 128 列像素,64 行像素,也就是有 12864 个像素点组成,通常显示一个汉字需要 1616 个像素点,所以 LCD12864 一行最多能显示 8个汉字,最多能显示 4 行。通常显示一个字符需要 8*8 个像素点,所以 LCD12864 一行最多能显示 16 个字符,最多能显示 8 行。

引脚说明(16引脚):
GND:电源地(0V)
VCC:电压输入(+5V)
RS:寄存器选择端,高:读操作 低:写操作
RD:读使能,低电平有效,高电平读失能
WR:读写信号,高:读操作 低:写操作
D0-D7:数据总线
CS:片选信号,低有效
RESET:复位信号,低有效
在这里插入图片描述
从上图可知,LCD12864 能直接显示的地址范围如下:
第一行:0X80-0X87;(一个汉字占用 2 个字节,共 8 个汉字)
第二行:0X90-0X97;
第三行:0X88-0X8F;
第四行:0X98-0X9F;

不带字库的 LCD12864 背面没有芯片,一般为转接板,将 12864 显示屏转接到开发板,所有的显示都需要取模,取模方法和点阵取模一样。内部驱动芯片是 ST7565P,ST7565P 数据手册是液晶屏内核手册,里面有驱动方法和指令和程序有关的数据。

硬件连接:
D0-D7--------P0
CS-----------P3.2
RESET--------P3.3
RS-----------P2.6
RW-----------P2.7
RD-----------P2.5

2.2驱动代码

lcd12864.h

#ifndef __ST7565_H
#define __ST7565_H

#include<reg51.h>
#include<intrins.h>

//---包含字库头文件
#define CHAR_CODE


//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

//--定时使用的IO口--//
#define DATA_PORT P0
sbit LCD12864_CS   = P3^2;
sbit LCD12864_RSET = P3^3;
sbit LCD12864_RS   = P2^6;
sbit LCD12864_RW   = P2^7;
sbit LCD12864_RD   = P2^5;

//--定义全局函数--//
void LcdSt7565_WriteCmd(cmd);
void LcdSt7565_WriteData(dat);
void Lcd12864_Init();
void Lcd12864_ClearScreen(void);
uchar Lcd12864_Write16CnCHAR(uchar x, uchar y, uchar *cn);

#endif

lcd12864.c

#include"st7565.h"

/*******************************************************************************
* 函 数 名         : LCD12864_WriteCmd
* 函数功能		   : 写入一个命令到12864
* 输    入         : cmd
* 输    出         : 无
*******************************************************************************/

void LcdSt7565_WriteCmd(cmd)
{
	LCD12864_CS = 0;	   //chip select,打开片选
	LCD12864_RD = 1;	   //disable read,读失能	
	LCD12864_RS = 0;       //select command,选择命令
	LCD12864_RW = 0;       //select write,选择写模式
	_nop_();
	_nop_();

	DATA_PORT = cmd; //put command,放置命令
	_nop_();
	_nop_();

	LCD12864_RW = 1;	   //command writing ,写入命令
}

/*******************************************************************************
* 函 数 名         : LcdSt7565_WriteData
* 函数功能		   : 写入一个数据到12864
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/

void LcdSt7565_WriteData(dat)
{	
	LCD12864_CS = 0;	   //chip select,打开片选
	LCD12864_RD = 1;	   //disable read,读失能	
	LCD12864_RS = 1;       //select data,选择数据
	LCD12864_RW = 0;       //select write,选择写模式
	_nop_();
	_nop_();

	DATA_PORT = dat;       //put data,放置数据
	_nop_();
	_nop_();

	LCD12864_RW = 1;	   //data writing,写数据 
}

/*******************************************************************************
* 函 数 名         : LCD12864_Init
* 函数功能		   : 初始化12864
* 输    入         : 无
* 输    出         : 无
* 说    明         : LCD12864的命令指令可以查看例程文件夹下的《ST7565p数据手册》
*                  * 的第51页的位置。
*******************************************************************************/

void Lcd12864_Init()
{
	uchar i;
	LCD12864_RSET = 0;
	for (i=0; i<100; i++);
	LCD12864_CS = 0;
	LCD12864_RSET = 1;
	
	//----------------Star Initial Sequence-------//
	//------程序初始化设置,具体命令可以看文件夹下---//

	//--软件初始化--//
	LcdSt7565_WriteCmd(0xE2);  //reset
	for (i=0; i<100; i++);	   //延时一下

	//--表格第8个命令,0xA0段(左右)方向选择正常方向(0xA1为反方向)--//
	LcdSt7565_WriteCmd(0xA1);  //ADC select segment direction 
	
	//--表格第15个命令,0xC8普通(上下)方向选择选择反向,0xC0为正常方向--// 
	LcdSt7565_WriteCmd(0xC8);  //Common direction 
	                  
	//--表格第9个命令,0xA6为设置字体为黑色,背景为白色---//
	//--0xA7为设置字体为白色,背景为黑色---//
	LcdSt7565_WriteCmd(0xA6);  //reverse display

	//--表格第10个命令,0xA4像素正常显示,0xA5像素全开--//
	LcdSt7565_WriteCmd(0xA4);  //normal display
	
	//--表格第11个命令,0xA3偏压为1/7,0xA2偏压为1/9--//
	LcdSt7565_WriteCmd(0xA2);  //bias set 1/9
	
	//--表格第19个命令,这个是个双字节的命令,0xF800选择增压为4X;--//
	//--0xF801,选择增压为5X,其实效果差不多--//	
	LcdSt7565_WriteCmd(0xF8);  //Boost ratio set
	LcdSt7565_WriteCmd(0x01);  //x4
	
	//--表格第18个命令,这个是个双字节命令,高字节为0X81,低字节可以--//
	//--选择从0x00到0X3F。用来设置背景光对比度。---/
	LcdSt7565_WriteCmd(0x81);  //V0 a set
	LcdSt7565_WriteCmd(0x23);

	//--表格第17个命令,选择调节电阻率--//
	LcdSt7565_WriteCmd(0x25);  //Ra/Rb set
	
	//--表格第16个命令,电源设置。--//
	LcdSt7565_WriteCmd(0x2F);
	for (i=0; i<100; i++);

	//--表格第2个命令,设置显示开始位置--//
	LcdSt7565_WriteCmd(0x40);  //start line

	//--表格第1个命令,开启显示--//
	LcdSt7565_WriteCmd(0xAF);  // display on
	for (i=0; i<100; i++);

}


/*******************************************************************************
* 函 数 名         : LCD12864_ClearScreen
* 函数功能		   : 清屏12864
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Lcd12864_ClearScreen(void)
{
	uchar i, j;

	for(i=0; i<8; i++)
	{
		//--表格第3个命令,设置Y的坐标--//
		//--Y轴有64个,一个坐标8位,也就是有8个坐标--//
		//所以一般我们使用的也就是从0xB0到0x07,就够了--//	
		LcdSt7565_WriteCmd(0xB0+i); 

		//--表格第4个命令,设置X坐标--//
		//--当你的段初始化为0xA1时,X坐标从0x10,0x04到0x18,0x04,一共128位--//
		//--当你的段初始化为0xA0时,X坐标从0x10,0x00到0x18,0x00,一共128位--//
		//--在写入数据之后X坐标的坐标是会自动加1的,我们初始化使用0xA0所以--//
		//--我们的X坐标从0x10,0x00开始---//
		LcdSt7565_WriteCmd(0x10); 
		LcdSt7565_WriteCmd(0x04);							   
		
		//--X轴有128位,就一共刷128次,X坐标会自动加1,所以我们不用再设置坐标--//
		for(j=0; j<128; j++)
		{
			LcdSt7565_WriteData(0x00);  //如果设置背景为白色时,清屏选择0XFF
		}
	}
}

/*******************************************************************************
* 函 数 名         : LCD12864_Write16CnCHAR
* 函数功能		   : 在12864上面书写16X16的汉字
* 输    入         : x, y, cn
* 输    出         : 无
* 说    明		   : 该函数可以直接书写字符串,但是书写是从右到左,所以输入的时
*                  * 侯注意输入。汉字的取模方式请观看文件夹下的《汉字取模软件的
*                  * 使用说明》
*******************************************************************************/

#ifdef  CHAR_CODE

#include"charcode.h"

uchar Lcd12864_Write16CnCHAR(uchar x, uchar y, uchar *cn)
{
	uchar j, x1, x2, wordNum;

	//--Y的坐标只能从0到7,大于则直接返回--//
	if(y > 7)
	{
		return 0;
	}

	//--X的坐标只能从0到128,大于则直接返回--//
	if(x > 128)
	{
		return 0;
	}
	y += 0xB0;	   //求取Y坐标的值
	//--设置Y坐标--//
	LcdSt7565_WriteCmd(y);
	while ( *cn != '\0')	 //在C语言中字符串结束以‘\0’结尾
	{	
	
		//--设置Y坐标--//
		LcdSt7565_WriteCmd(y);

		x1 = (x >> 4) & 0x0F;   //由于X坐标要两句命令,分高低4位,所以这里先取出高4位
		x2 = x & 0x0F;          //去低四位
		//--设置X坐标--//
		LcdSt7565_WriteCmd(0x10 + x1);   //高4位
		LcdSt7565_WriteCmd(0x04 + x2);	//低4位

		for (wordNum=0; wordNum<50; wordNum++)
		{
		    //--查询要写的字在字库中的位置--//
			if ((CN16CHAR[wordNum].Index[0] == *cn)
			     &&(CN16CHAR[wordNum].Index[1] == *(cn+1)))
			{
				for (j=0; j<32; j++) //写一个字
				{		
					if (j == 16)	 //由于16X16用到两个Y坐标,当大于等于16时,切换坐标
					{
						//--设置Y坐标--//
			   			LcdSt7565_WriteCmd(y + 1);
			
						//--设置X坐标--//
						LcdSt7565_WriteCmd(0x10 + x1);   //高4位
						LcdSt7565_WriteCmd(0x04 + x2);	//低4位
					}
					LcdSt7565_WriteData(CN16CHAR[wordNum].Msk[j]);
				}
				x += 16;
			}//if查到字结束		
		} //for查字结束	
		cn += 2;
	}	//while结束
	return 1;
}

#endif

main.c

#include<reg51.h>
#include"st7565.h"

//---声明一个全局变量---//
void Delay10ms(unsigned int c);

/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void main()
{
	uchar i = 128;
	Lcd12864_Init();
	Lcd12864_ClearScreen();
		
	while (1)
	{
		for (i=0; i<2; i += 2)
		{
			Lcd12864_ClearScreen();

			//--由于这个函数显示方向正好相反--//
			Lcd12864_Write16CnCHAR(32, i, "钟时子电气天");
			Delay10ms(100);
		}
	
	}
}

/*******************************************************************************
* 函 数 名         : Delay10ms
* 函数功能		   : 延时函数,延时10ms
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Delay10ms(unsigned int c)   //误差 0us
{
    unsigned char a,b;
    for(;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

2.3显示效果图

在这里插入图片描述

3.OLED(IIC)

3.1简介

OLED显示和传统的LCD显示不同,其可以自发光,所以不需要背光灯,这使得OLED显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。 常用的OLED屏幕有蓝色、黄色、白色等几种。屏的大小为0.96寸,像素点为 128*64,所以我们称为0.96oled屏或者12864屏。电源电压为3.3-5.5V,驱动芯片为SSD1306

硬件连接
GND-------OLED模块电源地
VCC-------OLED模块电源正极(3.3V/5V)
SCL--------IIC总线时钟信号,P0.2
SDA--------IIC总线数据信号,P0.3

3.2代码

oled.h

#ifndef __OLED_H
#define __OLED_H
#include <reg52.h>

#define  u8 unsigned char 
#define  u16 unsigned int
#define  u32 unsigned int
	
#define OLED_CMD  0	//写命令
#define OLED_DATA 1	//写数据

sbit OLED_SCL=P0^2;//SCL
sbit OLED_SDA=P0^3;//SDA
sbit OLED_RES =P0^4;//RES


//-----------------OLED端口定义----------------

#define OLED_SCL_Clr() OLED_SCL=0
#define OLED_SCL_Set() OLED_SCL=1

#define OLED_SDA_Clr() OLED_SDA=0
#define OLED_SDA_Set() OLED_SDA=1

#define OLED_RES_Clr() OLED_RES=0
#define OLED_RES_Set() OLED_RES=1


//OLED控制用函数
void delay_ms(unsigned int ms);
void OLED_ColorTurn(u8 i);
void OLED_DisplayTurn(u8 i);
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Set_Pos(u8 x, u8 y);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Clear(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey);
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey);
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]);
void OLED_Init(void);

#endif 

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_ms(unsigned int ms)
{                         
	unsigned int a;
	while(ms)
	{
		a=1800;
		while(a--);
		ms--;
	}
	return;
}

//反显函数
void OLED_ColorTurn(u8 i)
{
	if(i==0)
		{
			OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
		}
	if(i==1)
		{
			OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
		}
}

//屏幕旋转180度
void OLED_DisplayTurn(u8 i)
{
	if(i==0)
		{
			OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
			OLED_WR_Byte(0xA1,OLED_CMD);
		}
	if(i==1)
		{
			OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
			OLED_WR_Byte(0xA0,OLED_CMD);
		}
}


//起始信号
void I2C_Start(void)
{
	OLED_SDA_Set();
	OLED_SCL_Set();
	 
	OLED_SDA_Clr();
	 
	OLED_SCL_Clr();
	 
}

//结束信号
void I2C_Stop(void)
{
	OLED_SDA_Clr();
	OLED_SCL_Set();
	 
	OLED_SDA_Set();
}

//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
	OLED_SDA_Set();
	 
	OLED_SCL_Set();
	 
	OLED_SCL_Clr();
	 
}

//写入一个字节
void Send_Byte(u8 dat)
{
	u8 i;
	for(i=0;i<8;i++)
	{
		OLED_SCL_Clr();//将时钟信号设置为低电平
		if(dat&0x80)//将dat的8位从最高位依次写入
		{
			OLED_SDA_Set();
    }
		else
		{
			OLED_SDA_Clr();
    }
		 
		OLED_SCL_Set();
		 
		OLED_SCL_Clr();
		dat<<=1;
  }
}

//发送一个字节
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
	I2C_Start();
	Send_Byte(0x78);
	I2C_WaitAck();
	if(mode){Send_Byte(0x40);}
  else{Send_Byte(0x00);}
	I2C_WaitAck();
	Send_Byte(dat);
	I2C_WaitAck();
	I2C_Stop();
}

//坐标设置

void OLED_Set_Pos(u8 x, u8 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); 
	} //更新显示
}

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63				 
//sizey:选择字体 6x8  8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey)
{      	
	u8 c=0,sizex=sizey/2;
	u16 i=0,size1;
	if(sizey==8)size1=6;
	else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
	c=chr-' ';//得到偏移后的值
	OLED_Set_Pos(x,y);
	for(i=0;i<size1;i++)
	{
		if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);
		if(sizey==8) OLED_WR_Byte(asc2_0806[c][i],OLED_DATA);//6X8字号
		else if(sizey==16) OLED_WR_Byte(asc2_1608[c][i],OLED_DATA);//8x16字号
//		else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号
		else return;
	}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}				  
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey)
{         	
	u8 t,temp,m=0;
	u8 enshow=0;
	if(sizey==8)m=2;
	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+(sizey/2+m)*t,y,' ',sizey);
				continue;
			}else enshow=1;
		}
	 	OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
	}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey)
{
	u8 j=0;
	while (chr[j]!='\0')
	{		
		OLED_ShowChar(x,y,chr[j++],sizey);
		if(sizey==8)x+=6;
		else x+=sizey/2;
	}
}
//显示汉字
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey)
{
	u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;
	for(i=0;i<size1;i++)
	{
		if(i%sizey==0) OLED_Set_Pos(x,y++);
		if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号
//		else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号
		else return;
	}				
}


//显示图片
//x,y显示坐标
//sizex,sizey,图片长宽
//BMP:要显示的图片
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[])
{ 	
  u16 j=0;
	u8 i,m;
	sizey=sizey/8+((sizey%8)?1:0);
	for(i=0;i<sizey;i++)
	{
		OLED_Set_Pos(x,i+y);
    for(m=0;m<sizex;m++)
		{      
			OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
		}
	}
} 



//初始化				    
void OLED_Init(void)
{
	OLED_RES_Clr();
  delay_ms(200);
	OLED_RES_Set();
	
	OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
	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  Set Mapping RAM Display Start Line (0x00~0x3F)
	OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
	OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
	OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
	OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
	OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	OLED_WR_Byte(0x00,OLED_CMD);//-not offset
	OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
	OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
	OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
	OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
	OLED_WR_Byte(0x12,OLED_CMD);
	OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
	OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
	OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
	OLED_WR_Byte(0x02,OLED_CMD);//
	OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
	OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
	OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
	OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) 
	OLED_Clear();
	OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ 
}


main.c

#include <reg52.h>
#include "oled.h"


int main(void)
{	
	u8 t=' ';
	OLED_Init();//初始化OLED
	OLED_ColorTurn(0);//0正常显示,1 反色显示
  OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
	while(1) 
	{		
		OLED_ShowChinese(18,0,0,16);//
		OLED_ShowChinese(36,0,1,16);//
		OLED_ShowChinese(54,0,2,16);//
		OLED_ShowChinese(72,0,3,16);//
		OLED_ShowChinese(90,0,4,16);//
		OLED_ShowChinese(108,0,5,16);//

		OLED_ShowString(20,4,"2024/06/06",16);
	}
}

3.3显示效果图

在这里插入图片描述

4.下载链接

51驱动LCD

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/695813.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【微信小程序开发(从零到一)】——个人中心页面的实战项目(二)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

「动态规划」如何计算能获得多少点数?

740. 删除并获得点数https://leetcode.cn/problems/delete-and-earn/description/ 给你一个整数数组nums&#xff0c;你可以对它进行一些操作。每次操作中&#xff0c;选择任意一个nums[i]&#xff0c;删除它并获得nums[i]的点数。之后&#xff0c;你必须删除所有等于nums[i] …

【网络安全的神秘世界】web应用程序安全与风险

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 第一章&#xff1a;web应用程序安全与风险 web攻击基础知识 1、什么是web应用攻击 web攻击的本质&#xff0c;就是通过http协议篡改应用程序&#xff0…

虚拟机ping不通主机,但是主机可以ping通虚拟机

我在Windows10系统安装了虚拟机&#xff0c;设置的主机与虚拟机的连接方式是桥接&#xff0c;安装好后&#xff0c;发现虚拟机ping不通主机&#xff0c;但是主机可以ping通虚拟机。 我的操作是&#xff1a;关闭防火墙&#xff0c;发现虚拟机可以ping通主机了。说明是Windows10…

python后端结合uniapp与uview组件tabs,实现自定义导航按钮与小标签颜色控制

实现效果&#xff08;红框内&#xff09;&#xff1a; 后端api如下&#xff1a; task_api.route(/user/task/states_list, methods[POST, GET]) visitor_token_required def task_states(user):name_list [待接单, 设计中, 交付中, 已完成, 全部]data []color [#F04864, …

CPP初级:模板的运用!

目录 一.泛型编程 二.函数模板 1.函数模板概念 2.函数模板格式 3.函数模板的原理 三.函数模板的实例化 1.隐式实例化 2.显式实例化 3.模板参数的匹配原则 四.类模板 1.类模板的定义格式 2.类模板的实例化 一.泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码…

express入门01服务器搭建以及get和post请求的监听

微搭提供了后端API的能力&#xff0c;但是不同的版本收费差别巨大&#xff0c;因为使用的门槛限制了中小企业使用低代码平台。那可不可以既要又要呢&#xff1f;答案是肯定的&#xff0c;那其实掌握一定的后端框架&#xff0c;借助我们在低代码中已经熟练掌握的技能其实是比较容…

2024.6.9 七

Python的time库 先导入库 import time相关函数 time.time() 返回当前时间的时间戳(一个记录时间的浮点数),从1970年开始算的 time.localtime(sec) 返回一个指定时间戳(sec)的struct_time对象,是一个元组封装起来的,默认是当地时间 struct_time对象 tm_year 年 tm_mon 月 tm_…

CDR2024软件破解Keygen激活工具2024最新版

CorelDRAW Graphics Suite2024最新版&#xff0c;这是一款让我爱不释手的图形设计神器&#xff01;作为一个软件评测专家&#xff0c;我一直在寻找一款能够提升我的设计效率和创造力的工具。而这款软件&#xff0c;简直就是为我量身定制的&#xff01;&#x1f389; 「CorelDR…

算法金 | AI 基石,无处不在的朴素贝叶斯算法

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 历史上&#xff0c;许多杰出人才在他们有生之年默默无闻&#xff0c; 却在逝世后被人们广泛追忆和崇拜。 18世纪的数学家托马斯贝叶斯…

温度传感器十大品牌

温度传感器品牌排行榜-十大热电偶品牌-热敏电阻品牌排行-Maigoo品牌榜

TikTok Shop账号需要防关联吗?

在TikTokShop作为新兴的电商销售渠道中&#xff0c;保护账号的安全和隐私&#xff0c;防止账号关联成为了重要的任务。为了更好地理解为何需要防关联以及如何进行防范&#xff0c;让我们深入探讨一下这个问题。 为什么要防关联&#xff1f; 1. 账号异常风险&#xff1a;防关联…

电容十大品牌供应商

十大电容器品牌&#xff0c;电解电容-陶瓷电容-超级电容器品牌排行榜-Maigoo品牌榜

Android gradle kts 8.0以上版本配置签名和修改APK输出名字

目录 概述修改签名配置新建签名文件目录配置签名信息使用签名信息打包 修改APK名称 概述 之前写过一篇文章是通过Kotlin的Dsl结合gradle编写的插件来管理项目依赖&#xff0c;我是从一个开源项目叫DanDanPlayAndroid项目上学到的&#xff0c;那时还没有使用toml文件来管理项目…

Linux入门学习(2)

1.相关复习新的指令学习 &#xff08;1&#xff09;我们需要自己创建一个用户&#xff0c;这个用户前期可以是一个root用户&#xff0c;后期使用创建的普通用户 &#xff08;2&#xff09;文件等于文件内容加上文件属性,对于文件的操作就包括对于文件内容的操作和文件属性&…

Apache SeaTunnel社区5月月报更新!

各位热爱 SeaTunnel 的小伙伴们&#xff0c;社区 5 月份月报来啦&#xff01; SeaTunnel 正在迅猛发展&#xff0c;积极投入社区项目建设的小伙伴将促进SeaTunnel不断提升数据同步的高可扩展性、高性能及高可靠性。欢迎关注每月月报更新&#xff0c;期待在下个月的Merge Star月…

Redis持久化说明

Redis的持久化是指将内存中的数据持久化到磁盘中&#xff0c;以保证数据在重启或宕机后不会丢失。 Redis提供了两种主要的持久化方式&#xff1a;RDB(Redis DataBase)和AOF(Append Only File)。 RDB&#xff08;Redis DataBase&#xff09; 1、RDB快照原理 RDB持久化方式会定…

STM32 | 独立看门狗 | RTC(实时时钟)

01、独立看门狗概述 在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状…

ffmpeg视频解码原理和实战-(5)硬件加速解码后进行渲染并输出帧率

头文件&#xff1a; xvideoview.h #ifndef XVIDEO_VIEW_H #define XVIDEO_VIEW_H #include <mutex> #include <fstream> struct AVFrame;void MSleep(unsigned int ms);//获取当前时间戳 毫秒 long long NowMs();/// 视频渲染接口类 /// 隐藏SDL实现 /// 渲染方案…

初阶 《函数》 4. 函数的调用

4. 函数的调用 4.1 传值调用 函数的形参和实参分别占有不同内存块&#xff0c;对形参的修改不会影响实参 4.2 传址调用 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式 这种传参方式可以让函数和函数外边的变量建立起真正的联系&#xff0c;也就是…