1 OLED原理
1.3寸oled的显示原理与0.96寸的差不多,这里以常见的0.96寸oled来学习。 向下内容可以参考这边文章:
https://blog.csdn.net/qq_36461474/article/details/112591234
2 I2C协议
I2C协议讲解网线内容很多,可以参考下面这篇文章:
https://blog.csdn.net/XiaoCaiDaYong/article/details/106251696
I2C代码调试
1.1 引脚电平更改函数
这里使用(GPIO_PinState)将BitValue强制转化为GPIO_PinState枚举中的值。
这里如果要移植的化,只要将下面的GPIOB以及I2C1_SCL_Pin根据自己的使用的引脚进行更改即可。
void OLED_W_SCL(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOB, I2C1_SCL_Pin, (GPIO_PinState)BitValue);
}
void OLED_W_SDA(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOB, I2C1_SDA_Pin, (GPIO_PinState)BitValue);
}
1.2 起始信号
起始信号代码:
void IIC_Start(void)
{
OLED_W_SCL(1);
OLED_W_SDA(1);
Delay_us(2);
OLED_W_SDA(0);
Delay_us(2);
}
测试代码,在main函数的while循环中调用IIC_Start
while (1)
{
IIC_Start();
}
使用逻辑分析查看输出波形,这里SCL一直为高电平,SDA电平被拉高后,出现低电平。可以看到输出的SDA高电平时长也是延时的2u。这里符合I2C协议中起始信号,SCL为高时,SDA由高电平转化低电平。
1.3 停止信号
停止信号代码
void IIC_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
Delay_us(2);
OLED_W_SDA(1);
Delay_us(2);
}
测试代码
while (1)
{
IIC_Stop();
}
逻辑分析仪查看输出波形,SCL为高点,SDA一开始为未知信号,执行代码后,SDA被拉低2u秒,然后再跳转为高电平。符合I2C停止信号的,SCL为高电平,SDA由低电平转化为高电平。
1.4 发送数据代码
代码实现
void IIC_Send_Byte(uint8_t Byte)
{
uint8_t i;
OLED_W_SCL(0);
for(i=0; i<8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
Delay_us(2);
OLED_W_SCL(1);
Delay_us(2);
OLED_W_SCL(0);
Delay_us(2);
}
OLED_W_SCL(1);
Delay_us(2);
OLED_W_SCL(0);
}
测试代码
while (1)
{
IIC_Send_Byte(0xaa);
}
逻辑分析仪查看输出波形,0xaa,的2进制为10101010,从波形上看,在SCL为高电平时,SDA为10101010,SCL为低电平时,SDA实现电平更改,在最后实现了代码中循环完成后的一个ACK。
1.5 IIC数据发送的整个过程
这里使用了I2C发送数据和发送指令两个代码:
void IIC_Write_Command(uint8_t IIC_Command)
{
IIC_Start();
IIC_Send_Byte(0x78);
IIC_Send_Byte(0x00);
IIC_Send_Byte(IIC_Command);
IIC_Stop();
}
void IIC_Write_Data(uint8_t IIC_Data)
{
IIC_Start();
IIC_Send_Byte(0x78);
IIC_Send_Byte(0x40);
IIC_Send_Byte(IIC_Data);
IIC_Stop();
}
测试代码
while (1)
{
IIC_Write_Data(0xaa);
}
逻辑分析仪查看输出波形,发送数据整个波形,先发送地址,然后发送显示屏显存地址,最后是发送的数据。在这里ACK由于我们在IIC_Send_Byte中循环完成后加了ACK,所以可以看到每发送一次Byte都会有一个ACK。
2 所有代码
代码中有部分为一直官方的代码,但有些小改动
2.1 代码改动部分
这里添加了代码无效的处理
这里在测试时发现,如果不 -size2,显示的数字无法实现在(0,x)位置显示(x为任意值),现象就是显示数字显示位置为(size2,x)。
2.2 所有代码
#include "oled.h"
#include "oledfont.h"
void OLED_W_SCL(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOB, I2C1_SCL_Pin, (GPIO_PinState)BitValue);
}
void OLED_W_SDA(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOB, I2C1_SDA_Pin, (GPIO_PinState)BitValue);
}
void IIC_Start(void)
{
OLED_W_SCL(1);
OLED_W_SDA(1);
Delay_us(2);
OLED_W_SDA(0);
Delay_us(2);
}
void IIC_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
Delay_us(2);
OLED_W_SDA(1);
Delay_us(2);
}
void IIC_Send_Byte(uint8_t Byte)
{
uint8_t i;
OLED_W_SCL(0);
for(i=0; i<8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
Delay_us(2);
OLED_W_SCL(1);
Delay_us(2);
OLED_W_SCL(0);
Delay_us(2);
}
OLED_W_SCL(1);
Delay_us(2);
OLED_W_SCL(0);
}
void IIC_Write_Command(uint8_t IIC_Command)
{
IIC_Start();
IIC_Send_Byte(0x78);
IIC_Send_Byte(0x00);
IIC_Send_Byte(IIC_Command);
IIC_Stop();
}
void IIC_Write_Data(uint8_t IIC_Data)
{
IIC_Start();
IIC_Send_Byte(0x78);
IIC_Send_Byte(0x40);
IIC_Send_Byte(IIC_Data);
IIC_Stop();
}
void fill_picture(unsigned char fill_Data)
{
unsigned char m,n;
for(m=0;m<8;m++)
{
IIC_Write_Command(0xb0+m); //page0-page1
IIC_Write_Command(0x00); //low column start address
IIC_Write_Command(0x10); //high column start address
for(n=0;n<128;n++)
{
IIC_Write_Data(fill_Data);
}
}
}
//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
IIC_Write_Command(0xb0+y);
IIC_Write_Command(((x&0xf0)>>4)|0x10);
IIC_Write_Command((x&0x0f)|0x01);
}
//开启OLED显示
void OLED_Display_On(void)
{
IIC_Write_Command(0X8D); //SET DCDC命令
IIC_Write_Command(0X14); //DCDC ON
IIC_Write_Command(0XAF); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
IIC_Write_Command(0X8D); //SET DCDC命令
IIC_Write_Command(0X10); //DCDC OFF
IIC_Write_Command(0XAE); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
IIC_Write_Command (0xb0+i); //设置页地址(0~7)
IIC_Write_Command (0x02); //设置显示位置—列低地址
IIC_Write_Command (0x10); //设置显示位置—列高地址
for(n=0;n<128;n++)IIC_Write_Data(0);
} //更新显示
}
void OLED_On(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
IIC_Write_Command(0xb0+i); //设置页地址(0~7)
IIC_Write_Command(0x02); //设置显示位置—列低地址
IIC_Write_Command(0x10); //设置显示位置—列高地址
for(n=0;n<128;n++)IIC_Write_Data(1);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
{
unsigned char c=0,i=0;
c = chr - ' ';
if (chr < ' ' || chr > '~')
{
return; // 如果字符无效,直接返回
}
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++)
IIC_Write_Data(F8X16[c*16+i]);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
IIC_Write_Data(F8X16[c*16+i+8]);
}
else
{
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
IIC_Write_Data(F6x8[c][i]);
}
}
//m^n函数
uint32_t oled_pow(uint8_t m,uint8_t n)
{
uint32_t result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size2)
{
uint8_t t,temp;
uint8_t 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 -size2,y,temp+'0',size2);
}
}
//显示一个字符号串
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t 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(uint8_t x,uint8_t y,uint8_t no)
{
uint8_t t,adder=0;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)
{
IIC_Write_Data(Hzk[2*no][t]);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
IIC_Write_Data(Hzk[2*no+1][t]);
adder+=1;
}
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
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++)
{
IIC_Write_Data(BMP[j++]);
}
}
}
void OLED_Init(void)
{
IIC_Write_Command(0xAE);//--display off
IIC_Write_Command(0x02);//---set low column address
IIC_Write_Command(0x10);//---set high column address
IIC_Write_Command(0x40);//--set start line address
IIC_Write_Command(0xB0);//--set page address
IIC_Write_Command(0x81); // contract control
IIC_Write_Command(0xFF);//--128
IIC_Write_Command(0xA1);//set segment remap
IIC_Write_Command(0xA6);//--normal / reverse
IIC_Write_Command(0xA8);//--set multiplex ratio(1 to 64)
IIC_Write_Command(0x3F);//--1/64 duty
IIC_Write_Command(0xAD);//set charge pump enable
IIC_Write_Command(0x8B);//-0x8B 内供 VCC
IIC_Write_Command(0x33);//-0X30---0X33 set VPP 9V
IIC_Write_Command(0xC8);//Com scan direction
IIC_Write_Command(0xD3);//-set display offset
IIC_Write_Command(0x00);//
IIC_Write_Command(0xD5);//set osc division
IIC_Write_Command(0x80);//
IIC_Write_Command(0xD8);//set area color mode off
IIC_Write_Command(0x05);//
IIC_Write_Command(0xD9);//Set Pre-Charge Period
IIC_Write_Command(0x1F);//
IIC_Write_Command(0xDA);//set com pin configuartion
IIC_Write_Command(0x12);//
IIC_Write_Command(0xDB);//set Vcomh
IIC_Write_Command(0x40);//
IIC_Write_Command(0xAF);//--turn on oled panel
OLED_Clear();
}
头文件
#ifndef __OLED_H
#define __OLED_H
#include "stm32f4xx_hal.h"
#include "main.h"
#include "delay.h"
#include "stdlib.h"
#define OLED_MODE 0
#define SIZE 8
#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
void OLED_W_SCL(uint8_t BitValue);
void OLED_W_SDA(uint8_t BitValue);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Send_Byte(uint8_t Byte);
void IIC_Write_Command(uint8_t IIC_Command);
void IIC_Write_Data(uint8_t IIC_Data);
void fill_picture(unsigned char fill_Data);
void OLED_Set_Pos(unsigned char x, unsigned char y) ;
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Clear(void) ;
void OLED_On(void);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size);
uint32_t oled_pow(uint8_t m,uint8_t n);
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size2);
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size);
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no);
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
void OLED_Init(void);
#endif