基于STM32单片机的汽车疲劳驾驶监测系统设计
摘要:本文设计了一种基于STM32单片机的汽车疲劳驾驶监测系统,该系统通过MAX30102传感器采集司机的心率和血氧含量,利用酒精传感器检测酒驾行为,并结合驾驶时间监控,实现对疲劳驾驶的有效监测与预警。系统还具备按键控制和液晶显示功能,方便用户设置阈值和查看监测数据。实验结果表明,该系统能够准确检测疲劳驾驶状态,及时发出预警,有效保障行车安全。
关键词:STM32单片机;疲劳驾驶监测;MAX30102传感器;酒精检测;液晶显示
一、引言
随着交通运输事业的快速发展,汽车已成为人们日常生活中不可或缺的交通工具。然而,随着驾驶时间的增加,驾驶员容易出现疲劳驾驶现象,这不仅危及自身安全,也对他人生命财产构成严重威胁。据统计,疲劳驾驶引发的交通事故在交通事故总数中占有较大比例,因此,设计一种有效的汽车疲劳驾驶监测系统具有重要意义。
本系统基于STM32单片机,通过集成多种传感器和模块,实现对驾驶员疲劳驾驶状态的实时监测与预警。本文将从系统总体设计、硬件设计、软件设计以及实验测试等方面进行详细阐述。
二、系统总体设计
(一)系统功能需求
- 传感器采集
- 运用MAX30102传感器采集当前司机的心率数值和血氧含量数值。
- 运用酒精传感器上车检测,采集司机酒精含量,当检测到酒驾时,进行语音播报并触发蜂鸣器警报。
- 疲劳驾驶时间监控:汽车发动机开启运行后,系统开启驾驶计时,当检测到司机疲劳驾驶时,系统进行语音模块播报并触发蜂鸣器警报,提醒司机尽快进入服务区休息。
- 按键控制
- 采用5个按键控制,实现设置心率和血氧含量阈值的加减、发动机的启动、休息时间的启动等功能。
- 液晶显示
- 显示心率数值、心率阈值、血氧含量、血氧阈值、启动计时、酒精含量等内容。
(二)系统总体框架
系统主要由STM32单片机、MAX30102传感器、酒精传感器、语音播报模块、蜂鸣器、按键模块、液晶显示模块以及电源模块等组成。STM32单片机作为系统的核心控制器,负责协调各个模块的工作,处理传感器数据,并根据逻辑判断作出相应的控制决策。
三、硬件设计
(一)STM32单片机选型
本系统选用STM32F103C8T6单片机作为核心控制器。该单片机具有高性能、低功耗、丰富的外设接口和强大的处理能力,能够满足系统对数据处理和控制的需求。
(二)传感器模块
- MAX30102传感器
- MAX30102是一款集成了红外光源、光电检测器和信号处理电路的高度集成传感器,主要用于心率和血氧饱和度的测量。其工作原理基于红外光在血液中的吸收特性,通过测量红外光的吸收情况来推断血液的氧合状态,从而计算心率和血氧饱和度。
- 在硬件连接上,MAX30102传感器通过I2C接口与STM32单片机相连。SDA和SCL引脚分别连接到STM32单片机的I2C总线对应的引脚,电源线使用3.3V供电,并确保电源稳定且连接好地线。
- 酒精传感器
- 酒精传感器用于检测驾驶员呼出的空气中酒精含量。当检测到酒精含量超标时,传感器会输出相应的信号给STM32单片机。
- 酒精传感器的具体型号和连接方式可以根据实际需求进行选择和设计。一般来说,酒精传感器会输出模拟信号,需要通过ADC(模数转换器)将其转换为数字信号,以便STM32单片机进行处理。
(三)语音播报模块
语音播报模块用于在检测到酒驾或疲劳驾驶时,向驾驶员发出语音提示。本系统选用常见的语音芯片或模块,如ISD1820等。语音芯片通过串口或SPI接口与STM32单片机相连,接收单片机发送的语音指令,并播放相应的语音提示。
(四)蜂鸣器模块
蜂鸣器模块用于在检测到酒驾或疲劳驾驶时,发出警报声以提醒驾驶员。蜂鸣器通过GPIO接口与STM32单片机相连,当单片机检测到异常情况时,会控制GPIO引脚输出高电平或低电平,从而驱动蜂鸣器发声。
(五)按键模块
按键模块用于实现用户与系统的交互,包括设置心率和血氧含量的阈值、启动发动机、设置休息时间等功能。本系统采用5个按键,分别连接到STM32单片机的不同GPIO引脚。通过检测按键的按下和释放状态,单片机可以执行相应的操作。
(六)液晶显示模块
液晶显示模块用于显示心率数值、心率阈值、血氧含量、血氧阈值、启动计时、酒精含量等信息。本系统选用常见的LCD1602或OLED显示屏。显示屏通过I2C或SPI接口与STM32单片机相连,接收单片机发送的显示数据,并更新显示内容。
(七)电源模块
电源模块为整个系统提供稳定的电源供应。本系统采用车载电源作为输入,通过稳压芯片将车载电源的电压转换为系统所需的3.3V和5V电压。同时,电源模块还需要具备过压保护、过流保护等功能,以确保系统的稳定运行。
四、软件设计
(一)开发环境
本系统采用Keil uVision5作为开发环境。Keil uVision5是一款功能强大的集成开发环境(IDE),支持C语言编程,提供了丰富的库函数和调试工具,方便开发者进行程序编写和调试。
(二)主程序设计
主程序是系统的核心部分,负责初始化各个模块、处理传感器数据、执行控制决策以及更新显示内容等。主程序的设计流程如下:
- 系统初始化
- 初始化STM32单片机的时钟系统、GPIO端口、I2C接口、ADC模块、串口等外设。
- 初始化MAX30102传感器、酒精传感器、语音播报模块、蜂鸣器模块、按键模块和液晶显示模块等。
- 主循环
- 读取MAX30102传感器采集的心率和血氧数据,并进行处理和分析。
- 读取酒精传感器采集的酒精含量数据,判断是否酒驾。如果酒驾,则进行语音播报并触发蜂鸣器警报。
- 监控驾驶时间,判断是否疲劳驾驶。如果疲劳驾驶,则进行语音播报并触发蜂鸣器警报。
- 检测按键状态,执行相应的操作,如设置心率和血氧阈值、启动发动机、设置休息时间等。
- 更新液晶显示模块的内容,显示心率数值、心率阈值、血氧含量、血氧阈值、启动计时、酒精含量等信息。
(三)子程序设计
- MAX30102传感器驱动程序
- MAX30102传感器的驱动程序负责初始化传感器、配置传感器参数、读取传感器数据等。驱动程序需要按照MAX30102传感器的通信协议进行编写,确保能够正确读取心率和血氧数据。
- 酒精传感器驱动程序
- 酒精传感器的驱动程序负责初始化ADC模块、读取酒精含量数据等。驱动程序需要根据酒精传感器的特性进行编写,确保能够准确测量酒精含量。
- 语音播报模块驱动程序
- 语音播报模块的驱动程序负责初始化语音芯片、发送语音指令等。驱动程序需要根据语音芯片的特性进行编写,确保能够正确播放语音提示。
- 蜂鸣器模块驱动程序
- 蜂鸣器模块的驱动程序负责控制GPIO引脚输出高电平或低电平,从而驱动蜂鸣器发声。驱动程序需要根据蜂鸣器的特性进行编写,确保能够发出清晰的警报声。
- 按键模块驱动程序
- 按键模块的驱动程序负责检测按键的按下和释放状态,并执行相应的操作。驱动程序需要采用消抖处理,避免按键抖动对系统的影响。
- 液晶显示模块驱动程序
- 液晶显示模块的驱动程序负责初始化显示屏、发送显示数据等。驱动程序需要根据显示屏的特性进行编写,确保能够正确显示各种信息。
五、实验测试
(一)测试环境
本系统在实际车辆上进行测试。测试环境包括车辆内部空间、车载电源、驾驶员等。为了确保测试的安全性和准确性,测试过程中需要严格遵守交通规则和安全操作规范。
(二)测试内容
- 传感器数据采集测试
- 测试MAX30102传感器是否能够准确采集心率和血氧数据。通过与实际测量值进行对比,验证传感器的准确性和稳定性。
- 测试酒精传感器是否能够准确测量酒精含量。通过模拟不同酒精含量的呼出气体进行测试,验证传感器的灵敏度和准确性。
- 疲劳驾驶监测测试
- 测试系统是否能够准确判断疲劳驾驶状态。通过模拟不同驾驶时间下的驾驶员状态进行测试,验证系统的判断逻辑和准确性。
- 测试语音播报和蜂鸣器警报功能是否正常。当检测到疲劳驾驶时,观察语音播报和蜂鸣器是否能够及时发出警报。
- 按键控制和液晶显示测试
- 测试按键模块是否能够正常实现设置心率和血氧阈值、启动发动机、设置休息时间等功能。通过按下不同按键观察系统的反应进行验证。
- 测试液晶显示模块是否能够正常显示心率数值、心率阈值、血氧含量、血氧阈值、启动计时、酒精含量等信息。通过观察显示屏的内容进行验证。
(三)测试结果
经过实验测试,本系统能够准确采集心率和血氧数据、测量酒精含量、判断疲劳驾驶状态,并及时发出语音播报和蜂鸣器警报。按键模块和液晶显示模块也能够正常工作,实现用户与系统的交互和信息显示。测试结果表明,本系统满足设计要求,能够有效监测驾驶员的疲劳驾驶状态,保障行车安全。
六、结论与展望
(一)结论
本文设计了一种基于STM32单片机的汽车疲劳驾驶监测系统,该系统通过集成MAX30102传感器、酒精传感器、语音播报模块、蜂鸣器模块、按键模块和液晶显示模块等,实现了对驾驶员疲劳驾驶状态的实时监测与预警。实验测试结果表明,该系统能够准确采集传感器数据、判断疲劳驾驶状态,并及时发出警报,有效保障行车安全。
(二)展望
尽管本系统已经实现了基本的功能需求,但仍存在一些不足之处和改进空间。例如,可以进一步优化传感器数据的处理算法,提高系统的准确性和稳定性;可以增加更多的监测指标,如驾驶员的眼部特征、头部姿态等,以更全面地评估驾驶员的疲劳状态;还可以将系统与车载导航系统、智能手机等设备进行集成,实现更丰富的功能和更便捷的用户体验。
在未来的研究中,我们将继续完善和优化本系统,探索更多的监测技术和方法,为汽车安全驾驶提供更全面、更可靠的解决方案。同时,我们也将关注相关领域的最新发展动态,积极引入新技术和新方法,不断提升系统的性能和功能。
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
u8 OLED_GRAM[144][8];
//void delay_ms(u16 nms)
//{
//
// u32 f=nms,k;
// for (; f!=0; f--)
// {
// for(k=0x2fff; k!=0; k--);
// }
//
//}
//反显函数
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);//关闭屏幕
}
//更新显存到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); //设置高列起始地址
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();
}
}
//清屏函数
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_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能A端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PA0,1
GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
GPIO_SetBits(GPIOA,GPIO_Pin_2);
OLED_RES_Clr();
delay_ms(200);
OLED_RES_Set();
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x30,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD);
}