目录
一、介绍
二、模块原理
1.原理图
2.工作原理:SSD1306显存与命令
三、程序设计
main.c文件
oled.h文件
oled.c文件
四、实验效果
五、资料获取
项目分享
一、介绍
OLED是有机发光二极管,又称为有机电激光显示(Organic Electroluminescence Display, OLED)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术
以下是OLED显示屏的参数:
尺寸 | 0.96寸 |
模块电压 | DC:3~5V |
分辨率 | 128×64 |
驱动 | SSD1306 |
管脚数 | 4针 |
接口 | IIC |
工作温度 | -20℃~70℃ |
哔哩哔哩视频链接:
https://www.bilibili.com/video/BV17Z421K7vV/?share_source=copy_web&vd_source=097fdeaf6b6ecfed8a9ff7119c32faf2
(资料分享见文末)
二、模块原理
1.原理图
以下为OLED显示屏的引脚描述
引脚名称 | 描述 |
VCC | 供给电压3~5V |
SCL | I2C总线时钟线 |
SDA | I2C总线数据线 |
GND | 电源地 |
2.工作原理:SSD1306显存与命令
SSD1306的显存总共为128*64bit大小,其将这些显存分为了8页。每页包含了128个字节,总共8页,这样刚好是128*64的点阵大小。
- 命令 0X81 : 设置对比度 。 包含两个字节,第一个 0X81 为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
- 命令0XAE/0XAF : 0XAE 为关闭显示命令; 0XAF 为开启显示命令。
- 命令0XB0~B7 : 用于设置页地址,其低三位的值对应着 GRAM 的页地址。
- 命令0X00~0X0F : 用于设置显示时的起始列地址低四位。
- 命令0X10~0X1F : 用于设置显示时的起始列地址高四位。
三、程序设计
使用STM32F103C8T6将中英文字符、数字和图片显示在OLED显示屏上
main.c文件
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "dht11.h"
#include "oled.h"
#include "bmp.h"/*****************辰哥单片机设计******************STM32* 项目 : OLED显示屏实验 * 版本 : V1.0* 日期 : 2024.8.7* MCU : STM32F103C8T6* 接口 : 参看oled.h * BILIBILI : 辰哥单片机设计* CSDN : 辰哥单片机设计* 作者 : 辰哥 **********************BEGIN***********************/int main(void)
{ SystemInit();//配置系统时钟为72M delay_init(72);LED_Init();LED_On();USART1_Config();//串口初始化OLED_Init();printf("Start \n");delay_ms(1000);//OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode) //x,y:起点坐标 num:汉字对应的序号 mode:0,反色显示;1,正常显示OLED_ShowChinese(0,32,0,16,1); //你OLED_ShowChinese(32,32,1,16,1);//好OLED_ShowChinese(64,32,2,16,1);//世OLED_ShowChinese(96,32,3,16,1);//界//OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode);//x,y:起点坐标 size1:字体大小 *chr:字符串起始地址 mode:0,反色显示;1,正常显示//OLED_ShowString(0,16,"HELLO WORLD!",16,1);//OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode);//x,y :起点坐标 num :要显示的数字 len :数字的位数 size:字体大小 mode:0,反色显示;1,正常显示//OLED_ShowNum(0,32,666,3,24,1);//OLED_Clear();//OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode)//x,y:起点坐标 sizex,sizey,图片长宽 BMP[]:要写入的图片数组 mode:0,反色显示;1,正常显示
// OLED_ShowPicture(0,0,128,64,BMP4,0);while (1){LED_Toggle();delay_ms(500);}
}
oled.h文件
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#include "stdlib.h" /*****************辰哥单片机设计******************STM32* 文件 : OLED显示屏h文件 * 版本 : V1.0* 日期 : 2024.8.7* MCU : STM32F103C8T6* 接口 : 见代码 * BILIBILI : 辰哥单片机设计* CSDN : 辰哥单片机设计* 作者 : 辰哥 **********************BEGIN***********************///----------------OLED端口定义-----------------
/***************根据自己需求更改****************/
#define OLED_SCL_PROT GPIOB
#define OLED_SCL_PIN GPIO_Pin_11
#define OLED_SCL_GPIO_CLK RCC_APB2Periph_GPIOB
#define OLED_SDA_PROT GPIOB
#define OLED_SDA_PIN GPIO_Pin_10
#define OLED_SDA_GPIO_CLK RCC_APB2Periph_GPIOB
/*********************END**********************/#define OLED_SCL_Clr() GPIO_ResetBits(OLED_SCL_PROT,OLED_SCL_PIN)//SCL
#define OLED_SCL_Set() GPIO_SetBits(OLED_SCL_PROT,OLED_SCL_PIN)#define OLED_SDA_Clr() GPIO_ResetBits(OLED_SDA_PROT,OLED_SDA_PIN)//DIN
#define OLED_SDA_Set() GPIO_SetBits(OLED_SDA_PROT,OLED_SDA_PIN)#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据void OLED_ClearPoint(u8 x,u8 y);
void OLED_ColorTurn(u8 i);
void OLED_DisplayTurn(u8 i);
void OLED_I2C_Start(void);
void OLED_I2C_Stop(void);
void OLED_I2C_WaitAck(void);
void OLED_Send_Byte(u8 dat);
void OLED_WR_Byte(u8 dat,u8 mode);
void OLED_DisPlay_On(void);
void OLED_DisPlay_Off(void);
void OLED_Refresh(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2,u8 mode);
void OLED_DrawCircle(u8 x,u8 y,u8 r);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1,u8 mode);
void OLED_ShowChar6x8(u8 x,u8 y,u8 chr,u8 mode);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode);
void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode);
void OLED_ScrollDisplay(u8 num,u8 space,u8 mode);
void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode);
void OLED_Init(void);#endif
oled.c文件
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"/*****************辰哥单片机设计******************STM32* 文件 : OLED显示屏c文件 * 版本 : V1.0* 日期 : 2024.8.7* MCU : STM32F103C8T6* 接口 : 见代码 * BILIBILI : 辰哥单片机设计* CSDN : 辰哥单片机设计* 作者 : 辰哥 **********************BEGIN***********************/u8 OLED_GRAM[144][8];//反显函数
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 OLED_I2C_Start(void)
{OLED_SDA_Set();OLED_SCL_Set();IIC_delay();OLED_SDA_Clr();IIC_delay();OLED_SCL_Clr();IIC_delay();
}//结束信号
void OLED_I2C_Stop(void)
{OLED_SDA_Clr();OLED_SCL_Set();IIC_delay();OLED_SDA_Set();
}//等待信号响应
void OLED_I2C_WaitAck(void) //测数据信号的电平
{OLED_SDA_Set();IIC_delay();OLED_SCL_Set();IIC_delay();OLED_SCL_Clr();IIC_delay();
}//写入一个字节
void OLED_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)
{OLED_I2C_Start();OLED_Send_Byte(0x78);OLED_I2C_WaitAck();if(mode){OLED_Send_Byte(0x40);}else{OLED_Send_Byte(0x00);}OLED_I2C_WaitAck();OLED_Send_Byte(dat);OLED_I2C_WaitAck();OLED_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); //设置高列起始地址OLED_I2C_Start();OLED_Send_Byte(0x78);OLED_I2C_WaitAck();OLED_Send_Byte(0x40);OLED_I2C_WaitAck();for(n=0;n<128;n++){OLED_Send_Byte(OLED_GRAM[n][i]);OLED_I2C_WaitAck();}OLED_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];}
// OLED_Refresh();
}//画线
//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;}}
// OLED_Refresh();
}
//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--;}}
// OLED_Refresh();
}//在指定位置显示一个字符,包括部分字符
//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;}OLED_Refresh();
}//显示字符串
//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++;}OLED_Refresh();
}//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);}}OLED_Refresh();
}//显示汉字
//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;}OLED_Refresh();
}//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_Refresh();
}
//OLED的初始化
void OLED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(OLED_SCL_GPIO_CLK|OLED_SDA_GPIO_CLK, ENABLE); //使能A端口时钟GPIO_InitStructure.GPIO_Pin = OLED_SCL_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHzGPIO_Init(OLED_SCL_PROT, &GPIO_InitStructure); //初始化PA0,1GPIO_SetBits(OLED_SCL_PROT,OLED_SCL_PIN);GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN; GPIO_Init(OLED_SDA_PROT, &GPIO_InitStructure); //初始化PA0,1GPIO_SetBits(OLED_SDA_PROT,OLED_SDA_PIN);delay_ms(200);OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel 关闭显示OLED_WR_Byte(0x00,OLED_CMD);//---set low column addressOLED_WR_Byte(0x10,OLED_CMD);//---set high column addressOLED_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 registerOLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current BrightnessOLED_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 displayOLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64) 设置驱动路数OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 dutyOLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)OLED_WR_Byte(0x00,OLED_CMD);//-not offsetOLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequencyOLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/SecOLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge periodOLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 ClockOLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configurationOLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomhOLED_WR_Byte(0x30,OLED_CMD);//Set VCOM Deselect LevelOLED_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/disableOLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disableOLED_Clear();OLED_WR_Byte(0xAF,OLED_CMD);
}