Files
CHJ/user/Device/oled.c
2026-03-20 21:19:04 +08:00

749 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "../main/SystemInclude.h"
#include "../Device/oledfont.h"
// --- 1. 显存定义 ---
// 前台缓冲区:用于写入新的图形数据
u8 OLED_GRAM[144][8];
// 后台缓冲区:用于存储当前屏幕上实际显示的内容,用于对比差异
u8 OLED_GRAM_Back[144][8];
//反显函数
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 IIC_delay(void)
{
u8 t=3;
while(t--);
}
//起始信号
void I2C_Start(void)
{
OLED_SDA_Set();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Clr();
IIC_delay();
OLED_SCL_Clr();
IIC_delay();
}
//结束信号
void I2C_Stop(void)
{
OLED_SDA_Clr();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Set();
}
//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
OLED_SDA_Set();
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();
IIC_delay();
}
//写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i=0;i<8;i++)
{
if(dat&0x80)//将dat的8位从最高位依次写入
{
OLED_SDA_Set();
}
else
{
OLED_SDA_Clr();
}
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();//将时钟信号设置为低电平
dat<<=1;
}
}
//发送一个字节
//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();
}
//开启OLED显示
void OLED_DisPlay_On(void)
{
OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
}
//关闭OLED显示
void OLED_DisPlay_Off(void)
{
OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
OLED_WR_Byte(0xAE,OLED_CMD);//关闭屏幕
}
/**
* @brief 差异刷新全屏(高效)
* @note 对比 OLED_GRAM 和 OLED_GRAM_Back仅刷新变化的字节
*/
void OLED_Refresh_Diff(void)
{
u8 i, n;
for(i=0; i<8; i++)
{
// 设置页地址
OLED_WR_Byte(0xb0+i, OLED_CMD);
OLED_WR_Byte(0x02, OLED_CMD); // Low Col Start Addr
OLED_WR_Byte(0x10, OLED_CMD); // High Col Start Addr
// 开启数据流传输
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
Send_Byte(0x40);
I2C_WaitAck();
for(n=0; n<128; n++)
{
// 对比前后台缓冲区
if(OLED_GRAM[n][i] != OLED_GRAM_Back[n][i])
{
// 如果数据变化,发送新数据到硬件
Send_Byte(OLED_GRAM[n][i]);
// 更新后台缓冲区,保持同步
OLED_GRAM_Back[n][i] = OLED_GRAM[n][i];
}
else
{
}
}
I2C_Stop();
}
}
// 【重新实现的差异刷新】:针对行的优化
void OLED_Refresh_Line_Diff(u8 line) // line 0-7
{
u8 n;
u8 x_start = 0;
u8 is_diff = 0;
// 1. 先扫描这一行有没有变化
for(n=0; n<128; n++)
{
if(OLED_GRAM[n][line] != OLED_GRAM_Back[n][line])
{
is_diff = 1;
break;
}
}
// 如果整行都没变直接返回省去所有I2C操作
if(!is_diff) return;
// 2. 设置页地址
OLED_WR_Byte(0xb0 + line, OLED_CMD);
OLED_WR_Byte(0x02, OLED_CMD);
OLED_WR_Byte(0x10, OLED_CMD);
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
Send_Byte(0x40);
I2C_WaitAck();
// 3. 逐字节对比并发送
for(n=0; n<128; n++)
{
if(OLED_GRAM[n][line] != OLED_GRAM_Back[n][line])
{
Send_Byte(OLED_GRAM[n][line]);
// 同步后台
OLED_GRAM_Back[n][line] = OLED_GRAM[n][line];
}
else
{
// 【注意】在连续I2C传输模式下如果不发送字节从机地址计数器不会前进
// 导致后续数据写入错位。
// 必须发送当前屏幕上的值(即 Back 缓存的值)来"占位"。
Send_Byte(OLED_GRAM_Back[n][line]);
}
I2C_WaitAck();
}
I2C_Stop();
}
// 兼容旧接口的全屏刷新
void OLED_Refresh(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD);
OLED_WR_Byte(0x02,OLED_CMD);
OLED_WR_Byte(0x10,OLED_CMD);
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
Send_Byte(0x40);
I2C_WaitAck();
for(n=0;n<128;n++)
{
Send_Byte(OLED_GRAM[n][i]);
I2C_WaitAck();
}
I2C_Stop();
}
// 全屏刷新后,同步后台
memcpy(OLED_GRAM_Back, OLED_GRAM, sizeof(OLED_GRAM));
}
// 旧版刷新行接口(保留兼容)
void OLED_Refresh_Line(u8 line)
{
u8 n;
OLED_WR_Byte(0xb0 + line, OLED_CMD);
OLED_WR_Byte(0x02, OLED_CMD);
OLED_WR_Byte(0x10, OLED_CMD);
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
Send_Byte(0x40);
I2C_WaitAck();
for(n=0; n<128; n++)
{
Send_Byte(OLED_GRAM[n][line]);
I2C_WaitAck();
}
I2C_Stop();
// 同步该行后台
memcpy(OLED_GRAM_Back[0] + line*128, OLED_GRAM[0] + line*128, 128); // 简单处理,实际需按维度拷贝
// 上面的memcpy写法针对二维数组可能不直观改用循环:
for(n=0;n<128;n++) OLED_GRAM_Back[n][line] = OLED_GRAM[n][line];
}
//清屏函数
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
for(n=0;n<128;n++)
OLED_GRAM[n][i]=0;
}
// 这里不调用 OLED_Refresh由外部决定如何刷新
}
//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
//画点
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 i,m,n;
i=y/8;
m=y%8;
n=1<<m;
if(t){OLED_GRAM[x][i]|=n;}
else
{
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
OLED_GRAM[x][i]|=n;
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
}
}
//画线
//x1,y1:起点坐标
//x2,y2:结束坐标
void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2,u8 mode)
{
u16 t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
delta_x=x2-x1; //计算坐标增量
delta_y=y2-y1;
uRow=x1;//画线起点坐标
uCol=y1;
if(delta_x>0)incx=1; //设置单步方向
else if (delta_x==0)incx=0;//垂直线
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if (delta_y==0)incy=0;//水平线
else {incy=-1;delta_y=-delta_x;}
if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
else distance=delta_y;
for(t=0;t<distance+1;t++)
{
OLED_DrawPoint(uRow,uCol,mode);//画点
xerr+=delta_x;
yerr+=delta_y;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
//x,y:圆心坐标
//r:圆的半径
void OLED_DrawCircle(u8 x,u8 y,u8 r)
{
int a, b,num;
a = 0;
b = r;
while(2 * b * b >= r * r)
{
OLED_DrawPoint(x + a, y - b,1);
OLED_DrawPoint(x - a, y - b,1);
OLED_DrawPoint(x - a, y + b,1);
OLED_DrawPoint(x + a, y + b,1);
OLED_DrawPoint(x + b, y + a,1);
OLED_DrawPoint(x + b, y - a,1);
OLED_DrawPoint(x - b, y - a,1);
OLED_DrawPoint(x - b, y + a,1);
a++;
num = (a * a + b * b) - r*r;//计算画的点离圆心的距离
if(num > 0)
{
b--;
a--;
}
}
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size1:选择字体 6x8/6x12/8x16/12x24
//mode:0,反色显示;1,正常显示
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1,u8 mode)
{
u8 i,m,temp,size2,chr1;
u8 x0=x,y0=y;
if(size1==8)size2=6;
else size2=(size1/8+((size1%8)?1:0))*(size1/2); //得到字体一个字符对应点阵集所占的字节数
chr1=chr-' '; //计算偏移后的值
for(i=0;i<size2;i++)
{
if(size1==8)
{temp=asc2_0806[chr1][i];} //调用0806字体
else if(size1==12)
{temp=asc2_1206[chr1][i];} //调用1206字体
else if(size1==16)
{temp=asc2_1608[chr1][i];} //调用1608字体
else if(size1==24)
{temp=asc2_2412[chr1][i];} //调用2412字体
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((size1!=8)&&((x-x0)==size1/2))
{x=x0;y0=y0+8;}
y=y0;
}
}
//显示字符串
//x,y:起点坐标
//size1:字体大小
//*chr:字符串起始地址
//mode:0,反色显示;1,正常显示
//显示字符串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode)
{
while((*chr>=' ')&&(*chr<='~'))
{
OLED_ShowChar(x,y,*chr,size1,mode);
if(size1==8)x+=6;
else x+=size1/2;
chr++;
}
}
//m^n
u32 OLED_Pow(u8 m,u8 n)
{
u32 result=1;
while(n--) result*=m;
return result;
}
//显示数字
//x,y :起点坐标
//num :要显示的数字
//len :数字的位数
//size:字体大小
//mode:0,反色显示;1,正常显示
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode)
{
u8 t,temp,m=0;
if(size1==8)m=2;
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(temp==0) OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1,mode);
else OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1,mode);
}
}
//显示汉字
//x,y:起点坐标
//num:汉字对应的序号
//mode:0,反色显示;1,正常显示
void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode)
{
u8 m,temp;
u8 x0=x,y0=y;
u16 i,size3=(size1/8+((size1%8)?1:0))*size1; //得到字体一个字符对应点阵集所占的字节数
for(i=0;i<size3;i++)
{
if(size1==16)
{temp=Hzk1[num][i];}//调用16*16字体
else if(size1==24)
{temp=Hzk2[num][i];}//调用24*24字体
else if(size1==32)
{temp=Hzk3[num][i];}//调用32*32字体
else if(size1==64)
{temp=Hzk4[num][i];}//调用64*64字体
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==size1)
{x=x0;y0=y0+8;}
y=y0;
}
}
//num 显示汉字的个数
//space 每一遍显示的间隔
//mode:0,反色显示;1,正常显示
void OLED_ScrollDisplay(u8 num,u8 space,u8 mode)
{
u8 i,n,t=0,m=0,r;
while(1)
{
if(m==0)
{
OLED_ShowChinese(128,24,t,16,mode); //写入一个汉字保存在OLED_GRAM[][]数组中
t++;
}
if(t==num)
{
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_Refresh();
}
t=0;
}
m++;
if(m==16){m=0;}
for(i=1;i<144;i++) //实现左移
{
for(n=0;n<8;n++)
{
OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
}
}
OLED_Refresh();
}
}
//x,y起点坐标
//sizex,sizey,图片长宽
//BMP[]:要写入的图片数组
//mode:0,反色显示;1,正常显示
void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode)
{
u16 j=0;
u8 i,n,temp,m;
u8 x0=x,y0=y;
sizey=sizey/8+((sizey%8)?1:0);
for(n=0;n<sizey;n++)
{
for(i=0;i<sizex;i++)
{
temp=BMP[j];
j++;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==sizex)
{
x=x0;
y0=y0+8;
}
y=y0;
}
}
}
//OLED的初始化
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 1. 配置GPIO1引脚4的参数 */ //P1.4SDA
GPIO_InitStruct.Pin = GPIO_PIN_4; // 选择引脚4需根据实际硬件修改
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;// 输出模式(非复用功能)
GPIO_InitStruct.Current = GPIO_CURRENT_4mA;// 驱动能力4mA根据负载调整
GPIO_InitStruct.Pull = GPIO_NOPULL;// 无上拉/下拉电阻
GPIO_InitStruct.SchmittTrigger = ENABLE;
GPIO_InitStruct.Alternate = GPIOx_AF_GPIO; // // AF为普通IO
/* 2. 应用GPIO配置 */
LHL_GPIO_Init(pGPIO1, &GPIO_InitStruct); // 初始化GPIO1
/* 配置GPIO2引脚0的参数 */ //P2.0SCL
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择引脚4需根据实际硬件修改
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;// 输出模式(非复用功能)
GPIO_InitStruct.Current = GPIO_CURRENT_4mA;// 驱动能力4mA根据负载调整
GPIO_InitStruct.Pull = GPIO_NOPULL;// 无上拉/下拉电阻
GPIO_InitStruct.SchmittTrigger = ENABLE;
GPIO_InitStruct.Alternate = GPIOx_AF_GPIO; // // AF为普通IO
LHL_GPIO_Init(pGPIO2, &GPIO_InitStruct); // 初始化GPIO2
/* 5. 配置GPIO1引脚6的参数 */ //P1.6RES
GPIO_InitStruct.Pin = GPIO_PIN_6; // 选择引脚4需根据实际硬件修改
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;// 输出模式(非复用功能)
GPIO_InitStruct.Current = GPIO_CURRENT_4mA;// 驱动能力4mA根据负载调整
GPIO_InitStruct.Pull = GPIO_NOPULL;// 无上拉/下拉电阻
GPIO_InitStruct.SchmittTrigger = ENABLE;
GPIO_InitStruct.Alternate = GPIOx_AF_GPIO; // // AF为普通IO
LHL_GPIO_Init(pGPIO1, &GPIO_InitStruct); // 初始化GPIO2
// --- 复位操作 ---
OLED_RES_Clr(); // 拉低 RES 引脚
delay_ms(200); // 延时 200ms
OLED_RES_Set(); // 拉高 RES 引脚,完成硬件复位
// --- OLED 初始化命令序列 ---
// 1. 基础显示设置
OLED_WR_Byte(0xAE,OLED_CMD); // **[0xAE] 关闭显示**
// 初始化过程中通常先关闭显示,配置完成后再开启。
// [可修改]:无特殊情况不建议修改顺序。
OLED_WR_Byte(0x02,OLED_CMD); // **[0x00~0x0F] 设置低列地址**
// 设置显存列地址的低4位。这里设为 0x02。
// [可修改]:通常设为 0x00。设为 0x02 可能是为了微调画面水平位置。
OLED_WR_Byte(0x10,OLED_CMD); // **[0x10~0x1F] 设置高列地址**
// 设置显存列地址的高4位。这里设为 0x10 (即地址0)。
// [可修改]:通常配合低列地址使用,一般不建议修改。
OLED_WR_Byte(0x40,OLED_CMD); // **[0x40~0x7F] 设置显示起始行**
// 设置屏幕显示的起始行地址(垂直滚动用)。
// 0x40 代表从第 0 行开始显示。
// [可修改]:若需要垂直滚动画面,可修改此值 (0x40~0x7F)。
OLED_WR_Byte(0xB0,OLED_CMD); // **[0xB0~0xB7] 设置页地址**
// 设置页地址模式下的页地址0-7。初始化时通常设为第0页。
// [可修改]:初始化设置,一般不改。
// 2. 亮度与对比度 (影响显示效果)
OLED_WR_Byte(0x81,OLED_CMD); // **双字节命令:设置对比度**
OLED_WR_Byte(0xcf,OLED_CMD); // 对比度值0xCF (范围 0x00~0xFF)
// **[可更改]**:数值越大越亮。
// 建议:根据环境光调整。若觉得太亮刺眼或想省电,可调小 (如 0x7F)。
// 文档默认复位值为 0x7F。
// 3. 扫描方向 (屏幕方向翻转)
OLED_WR_Byte(0xA1,OLED_CMD); // **[0xA0/0xA1] 段重映射**
// 0xA0: 列地址0映射到SEG0 (正常)
// 0xA1: 列地址0映射到SEG127 (水平镜像翻转)
// **[可更改]**:如果屏幕显示左右镜像了,改用 0xA0。
OLED_WR_Byte(0xA6,OLED_CMD); // **[0xA6/0xA7] 设置正常/反显**
// 0xA6: 正常显示 (0灭1亮)
// 0xA7: 反显 (0亮1灭)
// **[可更改]**:可视需求改为 0xA7 实现反色效果。
// 4. 硬件驱动配置 (匹配屏幕分辨率 128x64)
OLED_WR_Byte(0xA8,OLED_CMD); // **双字节命令:设置多路复用率**
OLED_WR_Byte(0x3F,OLED_CMD); // 值0x3F (十进制63)
// 计算公式MUX Ratio = 值 + 1。63+1=64。
// 因为屏幕是 64 行,**不可修改**。
// 5. 电源与电荷泵配置 (关键!决定屏幕能否点亮)
OLED_WR_Byte(0xad,OLED_CMD); // **双字节命令:电荷泵设置**
OLED_WR_Byte(0x8b,OLED_CMD); // 0x8B: 开启内部 DC-DC 升压 (内供 VCC)
// 0x8A: 关闭内部升压 (需外部供高压 VCC)
// **[不建议修改]**:必须开启 (0x8B) 屏幕才会亮。
OLED_WR_Byte(0x33,OLED_CMD); // **设置 VPP 电压 (针对特定驱动IC)**
// 代码注释写的是 set VPP 9V。
// 0x30: ~7.4V, 0x31: ~8.0V, 0x32: ~8.4V, 0x33: ~9.0V
// **[可更改]**:如果屏幕显示对比度不够或字体太淡,可尝试微调 (0x30~0x33)。
// 但过高电压可能影响寿命,建议参考文档推荐值。
OLED_WR_Byte(0xC8,OLED_CMD); // **[0xC0/0xC8] COM 输出扫描方向**
// 0xC0: 正常模式 (从COM0扫到COM[N])
// 0xC8: 重映射模式 (从COM[N]扫到COM0垂直翻转)
// **[可更改]**:如果屏幕显示上下颠倒了,改用 0xC0。
OLED_WR_Byte(0xD3,OLED_CMD); // **双字节命令:设置显示偏移**
OLED_WR_Byte(0x00,OLED_CMD); // 偏移值0x00
// **[可更改]**:用于垂直平移显示区域。范围 0x00~0x3F。
OLED_WR_Byte(0xD5,OLED_CMD); // **双字节命令:设置时钟分频**
OLED_WR_Byte(0x80,OLED_CMD); // 低4位分频因子高4位振荡器频率。
// 值 0x80 表示分频比为 1。
// **[可更改]**:增大频率可提高刷新率,但可能导致显示不稳或功耗增加。
OLED_WR_Byte(0xD9,OLED_CMD); // **双字节命令:设置预充电周期**
OLED_WR_Byte(0x1f,OLED_CMD); // 高4位Phase 2; 低4位Phase 1。
// **[可更改]**:影响像素点亮的充电时间。如果显示有拖影或亮度不均,可微调。
// 文档中其他示例代码常用 0x22 或 0xF1。
OLED_WR_Byte(0xDA,OLED_CMD); // **双字节命令:设置 COM 引脚配置**
OLED_WR_Byte(0x12,OLED_CMD); // 0x12: Sequential COM pin config (适用于 128x64)
// 0x02: Alternative COM pin config (适用于 128x32)
// **[不可修改]**这是由屏幕硬件结构决定的128x64 必须用 0x12。
OLED_WR_Byte(0xdb,OLED_CMD); // **双字节命令:设置 VCOMH 电压倍率**
OLED_WR_Byte(0x40,OLED_CMD); // 0x40: ~0.89 x VCC
// **[可更改]**:影响“黑电平”电压。数值过低可能导致背景不够黑(发灰),过高可能导致对比度下降。
// 常用值0x20, 0x30, 0x40。
// --- 结束初始化 ---
OLED_Clear();
memset(OLED_GRAM_Back, 0, sizeof(OLED_GRAM_Back));
OLED_Refresh();
OLED_WR_Byte(0xAF,OLED_CMD); // **[0xAF] 开启显示**
// 配置完成后点亮屏幕。
}
/**
* @brief 在内存缓冲区中填充一个矩形区域(用于局部擦除)
* @param x1: 起始x坐标
* @param y1: 起始y坐标
* @param x2: 结束x坐标
* @param y2: 结束y坐标
* @note 此函数只修改内存中的OLED_GRAM不直接操作硬件
*/
void OLED_FillArea(u8 x1, u8 y1, u8 x2, u8 y2)
{
u8 x, y;
for(y=y1; y<y2; y++)
{
for(x=x1; x<x2; x++)
{
OLED_DrawPoint(x, y, 0); // 修改前台缓冲区
}
}
}
// 新增:填充矩形区域为黑色(用于绘制电量格)
// 参数x1,y1 起始坐标; x2,y2 结束坐标 (不包含x2,y2)
void OLED_FillRect(u8 x1, u8 y1, u8 x2, u8 y2)
{
u8 x, y;
for(y=y1; y<y2; y++)
{
for(x=x1; x<x2; x++)
{
OLED_DrawPoint(x, y, 0); // mode=1绘制黑色像素
}
}
}
// 新增:填充矩形区域为白色 (mode=0 代表画白色/清空)
void OLED_FillRect_White(u8 x1, u8 y1, u8 x2, u8 y2)
{
u8 x, y;
for(y = y1; y < y2; y++)
{
for(x = x1; x < x2; x++)
{
OLED_DrawPoint(x, y, 1); // mode=0绘制白色像素
}
}
}