“OLED屏幕,色彩绚丽,画面清晰,让每一帧都生动无比。“#IIC协议【下】

"OLED屏幕,色彩绚丽,画面清晰,让每一帧都生动无比。"#IIC协议【下】

    • 前言
    • 预备知识
    • 1. OLED显示一个点代码实现
      • 1.1 OLED显示一个点代码实现核心思路
      • 1.2和LCD1602一样需要初始化,看手册,写初识化函数
      • 1.3选择Page 0位置显示
      • 1.4**发送0x08显示一个点**
      • 1.5完整程序代码
    • 2. OLED列地址
      • 2.1 OLED列地址手册介绍
      • 2.2代码体现
      • 2.3完整程序代码(显示两条线)
      • 2.4补充说明
    • 3. OLED清屏添加清屏函数
      • 3.1为什么需要清屏函数
      • 3.2 OLED清屏添加清屏函数核心思想
      • 3.3清屏函数代码
      • 3.4完整程序代码
      • 3.5补充说明
    • 4. OLED显示字母A
      • 4.1 OLED显示字母A核心思路
      • 4.2使用液晶显示模块字模工具生成字符A的数据
      • 4.3根据生成的字符A的数据建立字符数组
      • 4.4使用for循环发送字符数据使OLED显示字符A
      • 4.5完整程序代码
    • 5. OLED显示中文
      • 5.1 OLED显示中文核心思路
      • 5.2使用液晶显示模块字模工具生成字符的数据
      • 5.3根据生成字符的数据建立字符数组
      • 5.4构造发送字符数据函数
      • 5.4完整程序代码
    • 6. OLED显示图片
      • 6.1 OLED显示图片核心思路
      • 6.2百度搜索简笔图片
      • 6.3 FastStone Capture软件进行截图修改图片尺寸并保存为bmp格式
      • 6.4使用液晶显示模块字模工具生成图片的数据
      • 6.5根据生成图片的数据建立图片数组
      • 6.6构造发送图片数据函数
      • 6.7补充知识
      • 6.8完整程序代码
    • 结束语

前言

  本篇博文介绍的是用51单片机的 IIC 协议【下】(OLED屏幕),包含OLED显示一个点代码实现,OLED列地址,OLED清屏添加清屏函数, OLED显示字母A,OLED显示中文,OLED显示图片。看到这篇博文的朋友,可以先赞再看吗?

预备知识

  一、基本电路标识识别和接线,例如VCC,GND。
  二、电脑基本操作复制粘贴
  三、准备软件FastStone Capture,会简单操作(此软件需要的评论区评论)
  四、数字电子时序图的识别
  五、一点点专业英语积累
  六、C变量
  七、基本输入输出
  八、流程控制
  九、函数

  十、指针
  十一、字符串

  如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!

1. OLED显示一个点代码实现

1.1 OLED显示一个点代码实现核心思路

  • 和LCD1602一样需要初始化,看手册,写初识化函数
  • 选择Page 0位置显示
  • 发送0x08显示一个点

  注:本程序建立在OLED写入指令和数据工程上

1.2和LCD1602一样需要初始化,看手册,写初识化函数

  • 手册内容

  OLED Initial
  ( 01) display off (0xae)
  ( 02) set low column address (0x00)
  ( 03) set high column address (0x10)
  ( 04) set start line address (0x40)
  ( 05) set page address (0xb0)
  ( 06) contract control (0x81)
  ( 07) send 0xff (多字节指令)
  ( 08) set segment remap (0xa1)
  ( 09) set normal/reverse (0xa6)
  ( 10) set multiplex ratio (1 to 64) (0xa8 )
  ( 11) set duty 1/32 (0x3f)
  ( 12) com scan direction (0xc8)
  ( 13) set display offset (0xd3)
  ( 14) send 0x00
  ( 15) set osc division (0xd5)
  ( 16) send 0x80
  ( 17) set area color mode off (0xd8)
  ( 18) send 0x05
  ( 19) set pre-charge period (0xd9)
  ( 20) send 0xf1
  ( 21) set com pin configuration (0xda)
  ( 22) send 0x12
  ( 23) set Vcomh (0xdb)
  ( 24) send 0x30
  ( 25) set charge pump enable (0x8d)
  ( 26) send 0x14
  ( 27) turn on oled panel(0xaf)

  • 初始化OLED屏幕函数代码

  建立思路:根据手册内容调用OLED写指令函数发送对应指令

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  	OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  	OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

1.3选择Page 0位置显示

  • 确认页寻址模式

  向OLED发送指令0x200x02即可

OledWriteCmd(0x20);
OledWriteCmd(0x02);
  • 确认哪个Page显示,Page 0

  一、手册内容

在这里插入图片描述

  X2,X1,X0,可以选择0到7Page。也就是2的3次方。

  二、代码体现

OledWriteCmd(0xB0);

1.4发送0x08显示一个点

  • 代码体现
OledWriteData(0x08);

1.5完整程序代码

#include "reg52.h"
#include "intrins.h"

sbit SCL = P0^1;                   //把SCL接单片机P0.1口
sbit SDA = P0^3;                   //把SDA接单片机P0.3口

void IICStart()                  //IIC起始信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA先是高电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //_nop_()寒素执行时间为5微秒,并不是1微秒,原因是调用函数时有进出栈操作
	                               //此时在这里,根据起始信号时序图可知需要延时》4.7微秒
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA此时为低电平
	_nop_();                       //延时5微秒
}

void IICStop()                   //IIC终止信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA先是低电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //延时5微秒
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA此时为高电平
	_nop_();                       //延时5微秒
}

char IIC_ACK()
{
	char flag;
	
	SDA = 1;                         //释放数据线
	_nop_();
	SCL = 1;
	_nop_();
	flag = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	
	return flag;
}

void IICSendByte(char cdata)
{
	char i;
	for(i=0; i<8; i++ )
  {   	
	  SCL = 0;                       //scl拉低,让sda做好数据准备
		SDA = cdata & 0x80;            //0x80 = 1000 0000获得cdata的最高位,给sda
		_nop_();                       //发送建立数据时间
		SCL = 1;                       //SCL被拉高开始发送数据
		_nop_();											 //数据发送时间
		SCL = 0;                       //发送完数据被拉低
		_nop_();
		cdata = cdata << 1;
	}
}

void OledWriteCmd(char Cmd)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x00);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Cmd);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void OledWriteData(char Data)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x40);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Data);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  	OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  	OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

void main()
{	
	//1.初始化OLED
	initOLED();
	//2.选择一个位置
	//2.1确认页寻址模式
	OledWriteCmd(0x20);
	OledWriteCmd(0x02);
	//2.2确认那个page显示,page 0
	OledWriteCmd(0xB0);
	//3.发送0x08显示一个点
	OledWriteData(0x08);
	//防止主函数退出
	while(1);
}

2. OLED列地址

2.1 OLED列地址手册介绍

在这里插入图片描述

  从手册中可以看出,列地址由两个8位数据控制。一个高8位,一个低8位。低8位默认前4位为0,高8为默认前四位为0001,也就是0x1\*。通过这两个8位数据的后四位的值来控制128列的列数据。

  要让显示图像左对齐,就可以通过列地址设置成为第一列。

2.2代码体现

OledWriteCmd(0xB2);
OledWriteCmd(0x00); //使图像从左边第一列开始显示
OledWriteCmd(0x10);

2.3完整程序代码(显示两条线)

#include "reg52.h"
#include "intrins.h"

sbit SCL = P0^1;                   //把SCL接单片机P0.1口
sbit SDA = P0^3;                   //把SDA接单片机P0.3口

void IICStart()                  //IIC起始信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA先是高电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //_nop_()寒素执行时间为5微秒,并不是1微秒,原因是调用函数时有进出栈操作
	                               //此时在这里,根据起始信号时序图可知需要延时》4.7微秒
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA此时为低电平
	_nop_();                       //延时5微秒
}

void IICStop()                   //IIC终止信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA先是低电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //延时5微秒
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA此时为高电平
	_nop_();                       //延时5微秒
}

char IIC_ACK()
{
	char flag;
	
	SDA = 1;                         //释放数据线
	_nop_();
	SCL = 1;
	_nop_();
	flag = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	
	return flag;
}

void IICSendByte(char cdata)
{
	char i;
	for(i=0; i<8; i++ )
  {   	
	  SCL = 0;                       //scl拉低,让sda做好数据准备
		SDA = cdata & 0x80;            //0x80 = 1000 0000获得cdata的最高位,给sda
		_nop_();                       //发送建立数据时间
		SCL = 1;                       //SCL被拉高开始发送数据
		_nop_();											 //数据发送时间
		SCL = 0;                       //发送完数据被拉低
		_nop_();
		cdata = cdata << 1;
	}
}

void OledWriteCmd(char Cmd)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x00);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Cmd);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void OledWriteData(char Data)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x40);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Data);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

void main()
{	
	char i;
	//1.初始化OLED
	initOLED();
	//2.选择一个位置
	//2.1确认页寻址模式
	OledWriteCmd(0x20);
	OledWriteCmd(0x02);
	//2.2确认那个page显示,page 0
	OledWriteCmd(0xB0);
	//3.发送0x08显示一个点
	OledWriteData(0x08);
	//4.显示一条线
	for(i=0; i<60; i++)
	{
		OledWriteData(0x08);
	}
	//5.复制这条线到其他Page
	OledWriteCmd(0xB2);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	for(i=0; i<60; i++)
	{
		OledWriteData(0x08);
	}
	
	//6.让第三根线都在左边开始显示
	//防止主函数退出
	while(1);
}

2.4补充说明

  此程序基于OLED显示一个点代码实现工程修改

3. OLED清屏添加清屏函数

3.1为什么需要清屏函数

  • 清屏函数可以清理上次OLED寄存器中的数据,使这次显示的内容不会和上次显示的内容混合在一起。
  • 清屏函数可以防止OLED出现雪花,因为多次像OLED中写入数据,没有清除上一次的数据,会是OLED出现雪花。

3.2 OLED清屏添加清屏函数核心思想

  向128*64个像素点内写入0,使像素点都熄灭。就可以达到清屏的作用。

3.3清屏函数代码

void OLEDClearScreen()
{
	unsigned char i;   //使用无符号的字符型变量i,j的作用是防止内存越界。因为
	unsigned char j;   //有符号的字符型数据只能表示 -128~127,会在内层for中越界
	
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10); 
		for(j=0; j<128; j++)    //列地址自动偏移
		{
			OledWriteData(0);     //写入清屏数据0
		}
	}
}

3.4完整程序代码

#include "reg52.h"
#include "intrins.h"

sbit SCL = P0^1;                   //把SCL接单片机P0.1口
sbit SDA = P0^3;                   //把SDA接单片机P0.3口

void IICStart()                  //IIC起始信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA先是高电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //_nop_()寒素执行时间为5微秒,并不是1微秒,原因是调用函数时有进出栈操作
	                               //此时在这里,根据起始信号时序图可知需要延时》4.7微秒
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA此时为低电平
	_nop_();                       //延时5微秒
}

void IICStop()                   //IIC终止信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA先是低电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //延时5微秒
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA此时为高电平
	_nop_();                       //延时5微秒
}

char IIC_ACK()
{
	char flag;
	
	SDA = 1;                         //释放数据线
	_nop_();
	SCL = 1;
	_nop_();
	flag = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	
	return flag;
}

void IICSendByte(char cdata)
{
	char i;
	for(i=0; i<8; i++ )
  {   	
	  SCL = 0;                       //scl拉低,让sda做好数据准备
		SDA = cdata & 0x80;            //0x80 = 1000 0000获得cdata的最高位,给sda
		_nop_();                       //发送建立数据时间
		SCL = 1;                       //SCL被拉高开始发送数据
		_nop_();											 //数据发送时间
		SCL = 0;                       //发送完数据被拉低
		_nop_();
		cdata = cdata << 1;
	}
}

void OledWriteCmd(char Cmd)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x00);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Cmd);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void OledWriteData(char Data)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x40);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Data);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

void OLEDClearScreen()
{
	unsigned char i;   //使用无符号的字符型变量i,j的作用是防止内存越界。因为
	unsigned char j;   //有符号的字符型数据只能表示 -128~127,会在内层for中越界
	
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10); 
		for(j=0; j<128; j++)    //列地址自动偏移
		{
			OledWriteData(0);     //写入清屏数据0
		}
	}
}

void main()
{	
	char i;
	//1.初始化OLED
	initOLED();
	//2.选择一个位置
	//2.1确认页寻址模式
	OledWriteCmd(0x20);
	OledWriteCmd(0x02);
	OLEDClearScreen();
	//2.2确认那个page显示,page 0
	OledWriteCmd(0xB0);
	//3.发送0x08显示一个点
	OledWriteData(0x08);
	//4.显示一条线
	for(i=0; i<59; i++)
	{
		OledWriteData(0x08);
	}
	//5.复制这条线到另外的Page
	OledWriteCmd(0xB2);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	for(i=0; i<60; i++)
	{
		OledWriteData(0x08);
	}
	//防止主函数退出
	while(1);
}

3.5补充说明

  此程序基于OLED列地址工程修改

4. OLED显示字母A

4.1 OLED显示字母A核心思路

  • 使用液晶显示模块字模工具生成字符A的数据
  • 根据生成的字符A的数据建立字符数组
  • 使用for循环发送字符数据使OLED显示字符A

  注:此程序基于OLED清屏添加清屏函数工程修改

4.2使用液晶显示模块字模工具生成字符A的数据

  1.打开液晶显示模块字模工具

在这里插入图片描述

  2.点击参数设置

在这里插入图片描述

  3.点击文字输入区字体选择

在这里插入图片描述

  4.设置字体为宋体,字形常规,大小为12号,点击确定

在这里插入图片描述

  5.点击其他选项

在这里插入图片描述

在这里插入图片描述

  6.取模方式选纵向取模,选择字节倒序,选择保留,A51数据位数选择任何时候都加0,点击确定。

在这里插入图片描述

  7.在文本输入区输入字符A并按Ctrl+Enter。

在这里插入图片描述

  8.点击取模方式,选择C51即可完成取模

在这里插入图片描述

4.3根据生成的字符A的数据建立字符数组

  • 生成数据分析

  生成数据为宽×高 = 8×16,一个Page高8,所以字符A占两个Page。每个Page占8列。所以可以构建两个大小为8字符数组A1、A2。

  • 建立字符数组
/*--  文字:  A  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
char A1[8] = {0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00};
char A2[8] = {0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20};

4.4使用for循环发送字符数据使OLED显示字符A

  • for循环代码
//写A字符的上半部分
OledWriteCmd(0xB0);
OledWriteCmd(0x00);
OledWriteCmd(0x10);
for(i=0; i<8; i++)
{
    OledWriteData(A1[i]);
}

//写A字符的下半部分
OledWriteCmd(0xB1);
OledWriteCmd(0x00);
OledWriteCmd(0x10);
for(i=0; i<8; i++)
{
    OledWriteData(A2[i]);
}

4.5完整程序代码

#include "reg52.h"
#include "intrins.h"

sbit SCL = P0^1;                   //把SCL接单片机P0.1口
sbit SDA = P0^3;                   //把SDA接单片机P0.3口

/*--  文字:  A  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
char A1[8] = {0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00};
char A2[8] = {0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20};


void IICStart()                  //IIC起始信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA先是高电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //_nop_()寒素执行时间为5微秒,并不是1微秒,原因是调用函数时有进出栈操作
	                               //此时在这里,根据起始信号时序图可知需要延时》4.7微秒
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA此时为低电平
	_nop_();                       //延时5微秒
}

void IICStop()                   //IIC终止信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA先是低电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //延时5微秒
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA此时为高电平
	_nop_();                       //延时5微秒
}

char IIC_ACK()
{
	char flag;
	
	SDA = 1;                         //释放数据线
	_nop_();
	SCL = 1;
	_nop_();
	flag = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	
	return flag;
}

void IICSendByte(char cdata)
{
	char i;
	for(i=0; i<8; i++ )
  {   	
	  SCL = 0;                       //scl拉低,让sda做好数据准备
		SDA = cdata & 0x80;            //0x80 = 1000 0000获得cdata的最高位,给sda
		_nop_();                       //发送建立数据时间
		SCL = 1;                       //SCL被拉高开始发送数据
		_nop_();											 //数据发送时间
		SCL = 0;                       //发送完数据被拉低
		_nop_();
		cdata = cdata << 1;
	}
}

void OledWriteCmd(char Cmd)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x00);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Cmd);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void OledWriteData(char Data)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x40);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Data);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

void OLEDClearScreen()
{
	unsigned char i;   //使用无符号的字符型变量i,j的作用是防止内存越界。因为
	unsigned char j;   //有符号的字符型数据只能表示 -128~127,会在内层for中越界
	
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10); 
		for(j=0; j<128; j++)    //列地址自动偏移
		{
			OledWriteData(0);     //写入清屏数据0
		}
	}
}

void main()
{	
	char i;
	//1.初始化OLED
	initOLED();
	//2.选择一个位置
	//2.1确认页寻址模式
	OledWriteCmd(0x20);
	OledWriteCmd(0x02);
	OLEDClearScreen();
	//2.2确认那个page显示,page 0
	//写A字符的上半部分
	OledWriteCmd(0xB0);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	for(i=0; i<8; i++)
	{
		OledWriteData(A1[i]);
	}
	
	//写A字符的下半部分
	OledWriteCmd(0xB1);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	for(i=0; i<8; i++)
	{
		OledWriteData(A2[i]);
	}
	//防止主函数退出
	while(1);
}

5. OLED显示中文

5.1 OLED显示中文核心思路

  • 使用液晶显示模块字模工具生成字符的数据
  • 根据生成字符的数据建立字符数组
  • 构造发送字符数据函数

  注:此程序基于OLED显示字符A工程修改

5.2使用液晶显示模块字模工具生成字符的数据

  • 使用方法和4.2一样

5.3根据生成字符的数据建立字符数组

  • 生成数据分析

  生成数据为宽×高 = 16×16,一个Page高8,所以字符A占两个Page。每个Page占16列。所以可以构建的字符数组大小为16

  • 建立字符数组注意事项

  需要使用code关键字,因为单纯的char 型是将数据存放在数据存储器RAM中,RAM容量小,无法存入16个数据。所以使用code关键字可以使这16个数据存入程序储存器ROM中,保障了16个数据的存储以及提高程序的执行效率和速度。

  • 建立字符数组
/*--  文字:  马  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char M1[16] = {0x00,0x02,0x02,0xF2,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x80,0x80,0x80,0x00,0x00};
code char M2[16] = {0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x80,0x40,0x3F,0x00,0x00};

/*--  文字:  哥  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char G1[16] = {0x00,0x02,0x02,0x7A,0x4A,0x4A,0x4A,0x4A,0x7A,0x02,0x02,0x7E,0x02,0x02,0x00,0x00};
code char G2[16] = {0x01,0x01,0x01,0x3D,0x25,0x25,0x25,0x25,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00};

/*--  文字:  成  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char C1[16] = {0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0x08,0x08,0xFF,0x08,0x09,0x0A,0xC8,0x08,0x00};
code char C2[16] = {0x80,0x60,0x1F,0x00,0x10,0x20,0x1F,0x80,0x40,0x21,0x16,0x18,0x26,0x41,0xF8,0x00};

/*--  文字:  长  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char Z1[16] = {0x80,0x80,0x80,0x80,0xFF,0x80,0x80,0xA0,0x90,0x88,0x84,0x82,0x80,0x80,0x80,0x00};
code char Z2[16] = {0x00,0x00,0x00,0x00,0xFF,0x40,0x21,0x12,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x00};

/*--  文字:  记  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char J1[16] = {0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00,0x00};
code char J2[16] = {0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x3F,0x40,0x40,0x40,0x40,0x41,0x40,0x70,0x00};

5.4构造发送字符数据函数

  • 构造函数思路

  在OLED中,列地址会自动偏移。所以只需要一次性发送一个字符的上半部分。然而一个字符的上半份宽16,所以需要用for循环16次发送。

  • 函数代码
void OLEDShowChineseChar(char CCdata[])
{
	unsigned char i;
	
	for(i=0; i<16; i++)
	{
		OledWriteData(CCdata[i]);
	}
}

5.4完整程序代码

#include "reg52.h"
#include "intrins.h"

sbit SCL = P0^1;                   //把SCL接单片机P0.1口
sbit SDA = P0^3;                   //把SDA接单片机P0.3口

/*--  文字:  马  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char M1[16] = {0x00,0x02,0x02,0xF2,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x80,0x80,0x80,0x00,0x00};
code char M2[16] = {0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x80,0x40,0x3F,0x00,0x00};

/*--  文字:  哥  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char G1[16] = {0x00,0x02,0x02,0x7A,0x4A,0x4A,0x4A,0x4A,0x7A,0x02,0x02,0x7E,0x02,0x02,0x00,0x00};
code char G2[16] = {0x01,0x01,0x01,0x3D,0x25,0x25,0x25,0x25,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00};

/*--  文字:  成  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char C1[16] = {0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0x08,0x08,0xFF,0x08,0x09,0x0A,0xC8,0x08,0x00};
code char C2[16] = {0x80,0x60,0x1F,0x00,0x10,0x20,0x1F,0x80,0x40,0x21,0x16,0x18,0x26,0x41,0xF8,0x00};

/*--  文字:  长  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char Z1[16] = {0x80,0x80,0x80,0x80,0xFF,0x80,0x80,0xA0,0x90,0x88,0x84,0x82,0x80,0x80,0x80,0x00};
code char Z2[16] = {0x00,0x00,0x00,0x00,0xFF,0x40,0x21,0x12,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x00};

/*--  文字:  记  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char J1[16] = {0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00,0x00};
code char J2[16] = {0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x3F,0x40,0x40,0x40,0x40,0x41,0x40,0x70,0x00};



void IICStart()                  //IIC起始信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA先是高电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //_nop_()寒素执行时间为5微秒,并不是1微秒,原因是调用函数时有进出栈操作
	                               //此时在这里,根据起始信号时序图可知需要延时》4.7微秒
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA此时为低电平
	_nop_();                       //延时5微秒
}

void IICStop()                   //IIC终止信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA先是低电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //延时5微秒
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA此时为高电平
	_nop_();                       //延时5微秒
}

char IIC_ACK()
{
	char flag;
	
	SDA = 1;                         //释放数据线
	_nop_();
	SCL = 1;
	_nop_();
	flag = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	
	return flag;
}

void IICSendByte(char cdata)
{
	char i;
	for(i=0; i<8; i++ )
  {   	
	  SCL = 0;                       //scl拉低,让sda做好数据准备
		SDA = cdata & 0x80;            //0x80 = 1000 0000获得cdata的最高位,给sda
		_nop_();                       //发送建立数据时间
		SCL = 1;                       //SCL被拉高开始发送数据
		_nop_();											 //数据发送时间
		SCL = 0;                       //发送完数据被拉低
		_nop_();
		cdata = cdata << 1;
	}
}

void OledWriteCmd(char Cmd)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x00);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Cmd);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void OledWriteData(char Data)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x40);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Data);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

void OLEDClearScreen()
{
	unsigned char i;   //使用无符号的字符型变量i,j的作用是防止内存越界。因为
	unsigned char j;   //有符号的字符型数据只能表示 -128~127,会在内层for中越界
	
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10); 
		for(j=0; j<128; j++)    //列地址自动偏移
		{
			OledWriteData(0);     //写入清屏数据0
		}
	}
}

void OLEDShowChineseChar(char CCdata[])
{
	unsigned char i;
	
	for(i=0; i<16; i++)
	{
		OledWriteData(CCdata[i]);
	}
}

void main()
{	
	
	//1.初始化OLED
	initOLED();
	//2.选择一个位置
	//2.1确认页寻址模式
	OledWriteCmd(0x20);
	OledWriteCmd(0x02);
	OLEDClearScreen();
	//2.2确认那个page显示,page 0
	
	//写马哥成长记字符的上半部分
	OledWriteCmd(0xB0);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	OLEDShowChineseChar(M1);
	OLEDShowChineseChar(G1);
	OLEDShowChineseChar(C1);
	OLEDShowChineseChar(Z1);
	OLEDShowChineseChar(J1);
	
	//写A字符的下半部分
	OledWriteCmd(0xB1);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	OLEDShowChineseChar(M2);
	OLEDShowChineseChar(G2);
	OLEDShowChineseChar(C2);
	OLEDShowChineseChar(Z2);
	OLEDShowChineseChar(J2);
	//防止主函数退出
	while(1);
}

6. OLED显示图片

6.1 OLED显示图片核心思路

  • 百度搜索简笔图片
  • FastStone Capture软件进行截图修改图片尺寸并保存为bmp格式
  • 使用液晶显示模块字模工具生成图片的数据
  • 根据生成图片的数据建立图片数组
  • 构造发送图片数据函数

6.2百度搜索简笔图片

在这里插入图片描述

6.3 FastStone Capture软件进行截图修改图片尺寸并保存为bmp格式

  • 根据自己设置的截图快捷键截图(我的是Alt + A)

在这里插入图片描述

  • 截图成功后在跳转页面按Ctrl + R调整图片大小为128×64图片,如果不够自行拖拽画布到适宜比例后再调整。(画布调整直接拖动图片四周的线即可)

在这里插入图片描述

  • Ctrl+S保存,保存选择格式为bmp

在这里插入图片描述

6.4使用液晶显示模块字模工具生成图片的数据

  • 打开液晶显示模块字模工具

在这里插入图片描述

  • 点击打开图像图标找到刚才生成的bmp图片点击打开

在这里插入图片描述

  • 点击取模方式–>点击C51即可。

在这里插入图片描述

在这里插入图片描述

6.5根据生成图片的数据建立图片数组

  • 液晶显示模块字模工具生成的数据较大,需要用到code关键字,并且使用unsigned无符号内型数据。

  • 图片数组代码

/*--  调入了一幅图像:C:\Users\MaJinJun\Desktop\小车.bmp  --*/
/*--  宽度x高度=128x58  --*/
/*--  宽度不是8的倍数,现调整为:宽度x高度=128x64  --*/
下面数组数据为128 * 8个,每个数组元素为8位
code unsigned char picture[] = 
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0xA0,
0xF0,0x50,0xA8,0xD8,0xD4,0x68,0x76,0xB6,0xBB,0x5B,0x5B,0x7D,0xAD,0xAD,0xAD,0xAF,
0xB6,0xB6,0x36,0xD6,0xB6,0xB6,0xAF,0xAD,0xAD,0x6D,0x7D,0x5B,0xDB,0xB7,0xB6,0x6A,
0xEC,0xD4,0xA8,0xF0,0xD0,0xA0,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE8,0xFC,0xB6,0xFD,0xF6,0xBB,0xDD,
0xF6,0xBB,0xDD,0x6D,0xB6,0xDB,0x6D,0xAE,0x56,0x37,0x0B,0x1B,0x03,0x0D,0xFD,0x05,
0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x05,0xFD,0x0D,0x1B,0x1B,0x2B,0x76,0x56,0xAD,0x5D,
0xBB,0x76,0xED,0xDB,0x77,0xDF,0xBB,0xF6,0xFD,0xB6,0xE8,0xA0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0xC0,
0xA0,0x50,0xB0,0xA0,0xD8,0xD8,0xE8,0x6C,0x6E,0xB7,0xBD,0xFF,0xBB,0x7E,0x17,0x7D,
0x7F,0x6F,0x6D,0x6F,0x6D,0x6A,0x69,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x6F,0x68,
0x7F,0x7F,0x00,0xFF,0x7F,0x7F,0x68,0x6F,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x6B,
0x6E,0x6B,0x6E,0x6B,0x6F,0x7E,0x73,0x4E,0x7B,0xDF,0x7E,0xF7,0xDF,0xBA,0x50,0xA0,
0x40,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xA0,0x40,0x90,0xB4,0xDA,0xED,0x7E,0xDF,0x6D,
0xB6,0x5B,0x2B,0x15,0x0D,0x0A,0x04,0x03,0x03,0x00,0x01,0x01,0x00,0x01,0x00,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x2F,0x37,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x37,
0x2D,0x2F,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x17,0x2F,0x17,0x37,0x2F,
0x2F,0x2F,0x2F,0x2F,0x37,0x2D,0x37,0x00,0x01,0x02,0x0D,0x1A,0x75,0x5B,0x77,0xEE,
0xBF,0xF6,0xDD,0x72,0xD0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x40,0xD0,0x7F,0xD5,0xFF,0x7F,0xB7,0xBF,0xBE,0xF7,0xFF,0x01,
0xF4,0x00,0x00,0x00,0xC0,0xA0,0xD0,0x68,0xA8,0xD0,0xEC,0x6C,0x74,0xB4,0xB4,0xB4,
0xB4,0xB4,0x74,0x6C,0xEC,0xD0,0xA8,0x58,0xD0,0xA0,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0xA0,0x58,0xA8,0xD8,0xEC,0x6C,0x74,0xB4,
0xB4,0xB4,0xB4,0xB4,0xB4,0x6C,0x6C,0xDC,0xD8,0xA8,0x50,0xA0,0x57,0x80,0xEF,0x77,
0xFF,0xED,0xBF,0xBF,0xB5,0xB7,0xFC,0xEC,0xB4,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x17,0x5F,0xB5,0x7F,0xBF,0xB5,0xB7,0xB7,0xB4,0xBF,0xBF,0xB4,
0xB7,0xB4,0xB4,0xB5,0xB6,0xFB,0xFE,0xB7,0xFD,0x36,0xEB,0xF5,0x3A,0xED,0xED,0xED,
0xED,0xFD,0xFA,0xF5,0xDB,0xBE,0xFB,0xAF,0xFE,0xFB,0x6E,0x6D,0x68,0x68,0x68,0x68,
0x68,0x68,0x68,0x68,0x68,0x6C,0x6F,0xEB,0xFD,0x5F,0xFB,0xFD,0xDA,0xF5,0xFA,0xDD,
0xED,0xED,0xED,0xED,0xDF,0xFB,0xFF,0x5E,0xFD,0x7B,0xFF,0xFD,0x6F,0x6E,0x6F,0x68,
0x7F,0x7F,0x6D,0x6F,0x6F,0x68,0x7F,0xBF,0x68,0xBF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x17,0x5D,0xBB,0x6F,0xFD,0xB7,0x6F,0xDE,0xDB,0xB7,0xAE,0xAD,0xAD,
0xAD,0xB6,0xB7,0xDB,0xDE,0x6F,0xB7,0xDE,0x6F,0xBB,0x5F,0x17,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x0B,0x2F,0x59,0xB7,0x5F,0xBB,0x77,0xEF,0xD5,0xDB,0xB6,
0xAF,0xAD,0xAD,0xAE,0xB6,0xDB,0xDD,0x6F,0x77,0xBD,0x7F,0xB7,0x5F,0x2F,0x03,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x01,0x02,0x02,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x02,0x02,0x01,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x03,0x02,0x02,0x01,
0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x01,0x03,0x02,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

6.6构造发送图片数据函数

  • 构造图片数据函数的思路和清屏函数的思路基本一致,都是让数据从Page0填充到Page7。但是发送图片数据函数需要发送的是8位的数据,所以不能将内存循环变量j简单的从0开始,而是从i×128开始,结束为128×(i+1)。内层循环变量j定义为无符号的整型变量,外层信循环变量定义为无符号的字符型变量。其余都与清屏函数一致。

  • 发送图片数据函数代码

void OLEDShowPicture(unsigned char *Pdata)
{
	unsigned char i;
	unsigned int  j;
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10);
		for(j=i*128; j<128*(i+1); j++)
		{
			OledWriteData(Pdata[j]);
		}
	}
}

6.7补充知识

  BMP格式是一种无损的位图图像文件格式,全称为位图(Bitmap)图像文件格式。它通常用于Windows操作系统中,以存储图像数据的像素颜色信息。BMP文件以.bmp为扩展名,可以存储单色、索引色、真彩色等不同类型的图像数据。每个像素的颜色信息都以RGB格式存储,使得BMP文件相对较大,但保留了图像的高质量和准确性。

6.8完整程序代码

#include "reg52.h"
#include "intrins.h"

sbit SCL = P0^1;                   //把SCL接单片机P0.1口
sbit SDA = P0^3;                   //把SDA接单片机P0.3口

/*--  调入了一幅图像:C:\Users\MaJinJun\Desktop\小车.bmp  --*/
/*--  宽度x高度=128x58  --*/
/*--  宽度不是8的倍数,现调整为:宽度x高度=128x64  --*/

code unsigned char picture[] = 
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0xA0,
0xF0,0x50,0xA8,0xD8,0xD4,0x68,0x76,0xB6,0xBB,0x5B,0x5B,0x7D,0xAD,0xAD,0xAD,0xAF,
0xB6,0xB6,0x36,0xD6,0xB6,0xB6,0xAF,0xAD,0xAD,0x6D,0x7D,0x5B,0xDB,0xB7,0xB6,0x6A,
0xEC,0xD4,0xA8,0xF0,0xD0,0xA0,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE8,0xFC,0xB6,0xFD,0xF6,0xBB,0xDD,
0xF6,0xBB,0xDD,0x6D,0xB6,0xDB,0x6D,0xAE,0x56,0x37,0x0B,0x1B,0x03,0x0D,0xFD,0x05,
0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x05,0xFD,0x0D,0x1B,0x1B,0x2B,0x76,0x56,0xAD,0x5D,
0xBB,0x76,0xED,0xDB,0x77,0xDF,0xBB,0xF6,0xFD,0xB6,0xE8,0xA0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0xC0,
0xA0,0x50,0xB0,0xA0,0xD8,0xD8,0xE8,0x6C,0x6E,0xB7,0xBD,0xFF,0xBB,0x7E,0x17,0x7D,
0x7F,0x6F,0x6D,0x6F,0x6D,0x6A,0x69,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x6F,0x68,
0x7F,0x7F,0x00,0xFF,0x7F,0x7F,0x68,0x6F,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x6B,
0x6E,0x6B,0x6E,0x6B,0x6F,0x7E,0x73,0x4E,0x7B,0xDF,0x7E,0xF7,0xDF,0xBA,0x50,0xA0,
0x40,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xA0,0x40,0x90,0xB4,0xDA,0xED,0x7E,0xDF,0x6D,
0xB6,0x5B,0x2B,0x15,0x0D,0x0A,0x04,0x03,0x03,0x00,0x01,0x01,0x00,0x01,0x00,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x2F,0x37,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x37,
0x2D,0x2F,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x17,0x2F,0x17,0x37,0x2F,
0x2F,0x2F,0x2F,0x2F,0x37,0x2D,0x37,0x00,0x01,0x02,0x0D,0x1A,0x75,0x5B,0x77,0xEE,
0xBF,0xF6,0xDD,0x72,0xD0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x40,0xD0,0x7F,0xD5,0xFF,0x7F,0xB7,0xBF,0xBE,0xF7,0xFF,0x01,
0xF4,0x00,0x00,0x00,0xC0,0xA0,0xD0,0x68,0xA8,0xD0,0xEC,0x6C,0x74,0xB4,0xB4,0xB4,
0xB4,0xB4,0x74,0x6C,0xEC,0xD0,0xA8,0x58,0xD0,0xA0,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0xA0,0x58,0xA8,0xD8,0xEC,0x6C,0x74,0xB4,
0xB4,0xB4,0xB4,0xB4,0xB4,0x6C,0x6C,0xDC,0xD8,0xA8,0x50,0xA0,0x57,0x80,0xEF,0x77,
0xFF,0xED,0xBF,0xBF,0xB5,0xB7,0xFC,0xEC,0xB4,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x17,0x5F,0xB5,0x7F,0xBF,0xB5,0xB7,0xB7,0xB4,0xBF,0xBF,0xB4,
0xB7,0xB4,0xB4,0xB5,0xB6,0xFB,0xFE,0xB7,0xFD,0x36,0xEB,0xF5,0x3A,0xED,0xED,0xED,
0xED,0xFD,0xFA,0xF5,0xDB,0xBE,0xFB,0xAF,0xFE,0xFB,0x6E,0x6D,0x68,0x68,0x68,0x68,
0x68,0x68,0x68,0x68,0x68,0x6C,0x6F,0xEB,0xFD,0x5F,0xFB,0xFD,0xDA,0xF5,0xFA,0xDD,
0xED,0xED,0xED,0xED,0xDF,0xFB,0xFF,0x5E,0xFD,0x7B,0xFF,0xFD,0x6F,0x6E,0x6F,0x68,
0x7F,0x7F,0x6D,0x6F,0x6F,0x68,0x7F,0xBF,0x68,0xBF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x17,0x5D,0xBB,0x6F,0xFD,0xB7,0x6F,0xDE,0xDB,0xB7,0xAE,0xAD,0xAD,
0xAD,0xB6,0xB7,0xDB,0xDE,0x6F,0xB7,0xDE,0x6F,0xBB,0x5F,0x17,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x0B,0x2F,0x59,0xB7,0x5F,0xBB,0x77,0xEF,0xD5,0xDB,0xB6,
0xAF,0xAD,0xAD,0xAE,0xB6,0xDB,0xDD,0x6F,0x77,0xBD,0x7F,0xB7,0x5F,0x2F,0x03,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x01,0x02,0x02,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x02,0x02,0x01,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x03,0x02,0x02,0x01,
0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x01,0x03,0x02,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};


void IICStart()                  //IIC起始信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA先是高电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //_nop_()寒素执行时间为5微秒,并不是1微秒,原因是调用函数时有进出栈操作
	                               //此时在这里,根据起始信号时序图可知需要延时》4.7微秒
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA此时为低电平
	_nop_();                       //延时5微秒
}

void IICStop()                   //IIC终止信号函数
{
	SCL = 0;                       //防止雪花
	SDA = 0;                       //根据起始信号时序图阴影部分,SDA先是低电平
	SCL = 1;                       //根据起始信号时序图,SCL一直为高电平
	_nop_();                       //延时5微秒
	SDA = 1;                       //根据起始信号时序图阴影部分,SDA此时为高电平
	_nop_();                       //延时5微秒
}

char IIC_ACK()
{
	char flag;
	
	SDA = 1;                         //释放数据线
	_nop_();
	SCL = 1;
	_nop_();
	flag = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	
	return flag;
}

void IICSendByte(char cdata)
{
	char i;
	for(i=0; i<8; i++ )
  {   	
	  SCL = 0;                       //scl拉低,让sda做好数据准备
		SDA = cdata & 0x80;            //0x80 = 1000 0000获得cdata的最高位,给sda
		_nop_();                       //发送建立数据时间
		SCL = 1;                       //SCL被拉高开始发送数据
		_nop_();											 //数据发送时间
		SCL = 0;                       //发送完数据被拉低
		_nop_();
		cdata = cdata << 1;
	}
}

void OledWriteCmd(char Cmd)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x00);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Cmd);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void OledWriteData(char Data)
{
	//1.start
	IICStart();
	//2.写入从机地址 b0111 1000 0x78
	IICSendByte(0x78);
	//3.ACK
	IIC_ACK();
	//4.cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
	IICSendByte(0x40);
	//5.ACK
	IIC_ACK();
	//6. 写入指令/数据
	IICSendByte(Data);
	//7.ACK
	IIC_ACK();
	//8.STOP
	IICStop();
}

void initOLED()
{
//( 01) display off (0xae)
	OledWriteCmd(0xae);
//( 02) set low column address (0x00)
	OledWriteCmd(0x00);
//( 03) set high column address (0x10)
	OledWriteCmd(0x10);
//( 04) set start line address (0x40)
	OledWriteCmd(0x40);
//( 05) set page address (0xb0)
	OledWriteCmd(0xb0);
//( 06) contract control (0x81)
	OledWriteCmd(0x81);
//( 07) send 0xff (多字节指令)
	OledWriteCmd(0xff);
//( 08) set segment remap (0xa1)
	OledWriteCmd(0xa1);
//( 09) set normal/reverse (0xa6)
	OledWriteCmd(0xa6);
//( 10) set multiplex ratio (1 to 64) (0xa8 )
	OledWriteCmd(0xa8);
//( 11) set duty 1/32 (0x3f)
	OledWriteCmd(0x3f);
//( 12) com scan direction (0xc8)
  OledWriteCmd(0xc8);
//( 13) set display offset (0xd3)
	OledWriteCmd(0xd3);
//( 14) send 0x00
  OledWriteCmd(0x00);
//( 15) set osc division (0xd5)
	OledWriteCmd(0xd5);
//( 16) send 0x80
	OledWriteCmd(0x80);
//( 17) set area color mode off (0xd8)
	OledWriteCmd(0xd8);
//( 18) send 0x05
	OledWriteCmd(0x05);
//( 19) set pre-charge period (0xd9)
	OledWriteCmd(0xd9);
//( 20) send 0xf1
	OledWriteCmd(0xf1);
//( 21) set com pin configuration (0xda)
	OledWriteCmd(0xda);
//( 22) send 0x12
	OledWriteCmd(0x12);
//( 23) set Vcomh (0xdb)
	OledWriteCmd(0xdb);
//( 24) send 0x30
	OledWriteCmd(0x30);
//( 25) set charge pump enable (0x8d)
	OledWriteCmd(0x8d);
//( 26) send 0x14
	OledWriteCmd(0x14);
//( 27) turn on oled panel(0xaf)
	OledWriteCmd(0xaf);
}

void OLEDClearScreen()
{
	unsigned char i;   //使用无符号的字符型变量i,j的作用是防止内存越界。因为
	unsigned char j;   //有符号的字符型数据只能表示 -128~127,会在内层for中越界
	
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10); 
		for(j=0; j<128; j++)    //列地址自动偏移
		{
			OledWriteData(0);     //写入清屏数据0
		}
	}
}

void OLEDShowPicture(unsigned char *Pdata)
{
	unsigned char i;          //防止内存越界
	unsigned int  j;          //防止内存越界
	for(i=0; i<8; i++)
	{
		OledWriteCmd(0xB0 + i); //偏移Page
		OledWriteCmd(0x00);     //从第一列开始清屏
		OledWriteCmd(0x10);
		/*
			发送图片数据函数需要发送的是`8位`的数据,所以不能将内存循环变量`j`简单的从`0`开始,
		  而是从`i×128`开始,结束为`128×(i+1)`。
		*/
		for(j=i*128; j<128*(i+1); j++) 
		{
			OledWriteData(Pdata[j]);
		}
	}
}

void main()
{	
	
	//1.初始化OLED
	initOLED();
	//2.选择一个位置
	//2.1确认页寻址模式
	OledWriteCmd(0x20);
	OledWriteCmd(0x02);
	OLEDClearScreen();
	//2.2确认那个page显示,page 0
	
	//写马哥成长记字符的上半部分
	OledWriteCmd(0xB0);
	OledWriteCmd(0x00);
	OledWriteCmd(0x10);
	OLEDShowPicture(picture);
	//防止主函数退出
	while(1);
}

结束语

  很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!

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

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

相关文章

Redis -- 渐进式遍历

家&#xff0c;是心的方向。不论走多远&#xff0c;总有一盏灯为你留着。桌上的碗筷多了几双&#xff0c;笑声也多了几分温暖。家人团聚&#xff0c;是最美的风景线。时间&#xff1a;2024年 2月 8日 12:51:20 目录 前言 语法 示例 前言 试想一个场景,那就是在key非常多的…

python 自我检测题--part 1

1. Which way among them is used to create an event loop ? Window.mainloop() 2. Suppose we have a set a {10,9,8,7}, and we execute a.remove(14) what will happen ? Key error is raised. The remove() method removes the specified element from the set. Th…

攻防世界——re2-cpp-is-awesome

64位 我先用虚拟机跑了一下这个程序&#xff0c;结果输出一串字符串flag ——没用 IDA打开后 F5也没有什么可看的 那我们就F12查看字符串找可疑信息 这里一下就看见了 __int64 __fastcall main(int a1, char **a2, char **a3) {char *v3; // rbx__int64 v4; // rax__int64 v…

DS:顺序栈的实现

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先…

test222

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

【SpringBoot】Redis集中管理Session和自定义用户参数解决登录状态及校验问题

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、分布…

【C语言】一道相当有难度的指针某大厂笔试真题(超详解)

这是比较复杂的题目&#xff0c;但是如果我们能够理解清楚各个指针代表的含义&#xff0c;画出各级指针的关系图&#xff0c;这道题就迎刃而解了。 学会这道笔试题&#xff0c;相信你对指针的理解&#xff0c;对数组&#xff0c;字符串的理解都会上一个档次。 字符串存储使用的…

Linux之umask的使用

一、umask的作用 umask值用于设置用户在创建新文件和目录时的默认权限。umask值一共有4组数字&#xff0c;其中第1组数字用于定义特殊权限&#xff0c;一般不关心&#xff0c;日常工作中大家用的更多的是后面三组数字。以下图为例&#xff0c;输入“umask”命令之后&#xff0c…

《动手学深度学习(PyTorch版)》笔记7.7

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…

DolphinScheduler-3.2.0 集群搭建

本篇文章主要记录DolphinScheduler-3.2.0 集群部署流程。 注&#xff1a;参考文档&#xff1a; DolphinScheduler-3.2.0生产集群高可用搭建_dophinscheduler3.2.0 使用说明-CSDN博客文章浏览阅读1.1k次&#xff0c;点赞25次&#xff0c;收藏23次。DolphinScheduler-3.2.0生产…

MySQL篇----第十八篇

系列文章目录 文章目录 系列文章目录前言一、SQL 语言包括哪几部分?每部分都有哪些操作关键二、完整性约束包括哪些?三、什么是锁?四、什么叫视图?游标是什么?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,…

【51单片机】自定义静态数码管显示(设计思路&代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 本章节内容为【实现动静态数码管】项目的第三个模块完整章节&#xff1a;传送门 欢迎订阅 YY滴C专栏&#xff01;更多干货持…

3D立方体图册

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>3D立方体图册</title><style>* {pad…

JVM相关-JVM模型、垃圾回收、JVM调优

一、JVM模型 JVM内部体型划分 JVM的内部体系结构分为三部分&#xff0c;分别是&#xff1a;类加载器&#xff08;ClassLoader&#xff09;子系统、运行时数据区&#xff08;内存&#xff09;和执行引擎 1、类加载器 概念 每个JVM都有一个类加载器子系统&#xff08;class l…

如何在vue中使用拖动排序组件sortablejs

效果图&#xff1a; 1.首先&#xff0c;我们需要在vue项目中安装依赖&#xff1a; npm install -save sortablejs2.创建demo文件>demoTest.vue&#xff0c;直接附上实例代码&#xff1a; <template><div><div id"table-names"><div class&…

EasyExcel操作Excel表格

一、EasyExcel介绍 1.1 介绍 EasyExcel 是一个基于 Java 的简单易用的 Excel 文件读写工具&#xff0c;它提供了一种简单而又高效的方式来读取、写入和操作 Excel 文件。EasyExcel 是阿里巴巴开源的项目&#xff0c;它旨在简化开发人员处理 Excel 文件的流程&#xff0c;使得…

SpringMVC第二天

一、SSM整合【重点】 1 SSM整合配置 问题导入 请描述“SSM整合流程”中各个配置类的作用&#xff1f; 1.1 SSM整合流程 创建工程 SSM整合 Spring SpringConfig MyBatis MybatisConfig JdbcConfig jdbc.properties SpringMVC ServletConfig SpringMvcConfig 功能模块…

初识文件包含漏洞

目录 什么是文件包含漏洞&#xff1f; 文件包含的环境要求 常见的文件包含函数 PHP伪协议 file://协议 php://协议 php://filter php://input zip://、bzip2://、zlib://协议 zip:// bzip2:// zlib:// data://协议 文件包含漏洞演示 案例1&#xff1a;php://inp…

VBA技术资料MF117:测试显示器大小

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

[SAP] ABAP设置非系统关键字代码提示功能

在事务码SE38(ABAP编辑器)屏幕右下角&#xff0c;点击【Options选项】图标 勾选【代码完成】|【建议文本中的非关键字】&#xff0c;并点击【保存】按钮 在下面的程序代码中&#xff0c;当我需要输入在11行的位置输入非关键字lv_str的时候&#xff0c;会有非关键字代码提示的功…