SSD1306 控制核心思想:
- 在内存中创建一块内存区域,通过操作内存区域的每一个bit位实现在内存中描点,划线等操作
- 一次性将显存全部更新到SSD1306
ssd1306 页模式内存分配
1. 向SSD1306 写入一个数据或一条命令
数据变化条件
图片解释
1、 第一个字节(Slave Address )发送的是地址 和 读写属性(一般只会写数据);SA0(D/C引脚就是SA0)决定了从机的地址; 0x78
2、第二个字节(control byte )决定了第三个字节是命令还是数据
a) Co = 0 代表后边全是数据
b) D/C = 0 代表后边是数据(0x00);D/C = 0 代表后边是命令;(0x40)
操作步骤
- 写入地址或读写状态,一般是写 :0x78
- 写入控制字节,表明下一个字节是命令还是数据
- 写入具体的数据
void OLED_WR_Byte(u8 dat, u8 mode)
{
I2C_Start();
Send_Byte(0x78);//发送地址和写指令
I2C_WaitAck();
if (mode)
{
Send_Byte(0x40);//通知oled即将发命令
}
else
{
Send_Byte(0x00);//通知oled即将发数据
}
I2C_WaitAck();
Send_Byte(dat);//发送真实的数据
I2C_WaitAck();
I2C_Stop();
}
定义显存
u8 OLED_GRAM[128][8]; //128*64 的oled
2.画点函数
- 获取需要操作的字节
- 获取需要操作字节的具体一个bit X
- 操作的字节的指定位置置1
//画点 操作的仅仅是内存
//x:0~127
//y:0~63
void OLED_DrawPoint(u8 x, u8 y)
{
u8 i, m, n;
i = y / 8;//得到行数
m = y % 8; //需要移动的bit数(一个字节内的bit位置) 每行8个bit,需要对指定的bit赋值
n = 1 << m;
OLED_GRAM[x][i] |= n; //指定字节的 指定bit赋值为1
//OLED_GRAM[x][i].bi
}
3. 划线函数
- 划线分为3类,横线、竖线,斜线
- 横线 x 不变 ,y变化
- 竖线 X 变化 ,Y不变
- 画斜线
- 需要计算斜率 斜率放大10倍,否则斜率为零
- 根据斜率依次变化想,计算得到Y
//画线
//x:0~128
//y:0~64
void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2)
{
u8 i, k, k1, k2, y0;
if ((x1 < 0) || (x2 > 128) || (y1 < 0) || (y2 > 64) || (x1 > x2) || (y1 > y2))
return;
if (x1 == x2) //画竖线
{
for (i = 0; i < (y2 - y1); i++)
{
OLED_DrawPoint(x1, y1 + i);
}
}
else if (y1 == y2) //画横线
{
for (i = 0; i < (x2 - x1); i++)
{
OLED_DrawPoint(x1 + i, y1);
}
}
else //画斜线
{
k1 = y2 - y1;
k2 = x2 - x1;
k = k1 * 10 / k2; //系数放大10倍
for (i = 0; i < (x2 - x1); i++)
{
OLED_DrawPoint(x1 + i, y1 + i * k / 10); //结果缩小10倍
}
}
}
4.更新显存到oled
原始资料
- 设置行地址 命令
- 设置列低地址 命令
- 设置列高地址 命令
- 发送数据到SSD1306 数据
//更新显存到OLED
void OLED_Refresh(void)
{
u8 i, n;
for (i = 0; i < 8; i++)
{
OLED_WR_Byte(0xb0 + i, OLED_CMD); //设置行起始地址
OLED_WR_Byte(0x00, OLED_CMD); //设置 低 列起始地址
OLED_WR_Byte(0x10, OLED_CMD); //设置 高 列起始地址
for (n = 0; n < 128; n++)
OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);//发送数据到SSD1306
}
}
5.显示单个字符
- 代码的数据是按照下图方式生成数据数据例如1212的数据,字符显示出来是612
- 数据显示就是先把一个的一列像素显示完,再显示第二列
- 子模数据是字节的高位就是 像素的上方,例如0b 1001 1100 从上到下依次是 亮灭灭亮 亮亮灭灭
字模生成
补充数据
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//
//取模方式 逐列式
/*
X 写入的X位置 横向x 0-127
Y 写入的Y的位置 竖直方向 0-63
chr 待显示字符
size1 字符大小 size:选择字体 12/16/24
代码里的数据
{0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00}, // "!",1
oled 从上至下显示
000
000
001
001
001
001
001
001
000
001
000
000
000
000
000
000
自己生成的数据
//0x00H 0x00H 0x00H 0x00H 0x3EH 0x40H 0x00H 0x00H 0x00H 0x00H 0x00H 0x00H;"!",0
*/
void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 size1)
{
u8 i, m, temp, size2, chr1;
u8 y0 = y;
size2 = (size1 / 8 + ((size1 % 8) ? 1 : 0)) * (size1 / 2); //得到一个字符对应点阵集所占的 字节数 12-> 12 16->16 24->36
chr1 = chr - ' '; //计算偏移后的值
for (i = 0; i < size2; i++) //循环处理子模的每一个自己,16*8 的子模就有16个字节
{
if (size1 == 12)
{
temp = asc2_1206[chr1][i];
} //调用1206字体
else if (size1 == 16)
{
temp = asc2_1608[chr1][i]; //竖直方向16个点,横向8个点
} //调用1608字体
else if (size1 == 24)
{
temp = asc2_2412[chr1][i];
} //调用2412字体
else
return;
for (m = 0; m < 8; m++) //一个字节8个bit 所以就是分别更新8个点
{
//循环处理每一个bit,先处理高位
if (temp & 0x80)
OLED_DrawPoint(x, y);
else
OLED_ClearPoint(x, y);
temp <<= 1;
//处理竖直方向依次需要写的点数
y++;
if ((y - y0) == size1)
{
y = y0;
x++;
break;
}
}
}
}
5. 滚动显示
- 建立一个缓冲区,这个缓冲区可以预存一个字符的子模空间
- 每次从从右至左每次左移1列像素
- 当移到宽度到达一个子模的宽度16列时将下一个子模数据写入缓冲器
- 当需要显示的内容循环跟新完成以后,中间的间隔就一次填充 0 (就不显示 黑屏)
//num 显示汉字的个数
//space 每一遍显示的间隔 144 = 128+16 16就是一个中文子模的宽度
void OLED_ScrollDisplay(u8 num, u8 space)
{
u8 i, n, t = 0, m = 0, r;
//m 管理移动的列数
// t 管理字符的索引
while (1)
{
if (m == 0)
{
OLED_ShowChinese(128, 24, t, 16); //写入一个汉字保存在OLED_GRAM[][]数组中
t++;
}
if (t == num) //t 表示的汉字序号 所有的汉字已经显示完毕
{
for (r = 0; r < 16 * space; r++) //显示间隔 会在这个循环里一直更新,知道间隔时间到
{
for (i = 1; i < 144; i++)
{
for (n = 0; n < 8; n++)
{
OLED_GRAM[i - 1][n] = OLED_GRAM[i][n];
}
OLED_GRAM[143][n]=0; //高位一直填写0,就是不亮
}
OLED_Refresh();
}
t = 0;//更新显示数据
m=15; //立即跟新
}
m++;
if (m == 16) //在一个字显示完成以后就在显示下一个子 例如 中 全部显出来以后就显示 景
{
m = 0;
}
//if(t==11){t=0;m=0;}
for (i = 1; i < 144; i++) //实现左移
{
for (n = 0; n < 8; n++)
{
OLED_GRAM[i - 1][n] = OLED_GRAM[i][n]; //144*8
}
OLED_GRAM[143][n]=0;
}
OLED_Refresh();
//delay_ms(500*2);
}
}