STM32 OLED屏的使用
//-----------------OLED端口预定义----------------
#define OLED_SCL_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_0) //CLK SCL 置0
#define OLED_SCL_Set() GPIO_SetBits(GPIOA,GPIO_Pin_0)
#define OLED_SDA_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_1) //MOSI SDA 置0
#define OLED_SDA_Set() GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define OLED_RES_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_2) //RES 复位 置0
#define OLED_RES_Set() GPIO_SetBits(GPIOA,GPIO_Pin_2)
#define OLED_DC_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_3) //DC 数据/命令选择 置0
#define OLED_DC_Set() GPIO_SetBits(GPIOA,GPIO_Pin_3)
#define OLED_CS_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_4) //CS 片选 置0
#define OLED_CS_Set() GPIO_SetBits(GPIOA,GPIO_Pin_4)
//使用STM32 的PA0、PA1、PA2、PA3、PA4的IO口
//OLED模块只支持向模块写数据不能读数据,所以只需要写SPI发送 MOSI SDA即可
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
//*** 自定义的 24*24 ASICII字库 ******************************************************
const unsigned char asc2_2412[ ][36]={
{0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,
0x00,0x01,0xFF,0xFE,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x18,0x0E,0x07,0x01,0x00},// "0" 0
{0x00,0x00,0x80,0x80,0x80,0xC0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00},// "1" 1
{0x00,0x80,0x40,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0x03,0x03,0x00,0x80,0x40,0x20,
0x38,0x1F,0x07,0x00,0x00,0x00,0x1C,0x1A,0x19,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00},//"2" 2
{0x00,0x00,0x00,0x00,0x80,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7C,0x43,0x40,0x47,
0x7F,0xF8,0x80,0x00,0x00,0x10,0x18,0x1F,0x10,0x00,0x00,0x00,0x00,0x13,0x1F,0x1C,0x10}, //"A" 4
{0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFF,0xFF,0x10,0x10,0x10,0x10,
0x18,0x2F,0xE7,0x80,0x00,0x10,0x1F,0x1F,0x10,0x10,0x10,0x10,0x10,0x18,0x0F,0x07,0x00},//"B" 5
{0x00,0x00,0x80,0xC0,0x40,0x20,0x20,0x20,0x20,0x60,0xE0,0x00,0x00,0xFC,0xFF,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x10,0x08,0x04,0x03,0x00},//"C" 6
}
//**** 自定义的汉字库Hzk [ ][32] *****************************
//字库代码用取模软件 PCtoLCD等生成字母、汉字、图片等生成。
const unsigned char Hzk [ ][32] = {
{0x00,0x80,0x60,0xF8,0x07,0x40,0x20,0x18,0x0F,0x08,0xC8,0x08,0x08,0x28,0x18,0x00,0x01,0x00,0x00,
0xFF,0x00,0x10,0x0C,0x03,0x40,0x80,0x7F,0x00,0x01,0x06,0x18,0x00}, //"你" 0
{0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x80,0x82,0x82,0xE2,0x92,0x8A,0x86,0x80,0x00,0x40,0x22,0x15,
0x08,0x16,0x61,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00}, //"好" 1
}
//***************************************************************************************************
//*** OLED的初始化 *****************************************************************************
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能A端口时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_15);
//初始IO置1
OLED_RES_Clr(); //复位拉低
delay_ms(200); //延时
OLED_RES_Set(); //复位结束拉高
OLED_WR_Byte(0xAE,OLED_CMD); //亮屏灭屏指令 OFF/ON: AE/AF)
OLED_WR_Byte(0x00,OLED_CMD); //设起始列地址指令,用8位中低4位
OLED_WR_Byte(0x10,OLED_CMD); //设起始列地址指令,用8位中高4位
OLED_WR_Byte(0x40,OLED_CMD); //设起始行地址指令
OLED_WR_Byte(0x81,OLED_CMD); // 81对比度设置指令,接着发送一个值来设置
OLED_WR_Byte(0xCF,OLED_CMD); // 屏幕对比度值(0X00--0XFF),FF最大
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(0xA8,OLED_CMD); //设置驱动路数指令 (1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD); // 默认0X3F(1/64) duty
OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移指令 (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD); //-00 不偏移
OLED_WR_Byte(0xd5,OLED_CMD); //设置时钟分频因子,震荡频率指令
OLED_WR_Byte(0x80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率t Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期指令,下面跟值
OLED_WR_Byte(0xF1,OLED_CMD); //预充15时钟/放电1时钟 [3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置 下面跟值
OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率指令,下面跟值
OLED_WR_Byte(0x40,OLED_CMD); //40 Deselect Level,[6:4] 000,0.65*vcc;001,011,0.83*vcc;
OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式 (0x00/0x01/0x02) 下面跟值
OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00/列地址模式,01/行地址模式,10/页地址模式,默认10;
OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵的指令,下面跟值
OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭(0为关闭,1为开启)(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启,bit0: 1/开启,0/关闭;(白屏/黑屏) (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD); //设置正常显示方式;bit0:0/A6,全屏黑底蓝字;反相显示bit0:1/A7,黑字蓝底
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD);// 亮屏
}
//***** 写字节函数 ****************************************************************************
void OLED_WR_Byte(u8 dat,u8 cmd) // 数据/命令标志, 0表示命令,1表示数据
{
u8 i;
if(cmd) //如果cmd=1,是命令
OLED_DC_Set(); //DC置1
else
OLED_DC_Clr(); //cmd=0,是数据DC置0
OLED_CS_Clr(); //CS置0 芯片使能
for(i=0;i<8;i++) //8位数据循环移位
{
OLED_SCL_Clr(); //SCL置0
if(dat&0x80) //数据和0x80与,判断数据最高位是否=1
OLED_SDA_Set(); //最高位=1,MOSI SDA输出1
else
OLED_SDA_Clr(); //最高位=0,MOSI SDA 输出0
OLED_SCL_Set(); //CLK置1
dat<<=1; //最高移位移走,次高位顶上
}
OLED_CS_Set(); //发送完毕,片选置1 失能
OLED_DC_Set(); //命令数据选择重置1
}
//*** 更新OLED显存 (1屏126*64点) ************************************************
void OLED_Refresh(void)
{
u8 i,n;
for(i=0;i<8;i++) //i为屏映射数组的行/页,上下共8页,每行/页8位*128位/列
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址,实际用该字节低3位 0-8页就够了
OLED_WR_Byte(0x00,OLED_CMD); //设置低8位,实际用该字节低4位 列起始地址
OLED_WR_Byte(0x10,OLED_CMD); //设置高8位,实际用该字节高4位 0-127列就够了
for(n=0;n<128;n++) //n为屏映射数组的列,左右共128列,1行1列是8位
// for(n=0;n<130;n++) //屏边框亮条可修改此值
OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); //OLED_DATA预定义为1/数据
} //用i页n列取屏映射数组GRAM内对应的数据,该数据刷OLED对应的点
} //OLED收到数据刷新屏幕对应点后,按设置的刷新模式(页地址模式),
//OLED行不动列地址自动加1,等待再次接收数据。
//*** 清屏函数 ****************************************************************************************************
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; //输入的Y坐标要除以8,以定位到要改变的那个点的相应字节,因为是以字节形式来写入的
m=y%8; // 该点在该字节中的位置
n=1<<m; //屏坐标和数组是上下相反,要把该点y坐标左移写入n
if(t)
{OLED_GRAM[x][i]|=n;} //t=1,就把该点写1
else
{
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
OLED_GRAM[x][i]|=n;
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
}
}
//*** 在指定位置显示一个字符,包括部分字符 ***********************************************
//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;
}
}