Files
STC32G_Power_Monitor/Source/oled_iic_SSD1306.c
2025-09-01 22:43:03 +08:00

491 lines
16 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 "oled_iic_SSD1306.h"
#include "oled_font.h"
#include "delay.h"
#include "printfs.h"
#if (1==OLED_USE_SOFT_IIC)
#include "iic_soft.h"
static IIC_Soft_Config oled_soft_iic;
#else
#include "iic.h"
#endif
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部调用,用户无需关心
// @param void
// @return
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_wrdat(uint8 dat)
{
#if (1==OLED_USE_SOFT_IIC)
soft_iic_write_reg(&oled_soft_iic, OLED_ADDR, 0x40, dat);
#else
iic_write_reg(OLED_ADDR, 0x40, dat);
#endif
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部调用,用户无需关心
// @param void
// @return
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_wrcmd(uint8 cmd)
{
#if (1==OLED_USE_SOFT_IIC)
soft_iic_write_reg(&oled_soft_iic, OLED_ADDR, 0x00, cmd);
#else
iic_write_reg(OLED_ADDR, 0x00, cmd);
#endif
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部调用,用户无需关心
// @param void
// @return
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_hexascii(uint16 hex,int8 * Print)
{
uint8 edata hexcheck ;
uint8 edata TEMP ;
TEMP = 6 ;
Print[TEMP ]='\0';
while(TEMP)
{
TEMP -- ;
hexcheck = hex%10 ;
hex /=10 ;
Print[TEMP ] = hexcheck + 0x30 ;
}
}
#if (1==OLED_USE_SOFT_IIC)
void oled_scl_set()
{
OLED_SCL_LEVEL(1);
}
void oled_sda_set()
{
OLED_SDA_LEVEL(1);
}
void oled_sda_clr()
{
OLED_SDA_LEVEL(0);
}
void oled_scl_clr()
{
OLED_SCL_LEVEL(0);
}
uint8 oled_sda_read()
{
return OLED_SDA_READ();
}
#endif
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED初始化函数
// @param NULL
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_init(void)
{
// unsigned char i;
// unsigned char initData[] = {0xAE,0x00,0x10,0x40,0xB0,0x81,0xFF,0xA0,0xA6,0xA8,0x3F,0xC8,0xD3,0x00,0xD5,0x80,0xD9,0xF1,0xDA,0x12,0xDB,0x30,0x8D,0x14,0xAF};
#if (1==OLED_USE_SOFT_IIC)
// oled_soft_iic.sda_pin = OLED_SDA_PIN;
// oled_soft_iic.scl_pin = OLED_SCL_PIN;
oled_soft_iic.SCL_SET = oled_scl_set;
oled_soft_iic.SCL_CLR = oled_scl_clr;
oled_soft_iic.SDA_SET = oled_sda_set;
oled_soft_iic.SDA_CLR = oled_sda_clr;
oled_soft_iic.SDA_READ = oled_sda_read;
oled_soft_iic.wait_time = OLED_SOFT_WAIT_TIME;
soft_iic_init(&oled_soft_iic);
#else
iic_init(OLED_IIC,OLED_HARD_WAIT_TIME);
#endif
// for(i=0;i<25;i++){
// oled_wrcmd(initData[i]);
// }
// oled_wrcmd(0xAE);
// oled_wrcmd(0x40);
// oled_wrcmd(0xB0);
// oled_wrcmd(0xC8);
// oled_wrcmd(0x81);
// oled_wrcmd(0xFF);
// oled_wrcmd(0xA1);
// oled_wrcmd(0xA6);
// oled_wrcmd(0xA8);
// oled_wrcmd(0x1F);
// oled_wrcmd(0xD3);
// oled_wrcmd(0x00);
// oled_wrcmd(0xD5);
// oled_wrcmd(0xF0);
// oled_wrcmd(0xD9);
// oled_wrcmd(0x22);
// oled_wrcmd(0xDA);
// oled_wrcmd(0x02);
// oled_wrcmd(0xDB);
// oled_wrcmd(0x49);
// oled_wrcmd(0x8D);
// oled_wrcmd(0x14);
// oled_wrcmd(0xAF);
oled_wrcmd(0xae);//--turn off oled panel
oled_wrcmd(0x00);//---set low column address
oled_wrcmd(0x10);//---set high column address
oled_wrcmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
oled_wrcmd(0x81);//--set contrast control register
oled_wrcmd(Brightness); // Set SEG Output Current Brightness
#if (0 == OLED_DISPLAY_DIR)
oled_wrcmd(0xa1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
oled_wrcmd(0xc8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
#else
oled_wrcmd(0xa0);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
oled_wrcmd(0xc0);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
#endif
oled_wrcmd(0xa6);//--set normal display
oled_wrcmd(0xa8);//--set multiplex ratio(1 to 64)
oled_wrcmd(0x3f);//--1/64 duty
oled_wrcmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
oled_wrcmd(0x00);//-not offset
oled_wrcmd(0xd5);//--set display clock divide ratio/oscillator frequency
oled_wrcmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
oled_wrcmd(0xd9);//--set pre-charge period
oled_wrcmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
oled_wrcmd(0xda);//--set com pins hardware configuration
oled_wrcmd(0x12);
oled_wrcmd(0xdb);//--set vcomh
oled_wrcmd(0x40);//Set VCOM Deselect Level
oled_wrcmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
oled_wrcmd(0x02);//
oled_wrcmd(0x8d);//--set Charge Pump enable/disable
oled_wrcmd(0x14);//--set(0x10) disable
oled_wrcmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
oled_wrcmd(0xa6);// Disable Inverse Display On (0xa6/a7)
oled_wrcmd(0xaf);//--turn on oled panel
oled_fill(0x00); //初始清屏
oled_set_pos(0,0);
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示坐标设置
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_set_pos(uint8 x, uint8 y)
{
oled_wrcmd((uint8)(0xb0+y));
oled_wrcmd((uint8)(((x&0xf0)>>4)|0x10));
oled_wrcmd((uint8)((x&0x0f)));
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED清屏函数
// @param bmp_data 填充颜色选着(0x00 or 0xff)
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_fill(uint8 bmp_data)
{
uint8 edata y,x;
for(y=0;y<8;y++)
{
oled_wrcmd((uint8)(0xb0+y));
oled_wrcmd((uint8)(0x01));
oled_wrcmd((uint8)(0x10));
for(x=0;x<X_WIDTH;x++) oled_wrdat(bmp_data);
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED控制一个坐标下8个像素的点亮与熄灭
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @return void
// @since v1.0
// Sample usage: oled_putpixel(0,0,0xff);//将0,0坐标 8个点全部点亮
// Sample usage: oled_putpixel(0,0,0x01);//将0,0坐标 最低位点亮其余7个熄灭
// @note 同理可以任意控制一个坐标下8个像素的点亮与熄灭
//-------------------------------------------------------------------------------------------------------------------
void oled_putpixel(uint8 x,uint8 y,uint8 data1)
{
oled_set_pos(x,y);
oled_wrcmd((uint8)(0xb0+y));
oled_wrcmd((uint8)(((x&0xf0)>>4)|0x10));
oled_wrcmd((uint8)((x&0x0f)|0x00));
oled_wrdat(data1);
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED关闭一个坐标所有亮点
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_clrpixel(uint8 x,uint8 y)
{
oled_set_pos(x,y);
oled_wrcmd((uint8)(0xb0+y));
oled_wrcmd((uint8)(((x&0xf0)>>4)|0x10));
oled_wrcmd((uint8)((x&0x0f)|0x00));
oled_wrdat(0x00);
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示字符串(6*8字体)
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @param ch[] 字符串
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_p6x8str(uint8 x,uint8 y,const int8 ch[])
{
uint8 edata c=0,i=0,j=0;
while (ch[j]!='\0')
{
c =ch[j]-32;
if(x>126){x=0;y++;}
oled_set_pos(x,y);
for(i=0;i<6;i++) oled_wrdat(oled_6x8[c][i]);
x+=6;
j++;
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示无符号数(6*8字体)
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @param num 无符号数
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_uint16(uint8 x, uint8 y, uint16 num)
{
int8 ch[7];
oled_hexascii(num,ch);
oled_p6x8str(x, y, &ch[1]); //显示数字 6*8字体
//oled_p8x16str(x, y, &ch[1]); //显示数字 8*16字体
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示有符号数(6*8字体)
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @param num 有符号数
// @return void
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void oled_int16(uint8 x, uint8 y, int16 num)
{
int8 ch[7];
if(num<0) {num = -num;oled_p6x8str(x, y, "-");}
else oled_p6x8str(x, y, " ");
x+=6;
oled_hexascii(num,ch);
oled_p6x8str(x, y, &ch[1]); //显示数字 6*8字体
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示32位有符号(去除整数部分无效的0)
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @param dat 需要显示的变量数据类型uint32
// @param num 需要显示的位数 最高10位 不包含正负号
// @return void
// @since v1.0
// Sample usage: oled_printf_int32(0,0,x,5);//x可以为int32 uint16 int16 uint8 int8类型
// Sample usage: 负数会显示一个 -’号 正数显示一个空格
//-------------------------------------------------------------------------------------------------------------------
void oled_printf_int32(uint16 x,uint16 y,int32 dat,uint8 num)
{
int8 buff[34];
uint8 length;
if(10<num) num = 10;
num++;
if(0>dat) length = zf_sprintf( &buff[0],"%d",dat);//负数
else
{
buff[0] = ' ';
length = zf_sprintf( &buff[1],"%d",dat);
length++;
}
while(length < num)
{
buff[length] = ' ';
length++;
}
buff[num] = '\0';
oled_p6x8str((uint8)x, (uint8)y, (int *)buff); //显示数字
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示浮点数(去除整数部分无效的0)
// @param x x轴坐标设置0-127
// @param y y轴坐标设置0-7
// @param dat 需要显示的变量数据类型float或double
// @param num 整数位显示长度 最高10位
// @param pointnum 小数位显示长度 最高6位
// @return void
// @since v1.0
// Sample usage: oled_printf_float(0,0,x,2,3);//显示浮点数 整数显示2位 小数显示三位
// @note 特别注意当发现小数部分显示的值与你写入的值不一样的时候,
// 可能是由于浮点数精度丢失问题导致的,这并不是显示函数的问题,
// 有关问题的详情,请自行百度学习 浮点数精度丢失问题。
// 负数会显示一个 -’号 正数显示一个空格
//-------------------------------------------------------------------------------------------------------------------
void oled_printf_float(uint16 x,uint16 y,double dat,uint8 num,uint8 pointnum)
{
uint8 length;
int8 buff[34];
int8 start,end,point;
if(6<pointnum) pointnum = 6;
if(10<num) num = 10;
if(0>dat) length = zf_sprintf( &buff[0],"%f",dat);//负数
else
{
length = zf_sprintf( &buff[1],"%f",dat);
length++;
}
point = length - 7; //计算小数点位置
start = point - num - 1; //计算起始位
end = point + pointnum + 1; //计算结束位
while(0>start)//整数位不够 末尾应该填充空格
{
buff[end] = ' ';
end++;
start++;
}
if(0>dat) buff[start] = '-';
else buff[start] = ' ';
buff[end] = '\0';
oled_p6x8str((uint8)x, (uint8)y, (int8 *)buff); //显示数字
}
//-------------------------------------------------------------------------------------------------------------------
// @brief OLED显示图像
// @param high 图像高度
// @param width 图像宽度
// @param *p 图像地址(数组)
// @param value 二值化阀值
// @return void
// @since v1.0
// Sample usage:
// @Note 使用Image2lcd V3.2软件取模 C语言数组 水平扫描
// 宽度高度自行设置 颜色反转 256色
//-------------------------------------------------------------------------------------------------------------------
void oled_dis_bmp(uint16 high, uint16 width, uint8 *p,uint8 value)
{
uint16 i = 0;
uint16 edata j = 0;
uint16 temp = 0,temp1 = 0;
uint8 dat = 0;
temp1 = high%8;
if(temp1 == 0) temp = high/8;
else temp = high/8+1;
for(i=0; i<temp; i++)
{
oled_set_pos((uint8)0,(uint8)i);
for(j=0; j<width; j++)
{
dat = 0;
if( (i<(temp-1)) || !temp1 || (temp1>=1))dat |= (*(p+i*8*width+j+width*0) > value? 1: 0)<<0;
if( (i<(temp-1)) || !temp1 || (temp1>=2))dat |= (*(p+i*8*width+j+width*1) > value? 1: 0)<<1;
if( (i<(temp-1)) || !temp1 || (temp1>=3))dat |= (*(p+i*8*width+j+width*2) > value? 1: 0)<<2;
if( (i<(temp-1)) || !temp1 || (temp1>=4))dat |= (*(p+i*8*width+j+width*3) > value? 1: 0)<<3;
if( (i<(temp-1)) || !temp1 || (temp1>=5))dat |= (*(p+i*8*width+j+width*4) > value? 1: 0)<<4;
if( (i<(temp-1)) || !temp1 || (temp1>=6))dat |= (*(p+i*8*width+j+width*5) > value? 1: 0)<<5;
if( (i<(temp-1)) || !temp1 || (temp1>=7))dat |= (*(p+i*8*width+j+width*6) > value? 1: 0)<<6;
if( (i<(temp-1)) || !temp1 || (temp1>=8))dat |= (*(p+i*8*width+j+width*7) > value? 1: 0)<<7;
oled_wrdat(dat);
}
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 汉字显示
// @param x 横坐标 0-127
// @param y 纵坐标 0-7
// @param size 取模的时候设置的汉字字体大小,也就是一个汉字占用的点阵长宽为多少个点,取模的时候需要长宽是一样的。
// @param *p 需要显示的汉字数组
// @param len 需要显示多少位
// @return void
// @since v1.0
// Sample usage:
// @Note 使用PCtoLCD2002软件取模 阴码、逐行式、顺向 16*16
//-------------------------------------------------------------------------------------------------------------------
void oled_print_chinese(uint8 x, uint8 y, uint8 size, const uint8 *p, uint8 len)
{
uint16 i,j,k;
for(i=0; i<len; i++)
{
for(j=0; j<(size/8); j++)
{
oled_set_pos((uint8)(x+i*size), (uint8)(y+j));
for(k=0; k<16; k++)
{
oled_wrdat(*p);
p++;
}
}
}
}