简介:利用STM32F103C8T6芯片,0.96寸液晶屏显示与MPL3115A模块对大气压,海拔和温度的读取。
利用STM32作为主控对MPL3115A模块进行读取,并将显示的大气压值,温度值显示到液晶屏上面。
MPL3115A模块介绍:
20bit压力测量(Pascal);20bit高度测量(米);12bit温度测量;
绝对压力测量范围:20至110 kPa
相对测量精度: - + 0.05 kPa
有效分辨率:1.5Pa / 0.3m
工作温度范围:-40至85摄氏度;
I2C数字输出接口;
内置32个FIFO采样缓冲区;
软件代码流程如下:
/*配置SDA的IO口模式信息*/
void GPIO_Output_I2C_Configuration(GPIO_TypeDef* SDA, u16 GPIO_Pin)
{
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Pin = GPIO_Pin;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(SDA, &GPIO_Initstructure);
}
/*配置SCL的IO口模式信息*/
void GPIO_Input_I2C_Configuration(GPIO_TypeDef* SDA, u16 GPIO_Pin)
{
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Pin = GPIO_Pin;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(SDA, &GPIO_Initstructure);
}
/*IIC总线启动*/
void I2C_Start ()//I2C开始
{
GPIO_Output_I2C_Configuration(SCL.GPIOx, SCL.GPIO_Pin); //SCL置输出
GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出
GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=1;
delay_us(50); //此处延时50us
GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=1;
delay_us(50); //此处延时50us
GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=0;
delay_us(50); //此处延时50us
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0;
delay_us(50); //此处延时50us
}
/*IIC总线结束*/
void I2C_Stop () //I2C结束
{
GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出
GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=0;
delay_us(50); //此处延时50us
GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=1;
delay_us(50); //此处延时50us
GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=1;
delay_us(50); //此处延时50us
}
/*主机检查从机的响应信号*/
int I2C_Slave_ACK(void) // 检查从机应答信号,返回0有ACK,返回1无ACK
{
int ACK;
u8 s1;
GPIO_Input_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输入
GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=1;
delay_us(50); //此处延时50us
s1 = GPIO_ReadInputDataBit(SDA.GPIOx, SDA.GPIO_Pin);
if (s1) //判断返回的数据类型,确定是否正常
{
ACK = 1;
}
else
{
ACK = 0;
}
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0;
delay_us(50); //此处延时50us
return(ACK); //返回应答信号
}
/*主机发送IIC总线上一个字节数据*/
void I2C_SendByte(u8 data) //发送一个字节
{
u8 i; //发送8位
GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出
for(i = 0; i < 8; i++)
{
if((data & 0x80) == 0x80)
{
GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);
} //SDA=1,写 1
else
{
GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);
} //SDA=0,写 0
GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1;
delay_us(50); //在时钟大于4u秒期间写数据
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0;
delay_us(50); //此处延时50us
data = data << 1; //将返回的数据进行移位处理
}
}
/*主机接收IIC总线上一个字节数据*/
u8 I2C_ReciveByte(void) //接受一个字节
{
u8 s1 = 0, temp1 = 0;
u8 i;
GPIO_Input_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输入
for(i = 0; i < 8; i++)
{
temp1 = temp1 << 1;
GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1;
delay_us(50); //在时钟大于4u秒期间读数据
s1 = GPIO_ReadInputDataBit(SDA.GPIOx, SDA.GPIO_Pin);
if(s1) //读 1
{
temp1 = temp1 | 0x01;
}
else //读 0
{
temp1 = temp1 & 0xfe;
}
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0;
delay_us(50); //此处延时50us
}
return(temp1);
}
/*主机向IC总线发送连续读信号*/
void I2C_ack(void) // 发送连续读信号
{
GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出;
GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=0;
delay_us(50); //此处延时50us
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1;
delay_us(50); //此处延时50us
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0;
}
/*主机向IC总线发送不连续读信号*/
void I2C_nack(void) // 发送不连续读信号
{
GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出 ;
GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=1;
delay_us(50); //此处延时50us
GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1;
delay_us(50); //此处延时50us
GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0;
delay_us(50); //此处延时50us
}
void Write_MPL3115A2(u8 Address, u8 Dat)
{
I2C_Start(); //启动IIC时序
I2C_SendByte(MPL3115A2Wcmd);//主机发送MPL3115A2W的发送字节命令
I2C_Slave_ACK(); //主机等待模块返回应答指令
I2C_SendByte(Address);//主机发送MPL3115A2W的地址
I2C_Slave_ACK(); //主机等待模块返回应答指令
I2C_SendByte(Dat); //主机发送MPL3115A2W的数据
I2C_Slave_ACK(); //主机等待模块返回应答指令
I2C_Stop(); //停止IIC时序
}
u8 MPL3115A2Read(u8 adrr)
{
char p;
I2C_Start(); //启动IIC时序
I2C_SendByte(MPL3115A2Wcmd);//主机发送MPL3115A2W的发送字节命令
I2C_Slave_ACK(); //主机等待模块返回应答指令
I2C_SendByte(adrr); //主机发送MPL3115A2W的发送地址命令信息
I2C_Slave_ACK(); //主机等待模块返回应答指令
I2C_Start(); //启动IIC时序
I2C_SendByte(MPL3115A2Rcmd);
I2C_Slave_ACK(); //主机等待模块返回应答指令
p = I2C_ReciveByte();//将模块返回
I2C_nack(); //确定IIC无应答
I2C_Stop(); //停止IIC时序
return p;
}
void MPL3115A2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/************引脚设置******************/
SDA.GPIOx = GPIOB;
SDA.GPIO_Pin = GPIO_Pin_13;
SCL.GPIOx = GPIOB;
SCL.GPIO_Pin = GPIO_Pin_12;
/**************************************/
/* Set to Altimeter with an OSR = 1 */
Write_MPL3115A2(0x26, 0x80);
/* Enable Data Flags in PT_DATA_CFG */
Write_MPL3115A2(0x13, 0x07);
/* Set Active */
Write_MPL3115A2(0x26, 0xB9);
}
void MPL3115A2_Read(struct MPL3115A2 *p)
{
static u16 AData;
static u8 BData, CData, DData;
u16 pre;
loat Alt_Integer,Alt_Fraction,Tmp_Integer,Tmp_Fraction,Pre_Integer,Pre_Fraction; //临时变量存放气压高度温度的小数和整数部分
/* Set to Altimeter with an OSR = 1 *///高度模式
Write_MPL3115A2(0x26, 0x80);
/* Enable Data Flags in PT_DATA_CFG */
Write_MPL3115A2(0x13, 0x07);
Write_MPL3115A2(0x26, 0xB9);
/* Read STATUS Register */
while((MPL3115A2Read(0x00) & 0x08) == 0);
AData = MPL3115A2Read(0x01) << 8 | MPL3115A2Read(0x02);
BData = MPL3115A2Read(0x03);
CData = MPL3115A2Read(0x04);
DData = MPL3115A2Read(0x05);
Alt_Integer = (s16)AData;
Alt_Fraction=0;
if (BData & 0x80)
{
Alt_Fraction += FRAC_2d1;
}
if (BData & 0x40)
{
Alt_Fraction += FRAC_2d2;
}
if (BData & 0x20)
{
Alt_Fraction += FRAC_2d3;
}
if (BData & 0x10)
{
Alt_Fraction += FRAC_2d4;
}
if(Alt_Integer>0)
{
p->Alt = Alt_Integer + Alt_Fraction/10000;
}
else
{
p->Alt = Alt_Integer - Alt_Fraction/10000;
}
Tmp_Integer = (s8)CData;
Tmp_Fraction=0;
if (DData & 0x80)
{
Tmp_Fraction += FRAC_2d1;
}
if (DData & 0x40)
{
Tmp_Fraction += FRAC_2d2;
}
if (DData & 0x20)
{
Tmp_Fraction += FRAC_2d3;
}
if (DData & 0x10)
{
Tmp_Fraction += FRAC_2d4;
}
if(Tmp_Integer>0)
{
p->Tmp = Tmp_Integer + Tmp_Fraction/10000;
}
else
{
p->Tmp = Tmp_Integer - Tmp_Fraction/10000;
}
/* Set to Altimeter with an OSR = 1 *///气压模式
/* Enable Data Flags in PT_DATA_CFG */
Write_MPL3115A2(0x26, 0x00);
Write_MPL3115A2(0x13, 0x07);
Write_MPL3115A2(0x26, 0x39);
/* Read STATUS Register */
while((MPL3115A2Read(0x00) & 0x08) == 0);
AData = MPL3115A2Read(0x01) << 8 | MPL3115A2Read(0x02);
BData = MPL3115A2Read(0x03);
CData = MPL3115A2Read(0x04);
DData = MPL3115A2Read(0x05);
pre=AData;
pre=pre<<2;
pre|=BData>>6;
Pre_Integer=(float)pre;
Pre_Fraction = 0;
if (BData & 0x20)//第5位
{
Pre_Fraction += FRAC_2d1;
}
if (BData & 0x10)//第4位
{
Pre_Fraction += FRAC_2d2;
}
p->pre=(Pre_Integer+Pre_Fraction/10000)/100;
}模块使用心得:手册中提到读取气压的方式有轮询法和中断法。轮询法就是不使用中断的方法。我这里只是测试模块功能,对精度要求不是很高,所以就选择的该方式。只需要接SDA和SCI,而IN1 IN2只有在中断法中才会使用到,这里就不做过多的介绍。
MPL3115A2有3种工作模式。就绪模式、活动测高模式、活动测压模式。
步骤1:先进入就绪模式,CTRL_REG1寄存器(0x26)写入0x04,即就绪模式;
步骤2:再对该寄存器写入0xB9,进入活动测高模式;
步骤3:将PT_DATA_CDG寄存器(0x13)的值写为0x07。配置工作就完成了。
然后它就可以开始按照iic的工作时序开始工作了。我们需要的数据在0x01 0x02 0x03 这三个寄存器中。0x01和0x02都是以米做单位的,读出来就直接是海拔。
在大多数城市 0x01这个寄存器的值都是0,如果你在青藏高原就当我没说;
0x02的数据就是你城市的海拔,0x03的数据,就可以理解为小数点后的数值了。
2:OLED模块介绍:
2.1:OLED 简介:
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。因为具备轻薄、省电等特性,因此从 2003 年开始,这种显示设备在 MP3 播放器上得到了广泛应用,而对于同属数码类产品的 DC 与手机,此前只是在一些展会上展示过采用 OLED 屏幕的工程样品。自 2007 年后,寿命得 到很大提高,具备了许多 LCD 不可比拟的优势。
GND:电源地 VCC:2.2V~5.5V SCL(D0):CLK 时钟 (高电平 2.2V~5.5V) SDA(D1):MOSI 数据(高电平 2.2V~5.5V) RST:复位(高电平 2.2V~5.5V) D/C:数据/命令(高电平 2.2V~5.5V) 兼容 3.3V 和 5V 控制芯片的 I/O 电平(无需任何设置,直接兼容)。
实物图片

2.2:汉字显示方法:
需要使用软件做自己的字库

//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
for(i=0;i<8;i++)
{
OLED_SCLK_Clr();
if(dat&0x80)
OLED_SDIN_Set();
else
OLED_SDIN_Clr();
OLED_SCLK_Set();
dat<<=1;
}
OLED_CS_Set();
OLED_DC_Set();
}
void OLED_Set_Pos(u8 x, u8 y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x02,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符 调用OLED_ShowChar(48,6,16,t);
//x0,y0显示起点坐标,x0(范围0~127),y0(范围0~7)*8
//size:选择字体 16/12
//chr:字符串ascii码
void OLED_ShowChar(u8 x, u8 y, u8 size, u8 chr)
{
u8 c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>X_WIDTH-1){x=0;y=y+2;}
if(size ==ASCII32x32)
{
OLED_Set_Pos(x,y);
for(i=0;i<ASCII32x32/4;i++)
OLED_WR_Byte(ASCII16x32[c*ASCII32x32+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<ASCII32x32/4;i++)
OLED_WR_Byte(ASCII16x32[c*ASCII32x32+i+ASCII32x32/4],OLED_DATA);//四列显示完
OLED_Set_Pos(x,y+2);
for(i=0;i<ASCII32x32/4;i++)
OLED_WR_Byte(ASCII16x32[c*ASCII32x32+i+2*ASCII32x32/4],OLED_DATA);
OLED_Set_Pos(x,y+3);
for(i=0;i<ASCII32x32/4;i++)
OLED_WR_Byte(ASCII16x32[c*ASCII32x32+i+3*ASCII32x32/4],OLED_DATA);
}
else if(size ==ASCII24x24)
{
OLED_Set_Pos(x,y);
for(i=0;i<ASCII24x24/3;i++)
OLED_WR_Byte(ASCII12x24[c*ASCII24x24+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<ASCII24x24/3;i++)
OLED_WR_Byte(ASCII12x24[c*ASCII24x24+i+ASCII24x24/3],OLED_DATA);//三列显示完
OLED_Set_Pos(x,y+2);
for(i=0;i<ASCII24x24/3;i++)
OLED_WR_Byte(ASCII12x24[c*ASCII24x24+i+2*ASCII24x24/3],OLED_DATA);
}
else if(size ==ASCII16x16)
{
OLED_Set_Pos(x,y);
for(i=0;i<ASCII16x16/2;i++)
OLED_WR_Byte(ASCII8X16[c*ASCII16x16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<ASCII16x16/2;i++)
OLED_WR_Byte(ASCII8X16[c*ASCII16x16+i+ASCII16x16/2],OLED_DATA);//两列显示完
}
else if(size ==ASCII12x8)
{
OLED_Set_Pos(x,y);
for(i=0;i<ASCII12x8;i++)
OLED_WR_Byte(ASCII6x8[c*ASCII12x8+i],OLED_DATA); //一列显示完
}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示数字 调用OLED_ShowNum(103,6,t,3,16);
//x0,y0显示起点坐标,x0(范围0~127),y0(范围0~7)*8
//len :数字的位数
//size:选择字体 16/12
//num:数值(0~65536);
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size)
{
u8 t,temp;
u8 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+(size/2)*t,y,size,' ');
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size/2)*t,y,size,temp+'0');
}
}
//显示一个字符号串 调用OLED_ShowString(30,0,"OLED TEST");
//x0,y0:显示起点坐标,x0(范围0~127),y0(范围0~7)*8
//size:选择字体 16/12
//char:字符串ascii码
void OLED_ShowString(u8 x,u8 y,u8 size,u8 *chr)
{
u8 j=0;
while (chr[j]!='\0')
{
OLED_ShowChar(x,y,size,chr[j]);
if(size==ASCII12x8)
{
x+=6;//单个ascii偏移量
}
else if(size==ASCII16x16)
{
x+=ASCII16x16/2;//单个ascii偏移量
}
else if(size==ASCII24x24)
{
x+=ASCII24x24/3;//单个ascii偏移量
}
else if(size==ASCII32x32)
{
x+=ASCII32x32/4;//单个ascii偏移量
}
if(x>X_WIDTH-size){x=0;y+=size/8;}
j++;
}
}
//显示显示BMP图片 调用OLED_DrawBMP(0,0,128,8,BMP1);最大图片
//x0,y0:显示起点坐标,x0(范围0~127),y0(范围0~7)*8
//x1,y1:显示图片长度和宽度,x1(范围0~127),y1(范围0~7)*8
//BMP[]:图片首地址
void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[])
{
u16 j=0;
u8 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++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}
//-----------------------------------显示中文------------------
u32 *getchinesecodepos(u16 ac)
{
u16 min,max,mid,midc;
min=0;
max=CHINESECHARNUMBER-1;
while(1)
{ if(max-min<2)
{ if(ChineseCode[min]==ac)
mid=min;
else if(ChineseCode[max]==ac)
mid=max;
else
mid=0;
break;
}
mid=(max+min)/2;
midc=ChineseCode[mid];
if(midc==ac)
break;
else if(midc>ac)
max=mid-1;
else
min=mid+1;
}
return (u32*)(ChineseCharDot+mid*CHINESECHARDOTSIZE);
}
void Get_Code(u8* dis_buf,u32* address,u8 leng)
{
u8 i;
for(i=0;i<leng/4;i++) //32为单片机4个字节
{
*dis_buf=*address;
dis_buf++;
*dis_buf=*address>>8;
dis_buf++;
*dis_buf=*address>>16;
dis_buf++;
*dis_buf=*address>>24;
dis_buf++;
address++;
}
}
void LCD_Char_CH(u8 x,u8 y,vu8 *str)
{
u8 i,buffer[CHINESECHARDOTSIZE]={0};
u16 chinese_ascii;
u32 *p_address;
chinese_ascii = *str;
str++;
chinese_ascii = chinese_ascii<<8|*str; //找到汉字内码
p_address=getchinesecodepos(chinese_ascii);
Get_Code(buffer,p_address,32); // 取字模数据
OLED_Set_Pos(x,y);
for(i=0;i<CHINESECHARSIZE;i++)
OLED_WR_Byte(buffer[i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<CHINESECHARSIZE;i++)
OLED_WR_Byte(buffer[i+CHINESECHARSIZE],OLED_DATA);
}
// * 函数名:LCD_Str_CH diao
// * 描述 :在指定坐标处显示16*16大小汉字字符串
// * 输入 : - x: 显示位置横向坐标
// * - y: 显示位置纵向坐标
// * - str: 显示的中文字符串
// * 举例 :
void LCD_Str_CHinese(u8 x,u8 y,vu8 *str)
{
while(*str != '\0')
{
LCD_Char_CH(x,y,str);
str += 2 ;
x += 16 ;
}
}
//-----------------------------------------------------------------------------
//初始化SSD1306
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能PD端口时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOD3,6
GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
// DBGMCU->CR = DBGMCU->CR & ~((uint32_t)1<<5);
// RCC->APB2ENR = 1 | (1<<3); /*AFIO/ GPIOB*/
// AFIO->MAPR = (AFIO->MAPR & ~((uint32_t)0x7 << 24)) | (2 << 24); /*释放 PA15 PB3 PB4*/
OLED_RST_Set();
delay_ms(100);
OLED_RST_Clr();
delay_ms(100);
OLED_RST_Set();
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x02,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(0x81,OLED_CMD); //对比度设置
OLED_WR_Byte(0xfF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
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(0x40,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_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
OLED_Clear();
OLED_Set_Pos(0,0);
}测试图片如下:

我要赚赏金
