一、OLED显示屏
????????STC15W408AS单片机并没有提供IIC总线的接口,但是我们可以通过模拟IIC的方式实现。关于IIC总线的只是大家可以自行上网搜索。这里以驱动SSD1306芯片的0.96寸的128*64的OLED显示屏为例。下图为OLED的外观图。
? ? ? ?
? ? ? ?
二、SSD1306芯片的IIC时序图
? ? ? ?
? ? ? ?
? ? ? ?
这里我们需要看清楚START信号和STOP信号。关于时间,芯片的数据手册也有说明。
?
? ? ?
IIC数据传输格式??
? ? ? ? ?
这个是芯片的数据传输格式。
2) The slave address is following the start condition for recognition use. For the SSD1306, the slave ?address is either “b0111100” or “b0111101” by changing the SA0 to LOW or HIGH (D/C pin acts as ?SA0).
手册中的这句话和上图右下角的,也说明了芯片的器件地址是0x78或者0x79。至于我们用的OLED液晶是哪一个,需要我们用这两个地址测试,我没找到哪个手册有说明,具体是哪一个。关于芯片的寄存器,手册上面有很多,这里不做说明,自己查阅手册即可。
三、测试程序
1.IIC.h文件
#ifndef __IIC_H_
#define __IIC_H_
#define u16 unsigned int
#define u8 unsigned char
void IIC_Start();
void IIC_Stop();
void IIC_Write_Byte(u8 byte);
void IIC_Wait_Ack();
void IIC_Write_Command(u8 cmd);
void IIC_Write_Data(u8 dat);
#endif
2.IIC.c文件
#include "stc15.h"
#include "iic.h"
#define IIC_SCL P10 // 时钟
#define IIC_SDA P11 // 数据
// IIC 开始信号
void IIC_Start()
{
IIC_SCL = 1 ;
IIC_SDA = 1;
IIC_SDA = 0;
IIC_SCL = 0;
}
// IIC 停止信号
void IIC_Stop()
{
IIC_SCL = 1 ;
// IIC_SCL = 0;
IIC_SDA = 0;
IIC_SDA = 1;
}
// IIC 应答信号
void IIC_Wait_Ack()
{
IIC_SCL = 1 ;
IIC_SCL = 0;
}
// IIC 写一字节数据
void IIC_Write_Byte(u8 IIC_Byte)
{
u8 i;
u8 m,da;
da = IIC_Byte;
IIC_SCL = 0;
for(i = 0;i < 8;i++)
{
m = da;
// IIC_SCL = 0;
m = m&0x80;
if(m==0x80)
{
IIC_SDA = 1;
}
else IIC_SDA = 0;
da = da<<1;
IIC_SCL = 1;
IIC_SCL = 0;
}
}
3.OLED.h文件
#ifndef __OLED_H_
#define __OLED_H_
#define u16 unsigned int
#define u8 unsigned char
#define OLED_CMD 0 // 写命令
#define OLED_DATA 1 // 写数据
#define OLED_MODE 0 // 显示模式
//OLED模式设置
//0:4线串行模式
//1:并行8080模式
#define OLED_Address 0x78
#define OLED_Cmd 0x00
#define OLED_Data 0x40
#define SIZE 16
#define XLevelL 0x02
#define XLevelH 0x10
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xFF
#define X_WIDTH 128
#define Y_WIDTH 64
//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size2);
void OLED_ShowString(u8 x,u8 y, u8 *p,u8 Char_Size);
void OLED_Set_Pos(u8 x, u8 y);
void OLED_ShowCHinese(u8 x,u8 y,u8 no);
void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]);
void fill_picture(u8 fill_Data);
void Picture();
#endif
4.OLED.c文件
#include "oled.h"
#include "iic.h"
#include "oledfont.h"
// IIC 写命令
void IIC_Write_Command(u8 IIC_Command)
{
IIC_Start();
IIC_Write_Byte(OLED_Address);
IIC_Wait_Ack();
IIC_Write_Byte(OLED_Cmd);
IIC_Wait_Ack();
IIC_Write_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
}
// IIC 写数据
void IIC_Write_Date(u8 IIC_Data)
{
IIC_Start();
IIC_Write_Byte(OLED_Address);
IIC_Wait_Ack();
IIC_Write_Byte(OLED_Data);
IIC_Wait_Ack();
IIC_Write_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
}
// 往OLED写一字节数据
void OLED_WR_Byte(u8 dat,u8 cmd)
{
if(cmd)
{
IIC_Write_Date(dat);
}
else {
IIC_Write_Command(dat);
}
}
/********************************************
// fill_Picture
********************************************/
void fill_picture(u8 fill_Data)
{
u8 m,n;
for(m=0;m<8;m++)
{
OLED_WR_Byte(0xb0+m,0); //page0-page1
OLED_WR_Byte(0x00,0); //low column start address
OLED_WR_Byte(0x10,0); //high column start address
for(n=0;n<128;n++)
{
OLED_WR_Byte(fill_Data,1);
}
}
}
//坐标设置
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),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 (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
void OLED_On(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{
u8 c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1){x=0;y=y+2;}
if(Char_Size ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else {
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
}
//m^n函数
u16 oled_pow(u8 m,u8 n)
{
u16 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size2)
{
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+(size2/2)*t,y,' ',size2);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
u8 j=0;
while (chr[j]!='\0')
{
OLED_ShowChar(x,y,chr[j],Char_Size);
x+=8;
if(x>120){x=0;y+=2;}
j++;
}
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{
u8 t;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[no][t],OLED_DATA);
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[no][t+16],OLED_DATA);
}
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
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);
}
}
}
//初始化SSD1306
void OLED_Init(void)
{
OLED_WR_Byte(0xAE,OLED_CMD);//Set Display ON/OFF 关闭显示
OLED_WR_Byte(0x40,OLED_CMD);//Set Display Start Line
OLED_WR_Byte(0xB0,OLED_CMD);//Set Page Start Address for Page Addressing Mode
OLED_WR_Byte(0xC8,OLED_CMD);//重映射模式
OLED_WR_Byte(0x81,OLED_CMD);//设置对比度
OLED_WR_Byte(0xFF,OLED_CMD);
OLED_WR_Byte(0xA1,OLED_CMD);//垂直寻址方式
OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
OLED_WR_Byte(0xA8,OLED_CMD);//设置驱动路数
OLED_WR_Byte(0x1F,OLED_CMD);
OLED_WR_Byte(0xD3,OLED_CMD);//Set Display Offset 设置垂直移位0d~63d
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0xD5,OLED_CMD);//Set Display Clock Divide Ratio/ Oscillator Frequency
OLED_WR_Byte(0xF0,OLED_CMD);
OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-charge Period
OLED_WR_Byte(0x22,OLED_CMD);//Set Page Address
OLED_WR_Byte(0xDA,OLED_CMD);//设置COM引脚硬件配置
OLED_WR_Byte(0x02,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//调整VCOMH调节器输出
OLED_WR_Byte(0x49,OLED_CMD);
OLED_WR_Byte(0x8D,OLED_CMD);
OLED_WR_Byte(0x14,OLED_CMD);
OLED_WR_Byte(0xAF,OLED_CMD);//Set Display ON/OFF 打开显示
OLED_Clear();
}
关于字体文件和图片数据文件这里不贴代码了。关于其他的显示代码也不写了,网上很多。
5.main.c文件
#include "stc15.h"
#include "delay.h"
#include "oled.h"
#include "bmp.h"
int main(void)
{
OLED_Init();//初始化OLED
OLED_Clear() ;
while(1)
{
OLED_ShowCHinese(0,0,0);//小
OLED_ShowCHinese(18,0,1);//猿
OLED_ShowCHinese(36,0,2);//猪
OLED_ShowCHinese(54,0,3);//哥
}
}
四、显示效果
? ? ?
?
?
|